- Move admin login lockout from client cookie to AppConfig (DB), keyed by hashed client IP — clearing browser cookies no longer bypasses it - Replace rate-limit $transaction (TOCTOU) with atomic SQL INSERT...ON CONFLICT...RETURNING; add stale-entry cleanup on each submission to prevent table bloat - Add 5 s module-level cache for middleware runtime state fetch, reducing per-request DB roundtrips - Rename middleware.ts → proxy.ts to resolve Next.js 16 deprecation warning; update test import accordingly - Require ADMIN_PASSWORD, ADMIN_AUTH_SECRET, ADMIN_BASIC_AUTH_USER, and ADMIN_BASIC_AUTH_PASS in docker-compose.yml (:? syntax) — startup fails loudly instead of using placeholder defaults - Add set -e and informative echo lines to Dockerfile CMD for clearer startup failure attribution - Export requireAdminAuth() from lib/admin-auth for centralised use in admin pages - Add CLAUDE.md with architecture notes and working rules Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
# 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, contact protection, 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/contact-protection.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/contact-guard.ts`, `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
|
||||
|
||||
- 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.
|
||||
Reference in New Issue
Block a user