26 KiB
Code Vorlage
Next.js-Vorlage mit einem durchgängigen KI-Workflow für 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
- Der Workflow im Überblick
- Die neun Skills
- Die vier Sub-Agents
- Die vier Rules
- Kontext-Ebenen
- Das Feature-System
- Tech-Stack
- Authentifizierung: Passkeys
- Tests
- Deployment
- Kommandos
- Dateibaum
- Stolperfallen
- Anpassen
Schnellstart
git clone <repo-url> 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
flowchart LR
subgraph P["Planung — inline mit dir im Gespräch"]
direction LR
INIT["/init<br/><i>PRD + Feature-Map</i>"]
SPEC["/write-spec<br/><i>User Stories, AC</i>"]
ARCH["/architecture<br/><i>Tech Design</i>"]
end
subgraph B["Bauen — delegiert an Sub-Agents"]
direction LR
FE["/frontend<br/><i>UI</i>"]
BE["/backend<br/><i>API + Daten</i>"]
QA["/qa<br/><i>Tests + Audit</i>"]
end
DEP["/deploy<br/><i>Docker-Stack</i>"]
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.
sequenceDiagram
actor Du
participant S as Skill<br/>(Hauptgespräch)
participant A as Sub-Agent<br/>(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,<br/>Komponentenliste
A->>F: Komponenten schreiben,<br/>lint / typecheck / build
A-->>S: Bericht: Dateien, Abweichungen,<br/>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.
flowchart TB
QA["/qa PROJ-X"] --> A["QA Engineer<br/><i>Tut es, was die Spec verspricht?</i>"]
QA --> B["Security Auditor<br/><i>Ist es sicher fürs offene Internet?</i>"]
A --> AV{"Critical oder<br/>High Bugs?"}
B --> BV{"Verdikt"}
AV -->|ja| R["Status bleibt<br/><b>In Review</b>"]
BV -->|"BLOCK"| R
AV -->|nein| G((" "))
BV -->|"PASS"| G
G --> OK["Status <b>Approved</b><br/>→ /deploy"]
R --> FIX["/frontend oder /backend<br/>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.tsxsrc/app/**/layout.tsxsrc/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.
flowchart TB
subgraph AUTO["Automatisch"]
CM["<b>CLAUDE.md</b><br/>jede Session"]
RU["<b>.claude/rules/</b><br/>sobald passende Dateien<br/>bearbeitet werden"]
end
subgraph DEMAND["Auf Abruf"]
SK["<b>.claude/skills/</b><br/>beim /kommando"]
AG["<b>.claude/agents/</b><br/>wenn eine Skill delegiert"]
SP["<b>features/PROJ-X.md</b><br/>wenn die Skill sie liest"]
DOC["<b>docs/DEPLOYMENT.md</b><br/>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.
stateDiagram-v2
[*] --> Roadmap: /init
Roadmap --> Planned: /write-spec
Planned --> Architected: /architecture
Architected --> InProgress: /frontend<br/>/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.
/architectureentscheidet pro Projekt. Einzige Auflage: muss im Compose-Stack selbst hostbar sein. - Kein Supabase, kein Vercel. Nicht vergessen, sondern absichtlich ausgebaut.
In
CLAUDE.mdsteht das explizit, damit es nicht durch die Hintertür zurückkommt. - Keine Content-Security-Policy vorkonfiguriert. Geraten bricht sie Apps; pro
Projekt mit
Report-Onlyanfangen. - 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:
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_URLabgeleitet. 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.
flowchart LR
U["Nutzer"] -->|HTTPS| P["Reverse Proxy<br/><i>nginx / Caddy</i><br/>auf dem Host"]
P -->|"127.0.0.1:3000"| C["app-Container<br/><i>Next.js standalone</i>"]
C --> H["/api/health"]
subgraph SRV["Server"]
P
subgraph CMP["docker compose"]
C
H
DB[("Datenbank<br/><i>optional, pro Projekt</i>")]
end
end
C -.->|"nur wenn gewählt"| DB
G["git repo"] -->|"./scripts/update.sh"| CMP
style DB stroke-dasharray: 5 5
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 auf0.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:
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
flowchart TD
A["Start"] --> B{"Arbeitsverzeichnis<br/>sauber?"}
B -->|nein| X["Abbruch"]
B -->|ja| C["git fetch + fast-forward"]
C --> D{"Neuer Commit<br/>oder --force?"}
D -->|nein| Y["Nichts zu tun"]
D -->|ja| E["docker compose build"]
E --> F["docker compose up -d"]
F --> G{"Healthcheck<br/>innerhalb 120s?"}
G -->|ja| H["Alte Images aufräumen<br/>✓ 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.
./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.
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
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