From 0a842e684148595634ee5f89cc927ba86f431661 Mon Sep 17 00:00:00 2001 From: Janpeter Visser <30029041+madhura68@users.noreply.github.com> Date: Mon, 11 May 2026 21:13:06 +0200 Subject: [PATCH] docs(PBI-12 + /init): sprint-lifecycle runbook + MCP-tools plan + CLAUDE.md fixes (#192) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs(PBI-12 T-54): voeg sprint-tools toe aan mcp-integration.md Documenteert mcp__scrum4me__create_sprint en mcp__scrum4me__update_sprint onder de Authoring-sectie, met verwijzing naar plan-to-pbi-flow.md voor de werkwijze. Co-Authored-By: Claude Opus 4.7 (1M context) * docs(PBI-12 T-55): promote plan-to-pbi-flow.md naar active - frontmatter status: draft → active - ⚠️-tooling-banner verwijderd; tools live sinds adbea3f in scrum4me-mcp - korte note die naar mcp-integration.md verwijst voor tool-reference Co-Authored-By: Claude Opus 4.7 (1M context) * docs(CLAUDE.md): /init improvements (scripts, proxy hardstop, versies) - Stack-tabel: exacte versies Next.js 16.2, React 19.2, Tailwind v4, Prisma v7.8 - Hardstop bullet voor proxy.ts (géén middleware.ts, demo-write blokkering) - MCP-sectie: bewuste duplicatie van lib/job-config.ts ↔ scrum4me-mcp toegelicht - Verificatie-sectie: npm scripts-tabel (dev/test/seed/create-admin/docs/diagrams) + Vitest exclude + server-only mock note - Orientatie-tabel: verwijzing toegevoegd naar docs/runbooks/plan-to-pbi-flow.md - frontmatter last_updated: 2026-05-11 Co-Authored-By: Claude Opus 4.7 (1M context) * docs(PBI-12): implementatieplan voor sprint MCP-tools Plan-file voor de twee tools (create_sprint + update_sprint) die de sprint-lifecycle uit plan-to-pbi-flow.md ondersteunen. Beslissingen: - Eén generieke update_sprint (geen losse close/fail/archive tools) - Géén state-machine validatie (resubmit-mechanisme zit elders) - Auto-end_date bij CLOSED/FAILED/ARCHIVED - Cron + create_story sprint-param uit scope (apart later) Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Claude Opus 4.7 (1M context) --- CLAUDE.md | 28 +++- docs/INDEX.md | 2 + docs/plans/sprint-mcp-tools.md | 153 ++++++++++++++++++++++ docs/runbooks/mcp-integration.md | 6 + docs/runbooks/plan-to-pbi-flow.md | 206 ++++++++++++++++++++++++++++++ 5 files changed, 391 insertions(+), 4 deletions(-) create mode 100644 docs/plans/sprint-mcp-tools.md create mode 100644 docs/runbooks/plan-to-pbi-flow.md diff --git a/CLAUDE.md b/CLAUDE.md index 8aa39c1..bf80745 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3,7 +3,7 @@ title: "CLAUDE.md — Scrum4Me" status: active audience: [ai-agent] language: nl -last_updated: 2026-05-08 +last_updated: 2026-05-11 --- # CLAUDE.md — Scrum4Me @@ -23,6 +23,7 @@ Desktop-first Scrum-app voor solo developers en kleine teams. Hiërarchie: produ | `docs/design/styling.md` | **Lees vóór elk component** — MD3-tokens, shadcn | | `docs/adr/` | Architecture Decision Records — tech-keuzes (base-ui vs Radix, sort-order, demo-policy, …) | | `docs/architecture/` | 6 topische architecture-bestanden (data-model, auth, sprint-execution, …) — uitwerking van `docs/architecture.md` | +| `docs/runbooks/plan-to-pbi-flow.md` | **Na goedgekeurd plan** — PBI/Story/Task aanmaken via MCP, zónder direct uitvoeren | --- @@ -47,6 +48,7 @@ Volledige MCP-tool documentatie: [docs/runbooks/mcp-integration.md](./docs/runbo - **UI:** gebruik `@base-ui/react` met `render`-prop, niet Radix `asChild` - **Push:** commits accumuleren lokaal per taak (`git add -A && git commit`); push + PR pas bij lege queue of na expliciete gebruikersbevestiging — zie [branch-and-commit.md](./docs/runbooks/branch-and-commit.md) - **Demo:** drie lagen — proxy.ts + server action + UI disabled knop +- **Proxy:** `proxy.ts` in repo-root (géén `middleware.ts`) onverzegelt de iron-session, redirect niet-geauthenticeerde users op `/dashboard|/products|/ideas`, en blokkeert niet-GET API-writes voor demo-users behalve `/api/cron/*` - **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 @@ -60,11 +62,11 @@ Volledige MCP-tool documentatie: [docs/runbooks/mcp-integration.md](./docs/runbo | Laag | Technologie | |---|---| -| Framework | Next.js 16 (App Router) + React 19 | +| Framework | Next.js 16.2 (App Router) + React 19.2 — PPR/Cache Components beschikbaar | | Taal | TypeScript strict | -| Styling | Tailwind CSS + shadcn/ui + MD3 via `app/styles/theme.css` | +| Styling | Tailwind CSS v4 + shadcn/ui + MD3 via `app/styles/theme.css` | | State | Zustand + dnd-kit | -| DB | Prisma v7 + PostgreSQL (Neon) | +| DB | Prisma v7.8 + PostgreSQL (Neon) | | Auth | iron-session + bcryptjs | | Test | Vitest (`__tests__/`, config in `vitest.config.ts`) | | Utilities | Zod, Sonner, Sharp, Vercel Analytics | @@ -111,6 +113,7 @@ Volledig schema: `lib/env.ts`. Canonieke lijst: `.env.example` — bevat ook web ## MCP & cron - **MCP-server (extern):** standalone Node-proces in `~/Development/scrum4me-mcp/` — Prisma-schema gesynced via `sync-schema.sh`. 30+ tools (`get_claude_context`, `wait_for_job`, `update_task_status`, …) +- **Bewuste duplicaten:** `lib/job-config.ts` (deze repo) en `scrum4me-mcp/src/lib/job-config.ts` (externe MCP) bevatten dezelfde resolver-logica; dit voorkomt dat de MCP-server Next-deps importeert. **Wijzig beide** bij elke job-config aanpassing - **Cron (vercel.json):** - `/api/cron/expire-questions` — dagelijks 04:00 UTC - `/api/cron/cleanup-agent-artifacts` — dagelijks 03:00 UTC @@ -131,3 +134,20 @@ npm run verify && npm run build # verify = lint + typecheck + test ``` Worker job-status protocol (wanneer `DONE` / `SKIPPED` / `FAILED`): zie [docs/runbooks/worker-idempotency.md](./docs/runbooks/worker-idempotency.md). + +### Scripts + +| Commando | Doel | +|---|---| +| `npm run dev` | Next dev op poort 3000 (`predev` kill-port draait automatisch) | +| `npm test` | Vitest eenmalig (`vitest run`) | +| `npm run test:watch` | Vitest watch-mode | +| `npm test -- ` | Eén bestand draaien — bv. `npm test -- lib/env` | +| `npm run seed` | Prisma seed via `prisma/seed.ts` | +| `npm run create-admin` | Admin-user toevoegen (`scripts/create-admin.ts`) | +| `npm run db:insert-milestone` | Milestone-script (`scripts/insert-milestone.ts`) | +| `npm run db:sync-model-prices` | Sync Anthropic-model-prijzen — vereist `ANTHROPIC_API_KEY` | +| `npm run docs` | Regenereer `docs/INDEX.md` + check links | +| `npm run diagrams` | Mermaid → SVG (`public/diagrams/architecture-{light,dark}.svg`) | + +> Vitest sluit `.claude/**` uit (relevant voor worktrees). `server-only` wordt via alias gemockt naar `tests/stubs/server-only.ts`, zodat `*-server.ts` modules laadbaar zijn in jsdom-tests. diff --git a/docs/INDEX.md b/docs/INDEX.md index 35c9d7a..5c4dd21 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -47,6 +47,7 @@ Auto-generated on 2026-05-11 from front-matter and headings. | [M9 — Actief Product Backlog](./plans/M9-active-product-backlog.md) | active | 2026-05-03 | | [PBI-79: Product Backlog workflow — sprint-membership via vinkjes](./plans/PBI-79-backlog-sprint-workflow.md) | — | — | | [Queue-loop verplaatsen van Claude naar runner](./plans/queue-loop-extraction.md) | — | — | +| [Sprint MCP-tools — create_sprint & update_sprint](./plans/sprint-mcp-tools.md) | draft | 2026-05-11 | | [Advies - SprintRun, PR en worktree lifecycle als state machines](./plans/sprint-pr-worktree-state-machines.md) | draft | 2026-05-06 | | [ST-1109 — PBI krijgt een status (Ready / Blocked / Done)](./plans/ST-1109-pbi-status.md) | active | 2026-05-03 | | [ST-1110 — Demo gebruiker read-only](./plans/ST-1110-demo-readonly.md) | active | 2026-05-03 | @@ -122,6 +123,7 @@ Auto-generated on 2026-05-11 from front-matter and headings. | [Vercel Deployment](./runbooks/deploy-vercel.md) | `runbooks/deploy-vercel.md` | active | 2026-05-03 | | [Job-model-selectie per ClaudeJob-kind](./runbooks/job-model-selection.md) | `runbooks/job-model-selection.md` | active | 2026-05-09 (idea-kinds + PLAN_CHAT permission_mode → acceptEdits) | | [MCP Integration — Scrum4Me Tools](./runbooks/mcp-integration.md) | `runbooks/mcp-integration.md` | active | 2026-05-08 | +| [Plan → Sprint/PBI/Story/Task workflow](./runbooks/plan-to-pbi-flow.md) | `runbooks/plan-to-pbi-flow.md` | active | 2026-05-11 | | [v1.0 Smoke Test Checklist](./runbooks/v1-smoke-test.md) | `runbooks/v1-smoke-test.md` | active | 2026-05-04 | | [Worker idempotency & job-status protocol](./runbooks/worker-idempotency.md) | `runbooks/worker-idempotency.md` | active | 2026-05-09 | | [Scrum4Me — API Test Plan](./test-plan.md) | `test-plan.md` | active | 2026-05-03 | diff --git a/docs/plans/sprint-mcp-tools.md b/docs/plans/sprint-mcp-tools.md new file mode 100644 index 0000000..17ae366 --- /dev/null +++ b/docs/plans/sprint-mcp-tools.md @@ -0,0 +1,153 @@ +--- +title: "Sprint MCP-tools — create_sprint & update_sprint" +status: draft +audience: [maintainer, ai-agent] +language: nl +last_updated: 2026-05-11 +applies_to: [scrum4me-mcp] +--- + +# Plan — `create_sprint` + `update_sprint` in scrum4me-mcp + +## Context + +Het runbook [docs/runbooks/plan-to-pbi-flow.md](../runbooks/plan-to-pbi-flow.md) (draft) beschrijft een sprint-lifecycle als onderdeel van de plan→PBI→story→task workflow: + +- **Bij plan-goedkeuring** opent Claude een nieuwe sprint (`status: OPEN`) +- **Na PR-merge + verify groen** sluit Claude die sprint (`status: CLOSED`) +- **Cron** mag stale/falende sprints later op `FAILED` zetten + +Hiervoor zijn twee MCP-tools nodig die nog **niet** bestaan in `~/Development/scrum4me-mcp/`: + +| Tool | Wat | Wie roept aan | +|---|---|---| +| `create_sprint` | Maakt nieuwe sprint, status `OPEN` | Claude bij plan-goedkeuring | +| `update_sprint` | Wijzigt status / dates / sprint_goal | Claude bij PR-close & cron bij stale-detect | + +Door één generieke `update_sprint` te bouwen (i.p.v. losse `close_sprint`/`fail_sprint`) is de tool-oppervlakte minimaal en zijn alle transities tussen `OPEN | CLOSED | ARCHIVED | FAILED` mogelijk. + +## Bestaande conventies (te respecteren) + +- **Toolpattern:** elk tool is één bestand onder `~/Development/scrum4me-mcp/src/tools/`, registreert via `register{ToolName}Tool(server: McpServer)` in `src/index.ts`. Voorbeeld-template: [scrum4me-mcp/src/tools/create-pbi.ts](https://github.com/madhura68/scrum4me-mcp/blob/main/src/tools/create-pbi.ts) +- **DB-toegang:** direct via `import { prisma } from '../prisma.js'` — **geen** REST-tussenstap, geen Next-deps +- **Auth:** `requireWriteAccess(token)` + `userCanAccessProduct(userId, productId)` zoals in `create-pbi.ts` +- **Error-pad:** `withToolErrors(...)`, `toolError(...)`, `toolJson(...)` uit `../errors.js` +- **Zod-input** apart gedefinieerd, status-enum gespiegeld uit Prisma +- **Schema-sync:** Prisma-schema is een git-submodule in `vendor/scrum4me`; geen schema-wijzigingen nodig (Sprint-model heeft alle statussen al) + +## Scope + +### A. `create_sprint` + +**Bestand:** `~/Development/scrum4me-mcp/src/tools/create-sprint.ts` + +**Input-schema:** + +```ts +const inputSchema = z.object({ + product_id: z.string().min(1), + code: z.string().min(1).max(30).optional(), // auto-generate als leeg + sprint_goal: z.string().min(1).max(500), + start_date: z.string().date().optional(), // ISO YYYY-MM-DD; default = today +}) +``` + +**Gedrag:** + +1. `requireWriteAccess(token)` → user_id +2. `userCanAccessProduct(user_id, product_id)` +3. **Code-generatie** (als niet meegegeven): `S-{YYYY-MM-DD}-{N}` waarbij `N` = `count(sprints van product op datum) + 1`. Dezelfde retry-on-unique-conflict pattern als `generateNextPbiCode()`. +4. `prisma.sprint.create({ data: { product_id, code, sprint_goal, status: 'OPEN', start_date } })` +5. Return: `{ id, code, status, start_date }` + +**Niet doen:** géén check op bestaande OPEN-sprints (per runbook-beslissing: "altijd nieuwe sprint"). + +### B. `update_sprint` + +**Bestand:** `~/Development/scrum4me-mcp/src/tools/update-sprint.ts` + +**Input-schema:** + +```ts +const inputSchema = z.object({ + sprint_id: z.string().min(1), + status: z.enum(['OPEN', 'CLOSED', 'ARCHIVED', 'FAILED']).optional(), + sprint_goal: z.string().min(1).max(500).optional(), + end_date: z.string().date().optional(), + start_date: z.string().date().optional(), +}).refine(d => + d.status !== undefined || d.sprint_goal !== undefined || + d.end_date !== undefined || d.start_date !== undefined, + { message: 'Minstens één veld vereist' } +) +``` + +**Gedrag:** + +1. `requireWriteAccess(token)` → user_id +2. Laad sprint → check `userCanAccessProduct(user_id, sprint.product_id)` +3. **Geen state-machine validatie** in deze tool — elke status-transitie is toegestaan. Het resubmit/heropen-pad wordt elders (buiten deze MCP-tool) afgehandeld. +4. **Auto-`end_date`:** als status naar `CLOSED`/`FAILED`/`ARCHIVED` gaat en `end_date` is niet meegegeven → set op `today()`. +5. `prisma.sprint.update({ where: { id }, data: {...} })` +6. Return: `{ id, code, status, start_date, end_date }` + +### C. `index.ts` — tool-registratie + +Twee regels toevoegen aan `~/Development/scrum4me-mcp/src/index.ts`: + +```ts +import { registerCreateSprintTool } from './tools/create-sprint.js' +import { registerUpdateSprintTool } from './tools/update-sprint.js' +// … +registerCreateSprintTool(server) +registerUpdateSprintTool(server) +``` + +## Out-of-scope (apart op te pakken) + +- **Cron auto-close/fail:** een Vercel cron-route (`/api/cron/sprint-lifecycle`) die OPEN-sprints scant, PR-status + verify check, en `update_sprint` aanroept met `CLOSED` of `FAILED`. Drempels: PR mergedAt → CLOSED, PR closed && !merged → FAILED, PR stale > 14d → FAILED. **Apart PBI** want vereist GitHub-API-koppeling en threshold-policy-besluiten. +- **Sprint-koppeling bij `create_story`:** runbook merkt op dat als er meerdere OPEN-sprints zijn de gebruiker moet bevestigen welke. Schoner is `create_story` uitbreiden met optionele `sprint_id`-param. Klein patch in `create-story.ts`, maar **niet** in deze PBI — eerst de basis-tools werkend hebben. +- **Sprint-events / SSE:** elke status-transitie zou een NOTIFY moeten emiteren zodat de UI live update. Bestaande pattern in [docs/patterns/realtime-notify-payload.md](../patterns/realtime-notify-payload.md). **Niet** in v1 van deze PBI — handmatige refresh acceptabel tot cron-flow er is. +- **REST-endpoints:** `POST /api/sprints` en `PATCH /api/sprints/[id]` in de Scrum4Me-app voor UI-pariteit. **Niet** in deze PBI — MCP gaat direct via Prisma, UI kan dat later naadloos volgen. + +## Testen + +In `scrum4me-mcp` zelf (Vitest): + +- `create-sprint.test.ts`: happy-path (alle velden + minimal), code-auto-generatie, code-conflict-retry, user-access-denied +- `update-sprint.test.ts`: legal transities (×3), illegal transities (×3), auto-`end_date` bij CLOSE/FAIL/ARCHIVE, multi-field update, access-denied + +In Scrum4Me-app: één integration-test in `__tests__/sprint-lifecycle.test.ts` die via een geseed token de MCP-tools aanroept en het Prisma-record verifieert. + +## Implementatie-stappen (volgorde) + +1. **`create-sprint.ts`** schrijven + registreren in `index.ts` +2. **`update-sprint.ts`** schrijven + registreren in `index.ts` +3. Unit-tests in scrum4me-mcp +4. `npm run verify` in scrum4me-mcp (typecheck + tests) +5. **Sync naar Scrum4Me-app:** `sync-schema.sh` is voor Prisma-schema; voor tool-discovery hoeft niets — MCP is een aparte service en de Scrum4Me-app importeert niets uit `scrum4me-mcp/src/tools/` +6. Update [docs/runbooks/mcp-integration.md](../runbooks/mcp-integration.md): voeg de twee tools toe aan de tool-lijst +7. Update [docs/runbooks/plan-to-pbi-flow.md](../runbooks/plan-to-pbi-flow.md): verwijder de ⚠️-tooling-banner; status van `draft` → `active` +8. PR-flow zoals gewend (branch-and-commit-runbook) + +## Open vragen — uitgesteld tot later + +Bewust pas later beslissen (niet blokkerend voor de eerste implementatie): + +- **`code`-conventie** — voor v1 default `S-{YYYY-MM-DD}-{N}`; later evalueren of `S-{N}` doorlopend per product (zoals PBI-N) beter past +- **Cron-drempels** — pas relevant in de vervolg-PBI voor de cron zelf +- **`update_sprint` zonder status-wijziging** — toegestaan (alle velden optioneel; refine eist minstens één) + +## Risico's + +- **Multi-sprint-context** bij `create_story`: nu impliciet (server resolveert "active sprint"). Met meerdere OPEN-sprints kan dit fout gaan. Mitigatie: korte termijn → het runbook waarschuwt, gebruiker bevestigt; lange termijn → expliciete `sprint_id` param in `create_story`. +- **Cron racet met handmatige close:** als gebruiker `update_sprint(CLOSED)` doet vóór de cron, en cron daarna `FAILED` zet, overschrijft cron de eerdere status. Acceptabel voor v1 — last-write-wins. Het externe resubmit-mechanisme bepaalt of een sprint überhaupt nog door cron geraakt mag worden. +- **Demo-modus:** demo-users mogen geen schrijfacties; `requireWriteAccess` checkt al op `isDemo`, dus geen extra werk. + +## Klaar wanneer + +- [ ] Beide tools live in scrum4me-mcp `main` +- [ ] Tests groen +- [ ] mcp-integration.md tool-lijst bijgewerkt +- [ ] plan-to-pbi-flow.md banner weg + status `active` +- [ ] Eén end-to-end smoke-test gedraaid: create_sprint → create_pbi → ... → update_sprint(CLOSED) op een lokale dev-DB diff --git a/docs/runbooks/mcp-integration.md b/docs/runbooks/mcp-integration.md index c6fb2b4..d838c4f 100644 --- a/docs/runbooks/mcp-integration.md +++ b/docs/runbooks/mcp-integration.md @@ -23,6 +23,12 @@ Scrum4Me heeft een eigen MCP-server in repo [`madhura68/scrum4me-mcp`](https://g - `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 +**Sprint-lifecycle (PBI-12):** +- `mcp__scrum4me__create_sprint` — `{ product_id, code?, sprint_goal, start_date? }`; status start altijd op `OPEN`; code auto-gegenereerd als `S-{YYYY-MM-DD}-{N}` per product per dag als niet meegegeven; géén reuse-check op bestaande OPEN-sprints +- `mcp__scrum4me__update_sprint` — `{ sprint_id, status?, sprint_goal?, start_date?, end_date? }`; minimaal één veld vereist; **géén state-machine validatie** (last-write-wins, het resubmit/heropen-pad zit elders); auto-`end_date=vandaag` bij status → `CLOSED`/`FAILED`/`ARCHIVED` zonder expliciete end_date + +> Wanneer en hoe deze sprint-tools in de plan-flow gebruikt worden: zie [docs/runbooks/plan-to-pbi-flow.md](./plan-to-pbi-flow.md). + > Idea-aanmaak loopt niet via MCP maar via de UI of `POST /api/ideas`. De voormalige `create_todo`-tool is verwijderd; idea-mutaties gaan via de Idea-tools onder *Idea-laag (M12)* hieronder. **Task / story writes:** diff --git a/docs/runbooks/plan-to-pbi-flow.md b/docs/runbooks/plan-to-pbi-flow.md new file mode 100644 index 0000000..0d8356d --- /dev/null +++ b/docs/runbooks/plan-to-pbi-flow.md @@ -0,0 +1,206 @@ +--- +title: "Plan → Sprint/PBI/Story/Task workflow" +status: active +audience: [ai-agent, maintainer] +language: nl +last_updated: 2026-05-11 +when_to_read: "Wanneer de gebruiker een plan goedkeurt en je het werk via Scrum4Me-MCP wilt vastleggen — inclusief sprint-lifecycle." +--- + +# Plan → Sprint / PBI / Story / Task workflow + +Hoe je een **goedgekeurd plan** omzet naar een hiërarchie van Sprint + PBI + Story + Task(s) via de Scrum4Me-MCP, zónder de taken meteen uit te voeren. Eén PBI = één increment = één sprint. + +Dit is de **creatie-kant** van het werk. De **uitvoer-kant** staat in [CLAUDE.md → "Hoe werk vinden"](../../CLAUDE.md) en [docs/runbooks/mcp-integration.md → Batch-loop](./mcp-integration.md). + +> Sprint-tools `create_sprint` en `update_sprint` zijn live in scrum4me-mcp (PBI-12). Tool-reference: [mcp-integration.md](./mcp-integration.md). + +--- + +## Wanneer wel — wanneer niet + +| Type werk | Sprint + PBI maken? | +|---|---| +| Nieuwe feature, refactor, UX-aanpassing, performance-fix | **Ja** | +| Bug-fix die meer dan een trivial-edit vereist | **Ja** | +| Doc-only edit (CLAUDE.md, runbook, README) | Nee — direct edit, commit, klaar | +| Typo, format-fix, dead-code verwijdering (<10 regels) | Nee | +| Spike / verkenning zonder concrete output | Nee — log eventueel als Idea (M12) | + +Sprint volgt PBI: **geen PBI → geen sprint**. Twijfel? Vraag het. + +--- + +## De vier-laagse flow + +``` +plan goedgekeurd + │ + ├─ create_sprint → Sprint-record (status=OPEN, start_date=vandaag) + │ │ + │ └─ create_pbi → PBI-record onder dat product + │ │ + │ └─ create_story → Story-record, koppelt aan de actieve sprint + │ │ + │ └─ create_task (× N) → sprint_id geërfd van story + │ + ├─ stop — wachten op uitvoer-instructie + │ + ├─ … execution-fase via "Hoe werk vinden" … + │ + └─ PR merged + verify groen → update_sprint(status=CLOSED, end_date=vandaag) +``` + +### 0. `create_sprint` (vóór alle andere create-calls) + +``` +{ product_id, code, sprint_goal, status: 'OPEN', start_date? } +``` + +- **`code`** — kort label, max 30 chars. Suggestie: `S-{YYYY-MM-DD}-{kebab-PBI-titel}` of een lopende teller (`S-2026-05-11-web-push`). +- **`sprint_goal`** — één regel, het increment in mensen-taal (komt uit de "Context" van het goedgekeurde plan). +- **`status`** — start op `OPEN`. +- **`start_date`** — vandaag; leeg laten als de server dit zelf invult. +- **Geen reuse:** altijd nieuw record. Bestaande OPEN-sprints van eerder werk blijven naast deze nieuwe leven; niet automatisch sluiten. + +> Eén PBI per sprint is de afgesproken één-op-één-koppeling. Als een plan logisch in meerdere onafhankelijke PBI's uiteenvalt, maak je ook meerdere sprints. + +### 1. `create_pbi` + +``` +{ product_id, title, description?, priority, sort_order? } +``` + +- **`title`** — korte feature-naam, geen PBI-nummer als prefix (DB kent al een id) +- **`description`** — markdown, het "wat & waarom" uit de Context-sectie van het plan +- **`priority`** — `LOW | NORMAL | HIGH` (default `NORMAL`); pas op `HIGH` zetten als de gebruiker het zelf zegt +- **`sort_order`** — leeg laten; server zet `last + 1` binnen de priority-groep +- Status start automatisch op `OPEN` + +### 2. `create_story` + +``` +{ pbi_id, title, description?, acceptance_criteria?, priority, sort_order? } +``` + +- **`title`** — concreet, in user-story stijl als dat past ("Als developer wil ik …") +- **`description`** — technische context, scope-grenzen, niet-doelen +- **`acceptance_criteria`** — markdown checklist (`- [ ] …`); bepaalt wanneer de Story `DONE` is +- `product_id` wordt afgeleid uit de PBI — niet meegeven +- **Sprint-koppeling:** de story wordt aan de actieve OPEN-sprint gehangen (de zojuist aangemaakte). Als er meerdere OPEN-sprints bestaan: bevestig eerst met de gebruiker welke sprint geldt, of breidt `create_story` uit met een expliciete `sprint_id` parameter (apart PBI). +- Status start op `OPEN` + +> **Eén story per PBI** is de gebruikelijke verhouding. Splits alleen op in meerdere stories als het plan logisch in onafhankelijk-shipbare delen valt — let op dat dit dan ook meerdere sprints betekent. + +### 3. `create_task` (één call per taak) + +``` +{ story_id, title, description?, implementation_plan?, priority, sort_order? } +``` + +- **`title`** — werkwoord-vorm: "Implementeer …", "Verplaats …", "Voeg test toe voor …" +- **`description`** — wat de taak afdekt, in 1-3 zinnen +- **`implementation_plan`** — **belangrijk**: markdown met de daadwerkelijke stappen + file-paths + reuse-pointers; dit is wat de Implementation-agent later inleest +- **`sort_order`** — leeg laten voor de eerste call; daarna server-side `last + 1`, of expliciet meegeven om volgorde af te dwingen +- `sprint_id` wordt geërfd van de Story — niet meegeven +- Status start op `TO_DO` + +> De gebruiker werkt taken af in **sort_order**. Zet voorbereidende taken (data-model, types) vóór UI-taken; tests komen ná de feature-implementatie tenzij TDD expliciet is afgesproken. + +--- + +## Hardstop — wachten op uitvoer-instructie + +Na `create_task` (de laatste): **stop**. Niet: + +- ❌ Branch aanmaken +- ❌ Code wijzigen +- ❌ `update_task_status` naar `IN_PROGRESS` zetten +- ❌ `get_claude_context` aanroepen om "vast te beginnen" + +De gebruiker leest de aangemaakte items, eventueel via de UI, en geeft expliciet de instructie *"voer de taken uit"* / *"pak deze story"* / *"begin met taak 1"*. Pas dan schakelt de flow over naar de **execution-loop** uit [CLAUDE.md → "Hoe werk vinden"](../../CLAUDE.md). + +--- + +## Sprint sluiten — `update_sprint` + +Na de execution-fase (laatste taak `DONE` → branch gepusht → PR aangemaakt) wordt de sprint pas `CLOSED` als **beide** condities waar zijn: + +1. **PR merged op `main`** — detecteer met `gh pr view --json mergedAt` (niet-leeg = merged) of een GitHub-merge-webhook +2. **Verify groen** — `gh pr checks ` allemaal ✅, óf de bestaande [`mcp__scrum4me__verify_sprint_task`](./mcp-integration.md) tool slaagt voor de laatste taak + +Pas dan: + +``` +update_sprint({ sprint_id, status: 'CLOSED', end_date: today }) + → status = CLOSED +``` + +**Wat als één van beide rood is?** + +| Situatie | Handmatige flow | Cron-flow (auto) | +|---|---|---| +| PR merged, verify rood | Sprint blijft `OPEN`. Hot-fix taak/PR, daarna close-check herhalen. | Cron mag de sprint na *N* mislukte verify-runs (drempel TBD) op `FAILED` zetten. | +| Verify groen, PR niet merged | Sprint blijft `OPEN`. Wacht op review/merge. | Cron mag na *X* dagen zonder merge op `FAILED` (stale-detectie). | +| PR gesloten zonder merge | Sprint blijft `OPEN` totdat gebruiker beslist. | Cron mag direct op `FAILED` zetten — PR-`closed && !merged` is een eindstatus. | +| Werk geannuleerd door gebruiker | Sprint → `ARCHIVED` (handmatig). | Niet door cron — vereist gebruikersactie. | + +> **Cron-trigger:** een geplande job mag dus zowel `CLOSED` zetten (happy-path: merge + verify groen) als `FAILED` (sad-path: stale PR, blijvend rode verify, PR-closed zonder merge). De drempels (*N*, *X*) en transitie-policy komen in het vervolg-PBI voor de MCP-tools — zie [docs/plans/sprint-mcp-tools.md](../plans/sprint-mcp-tools.md). + +--- + +## Verhouding tot de planning-agent + +[docs/plans/tweede-claude-agent-planning.md](../plans/tweede-claude-agent-planning.md) (status: `proposal`) beschrijft een **automatische planning-agent** die deze flow uit een `PLANNING`-job zelfstandig uitvoert. Tot die agent er is, doet de Claude-Code-sessie het handmatig zoals hierboven. De toolchain (`create_sprint`/`create_pbi`/`create_story`/`create_task` + `update_sprint`) blijft identiek — de agent zal dezelfde MCP-tools gebruiken. + +--- + +## Korte voorbeeld-sessie + +``` +Gebruiker: "plan goedgekeurd" +Claude: create_sprint({ product_id, code: "S-2026-05-11-web-push", + sprint_goal: "Web-Push end-to-end voor open vragen", + status: "OPEN" }) + → sprint_id: 73 + + create_pbi({ product_id, title: "Web-Push notifications voor open vragen", + description: "", priority: "NORMAL" }) + → pbi_id: 142 + + create_story({ pbi_id: 142, + title: "PBI-142: web-push end-to-end", + description: "", + acceptance_criteria: "- [ ] Service worker geregistreerd\n- [ ] …", + priority: "NORMAL" }) + → story_id: 988 (gekoppeld aan sprint 73) + + create_task({ story_id: 988, title: "Voeg VAPID-keys toe aan env-schema", + implementation_plan: "1. lib/env.ts uitbreiden …", + priority: "NORMAL" }) + create_task({ story_id: 988, title: "Server action: subscribe-endpoint", + implementation_plan: "…", priority: "NORMAL" }) + create_task({ story_id: 988, title: "Vitest: subscribe-endpoint smoke", + implementation_plan: "…", priority: "NORMAL" }) + + "Sprint 73 (OPEN), PBI 142, Story 988 met 3 taken aangemaakt. + Klaar om uit te voeren zodra je 'voer uit' zegt." + +Gebruiker: "voer uit" +Claude: + +…na PR-merge + verify groen… + +Claude: update_sprint({ sprint_id: 73, status: "CLOSED", end_date: "2026-05-12" }) + → sprint 73 status = CLOSED + "Sprint 73 gesloten. Increment shipped." +``` + +--- + +## Verwante docs + +- [docs/runbooks/mcp-integration.md](./mcp-integration.md) — volledige MCP-tool reference + execution-loop +- [docs/runbooks/branch-and-commit.md](./branch-and-commit.md) — git-discipline bij uitvoer +- [docs/runbooks/worker-idempotency.md](./worker-idempotency.md) — job-status protocol (uitvoer-fase) +- [docs/plans/tweede-claude-agent-planning.md](../plans/tweede-claude-agent-planning.md) — toekomstige planning-agent (proposal)