Files

6.7 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

# Development
npm run dev          # Start Next.js dev server
npm run build        # Build for production (--webpack flag applied in package.json)
npm run lint         # Run ESLint
npm run test         # Run all tests with Vitest
npx vitest run tests/some-file.test.ts  # Run a single test file

# Database
npm run prisma:generate   # Regenerate Prisma client after schema changes
npm run db:migrate        # Apply migrations (production)
npm run db:migrate:dev    # Create and apply dev migration
npm run db:seed           # Seed the database

Docker (production/staging)

make start       # Build and start all containers
make stop        # Stop containers
make deploy      # Pull + rebuild + restart
make logs        # Follow container logs
make db-init     # Generate client, apply migrations, and seed (first run)
make db-shell    # Open psql shell
make app-shell   # Open shell in app container
make health      # Hit /api/health via public URL

Architecture

This is a multilingual Next.js (App Router) portfolio site with an admin workspace. Stack: TypeScript, next-intl, Prisma + PostgreSQL, Tailwind CSS, Radix UI, framer-motion, nodemailer.

Routing overview

There are two applications sharing one Next.js instance:

Public siteapp/[locale]/(site)/ Localized routes for de, en, ar. Default locale is dynamic (stored in AppConfig), read at request time via /api/site/default-locale. Maintenance mode redirects visitors to /coming-soon.

Admin workspaceapp/_admin/ (canonical source) Accessed via a dedicated subdomain (root.mohfarawati.de) in production, or via the /root path prefix in development. The middleware rewrites both to app/admin-internal/. The app/root/ and app/admin-internal/ directories mirror app/_admin/ — treat app/_admin/ as the source of truth.

The full routing rewrite logic lives in lib/admin-routing.ts and middleware.ts.

i18n

  • Locales: de, en, ar — defined in i18n/routing.ts
  • Default locale is configurable at runtime via AppConfig (key: default_locale)
  • localePrefix: "as-needed" — default locale has no prefix in URLs
  • No locale cookie or browser detection; locale is set explicitly by user
  • Translation messages live in messages/{locale}.json

Persistence

Prisma client is in lib/prisma.ts. All DB access must go through server-side modules in lib/. Client components must never access Prisma.

AppConfig is a key-value table used for all runtime configuration: site settings, SMTP, marquee, maintenance mode, default locale. lib/app-config.ts is the aggregate entry point; individual settings are in lib/site-settings.ts, lib/mail-settings.ts, lib/marquee-settings.ts.

Module boundaries

  • lib/* — server-side application logic (queries, services, config)
  • components/ui/ — shared Radix UI primitives (design system base)
  • components/layout/, components/site/ — public site UI
  • components/admin/, components/dashboard/ — admin UI
  • Server actions (actions.ts files in page directories) are the entry points for form submissions; they call lib/* modules
  • Business logic must not live inside UI components

Key canonical files

Concern File
i18n routing i18n/routing.ts
Admin routing logic lib/admin-routing.ts
Middleware (routing + auth) middleware.ts
Prisma client lib/prisma.ts
AppConfig aggregate lib/app-config.ts
Portfolio queries lib/portfolio.ts
Media handling lib/media.ts
Contact flow lib/mail.ts

Documentation to read by task scope

  • Small UI/copy/style fixes: read only the relevant files
  • Feature changes: read specs/<feature>.md + docs/ARCHITECTURE.md if structure is affected
  • Cross-cutting/architecture changes: read docs/ARCHITECTURE.md, docs/DOMAIN_RULES.md, docs/FEATURES.md, and the relevant specs/ file

Update docs/ and specs/ only when the change affects feature scope, business rules, architecture, or public behavior.

Environment variables

Key variables (see .env.example for full list):

DATABASE_URL              PostgreSQL connection string
NEXT_PUBLIC_SITE_URL      Public site URL
NEXT_PUBLIC_ADMIN_URL     Admin subdomain URL
ADMIN_HOST                Admin hostname (used by middleware for host-based routing)
ADMIN_PASSWORD            In-app admin session password
ADMIN_AUTH_SECRET         JWT/cookie secret for admin session
ADMIN_BASIC_AUTH_USER     HTTP Basic Auth user (optional, adds middleware-level protection)
ADMIN_BASIC_AUTH_PASS     HTTP Basic Auth password
SITE_RUNTIME_ORIGIN       Internal origin for middleware to fetch runtime state (defaults to http://127.0.0.1:3000 in production)

Working rules

  • Tests are mandatory for every logic change, in the SAME change. New behaviour → new tests covering the intent (positive and negative cases), not one happy example. Deliberate change → update the affected tests and say which/why. A test that fails unexpectedly is a real bug → fix the code, not the test. Test the real thing — integration tests use a real (in-process PGlite) database, so do NOT mock our own lib//DB layer; only true external boundaries (the admin session, third-party APIs, SMTP) may be substituted. Keep the suite green (make test); the pre-push hook (.githooks/pre-push) enforces it. Frontend/UI is verified manually; add component tests only for components with real logic.
  • Before making any change, first explain the plan briefly and list the files that will be touched.
  • Make the smallest safe change that solves the task.
  • Do not modify unrelated files.
  • Preserve existing architecture, naming, and folder conventions.
  • Prefer server-side logic in lib/* and keep business logic out of UI components.
  • Never access Prisma from client components.
  • For admin-related changes, treat app/_admin/ as the canonical source of truth unless explicitly told otherwise.
  • Do not add new dependencies unless absolutely necessary and explicitly justified.
  • After code changes, run only the minimum relevant checks (for example: targeted test, lint on changed files, or build if necessary).
  • If a task may affect routing, auth, i18n, or runtime config, inspect middleware.ts, lib/admin-routing.ts, i18n/routing.ts, and the relevant lib/app-config.ts modules first.
  • For schema or database changes, inspect Prisma schema, migration flow, and seed impact before editing.
  • Ask before performing large refactors, file moves, destructive changes, or broad formatting changes.
  • When updating behavior, also update docs/specs if the change affects public behavior, business rules, or architecture.