# AI Coding Starter Kit Next.js-Vorlage mit einem durchgängigen KI-Workflow für [Claude Code](https://docs.anthropic.com/en/docs/claude-code). Neun Skills führen von der Idee bis zum laufenden Deployment. Jede Phase schreibt ihr Ergebnis in die Feature-Spec — der Projektstand liegt in Dateien, nicht im Chatverlauf. Genau das macht die Vorlage fürs Vibe-Coden brauchbar: Du musst dich nicht erinnern, wo du stehst. `/help` liest es aus den Dateien ab, und nach einem Kontextverlust liest sich jede Skill selbst wieder ein. --- ## Inhalt - [Schnellstart](#schnellstart) - [Der Workflow im Überblick](#der-workflow-im-überblick) - [Die neun Skills](#die-neun-skills) - [Die vier Sub-Agents](#die-vier-sub-agents) - [Die vier Rules](#die-vier-rules) - [Kontext-Ebenen](#kontext-ebenen) - [Das Feature-System](#das-feature-system) - [Tech-Stack](#tech-stack) - [Authentifizierung: Passkeys](#authentifizierung-passkeys) - [Tests](#tests) - [Deployment](#deployment) - [Kommandos](#kommandos) - [Dateibaum](#dateibaum) - [Stolperfallen](#stolperfallen) - [Anpassen](#anpassen) --- ## Schnellstart ```bash git clone mein-projekt cd mein-projekt npm install cp .env.example .env npx playwright install chromium # einmalig pro Rechner, für E2E-Tests npm run dev ``` Dann in Claude Code: ``` /init Ich will eine Aufgabenverwaltung für kleine Teams bauen ``` --- ## Der Workflow im Überblick ```mermaid flowchart LR subgraph P["Planung — inline mit dir im Gespräch"] direction LR INIT["/init
PRD + Feature-Map"] SPEC["/write-spec
User Stories, AC"] ARCH["/architecture
Tech Design"] end subgraph B["Bauen — delegiert an Sub-Agents"] direction LR FE["/frontend
UI"] BE["/backend
API + Daten"] QA["/qa
Tests + Audit"] end DEP["/deploy
Docker-Stack"] INIT --> SPEC --> ARCH --> FE FE -->|"braucht Server"| BE --> QA FE -->|"nur Frontend"| QA QA -->|"keine Critical/High"| DEP QA -.->|"Bugs gefunden"| FE QA -.->|"Bugs gefunden"| BE REF["/refine PROJ-X"] -.->|"Spec überarbeiten"| SPEC HELP["/help"] -.->|"Wo stehe ich?"| P ``` Übergaben sind **immer** von dir ausgelöst. Keine Skill springt selbstständig weiter, jede endet mit einem Freigabe-Checkpoint. ### Das Grill-Me-Prinzip `/init`, `/write-spec` und `/refine` interviewen nach denselben Regeln: - Eine Frage pro Runde, niemals eine Liste - Immer mit einer Empfehlung — du bestätigst oder korrigierst - Dem Gespräch folgen statt einem Skript - Erst im Code nachsehen, dann fragen - Kein Fragenlimit: Schluss ist, wenn es verstanden ist --- ## Die neun Skills | # | Skill | Argument | Liest | Schreibt | Ausführung | |---|-------|----------|-------|----------|------------| | 1 | **`/init`** | Beschreibung der Idee | PRD, INDEX | `docs/PRD.md`, `features/INDEX.md`, ggf. `docs/design-system.md` | inline | | 2 | **`/write-spec`** | Feature-Name oder `PROJ-X` | PRD, INDEX, Code | `features/PROJ-X-name.md`, INDEX, PRD | inline | | 3 | **`/refine`** | `PROJ-X` | Spec, INDEX, PRD | Spec, INDEX, PRD | inline | | 4 | **`/architecture`** | `PROJ-X` | Spec, PRD, Code | Tech Design + Entscheidungslog in der Spec | inline | | 5 | **`/frontend`** | `PROJ-X` | Spec, `components/ui/`, Design-System | Komponenten, Seiten, Spec-Notizen | → Sub-Agent | | 6 | **`/backend`** | `PROJ-X` | Spec, `app/api/`, `lib/` | Route Handler, Schema, Tests, `.env.example` | → Sub-Agent | | 7 | **`/qa`** | `PROJ-X` | Spec, INDEX, Git-Log | QA-Abschnitt in der Spec, Unit- und E2E-Tests | → Sub-Agent | | 8 | **`/deploy`** | `PROJ-X` | Spec (QA-Teil), INDEX | Deployment-Abschnitt, Git-Tag | inline | | 9 | **`/help`** | optionale Frage | PRD, INDEX, Specs, Code | nichts | inline | ### Was jede Skill konkret tut
/init Einmalig pro Projekt. Interviewt dich zu Problem, Zielgruppe, MVP-Umfang, Alternativen, Rahmenbedingungen, Erfolgsmetriken und Nicht-Zielen. Klärt verbindlich drei Dinge, bevor die Feature-Map entsteht: Braucht es dauerhafte Speicherung? Braucht es Nutzerkonten (dann wird „Auth-Grundlage" automatisch PROJ-1)? Gibt es ein Design-System? Legt danach PRD und priorisierte Feature-Map an — aber keine Spec-Dateien.
/write-spec Macht aus einer Feature-Idee eine testbare Spec. Drei Einstiege: Feature steht schon als „Roadmap" im INDEX, Feature fehlt dort noch (wird ergänzt), oder es hat bereits eine Spec (verweist auf /refine). Füllt neben User Stories und Acceptance Criteria auch Out of Scope, Produkt-Entscheidungen und Offene Fragen.
/refine Öffnet eine bestehende Spec. Fragt zuerst „Was bringt dich zurück zu dieser Spec?" und wählt danach den Pfad: 1) Scope hat sich geändert, 2) die Umsetzung hat eine Lücke aufgedeckt, 3) das Feature gehört grundsätzlich hinterfragt — bis hin zum Aufsplitten in zwei Specs. Schließt erledigte Offene Fragen mit Datum.
/architecture Übersetzt die Spec in ein Design, das auch ohne Technikhintergrund lesbar ist: Komponentenbaum, Datenmodell in Worten, begründete Tech-Entscheidungen, Paketliste. Schreibt bewusst keinen Code — kein SQL, kein TypeScript. Trifft hier die Datenbank-Entscheidung, die die Vorlage offenlässt.
/frontend Klärt Designfragen mit dir (oder liest docs/design-system.md), setzt den Status auf „In Progress" und übergibt an den Frontend-Sub-Agent. Präsentiert dessen Bericht, holt dein Urteil im Browser ein und iteriert im selben Sub-Agent-Kontext weiter.
/backend Klärt Rechte, Nebenläufigkeit, Validierung und Rate-Limiting, dann Übergabe an den Backend-Sub-Agent. Stoppt, wenn im Tech Design noch kein Daten-Layer steht — die Entscheidung gehört zu /architecture, nicht hierher.
/qa Setzt „In Review", übergibt an den QA-Sub-Agent, schreibt dessen Ergebnis als QA-Abschnitt in die Spec und priorisiert die Bugs mit dir. Setzt bei sauberem Lauf „Approved", sonst bleibt „In Review".
/deploy Blockiert ohne QA-Abschnitt oder bei offenen Critical/High-Bugs. Fährt Lint, Typecheck, Test und Build als Pre-Flight, führt beim ersten Mal durch die Servereinrichtung und danach durch ./scripts/update.sh. Setzt Status, Tag und Deployment-Notiz.
/help Liest PRD, INDEX und Spec-Abschnitte und sagt dir, wo das Projekt steht und was als Nächstes dran ist — mit dem exakten Kommando. Widersprechen sich Dateien und Status-Spalte, gewinnen die Dateien und es sagt dir das.
--- ## Die vier Sub-Agents `/frontend`, `/backend` und `/qa` führen Interview und Review mit dir im Hauptgespräch und geben die eigentliche Dateiarbeit ab. Der Sub-Agent arbeitet in eigenem Kontext und liefert einen kompakten Bericht zurück statt der vollen Erzählung. ```mermaid sequenceDiagram actor Du participant S as Skill
(Hauptgespräch) participant A as Sub-Agent
(eigener Kontext) participant F as Dateien Du->>S: /frontend PROJ-3 S->>F: Spec + INDEX lesen S->>Du: Designfragen, je eine mit Empfehlung Du-->>S: Antworten S->>F: Status → In Progress S->>A: Auftrag: Spec, Designentscheidungen,
Komponentenliste A->>F: Komponenten schreiben,
lint / typecheck / build A-->>S: Bericht: Dateien, Abweichungen,
offene Fragen S->>Du: Bericht + "Schau es dir an" Du-->>S: Feedback S->>A: Nachbesserung (gleicher Kontext) S->>F: Spec-Notizen + Status S->>Du: Handoff → /backend oder /qa ``` | Agent | Datei | Werkzeuge | Aufgabe | Hard Rule | |-------|-------|-----------|---------|-----------| | **Frontend Developer** | `.claude/agents/frontend-dev.md` | Read, Write, Edit, Bash, Glob, Grep | UI umsetzen | shadcn vor Eigenbau; Lint, Typecheck und Build müssen grün sein | | **Backend Developer** | `.claude/agents/backend-dev.md` | Read, Write, Edit, Bash, Glob, Grep | Routen, Daten, Auth | **Stoppt und meldet zurück**, wenn der Daten-Layer noch nicht entschieden ist | | **QA Engineer** | `.claude/agents/qa-engineer.md` | Read, Write, Edit, Bash, Glob, Grep | Funktion gegen die Spec testen | **Behebt niemals selbst einen Bug**. Spricht **nicht** über Sicherheit | | **Security Auditor** | `.claude/agents/security-auditor.md` | Read, Grep, Glob, Bash — **kein Write/Edit** | Sicherheit, adversarial | Hat ein **Veto** über `/deploy`. Findet er Critical oder High: BLOCK | Keiner der vier fasst `features/INDEX.md` an. Tracking gehört der aufrufenden Skill — so kann es keine zwei Wahrheiten über den Status geben. ### Der Skeptiker `/qa` startet **zwei** Agenten parallel, weil sie verschiedene Fragen beantworten: *Tut es, was die Spec verspricht?* und *Ist es sicher genug fürs offene Internet?* Das ist bewusst getrennt. Derselbe Agent, der „Produktionsreif: JA" empfehlen will, sollte nicht auch über Sicherheit urteilen — er hat ein Motiv, grün zu melden. Und als Unterpunkt neben Acceptance Criteria, Regression und Testschreiben fällt Security bei knappem Kontext zuerst hinten runter. Der Security Auditor arbeitet nach drei Prinzipien: - **Unsicher bis zum Beweis des Gegenteils.** Eine plausible Erklärung zählt nicht; er muss die Kontrolle im Code gesehen haben und Datei plus Zeile nennen können. - **Drei Verdikte, Schweigen ist keines davon:** PASS, FAIL oder **UNGEPRÜFT**. Was er nicht prüfen konnte, steht als UNGEPRÜFT in der Spec — ein Audit, das Ungeprüftes weglässt, liest sich wie Entwarnung und ist schlimmer als keins. - **Kein Write- oder Edit-Werkzeug.** Er *kann* nicht beheben, was er findet. Damit ist „niemals selbst fixen" strukturell erzwungen statt nur angewiesen — er kann einen Befund nicht still wegpatchen. Seine Checkliste ist `.claude/rules/security.md`, also derselbe Standard, an den sich die Entwickler-Agenten halten müssen. Jeder Pflichtpunkt darin braucht ein Verdikt. ```mermaid flowchart TB QA["/qa PROJ-X"] --> A["QA Engineer
Tut es, was die Spec verspricht?"] QA --> B["Security Auditor
Ist es sicher fürs offene Internet?"] A --> AV{"Critical oder
High Bugs?"} B --> BV{"Verdikt"} AV -->|ja| R["Status bleibt
In Review"] BV -->|"BLOCK"| R AV -->|nein| G((" ")) BV -->|"PASS"| G G --> OK["Status Approved
→ /deploy"] R --> FIX["/frontend oder /backend
beheben, dann erneut /qa"] style B stroke-width:3px style R stroke-width:3px ``` Beide müssen grün sein. Ein sauberer Funktionstest hebt ein `BLOCK` nicht auf, und `/deploy` verweigert den Start, wenn das Security-Verdikt fehlt oder blockiert. --- ## Die vier Rules Rules laden sich automatisch, sobald passende Dateien bearbeitet werden. Du musst sie nie manuell erwähnen. | Datei | Greift bei | Inhalt | |-------|-----------|--------| | **`general.md`** | immer aktiv | Feature-Tracking, Status-Flow, Commit-Format, „erst lesen, dann ändern", Write-then-Verify, Human-in-the-Loop, Sprachregel | | **`frontend.md`** | `src/components/**`
`src/app/**/page.tsx`
`src/app/**/layout.tsx`
`src/hooks/**` | shadcn-Pflicht, Tailwind-v4-Eigenheiten, semantische Tokens, Server Components, Loading/Error/Empty, Formulare | | **`backend.md`** | `src/app/api/**`
`src/lib/**`
`src/server/**`
`drizzle/**`, `prisma/**` | Kein vorgewählter Daten-Layer, Zod-Validierung, Statuscodes, Ownership im Query statt danach, Indizes, Migrationen, Secrets | | **`security.md`** | API-Routen, `src/lib/auth*`
`.env*`, `next.config.*`
`Dockerfile`, `compose.yaml` | Passkey-Standard, Autorisierung pro Ressource, Secrets, Security-Header, genehmigungspflichtige Änderungen | --- ## Kontext-Ebenen Nicht alles wird gleichzeitig geladen — das ist der Grund, warum lange Sessions nicht zerfasern. ```mermaid flowchart TB subgraph AUTO["Automatisch"] CM["CLAUDE.md
jede Session"] RU[".claude/rules/
sobald passende Dateien
bearbeitet werden"] end subgraph DEMAND["Auf Abruf"] SK[".claude/skills/
beim /kommando"] AG[".claude/agents/
wenn eine Skill delegiert"] SP["features/PROJ-X.md
wenn die Skill sie liest"] DOC["docs/DEPLOYMENT.md
nur wenn referenziert"] end CM --> SK RU --> SK SK --> AG SK --> SP AG --> SP ``` **Zustand liegt in Dateien, nicht im Gespräch.** Wird der Kontext komprimiert, liest die Skill Spec und `git diff` neu ein und macht weiter — ohne Arbeit zu wiederholen oder doppelt zu bauen. --- ## Das Feature-System Alles läuft über `features/INDEX.md` und eine Spec-Datei pro Feature (`features/PROJ-X-name.md`). Ein Feature = eine testbare, deploybare Einheit. ```mermaid stateDiagram-v2 [*] --> Roadmap: /init Roadmap --> Planned: /write-spec Planned --> Architected: /architecture Architected --> InProgress: /frontend
/backend InProgress --> InReview: /qa startet InReview --> Approved: keine Critical/High InReview --> InProgress: Bugs beheben Approved --> Deployed: /deploy Deployed --> [*] Planned --> Planned: /refine Architected --> Architected: /refine ``` ### Aufbau einer Spec Eine Spec wächst über die Phasen hinweg. Vorlage: `.claude/skills/write-spec/template.md` | Abschnitt | Gefüllt von | Wozu | |-----------|-------------|------| | Abhängigkeiten | `/write-spec` | Welche PROJ-X vorher fertig sein müssen | | User Stories | `/write-spec` | Als [Rolle] möchte ich [Aktion], um [Ziel] | | **Out of Scope** | `/write-spec` | Was bewusst *nicht* gebaut wird — sonst baut es der nächste Durchlauf nach | | Acceptance Criteria | `/write-spec` | Angenommen / Wenn / Dann, direkt abtestbar | | Edge Cases | `/write-spec` | Nebenläufigkeit, Netzfehler, leere Eingabe, Rechtegrenzen | | **Offene Fragen** | `/write-spec` | `- [ ]`, geschlossen in `/refine` mit Datum | | **Entscheidungslog** | `/write-spec` + `/architecture` | Produkt- und Tech-Entscheidungen mit Begründung | | Tech Design | `/architecture` | Komponentenbaum, Datenmodell, Abhängigkeiten | | QA Test Results | `/qa` | Kriterium für Kriterium, Bugs, Security, Urteil | | Deployment | `/deploy` | URL, Datum, Commit | Out of Scope und Entscheidungslog sind das Gedächtnis der Vorlage. ### Format der Acceptance Criteria ``` - [ ] Angenommen der Nutzer ist angemeldet, wenn er ein leeres Formular abschickt, dann erscheint pro Pflichtfeld eine Validierungsmeldung ``` **Sprache:** PRD, Specs und Acceptance Criteria auf Deutsch. Code, Kommentare, Commit-Messages und die Skill-Anweisungen selbst auf Englisch. --- ## Tech-Stack | Ebene | Wahl | Anmerkung | |-------|------|-----------| | Framework | Next.js 16, App Router | React 19, Server Components als Standard | | Sprache | TypeScript `strict` | `@/*` → `src/*` | | Styling | Tailwind CSS v4 | CSS-first, **keine `tailwind.config.ts`** | | Komponenten | shadcn/ui, Stil `new-york` | 6 vorinstalliert, Rest per CLI | | Icons | lucide-react | | | Formulare | react-hook-form + Zod | Zod-Schema gilt auch serverseitig | | Toasts | sonner | in `layout.tsx` gemountet | | Theming | next-themes | Dark Mode über `.dark` | | Auth | Better Auth + Passkey-Plugin | nur wenn das Projekt Anmeldung braucht | | Daten-Layer | **pro Projekt entschieden** | Vorlage bringt keinen mit | | Tests | Vitest + Playwright | strikt getrennte Scopes | | Betrieb | Docker Compose, selbst gehostet | App-Container, Proxy extern | ### Bewusst nicht enthalten - **Keine Datenbank, kein ORM.** `/architecture` entscheidet pro Projekt. Einzige Auflage: muss im Compose-Stack selbst hostbar sein. - **Kein Supabase, kein Vercel.** Nicht vergessen, sondern absichtlich ausgebaut. In `CLAUDE.md` steht das explizit, damit es nicht durch die Hintertür zurückkommt. - **Keine Content-Security-Policy vorkonfiguriert.** Geraten bricht sie Apps; pro Projekt mit `Report-Only` anfangen. - **Kein Error-Tracking vorinstalliert.** Sentry-Anleitung in `docs/DEPLOYMENT.md`. ### UI-Komponenten Sechs sind vorinstalliert: | Komponente | Wofür | |------------|-------| | `button` | Aktionen, Varianten über CVA | | `card` | Container mit Header/Content/Footer | | `input` | Textfelder | | `label` | Beschriftungen, barrierefrei verknüpft | | `form` | react-hook-form-Anbindung inkl. Fehlermeldungen | | `sonner` | Toaster, bereits in `layout.tsx` gemountet | Alles Weitere ist ein Kommando entfernt: ```bash npx shadcn@latest add dialog table tabs --yes ``` **Tailwind v4 ist CSS-first: es gibt keine `tailwind.config.ts`.** Theme-Tokens leben in `src/app/globals.css` unter `@theme inline`. Wer aus Gewohnheit eine Config-Datei anlegt, wundert sich, warum nichts greift. Nutze semantische Tokens (`bg-background`, `text-muted-foreground`) statt roher Palettenwerte (`bg-slate-900`) — sonst bricht der Dark Mode. --- ## Authentifizierung: Passkeys Sobald ein Projekt Anmeldung braucht, ist der Stack festgelegt: **Better Auth mit Passkey-Plugin**. Passkey ist der primäre Weg und wird zuerst angeboten; ein Passwort-Flow ist nur der Fallback für Geräte ohne WebAuthn. `/init` legt dafür automatisch „Auth-Grundlage" als **PROJ-1, P0** an. Jedes Feature, das angemeldete Nutzer braucht, hängt davon ab. Verbindlich, sobald Auth im Spiel ist: - Passkey-Registrierung wird bei der Anmeldung angeboten, nicht in den Einstellungen versteckt - Bestehende Passwort-Nutzer werden nach dem Login zum Passkey eingeladen - Passwort-Fallback ist rate-limited und verrät nie, ob ein Konto existiert - Produktion braucht HTTPS — localhost ist die einzige Ausnahme > **Die eine Sache, die dich sonst Stunden kostet:** Die WebAuthn-Relying-Party-ID > wird aus dem Hostnamen in `NEXT_PUBLIC_APP_URL` abgeleitet. Stimmt der nicht exakt > mit der ausgelieferten Domain überein, scheitern *alle* Passkeys — ohne verwertbare > Fehlermeldung. `/qa` prüft aktiv, dass der Passkey-Weg der primäre ist. Ein aufgeweichter oder fehlender Passkey-Flow gilt als **High**-Befund. --- ## Tests | Art | Ort | Kommando | Geschrieben von | |-----|-----|----------|-----------------| | Unit / Integration (Vitest) | neben der Quelle: `useThing.test.ts` neben `useThing.ts` | `npm test` | `/backend`, `/qa` | | E2E (Playwright) | `tests/PROJ-X-name.spec.ts` | `npm run test:e2e` | `/qa` | Die Läufe sind strikt getrennt: Vitest scannt ausschließlich `src/`, Playwright ausschließlich `tests/`. Zwei Smoke-Tests liegen als Muster bei und belegen, dass die Trennung greift. `/qa` schreibt für jedes bestandene Acceptance Criterion einen E2E-Test — daraus wächst die Regressions-Suite von selbst. **Port belegt?** `E2E_PORT=3177 npm run test:e2e`. Ohne das testet Playwright stillschweigend gegen einen fremden Server, der zufällig auf :3000 läuft. --- ## Deployment Selbst gehostet über Docker Compose. Der Stack veröffentlicht die App auf Loopback; ein Reverse Proxy auf dem Host terminiert TLS. ```mermaid flowchart LR U["Nutzer"] -->|HTTPS| P["Reverse Proxy
nginx / Caddy
auf dem Host"] P -->|"127.0.0.1:3000"| C["app-Container
Next.js standalone"] C --> H["/api/health"] subgraph SRV["Server"] P subgraph CMP["docker compose"] C H DB[("Datenbank
optional, pro Projekt")] end end C -.->|"nur wenn gewählt"| DB G["git repo"] -->|"./scripts/update.sh"| CMP style DB stroke-dasharray: 5 5 ``` ```bash docker compose up -d --build # Erststart ./scripts/update.sh # neuen Stand ausrollen ``` ### Nur der App-Port geht nach außen Im Stack veröffentlicht **ausschließlich der App-Service** einen Port, und auch den nur auf Loopback (`127.0.0.1`). Jeder weitere Service — Datenbank, Cache, Queue, Admin-UI — bekommt **keinen `ports:`-Eintrag**. Die Container erreichen sich über den Compose-Netzwerknamen, dafür muss nichts veröffentlicht werden: ``` DATABASE_URL=postgres://user:pass@db:5432/app ``` > `ports: "5432:5432"` bindet auf `0.0.0.0` — die Datenbank steht damit im offenen > Internet, geschützt nur durch ihr Passwort. Und Docker schreibt eigene > iptables-Regeln, die **ufw umgehen**: Der Server sieht abgeschottet aus, während > der Port offen ist. Das ist einer der häufigsten Wege, wie selbst gehostete Stacks > kompromittiert werden. Die Regel ist an vier Stellen verankert, damit sie beim Vibe-Coden nicht verloren geht: `rules/security.md` (lädt automatisch beim Bearbeiten von `compose.yaml`), der Backend-Sub-Agent, der QA-Sub-Agent (Verstoß = **Critical**) und der Pre-Flight von `/deploy`, der den Deploy abbricht. Prüfen, was wirklich gebunden ist: ```bash docker compose config | grep -B8 "published:" docker compose ps --format "{{.Service}}\t{{.Ports}}" ``` Zugriff zum Debuggen holst du dir per SSH-Tunnel, nicht per veröffentlichtem Port. ### Was `update.sh` macht ```mermaid flowchart TD A["Start"] --> B{"Arbeitsverzeichnis
sauber?"} B -->|nein| X["Abbruch"] B -->|ja| C["git fetch + fast-forward"] C --> D{"Neuer Commit
oder --force?"} D -->|nein| Y["Nichts zu tun"] D -->|ja| E["docker compose build"] E --> F["docker compose up -d"] F --> G{"Healthcheck
innerhalb 120s?"} G -->|ja| H["Alte Images aufräumen
✓ Deployed"] G -->|nein| I["Letzte 50 Logzeilen ausgeben"] I --> J["git reset auf Vorgänger-Commit"] J --> K["Neu bauen + starten"] K --> L["✓ Rollback"] ``` Ein kaputtes Deployment heilt sich selbst, statt die Seite liegen zu lassen. ```bash ./scripts/update.sh --force # neu bauen ohne neuen Commit ./scripts/update.sh --branch dev # anderen Branch ausrollen ``` Der Reverse Proxy muss `X-Forwarded-Proto` und `X-Forwarded-Host` durchreichen, sonst brechen Redirects und WebAuthn-Origin-Prüfungen. Fertige nginx- und Caddy-Blöcke sowie die Anleitung zum Nachrüsten einer Datenbank stehen in [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md). Security-Header (`X-Frame-Options`, `X-Content-Type-Options`, `Referrer-Policy`, `HSTS`) sind in `next.config.ts` gesetzt und nach dem Deploy im Browser gegenzuprüfen. --- ## Kommandos ```bash npm run dev # Dev-Server auf :3000 npm run build # Produktions-Build (standalone) npm run start # Produktions-Server lokal npm run lint # ESLint npm run typecheck # tsc --noEmit npm test # Vitest npm run test:watch # Vitest im Watch-Modus npm run test:e2e # Playwright npm run test:all # beide Suites npm run docker:up # Stack bauen und starten npm run docker:down # Stack stoppen npm run docker:logs # Logs folgen ``` --- ## Dateibaum ``` CLAUDE.md Wird jede Session geladen: Stack, Struktur, Konventionen README.md Dieses Dokument .claude/ settings.json Permissions: Deny für Secrets, Allow für Routine rules/ general.md Immer aktiv: Tracking, Status, Git, Human-in-the-Loop frontend.md Bei UI-Dateien backend.md Bei API-, lib- und Schema-Dateien security.md Bei API-, Auth-, Env- und Deploy-Dateien skills/ init/SKILL.md /init write-spec/SKILL.md /write-spec (+ template.md für neue Specs) refine/SKILL.md /refine architecture/SKILL.md /architecture frontend/SKILL.md /frontend backend/SKILL.md /backend qa/SKILL.md /qa deploy/SKILL.md /deploy help/SKILL.md /help agents/ frontend-dev.md Sub-Agent für UI backend-dev.md Sub-Agent für Server qa-engineer.md Sub-Agent für Funktionstests security-auditor.md Sub-Agent für Sicherheit — Veto über /deploy docs/ PRD.md Füllt /init im Interview DEPLOYMENT.md Docker-Betrieb, Proxy, DB nachrüsten, Troubleshooting features/ INDEX.md Zentrales Status-Tracking src/ app/ layout.tsx ThemeProvider + Toaster verdrahtet page.tsx Startseite mit Workflow-Übersicht globals.css Tailwind v4: Theme-Tokens in @theme inline api/health/route.ts Liveness-Probe für Docker und update.sh components/ theme-provider.tsx ui/ button, card, input, label, form, sonner lib/ utils.ts cn() utils.test.ts Vitest-Muster test/setup.ts tests/smoke.spec.ts Playwright-Muster scripts/update.sh Pull, Rebuild, Restart, Rollback Dockerfile Dreistufig → standalone, unprivilegierter User compose.yaml App-Service, Healthcheck, Log-Rotation .env.example Jede benötigte Variable mit Dummy-Wert .gitattributes Erzwingt LF — sonst scheitert update.sh auf dem Server .dockerignore .gitignore eslint.config.mjs next.config.ts playwright.config.ts postcss.config.mjs vitest.config.mts components.json tsconfig.json package.json ``` 56 Dateien im Repo. --- ## Stolperfallen Vier Dinge, die nicht offensichtlich sind und je einmal wehtun: | Fall | Was passiert | |------|--------------| | Ein DB-Service bekommt `ports: "5432:5432"` | Die Datenbank steht im offenen Internet — und Docker umgeht dabei ufw, der Server *wirkt* nur abgeschottet | | `NEXT_PUBLIC_APP_URL` weicht von der Domain ab | Alle Passkeys scheitern, ohne verwertbare Fehlermeldung | | Port 3000 ist von einem anderen Projekt belegt | Playwright testet still gegen den fremden Server — `E2E_PORT` setzen | | Jemand legt eine `tailwind.config.ts` an | Wird in v4 ignoriert; Tokens gehören in `globals.css` | | Checkout auf Windows ohne `.gitattributes` | `update.sh` bekommt CRLF und stirbt auf dem Server mit `bad interpreter` | --- ## Anpassen | Was | Wo | |-----|-----| | Stack, Konventionen, Kommandos | `CLAUDE.md` | | Coding-Standards | `.claude/rules/` | | Workflow-Schritte selbst | `.claude/skills/*/SKILL.md` | | Aufgabenteilung der Sub-Agents | `.claude/agents/` | | Permissions | `.claude/settings.json` | | Spec-Aufbau | `.claude/skills/write-spec/template.md` | Ein neues Kommando ist ein neuer Ordner unter `.claude/skills/` mit einer `SKILL.md` und `user-invocable: true` im Frontmatter. Ein neuer Sub-Agent ist eine Markdown-Datei in `.claude/agents/` mit `name`, `description`, `tools` im Frontmatter. --- ## Lizenz MIT