# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Commands ```bash # 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) ```bash 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 site** — `app/[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 workspace** — `app/_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/.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.