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 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 ini18n/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 UIcomponents/admin/,components/dashboard/— admin UI- Server actions (
actions.tsfiles in page directories) are the entry points for form submissions; they calllib/*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.mdif structure is affected - Cross-cutting/architecture changes: read
docs/ARCHITECTURE.md,docs/DOMAIN_RULES.md,docs/FEATURES.md, and the relevantspecs/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); thepre-pushhook (.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 relevantlib/app-config.tsmodules 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.