docs: AI-optimized docs restructure (Phases 1–8) (#61)

* docs(dialog-pattern): add generic entity-dialog spec

Introduceert docs/patterns/dialog.md als bron-of-truth voor elke
create/edit/detail-dialog in Scrum4Me, ongeacht het achterliggende
dataobject. Bevat 14 secties: uitgangspunten, stack, component-
architectuur, layout, validatie, drielaagse demo-policy, submission,
dialog-gedrag, theming, footer, triggers/URL-state, per-entiteit
profile-template, out-of-scope, en een verificatie-checklist.

Registreert het patroon in CLAUDE.md "Implementatiepatronen"-tabel
zodat Claude (en mensen) de spec verplicht raadplegen voor elke
nieuwe dialog.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(dialog-pattern): convert task spec + add pbi/story entity-profiles

Reduceert docs/scrum4me-task-dialog.md van 507 naar ~140 regels: alle
gedeelde regels verhuisd naar docs/patterns/dialog.md, dit document
bevat nu alleen Task-specifieke velden, URL-pattern, status-veld,
server actions, triggers en bewuste out-of-scope-keuzes.

Voegt twee nieuwe entity-profielen toe voor bestaande dialogen:
- docs/scrum4me-pbi-dialog.md (PbiDialog: state-based, code+title-rij,
  PbiStatusSelect, geen delete in v1)
- docs/scrum4me-story-dialog.md (StoryDialog: state-based, header met
  status/priority badges, inline activity-log, demo-readonly-fallback,
  inline-delete-confirm i.p.v. AlertDialog)

Beide profielen documenteren expliciet de "Bekende gaps t.o.v.
generieke spec" zodat opvolgende PR's de afwijkingen kunnen
rechtzetten of bewust kunnen accorderen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Added pdevelopment docs

* docs(plans): add docs-restructure plan for AI-optimized lookup

Audit of existing 39 doc files (~10.700 lines) and a phased restructure
proposal aimed at minimising the tokens an AI agent has to read to find
the right reference. Captures resolved decisions on language (English),
ADR template (Nygard default with MADR escape-hatch), index generator
(node script), and folder taxonomy. Proposal status — fase 1 to follow.

* docs(adr): add ADR scaffolding (templates, README, meta-ADR)

Set up docs/adr/ as the canonical home for architecture decisions:

- templates/nygard.md — default four-section format (Status, Context,
  Decision, Consequences) for one-way-door decisions.
- templates/madr.md — MADR v4 with YAML front-matter and explicit
  Considered Options for decisions where rejected alternatives matter.
- README.md — naming convention (NNNN-kebab-case), template-selection
  guidance (Nygard default; MADR for auth, queue mechanics, agent
  integration), status lifecycle, and ADR roster.
- 0000-record-architecture-decisions.md — meta-ADR establishing the
  practice itself, in Nygard format.

Backfilling existing implicit decisions (base-ui-over-radix, float
sort_order, demo-user three-layer policy, etc.) is fase 6 of the
docs-restructure plan.

* feat(docs): add docs index generator + initial INDEX.md

scripts/generate-docs-index.mjs walks docs/**/*.md, parses YAML
front-matter (or first H1 fallback) and a Nygard-style ## Status
section, then writes docs/INDEX.md with grouped tables for ADRs,
Specs, Plans (with archive subsection), Patterns, and Other.

Pure Node 20 (no external deps); idempotent — running it twice
produces byte-identical output. Excludes adr/templates/, the ADR
README, INDEX.md itself, and any *_*.md sidecar file.

Wire-up:
- package.json: docs:index → node scripts/generate-docs-index.mjs

Initial run indexed 35 docs across the existing structure; the
generated INDEX.md is committed so the table is reviewable in the
PR before hooking generation into a pre-commit step.

* chore: ignore Obsidian vault and personal sidecar files

Add .obsidian/ (Obsidian vault config) and _*.md (personal sidecar
notes) to .gitignore so the docs/ tree can serve as canonical source
of truth while still being usable as an Obsidian vault for personal
authoring. The docs index generator already excludes the same _*.md
pattern from INDEX.md.

* docs(plans): add PBI bulk-create spec for docs-restructure

Machine-parseable spec for an executor that calls the scrum4me MCP
(create_pbi → create_story → create_task) to seed the docs-restructure
work into the DB.

- Section 1 (Context) is the PBI description; serves as task-context
  via mcp__scrum4me__get_claude_context.
- Section 2 lists the 6 resolved decisions (English, MD3+styling
  merged, solo-paneel merged, .Plans archived, Nygard ADR default,
  node index script).
- Section 3 records what already shipped on this branch so the
  executor doesn't duplicate the ADR scaffolding or index generator.
- Section 4 carries the structured YAML graph: 1 PBI, 8 stories
  (one per phase), 39 tasks. product_id is REPLACE_ME — fill before
  running.
- YAML validated with PyYAML; field schema sanity-checked.

* docs(junk-cleanup): remove stub patterns/test.md

* docs(junk-cleanup): archive .Plans/ to docs/plans/archive/

* docs(front-matter): add YAML front-matter to docs/ root

* docs(front-matter): add YAML front-matter to patterns/

* docs(front-matter): add YAML front-matter to plans + agent files

* docs(index): regenerate INDEX.md after front-matter pass

* docs(naming): drop scrum4me- prefix from doc filenames

* docs(naming): lowercase API.md and MD3 filenames

* docs(naming): rename plan file to kebab-case ASCII

* docs(naming): rename middleware.md to proxy.md (next 16)

* docs(naming): polish CLAUDE.md doc-index after renames

* docs(taxonomy): scaffold topical folders under docs/

* docs(taxonomy): move spec files into docs/specs/

* docs(taxonomy): move design/api/qa/backlog/assets into folders

* docs(taxonomy): move agent-instruction-audit into decisions/

* docs(split): break architecture.md into 6 topical files

* docs(split): merge solo-paneel-spec into specs/functional.md

* docs(split): merge md3-color-scheme into design/styling

* docs(trim): extract branch/commit rules into runbook

* docs(trim): extract MCP integration into runbook

* docs(adr): add 0001-base-ui-over-radix

* docs(adr): add 0002-float-sort-order

* docs(adr): add 0003-one-branch-per-milestone

* docs(adr): add 0004-status-enum-mapping

* docs(adr): add 0005-iron-session-over-nextauth

* docs(adr): add 0006-demo-user-three-layer-policy

* docs(adr): add 0007-claude-question-channel-design

* docs(adr): add 0008-agent-instructions-in-claude-md + update README index

* docs(index): regenerate after ADR 0001-0008

* docs(glossary): add docs/glossary.md

* chore(docs): regenerate INDEX.md in pre-commit hook

* docs(readme): link INDEX + glossary + agent instructions

* feat(docs): add doc-link checker script

* chore(docs): wire docs:check-links and docs npm scripts

* ci(docs): block merge on broken doc links

* docs(links): fix broken cross-references after restructure

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-05-03 03:21:59 +02:00 committed by GitHub
parent 289bcf9bf0
commit 7e45bbdbc0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
81 changed files with 12364 additions and 3154 deletions

396
CLAUDE.md
View file

@ -1,372 +1,114 @@
---
title: "CLAUDE.md — Scrum4Me"
status: active
audience: [ai-agent]
language: nl
last_updated: 2026-05-03
---
# CLAUDE.md — Scrum4Me
Dit is het centrale instructiedocument voor Claude Code. Lees dit volledig voordat je iets bouwt.
Desktop-first Scrum-app voor solo developers en kleine teams. Hiërarchie: product → PBI → story → taak. Zie [README.md](./README.md) voor setup.
---
## Wat is Scrum4Me?
## Orientatie
Een desktop-first fullstack webapplicatie voor solo developers en kleine Scrum Teams die meerdere softwareprojecten parallel beheren. De app organiseert werk hiërarchisch (product → PBI → story → taak), biedt gesplitste planningsschermen met drag-and-drop, en integreert met Claude Code via een REST API.
---
## Specificatiedocumenten
Lees het relevante document voordat je aan een feature begint. Nooit gokken over requirements.
| Document | Gebruik voor |
| Bestand | Waarvoor |
|---|---|
| `docs/functional.md` | Acceptatiecriteria, randgevallen, user flows |
| `docs/architecture.md` | Stack, datamodel, Prisma schema, Zustand stores |
| `docs/backlog.md` | Welke task bouwen, volgorde, "done when"-criteria |
| `docs/personas.md` | Lars (primair), Dina, Remi — gebruik bij UI-beslissingen |
| `docs/product-backlog.md` | Historische domein-backlog (referentie); seed wordt sinds ST-004 gegenereerd uit `backlog.md` via `prisma/seed-data/parse-backlog.ts` |
| `docs/api.md` | REST-API contract voor Claude Code — endpoints, status-enums, foutcodes, voorbeeld-curls |
| `docs/styling.md` | **Lees dit voor elk component** — MD3-kleuren, shadcn patronen |
| `docs/agent-instruction-audit.md` | Waarom de agent-instructies zijn aangescherpt; checklist voor toekomstige wijzigingen |
| `docs/plans/<milestone-key>-*.md` | Implementatieplan per milestone — Bestanden, Stappen, Aandachtspunten, Verificatie. Lees vóór je aan een ST begint. Milestone-key matcht backlog-header (`M9`, `M3.5`, `PBI-9`, …). |
| [`madhura68/scrum4me-mcp`](https://github.com/madhura68/scrum4me-mcp) | MCP-server repo: native tools voor Claude Code, schema-sync via git submodule |
| `docs/INDEX.md` | Gegenereerde index van alle docs — begin hier |
| `docs/specs/functional.md` | Acceptatiecriteria, user flows |
| `docs/architecture.md` | Breadcrumb → 6 topische arch-bestanden |
| `docs/backlog/index.md` | Implementatievolgorde, "done when"-criteria |
| `docs/api/rest-contract.md` | REST API contract voor Claude Code |
| `docs/design/styling.md` | **Lees vóór elk component** — MD3-tokens, shadcn |
| `docs/plans/<key>-*.md` | Implementatieplan per milestone |
---
## Waar te beginnen
## Hoe werk vinden
Volg de backlog strikt op volgorde. Start bij **ST-001**. Sla geen milestone over.
```
M0 (ST-001008) → M1 (ST-101110) → M2 (ST-201210)
→ M3 (ST-301312) → M4 (ST-401410) → M5 (ST-501506)
→ M6 (ST-601612)
```
Werken aan een task kan via twee tracks. Track A heeft de voorkeur als je in Claude Code zit; Track B is voor Codex of omgevingen zonder MCP.
### Track A — via Claude Code MCP (aanbevolen)
1. Roep `mcp__scrum4me__implement_next_story` aan met `product_id` (gebruik `mcp__scrum4me__list_products` als je het id niet weet)
2. De prompt orkestreert: `get_claude_context``log_implementation` → per task `update_task_status(in_progress)` → bouw → `update_task_status(done)``log_test_result``log_commit`
3. Bouw de tasks in volgorde van `sort_order`; lees per task de relevante pattern-doc en styling
**Track A — MCP (aanbevolen):**
1. `mcp__scrum4me__get_claude_context` → pak de next story
2. Voer taken uit in `sort_order`; update status per taak
3. Lees het relevante patroon en styling vóór je begint
4. Verifieer: `npm run lint && npm test && npm run build`
5. Commit per laag (zie Commit Strategy)
5. Commit per laag — zie [docs/runbooks/branch-and-commit.md](./docs/runbooks/branch-and-commit.md)
### Track B — manueel (Codex of zonder MCP)
**Track B — manueel:**
1. Lees taak in `docs/backlog/index.md`
2. Zoek spec in `docs/specs/functional.md`
3. Lees patroon + styling → bouw → verifieer → vraag bevestiging → commit
1. Lees de task in `backlog.md`
2. Zoek de bijbehorende feature-spec in `functional.md`
3. Lees het relevante patroon in `docs/patterns/` en styling in `docs/styling.md` als dat van toepassing is
4. Bouw — test — verifieer de "Done when"-criteria
5. Vraag of de code correct is
6. Commit (zie Commit Strategy hieronder)
7. Vraag of de volgende taak gedaan moet worden
Volledige MCP-tool documentatie: [docs/runbooks/mcp-integration.md](./docs/runbooks/mcp-integration.md)
---
## Tech stack
## Hardstop regels
```
Next.js 16 (App Router) + React 19
TypeScript strict
Tailwind CSS + shadcn/ui
MD3 kleurensysteem via app/styles/theme.css
Zustand (client state)
dnd-kit (drag-and-drop)
Prisma v7 + PostgreSQL (Neon)
iron-session (auth cookies)
bcryptjs + Zod + Sonner
Sharp (avatarverwerking)
Vercel Analytics (@vercel/analytics/next)
```
> ⚠️ **Stylingregel:** Gebruik **nooit** `bg-blue-500` of willekeurige Tailwind-kleuren.
> Gebruik altijd semantische MD3-tokens: `bg-primary`, `bg-status-done`, `bg-priority-critical`.
> Zie `styling.md` voor alle patronen.
> ⚠️ **Next.js-versie:** Lees `node_modules/next/dist/docs/` bij twijfel — API's kunnen afwijken van trainingsdata.
- **Styling:** nooit `bg-blue-500`; altijd MD3-tokens (`bg-primary`, `bg-status-done`, …)
- **UI:** gebruik `@base-ui/react` met `render`-prop, niet Radix `asChild`
- **Push:** nooit pushen zonder expliciete gebruikersbevestiging — zie [branch-and-commit.md](./docs/runbooks/branch-and-commit.md)
- **Demo:** drie lagen — proxy.ts + server action + UI disabled knop
- **Enum:** DB UPPER_SNAKE ↔ API lowercase — uitsluitend via `lib/task-status.ts`
- **Foutcodes:** 400 = parse-fout, 422 = Zod-validatie, 403 = demo-token
- **Server/client grens:** `*-server.ts` bevat DB/node-only; nooit importeren in client component
- **Deployment:** `npm run lint && npm test && npm run build` vóór elke PR
---
## UI Library Conventions
## Stack
- Dit project gebruikt **`@base-ui/react`**, *niet* Radix UI — ondanks dat shadcn-componenten visueel-identiek zijn
- Composition gebeurt via de **`render`-prop**, niet via Radix's `asChild`:
- ✅ `<TooltipTrigger render={<button />}>...</TooltipTrigger>`
- ❌ `<TooltipTrigger asChild><button>...</button></TooltipTrigger>` — geeft TS-errors
- Vóór je een nieuwe shadcn-/UI-primitive gebruikt: grep eerst de codebase voor bestaand gebruik en volg dat patroon (`grep -rn "PrimitiveTrigger" components/`)
- shadcn-componenten in `components/ui/` zijn dunne wrappers rond `@base-ui/react`-primitives; lees die voor de exacte prop-API
| Laag | Technologie |
|---|---|
| Framework | Next.js 16 (App Router) + React 19 |
| Taal | TypeScript strict |
| Styling | Tailwind CSS + shadcn/ui + MD3 via `app/styles/theme.css` |
| State | Zustand + dnd-kit |
| DB | Prisma v7 + PostgreSQL (Neon) |
| Auth | iron-session + bcryptjs |
| Utilities | Zod, Sonner, Sharp, Vercel Analytics |
---
## Implementatiepatronen
Lees het relevante patroon vóór je begint. Nooit uit het hoofd schrijven.
## Patterns quickref
| Patroon | Bestand |
|---|---|
| iron-session (auth cookies) | `docs/patterns/iron-session.md` |
| Prisma Client singleton | `docs/patterns/prisma-client.md` |
| Server Action (met auth + Zod) | `docs/patterns/server-action.md` |
| Route Handler (REST API) | `docs/patterns/route-handler.md` |
| Zustand optimistische update + rollback | `docs/patterns/zustand-optimistic.md` |
| Float sort_order drag-and-drop | `docs/patterns/sort-order.md` |
| Proxy middleware (route protection) | `docs/patterns/proxy.md` |
| QR-pairing (unauth-SSE + pre-auth cookie) | `docs/patterns/qr-login.md` |
| Bidirectionele async-comms MCP-agent ↔ user | `docs/patterns/claude-question-channel.md` |
| **Entity Dialog (verplicht voor élke create/edit/detail-dialog)** | `docs/patterns/dialog.md` — bron-of-truth; per entiteit één profile-doc (bv. `docs/task-dialog.md`) |
| **Story met UI-component (verplicht 3-task-patroon: Helper / Component / Integration)** | `docs/patterns/story-with-ui-component.md` — elke story met een `*-component.tsx` vereist een afsluitende Integration-task die de component in `page.tsx` wirt |
| Status-enum mapping (DB ↔ API) | `lib/task-status.ts` |
| Client/server module-boundary | `*-server.ts` bevat DB-calls of node-only deps; `*.ts` is pure (client-safe). Nooit `import { ... } from '@/lib/foo-server'` in een client-component, anders krijg je `Module not found: 'dns'`/`'pg'`-style runtime fouten |
---
## Integration-task verificatie (smoke-test)
Voor stories met `*-component.tsx`: de Integration-task moet vóór
`update_job_status(done)` een smoke-test draaien op de daadwerkelijke
HTML-render:
```bash
# In de worktree — pas ROUTE en SECTIONS aan per story
ROUTE="/insights"
SECTIONS=("Sprint Health" "Plan-quality" "Agent throughput" "Velocity" "Backlog health")
npm run dev > /tmp/dev.log 2>&1 &
DEV_PID=$!
sleep 8 # wacht tot Next.js compiled
curl -s http://localhost:3000${ROUTE} > /tmp/page.html
SMOKE_FAIL=
for section in "${SECTIONS[@]}"; do
grep -q "$section" /tmp/page.html || { echo "MISSING: $section"; SMOKE_FAIL=1; }
done
kill $DEV_PID
[ -z "$SMOKE_FAIL" ] # exit-code 1 als iets miste
```
Als de smoke-test faalt: pas `page.tsx` aan zodat alle secties renderen, herhaal.
Markeer Integration-task DONE pas wanneer alle verwachte sections in de HTML zitten.
| iron-session | `docs/patterns/iron-session.md` |
| Prisma singleton | `docs/patterns/prisma-client.md` |
| Server Action (auth + Zod) | `docs/patterns/server-action.md` |
| Route Handler (REST) | `docs/patterns/route-handler.md` |
| Zustand optimistic update | `docs/patterns/zustand-optimistic.md` |
| Float sort_order / drag-and-drop | `docs/patterns/sort-order.md` |
| Proxy / route protection | `docs/patterns/proxy.md` |
| QR-pairing | `docs/patterns/qr-login.md` |
| Claude ↔ user vraagkanaal | `docs/patterns/claude-question-channel.md` |
| Entity Dialog (verplicht) | `docs/patterns/dialog.md` |
---
## Env vars
```bash
DATABASE_URL="" # postgresql://... (verplicht)
DIRECT_URL="" # postgresql://... — pooler-bypass voor LISTEN/NOTIFY (Neon/cloud)
SESSION_SECRET="" # min 32 chars; openssl rand -base64 32
CRON_SECRET="" # M11 — Bearer-secret voor /api/cron/*; verplicht in productie, optioneel lokaal (genereer met openssl rand -base64 32)
DATABASE_URL="" # postgresql://...
DIRECT_URL="" # pooler-bypass voor LISTEN/NOTIFY
SESSION_SECRET="" # min 32 chars
CRON_SECRET="" # Bearer-secret /api/cron/*
```
Volledige Zod-schema in `lib/env.ts`. `.env.example` is de canonieke lijst voor nieuwe checkouts.
Volledig schema: `lib/env.ts`. Canonieke lijst: `.env.example`.
---
## Conventies
- **Branches:** `feat/ST-001-scaffolding`
- **Server Actions:** altijd in `actions/[domein].ts`, nooit inline in page.tsx
- **Validatie:** altijd Zod, nooit handmatige checks
- **Toegangsmodel:** product-scoped resources gebruiken `productAccessFilter(userId)` tenzij het expliciet een eigenaarsactie is
- **Bulk-ID's:** reorder- en beslissingsacties valideren dat alle meegegeven IDs binnen dezelfde parent-scope vallen voordat er geschreven wordt
- **Foreign keys:** denormalized keys zoals `story.product_id` worden afgeleid uit de database-parent (`pbi.product_id`), nooit uit client-input
- **Demo-check (drie lagen — ST-1110):** write-acties zijn drielaags afgedekt: (1) middleware-guard in `proxy.ts` blokkeert non-GET op `/api/*` voor demo; (2) elke Server Action / Route Handler controleert `session.isDemo` vóór schrijven; (3) write-knoppen in UI zijn `disabled` met `<DemoTooltip show={isDemo}>`. Zie `docs/architecture.md#demo-user-policy` en `docs/plans/ST-1110-demo-readonly.md`
- **Foutberichten:** Nederlands voor eindgebruikers — comments in code: Engels
- **Dependencies:** elke geïmporteerde runtime package staat direct in `dependencies`, niet alleen transitief in `package-lock.json`
- **Docs-sync:** elke gedrags-, dependency-, API- of deploymentwijziging werkt README, relevante docs en patterns bij in dezelfde change
- **Entity codes:** gebruik product/PBI/story-codes in commit-titles wanneer aanwezig (`feat(ST-356.2): ...`); branchnaam blijft `feat/ST-XXX-slug`
- **Status-enums op API:** lowercase (`todo|in_progress|review|done`, `open|in_sprint|done`); DB houdt UPPER_SNAKE; conversie uitsluitend via `lib/task-status.ts`-mappers — nooit ad-hoc `.toLowerCase()` elders
- **Foutcodes API:** `400` alleen voor malformed JSON-body (parse-fout via `request.json()`); `422` voor zod-validatie en well-formed-maar-niet-acceptabel; `403` voor demo-tokens. Documenteer per endpoint in `docs/api.md`
- **Tests volgen contract:** bij een API-contract-wijziging (status, foutcode, response-shape) MOET in dezelfde commit ook `__tests__/api/` mee — een test die rood gaat omdat de oude waarde wordt verwacht is een onvolledige wijziging, niet een "kapotte test"
- **Dev port:** `npm run dev` draait altijd op **3000**. Een `predev`-hook killt vooraf elk proces op 3000 (stale Next.js dev-server, vorige sessie) zodat sessies, cookies en MCP-config consistent op één poort werken. Wijk hier niet van af — geen `-p 3001` o.i.d. tenzij je expliciet twee dev-servers naast elkaar wil draaien
---
## Branch & PR Strategy (STRICT — kostenbeheersing)
> **Core rule: één branch per milestone, PR alleen na gebruikerstest**
Elke `git push` naar een feature-branch triggert een Vercel preview-deployment. Op het huidige Hobby-account zijn die schaars en kosten geld; we minimaliseren preview-builds tot er werkelijk iets te reviewen valt.
### Wel doen
- Eén branch voor de hele milestone — `feat/M{N}-{slug}` (bv. `feat/M10-qr-login`); voor losse stories zonder milestone blijft `feat/ST-XXX-{slug}` geldig
- Commits accumuleren lokaal volgens de Commit Strategy hieronder — één commit per stap, ST-code in de titel
- Pushen + PR openen **pas nadat de gebruiker de milestone handmatig heeft getest en goedgekeurd** — vraag expliciet om bevestiging vóór `git push`
- Tussentijdse "klaar voor jouw test"-momenten markeren met een lokale tag of een berichtje in chat, niet met een push
### Niet doen
- Pushen na elke story of commit
- Een PR per story openen tijdens de implementatie
- "Just-in-case" pushen om backup te hebben — gebruik `git stash`, een lokale tag, of meerdere lokale branches
- `--force-push` om eerdere preview-builds "weg te toveren" (kost dezelfde build opnieuw bij hercreatie)
- **Direct pushen naar `main`** — die branch heeft protection rules; gebruik altijd een PR
### Wanneer wel commit-zonder-vragen, wanneer niet
- **Tijdens een directed sprint-flow** (Track A: `mcp__scrum4me__implement_next_story` of een expliciete *"implementeer M{N}"*-opdracht): commit-per-laag conform de Commit Strategy hieronder is impliciet geautoriseerd — niet per commit vragen
- **Bij ad-hoc / out-of-band werk** (bug-fix tussendoor, refactor, kleine wijziging op verzoek): toon de diff + voorgestelde commit-message en wacht op `"commit it"` voordat je `git commit` draait
- **`git push` is altijd expliciet** — de scope van de policy gaat over preview-builds, dus push gebeurt alleen na gebruiker-test, ongeacht commit-context
### Uitzonderingen op de push-regel
- Een **planning-PR** zonder code-wijzigingen (alleen docs in `docs/plans/` of `docs/`) mag direct gepusht worden — die triggert geen functional regressie en is goedkoop te bouwen
- Een **bugfix-hotfix** op `main` met aantoonbare productie-impact mag direct gepusht worden (via een PR — zie boven)
### Wanneer aanpassen
Zodra het Vercel-account naar Pro (of andere omgeving zonder per-build-kosten) gaat: vervang deze regel door "branch + PR per story" zoals oorspronkelijk in dit document stond. Werk deze sectie bij én documenteer de wijziging in `docs/agent-instruction-audit.md`.
---
## Plan Mode
- Voor simpele, goed-afgebakende file-edits: **niet** in plan mode gaan — gewoon de wijziging maken
- Reserveer plan mode voor multi-step refactors, ambigue verzoeken, of milestone-planning waarbij design-keuzes vooraf bevestigd moeten worden
- Plannen die uit plan mode komen: opslaan als `docs/plans/M{N}-{slug}.md` (zie memory `feedback_plan_location`), niet als ephemeral systeem-bestand
---
## Commit Strategy (STRICT)
> **Core rule: één commit = één verantwoordelijkheid**
### Nooit doen
- Database + API + UI in één commit mengen
- Feature + documentatie combineren
- Grote "alles gewijzigd" commits
- Vage berichten zoals "update stuff"
### Verplichte structuur
Splits werk op in logische lagen:
1. Database / Prisma
2. API / server actions
3. UI / components
4. Config / infra
5. Documentatie
### Commit-formaat
```
feat(ST-XXX): korte beschrijving
fix(ST-XXX): korte beschrijving
chore(ST-XXX): korte beschrijving
docs(ST-XXX): korte beschrijving
```
### Voorbeeld (verplicht patroon)
In plaats van:
```bash
feat: add profile system
```
Splits altijd op in:
```bash
feat(ST-XXX): add user profile fields to Prisma schema
feat(ST-XXX): add avatar upload endpoint
feat(ST-XXX): add profile editor component
chore(ST-XXX): configure sharp for avatar processing
docs(ST-XXX): document profile feature
```
---
## Scrum-terminologie
| Correct | Niet gebruiken |
|---|---|
| Product Backlog Item (PBI) | Feature, Epic, Issue |
| Story | User Story, Ticket |
| Sprint Goal | Sprint Objective |
| Scrum Team | Team |
PBI (niet: Feature/Epic) · Story (niet: Ticket) · Sprint Goal (niet: Objective)
---
## MCP-integratie
## Verificatie
Scrum4Me heeft een eigen MCP-server in repo [`madhura68/scrum4me-mcp`](https://github.com/madhura68/scrum4me-mcp) die de REST-API als native tools voor Claude Code aanbiedt. Schema's worden gedeeld via een git submodule (`vendor/scrum4me`), niet gedupliceerd.
### Tools beschikbaar in Claude Code (18)
**Read / context:**
- `mcp__scrum4me__health` — service + DB ping
- `mcp__scrum4me__list_products` — producten waar de tokengebruiker toegang tot heeft
- `mcp__scrum4me__get_claude_context` — bundled product / actieve sprint / next story (met tasks) / open todos
**Authoring (PBI/Story/Task aanmaken):**
- `mcp__scrum4me__create_pbi``{ product_id, title, description?, priority, sort_order? }`; auto sort_order = last+1 binnen prio-groep
- `mcp__scrum4me__create_story``{ pbi_id, title, description?, acceptance_criteria?, priority, sort_order? }`; product_id afgeleid uit PBI; status=OPEN
- `mcp__scrum4me__create_task``{ story_id, title, description?, implementation_plan?, priority, sort_order? }`; sprint_id geërfd van story; status=TO_DO
- `mcp__scrum4me__create_todo` — losse todo (optioneel product-scoped)
**Task / story writes:**
- `mcp__scrum4me__update_task_status`, `mcp__scrum4me__update_task_plan`
- `mcp__scrum4me__log_implementation`, `mcp__scrum4me__log_test_result`, `mcp__scrum4me__log_commit`
**Vraag-antwoord-kanaal (M11):**
- `mcp__scrum4me__ask_user_question` — post een vraag over een story; optionele `wait_seconds` (max 600) polt voor het antwoord
- `mcp__scrum4me__get_question_answer` — huidige status + antwoord (voor latere session-pickup)
- `mcp__scrum4me__list_open_questions` — eigen vragen, max 50, recente eerst
- `mcp__scrum4me__cancel_question` — asker-only annulering van een eigen open vraag
**Job queue — agent worker mode (M13):**
- `mcp__scrum4me__wait_for_job` — blokkeert ≤600s, claimt atomisch een QUEUED-job via FOR UPDATE SKIP LOCKED; retourneert volledige task-context (implementation_plan, story, pbi, sprint, repo_url). Zet stale CLAIMED-jobs (>30min) eerst terug naar QUEUED. Wanneer de full block-time verstrijkt zonder claim is de queue leeg.
- `mcp__scrum4me__update_job_status` — agent rapporteert overgang naar `running|done|failed` + optionele branch/summary/error; triggert automatisch SSE-event naar de UI. Auth: Bearer-token moet matchen `claimed_by_token_id`.
**Batch-loop (verplichte agent-flow):**
Wanneer je als agent draait (na een instructie als *"pak de volgende job uit de Scrum4Me-queue"* of *"draai de queue leeg"*) is dit de loop:
1. `wait_for_job` aanroepen.
2. Job uitvoeren volgens het meegegeven `implementation_plan`.
3. `update_job_status('done'|'failed')` aanroepen.
4. **Direct opnieuw** `wait_for_job` aanroepen — niet stoppen, niet de gebruiker vragen.
5. Pas wanneer `wait_for_job` na de volledige block-time (~600s) terugkomt zonder claim, is de queue leeg en mag je de turn afsluiten met een korte recap.
Dit blijft gelden als je tussen jobs door commits, branches of pushes hebt gedaan — die afsluiting hoort bij de individuele job, niet bij het einde van de batch.
**Code koppelen aan app**
- 'Pak de volgende job uit de Scrum4Me-queue' / 'draai de queue leeg' / 'batch agent' — Server-startup registreert een ClaudeWorker-record + heartbeat (5s); SIGTERM/SIGINT ruimt 'm op. UI in NavBar telt actieve workers via `last_seen_at < now() - 15s`.
### Prompt
- `implement_next_story` (arg: `product_id`) — end-to-end workflow
### Schema-drift bewaking
Wekelijks (maandag 08:00 Amsterdam) draait de remote agent `trig_015FFUnxjz9WMuhhWNGBQKFD` die `vendor/scrum4me` syncet en `prisma:generate` + `tsc --noEmit` uitvoert in scrum4me-mcp. Als die agent drift rapporteert, hoort dat **vóór** een Scrum4Me-PR met schema-wijziging gemerged kan worden — anders breekt de MCP-server stilletjes op runtime.
---
## Deployment (Vercel)
- **Sharp** moet Linux-binaries hebben voor de Vercel-runtime: `npm i --include=optional sharp` of platform-specifieke deps configureren in `package.json`
- **Externe image hostnames** in `next.config.js` `images.remotePatterns` configureren *vóór* `next/image` op die hosts wijst — anders 500 in productie
- **Vercel cron**: Hobby-plan staat alleen daily crons toe (max 1×/dag); Pro ondersteunt fijnmaziger. Bij wijziging van `vercel.json` `crons` ook `docs/api.md` + relevante pattern-docs updaten
- **`CRON_SECRET`** moet als env-var op de Vercel-project-omgeving staan vóór de eerste cron-run, anders 401 op `/api/cron/*`-endpoints
- **Preflight** vóór deploy: `npm run lint && npm test && npm run build` — falende build laat een PR niet door (CI blokkeert merge per ST-610)
---
## Definition of Done (MVP)
M7 (MCP-server) is post-MVP en heeft eigen acceptatie in `docs/backlog.md`.
- [ ] Alle 62 tasks (ST-001 t/m ST-612) afgerond
- [ ] Volledige Lars-flow zonder fouten (ST-612)
- [ ] Alle gedocumenteerde API-endpoints werken via curl (zie `docs/api.md`)
- [ ] Demo-gebruiker heeft geen schrijfrechten
- [ ] App opzetbaar via README zonder extra hulp
- [ ] CI/CD actief — falende build blokkeert merge
- [ ] Beveiligingsreview API geslaagd (cross-user toegang onmogelijk)
- [ ] Documentatie is bijgewerkt voor gewijzigde API's, dependencies, deployment en agent-instructies
```bash
npm run lint && npm test && npm run build
```