From 83262e20bb44943bb9abe6032c652d840f322d0a Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Sun, 3 May 2026 00:21:40 +0200 Subject: [PATCH] docs(junk-cleanup): archive .Plans/ to docs/plans/archive/ --- .gitignore | 1 - .../2026-04-27-claude-md-workflow-update.md | 141 +++++++++++++ .../2026-04-27-insert-milestone-tool.md | 102 ++++++++++ .../archive/2026-04-27-m8-realtime-solo.md | 186 ++++++++++++++++++ 4 files changed, 429 insertions(+), 1 deletion(-) create mode 100644 docs/plans/archive/2026-04-27-claude-md-workflow-update.md create mode 100644 docs/plans/archive/2026-04-27-insert-milestone-tool.md create mode 100644 docs/plans/archive/2026-04-27-m8-realtime-solo.md diff --git a/.gitignore b/.gitignore index 1cb6d2c..d20df70 100644 --- a/.gitignore +++ b/.gitignore @@ -52,7 +52,6 @@ next-env.d.ts .claude/settings.local.json # Local plan/scratch files (per-developer, not shared) -.Plans/ # Editor .vscode/ diff --git a/docs/plans/archive/2026-04-27-claude-md-workflow-update.md b/docs/plans/archive/2026-04-27-claude-md-workflow-update.md new file mode 100644 index 0000000..179b94e --- /dev/null +++ b/docs/plans/archive/2026-04-27-claude-md-workflow-update.md @@ -0,0 +1,141 @@ +# Plan: CLAUDE.md workflow-update na M7 + ST-509/511/512/513 + +## Aanleiding + +`CLAUDE.md` is voor het laatst groot bijgewerkt op 2026-04-25 (`docs/agent-instruction-audit.md`). Sindsdien is er substantieel werk geland dat de workflow raakt: + +- **ST-511** entity codes (Product/PBI/Story) — branch- en commit-conventies hangen er nu aan vast +- **ST-513** API hardening — `400` (malformed JSON) vs `422` (zod-validatie), lowercase status-enums op API-grens, `StoryLog.metadata` JSONB +- **PR #2** review-saga (8 testbestanden faalden bij contract-flip) — duidelijk leerpunt: testpariteit hoort bij contract-wijziging +- **M7 MCP-server** — Claude Code praat nu native met Scrum4Me via `mcp__scrum4me__*` tools en de prompt `implement_next_story`. De huidige 7-stap "vraag-de-gebruiker"-loop in CLAUDE.md is daarmee gedateerd +- **lib/code-server.ts** vs **lib/code.ts** — split is nodig om client-bundle vrij te houden van `pg`. Als gotcha noemenswaard +- **Schema-drift cron** (`trig_015FFUnxjz9WMuhhWNGBQKFD`) — wekelijkse remote agent — agents moeten weten wat ze met zijn rapport doen + +Doel: CLAUDE.md weerspiegelt de werkelijke 2026-04-27 workflow zonder dat het een changelog wordt. + +## Scope — wat we wél en niet aanpassen + +**Wel** (in `CLAUDE.md`): +1. Workflow-sectie — MCP-first met expliciete fallback +2. Conventies — uitbreiden met status-enums, foutcodes, test-pariteit, entity codes in commits +3. Implementatiepatronen — rij voor `lib/task-status.ts` en `lib/code-server.ts`-boundary toevoegen +4. Nieuwe sectie "MCP-integratie" — wat staat er, hoe te gebruiken, link naar scrum4me-mcp repo +5. Definition of Done — markeer expliciet als MVP-scope; M7 is post-MVP en heeft eigen acceptatie + +**Niet**: +- Geen changelog of historiek in CLAUDE.md zelf — dat hoort in `docs/agent-instruction-audit.md` (separate update) +- Geen volledige herschrijving — bestaande structuur blijft (Wat is Scrum4Me, Spec-tabel, Stack, Conventies, Commit Strategy, etc.) +- Geen wijziging in `AGENTS.md` (Codex) — die heeft geen MCP, mag los blijven +- Geen wijziging in functional-spec/architecture/styling docs — die zijn al actueel + +## Concrete edits in `CLAUDE.md` + +### 1. Sectie "Specificatiedocumenten" — uitbreiden + +Voeg toe onder de bestaande tabel: + +| Document | Gebruik voor | +|---|---| +| `https://github.com/madhura68/scrum4me-mcp` | MCP-server repo: tools, prompts, schema-sync workflow | + +(`docs/API.md` staat er al — laten staan.) + +### 2. Sectie "Waar te beginnen" — herschrijven + +Vervang de 7-stap manual loop door een dual-track: + +**Track A — via Claude Code MCP (aanbevolen)**: +``` +1. Roep `mcp__scrum4me__implement_next_story` aan met product_id + (of `list_products` als je het id niet weet) +2. De prompt orkestreert: get_claude_context → log_implementation + → per task in_progress/done → log_test_result → log_commit +3. Bouw de tasks in volgorde van `sort_order` +4. Test: `npm run lint && npm test && npm run build` +5. Commit per laag (zie Commit Strategy) +``` + +**Track B — manueel (Codex of zonder MCP)**: +- Lees task in `docs/scrum4me-backlog.md` +- Volg verder de bestaande 7-stappen-loop + +### 3. Sectie "Implementatiepatronen" — uitbreiden + +Twee rijen toevoegen aan de patronen-tabel: + +| Patroon | Bestand | +|---|---| +| Status-enum mapping (DB ↔ API) | `lib/task-status.ts` | +| Client/server module-boundary | regel: `*-server.ts` bevat DB-calls, `*.ts` is pure helpers — nooit `import { ... } from 'lib/foo-server'` in een client component | + +### 4. Sectie "Conventies" — vier regels toevoegen + +Voeg toe aan de bestaande lijst: + +- **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 via `lib/task-status.ts`-mappers — nooit ad-hoc lowercase elders +- **Foutcodes API**: `400` alleen voor malformed JSON-body (parse-fout); `422` voor zod-validatie en well-formed-maar-niet-acceptabel; `403` voor demo-tokens. Documenteren in `docs/API.md` +- **Tests volgen contract**: bij API-contract-wijziging (status, foutcode, response-shape) MOET in dezelfde commit ook `__tests__/api/` bijgewerkt worden — een falende test op review betekent niet dat de tests "stuk zijn" maar dat de wijziging onvolledig is + +### 5. Nieuwe sectie "MCP-integratie" — toevoegen vóór "Definition of Done" + +Korte sectie (~15 regels): + +```markdown +## MCP-integratie + +Scrum4Me heeft een eigen MCP-server (repo: `madhura68/scrum4me-mcp`) +die deze API exposed als native tools voor Claude Code. + +### Tools beschikbaar in Claude Code +- `mcp__scrum4me__health` — service + DB ping +- `mcp__scrum4me__list_products` — producten waar je toegang tot hebt +- `mcp__scrum4me__get_claude_context` — bundled product/sprint/story/todos +- `mcp__scrum4me__update_task_status`, `_update_task_plan` +- `mcp__scrum4me__log_implementation`, `_log_test_result`, `_log_commit` +- `mcp__scrum4me__create_todo` + +### Prompt +- `implement_next_story` (arg: `product_id`) — end-to-end workflow + +### Schema-drift bewaking +Wekelijks (maandag 08:00 Amsterdam) draait een remote agent +(`trig_015FFUnxjz9WMuhhWNGBQKFD`) die `vendor/scrum4me` syncet en +`prisma:generate + typecheck` uitvoert in scrum4me-mcp. Als die agent +een drift-rapport opent, hoort dat **vóór** een Scrum4Me-PR met +schema-wijziging gemerged kan worden — zodat de MCP-server niet +stilletjes breekt op runtime. +``` + +### 6. Sectie "Definition of Done" — kop verduidelijken + +Wijzig `## Definition of Done` → `## Definition of Done (MVP)` en voeg eronder een korte zin toe: *"M7 (MCP-server) is post-MVP en heeft eigen acceptatie in `docs/scrum4me-backlog.md`."* + +## Bijwerken van auditdoc + +Voeg een sectie aan `docs/agent-instruction-audit.md` toe (datum: 2026-04-27) met: + +- Aanleiding: ST-509/511/512/513 + M7 + PR #2 review-saga +- Gecontroleerde wijzigingen: zelfde tabel-stijl als 2026-04-25 +- Nieuwe regels: status-enums op API-grens, error-code split 400/422, test-pariteit bij contract-wijziging, client/server module-boundary +- Verwijzing naar scrum4me-mcp repo en schema-drift cron + +## Volgorde van uitvoering + +1. **Edits in `CLAUDE.md`** — alle 6 secties hierboven, in volgorde +2. **Edits in `docs/agent-instruction-audit.md`** — nieuwe sectie 2026-04-27 +3. **`npm run lint`** — sanity check +4. **Commit als één logische change** — `docs(workflow): align CLAUDE.md with M7 and post-PR-#2 contract` +5. **PR openen** — review-bare scope, deploys triggeren maar zijn docs-only + +## Wat het NIET oplost + +- `AGENTS.md` (Codex) blijft achter; los aan te pakken indien gewenst +- Eventuele drift in `docs/scrum4me-functional-spec.md` rond status-enums — niet onderzocht; te volgen bij volgende audit +- Geen check of de losse pattern-files in `docs/patterns/` nog kloppen — ook volgende audit + +## Geschatte size + +- ~80 regels toegevoegd/gewijzigd in `CLAUDE.md` +- ~30 regels nieuw in `docs/agent-instruction-audit.md` +- 1 commit, 1 PR diff --git a/docs/plans/archive/2026-04-27-insert-milestone-tool.md b/docs/plans/archive/2026-04-27-insert-milestone-tool.md new file mode 100644 index 0000000..b0a3729 --- /dev/null +++ b/docs/plans/archive/2026-04-27-insert-milestone-tool.md @@ -0,0 +1,102 @@ +# Plan: herbruikbaar `scripts/insert-milestone.ts` + +## Doel + +Eén commando dat een specifieke milestone (PBI + stories + tasks) uit de backlog leest en idempotent toevoegt aan de DB, zónder bestaande data te raken. Voor M8 nu, en voor M9..M∞ later. + +## Bron-keuze: backlog ipv plan-bestand + +Twee bronnen denkbaar: +- **`.Plans/-.md`** — freeform plan-tekst, niet gestructureerd, niet gecommit +- **`docs/scrum4me-backlog.md`** — al strict gestructureerd, gecommit, single source of truth voor alle bestaande seed-pipelines + +Voorstel: het script leest de **backlog**. Workflow blijft natuurlijk: + +1. Plan schrijven naar `.Plans/.md` (lokaal, draft) +2. Milestone-sectie + stories formaliseren in `docs/scrum4me-backlog.md` (PR) +3. Na merge: `npm run db:insert-milestone -- M8 [--product SCRUM4ME]` + +Eén canonical bron, geen ambiguïteit, en de bestaande parser doet 90% van het werk al. + +## Wijzigingen + +### 1. `prisma/seed-data/parse-backlog.ts` — tolerant maken + +Huidige parser kent alleen M0..M6 in `MILESTONE_PRIORITY/_GOAL/_SPRINT_STATUS` + asserts ≥8 milestones / ≥60 stories. M7 en M8 worden nu stilletjes overgeslagen. + +Concrete edits: +- Voeg `M7` en `M8` toe aan de drie maps (M7: priority 4, sprint COMPLETED, goal "MCP-server voor Claude Code"; M8: priority 4, sprint COMPLETED, goal "Realtime updates voor Solo Paneel") +- Voor onbekende sleutels: fallback naar `priority: 4`, `sprint_status: 'COMPLETED'`, `goal: `. Dat maakt M9..M∞ vanzelf bruikbaar zonder code-wijziging +- Verwijder de strikte filter `KNOWN_KEYS.includes(...)` of verleg naar een "alle-M[\d.]+ headers" check +- Voeg optionele `loadBacklog(repoRoot, { strict?: boolean })` toe. `strict: true` (default) behoudt de bestaande "≥8 milestones, ≥60 stories" asserts (zodat de seed niet stilletjes anders gedraagt). Insert-milestone roept met `strict: false` + +### 2. `scripts/insert-milestone.ts` (nieuw, ~90 regels) + +``` +Usage: tsx scripts/insert-milestone.ts [--product ] [--dry-run] +Default product code: SCRUM4ME +``` + +Logica: +1. Parse args; valideer dat milestone-key matcht `^M[\d.]+$` +2. `loadBacklog(repoRoot, { strict: false })` +3. Zoek milestone op `key`; faal helder met "milestone not found in docs/scrum4me-backlog.md" als ie er niet in staat +4. Lookup product via `code` (default `SCRUM4ME`); faal als niet gevonden +5. Upsert PBI: + - `where: { product_id_code: { product_id, code: milestone.key } }` + - sort_order = `(max(sort_order) van bestaande PBIs in product) + 1` als nieuw, anders ongemoeid +6. Voor elke story: + - Upsert Story op `(product_id, code = story.ref)` + - status = `'DONE'` of `'OPEN'` zoals gemarkeerd in markdown + - sort_order, priority en pbi_id correct ingesteld +7. Voor elke task: bulk insert **alleen** als de story op dit moment 0 tasks heeft (idempotent — herhaling dupliceert niets) +8. Print samenvatting: `M8: PBI created, 6 stories upserted (1 created, 5 unchanged), 6 tasks created` +9. `--dry-run`: alle DB-calls overslaan, alleen wat het zou doen printen + +Edge cases: +- Story-code conflict tussen producten: schema heeft `@@unique([product_id, code])` op Story dus dit is per-product safe +- Tasks zonder `code` veld in DB (klopt — code wordt afgeleid van story.code + index in get_claude_context) +- Demo-product: script accepteert `--product DEMO` o.i.d. — niet hardcoded SCRUM4ME + +### 3. `package.json` script + +```json +"db:insert-milestone": "tsx scripts/insert-milestone.ts" +``` + +### 4. Verificatie na implementatie + +- Dry-run eerst: `npm run db:insert-milestone -- M8 --dry-run` +- Daarna echt: `npm run db:insert-milestone -- M8` +- In Prisma Studio of via SQL: zie M8 PBI, 6 stories, 6 tasks onder SCRUM4ME-product +- Tweede run: `npm run db:insert-milestone -- M8` → "0 created, 6 unchanged" — geen duplicaten +- Niet-bestaande key: `npm run db:insert-milestone -- M99` → "milestone M99 not found" +- Bestaande seed-flow blijft werken: `prisma db seed` met `strict: true` faalt nog steeds bij format-drift in de backlog + +## Branch- en PR-strategie + +`scripts/insert-milestone.ts` is orthogonaal aan ST-801. Twee keuzes: + +- **A. Eigen mini-branch + PR** — `tooling/insert-milestone-script`, ~95 regels code, makkelijk reviewbaar, gemerged voordat M8 verder gaat. Daarna gebruiken om M8 in DB te zetten en met de implementatie door. +- **B. Aan ST-801 plakken** — voegt scope toe aan een PR die al code ↔ infra-overschrijdend is (migratie + tools). + +Voorgestelde keuze: **A**. De tool is breder bruikbaar dan M8 alleen. + +## Volgorde + +1. Switch naar `main` (ST-801 blijft op zijn eigen branch staan) +2. Branch `tooling/insert-milestone-script` +3. Edit `parse-backlog.ts` (M7/M8 maps + tolerant + strict-mode option) +4. Schrijf `scripts/insert-milestone.ts` +5. Voeg `db:insert-milestone` toe aan `package.json` +6. Lokaal testen met M8 (dry-run + echt + tweede run) +7. Commit, push, PR +8. Na merge: tool gebruiken om M8 in DB te krijgen, daarna ST-802 oppakken op feat/ST-801-branch + +## Geschatte size + +- ~10 regels parser-edit +- ~95 regels nieuw script +- ~1 regel package.json +- ~25 regels test/usage doc in script-comment +- 1 commit, 1 PR diff --git a/docs/plans/archive/2026-04-27-m8-realtime-solo.md b/docs/plans/archive/2026-04-27-m8-realtime-solo.md new file mode 100644 index 0000000..015e93f --- /dev/null +++ b/docs/plans/archive/2026-04-27-m8-realtime-solo.md @@ -0,0 +1,186 @@ +# Plan: Realtime updates voor Solo Paneel (M8) + +## Aanleiding + +Wanneer Lars in zijn Solo Paneel werkt en parallel Claude Code (via MCP) of Codex aan dezelfde sprint sleutelt, ziet hij de gevolgen pas na een refresh. We willen DB-wijzigingen op `tasks`/`stories` van zijn actieve sprint live in beeld zien. Vraag van de gebruiker: "open een websocket". + +## Transport-keuze — niet écht een WebSocket + +Vercel-deploys ondersteunen geen stateful native WebSockets in serverless of Edge functions. Drie reële opties: + +| Optie | Werkt op Vercel | Externe dienst | Latency | Complexiteit | +|---|---|---|---|---| +| **A. SSE + Postgres LISTEN/NOTIFY** | ✅ (Node runtime, streaming response) | nee | <100ms na DB-write | gemiddeld | +| B. SSE + polling 2–3s | ✅ | nee | 1–3s | laag | +| C. Pusher/Ably (echte WS) | ✅ | ja (gratis tier) | <50ms | laag, maar elke schrijver moet publishen | + +**Voorgestelde keuze: A — SSE met Postgres LISTEN/NOTIFY.** + +Reden: +- Eén bron van waarheid: de DB. Web-mutations, REST-API én MCP schrijven allemaal naar Postgres; een trigger NOTIFY't onafhankelijk van de schrijver. Geen coördinatie nodig met scrum4me-mcp. +- Geen externe dienst, geen extra dep, geen kosten erbij. +- Neon ondersteunt LISTEN/NOTIFY op directe verbindingen. `DIRECT_URL` is al geconfigureerd. +- Naar de client toe: éénrichtingsverkeer — server pusht events, client doet mutaties via bestaande Server Actions/REST. SSE volstaat dus; we hoeven geen full-duplex. +- Voor de gebruiker is het verschil onmerkbaar: realtime updates komen binnen, browsers ondersteunen `EventSource` native. + +We kiezen B (polling) niet omdat het meer DB-load geeft en je Pusher-achtige latency niet haalt. We kiezen C niet vanwege coördinatieoverhead met de MCP-server (extra publish-step in scrum4me-mcp). + +## Architectuur + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Postgres (Neon) │ +│ ┌────────────────────────┐ │ +│ │ TRIGGER on tasks │──► pg_notify('scrum4me_solo', payload_json) │ +│ │ TRIGGER on stories │ │ +│ └────────────────────────┘ │ +└──────────────┬──────────────────────────────────────────────────────────┘ + │ LISTEN scrum4me_solo + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Next.js Node.js runtime route: /api/realtime/solo │ +│ - auth via iron-session cookie │ +│ - opent dedicated pg client (DIRECT_URL), LISTEN scrum4me_solo │ +│ - filtert events: alleen tasks/stories in actieve sprint van een │ +│ product waar user lid/eigenaar is, EN (assignee_id == user OR │ +│ onbeklemtoonde unassigned-story-list) │ +│ - stuurt SSE: data: {type, entity, id, fields} \n\n │ +│ - heartbeat \n\n elke 25s │ +│ - sluit zelf na 4 min (Vercel maxDuration safety); client reconnect │ +└──────────────┬──────────────────────────────────────────────────────────┘ + │ EventSource('/api/realtime/solo?product_id=...') + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Browser — Solo Paneel │ +│ - useSoloRealtime(productId) hook │ +│ - reconnect met exponential backoff (max 30s) │ +│ - Page Visibility API: close on hidden, reopen on visible │ +│ - dispatcht naar solo-store: applyTaskUpdate, applyTaskCreate, │ +│ applyTaskDelete, applyStoryUpdate (assignee/title/status) │ +│ - reconcile-policy: skip update als optimistic in-flight is voor die │ +│ task; anders server wint │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +## Filtering — wie krijgt welke events? + +De trigger NOTIFY't elke task/story-mutatie globaal. De SSE-handler is verantwoordelijk voor toegangs- en relevantie-filtering: + +1. **Toegang**: alleen events waarvan de gerelateerde `story.product_id` in `productAccessFilter(userId)` zit. +2. **Sprint-scope**: alleen events binnen de actieve sprint van het product dat in de query-parameter zit. +3. **Persoonlijke relevantie**: tasks waar `story.assignee_id == userId` (jouw kolommen), plus stories met `assignee_id == null` (de "claim me" lijst). + +Per event extra DB-roundtrip om dit te checken zou duur zijn. Twee oplossingen, bij voorkeur (b): + +(a) Triggerpayload bevat `product_id`, `sprint_id`, `assignee_id` zodat de handler in-memory kan filteren — geen extra DB-call. + +(b) Cache in handler: bij connect resolveert de handler `userId → activeSprintId, productId, assignedStoryIds`. Bij elke notify checkt het de payload tegen die set; bij story-create/assignee-change herwoordt het de set on demand. + +Strategie: combineer (a) trigger zet `product_id` en `assignee_id` in de payload + (b) handler cacht `(activeSprintId, productId, accessibleProducts)` voor de connectie-duur. + +## Concrete implementatie — stories + +### ST-801 Postgres LISTEN/NOTIFY-infrastructuur +- Migration `prisma/migrations/_add_solo_realtime_triggers/migration.sql`: + - `CREATE OR REPLACE FUNCTION notify_solo_change() RETURNS TRIGGER ...` — bouwt JSON met `op` (`INSERT`/`UPDATE`/`DELETE`), `entity` (`task`/`story`), `id`, `product_id`, `sprint_id`, `assignee_id`, `fields` (alleen gewijzigde kolommen bij UPDATE) + - Triggers `AFTER INSERT OR UPDATE OR DELETE ON tasks`, idem op `stories` +- Pas `prisma migrate deploy` toe (idempotent, geen schema-wijziging dus geen TS-impact) +- Done when: `psql $DIRECT_URL -c "LISTEN scrum4me_solo;"` toont een payload bij UI-mutatie + +### ST-802 SSE-route `/api/realtime/solo` +- Bestand `app/api/realtime/solo/route.ts`, `runtime: 'nodejs'`, `maxDuration: 300` +- Gebruikt `pg.Client` (niet de Prisma adapter — directe `LISTEN`-verbinding) +- Auth via iron-session, 401 zonder cookie +- Query-parameter `product_id`, 403 zonder access +- Resolveert active sprint id eenmalig; cachet die in connection-scope +- `ReadableStream` met heartbeat-interval 25s, hard close na 240s +- Filter per event op `product_id == requested && (assignee_id == userId || (entity == 'story' && assignee_id == null))` +- Logged via `console.error` bij pg-disconnect +- Done when: handmatig met `curl -N` op localhost krijg je events binnen 1s na een UI-mutatie + +### ST-803 Client hook `useSoloRealtime(productId)` +- `lib/realtime/use-solo-realtime.ts` (client-only) +- Opent `EventSource('/api/realtime/solo?product_id=' + productId)` +- Reconnect: exponential backoff start 1s → 30s, reset op succesvolle connect +- Page Visibility: `document.visibilityState === 'hidden'` → close; bij visible → reopen +- Cleanup op unmount +- Dispatcht events naar solo-store via nieuwe acties (zie ST-804) +- Done when: tab wisselen sluit/opent connectie zichtbaar in DevTools Network + +### ST-804 Solo-store realtime-acties +- Uitbreiden `stores/solo-store.ts`: + - `applyTaskUpdate(taskId, fields)` — merge in tasks-record; skip als `pendingOps[taskId]` set is + - `applyTaskCreate(task)` — alleen als de task in de eigen kolommen hoort (assignee_id == userId) + - `applyTaskDelete(taskId)` + - `applyStoryAssignment(storyId, assigneeId)` — re-fetch unassigned-list (kleine GET) of ontvang als deel van payload + - `markPending(taskId)`/`clearPending(taskId)` — optimistic-flow markeert mutaties die we zelf doen, zodat we de echo van onze eigen NOTIFY niet dubbel verwerken +- Done when: unit-test op solo-store met simulated events laat juiste state zien + +### ST-805 Wire-up in SoloBoard +- `components/solo/solo-board.tsx`: roep `useSoloRealtime(productId)` aan na `useEffect`-init van tasks +- Klein "live" / "verbinden..." status-indicator (status uit hook): groene stip / pulserende grijze stip +- Toast bij langer dan 5s disconnected +- Done when: open Solo paneel in twee tabs, mutate task in tab A, zie status flippen in tab B binnen 1–2s zonder refresh + +### ST-806 Documentatie + acceptatietest +- Update `docs/scrum4me-architecture.md`: nieuwe sectie "Realtime updates" met diagram en filtering-regels +- Update `CLAUDE.md`: vermelding dat Solo Paneel realtime is + dat MCP-writes vanzelf doorkomen +- Update `docs/API.md`: korte note over `/api/realtime/solo` (Bearer auth, SSE format) +- E2E-acceptatie: lijst van scenario's (zelfde gebruiker twee tabs, MCP-write, REST-write, story-claim, network-flap) handmatig getest +- Done when: scenario's lopen door zonder onverwachte gedragingen + +## Backlog-edits + +In `docs/scrum4me-backlog.md`: + +1. **Milestone-overzicht** — rij toevoegen onder M7: + ``` + | M8: Realtime Solo Paneel | Live updates voor stories/tasks via SSE+LISTEN/NOTIFY | ST-801 – ST-806 | + ``` + +2. **Sectie M8** toevoegen na de M7-sectie, met de zes stories hierboven (ST-801..ST-806) inclusief "Done when"-criteria. Allemaal `[ ]` (nog niet gestart). + +## Wijzigingen elders + +- `.env.example` blijft ongewijzigd (DIRECT_URL stond er al) +- `docs/scrum4me-architecture.md` — sectie "Realtime updates" met diagram en regel "alle UPDATE-triggers zitten op tasks/stories; nieuwe entiteiten erbij vragen om uitbreiding van de trigger-functie" +- Geen wijziging in `lib/code.ts` of `lib/code-server.ts` — dit is server-only realtime +- Schema-drift agent in scrum4me-mcp pikt de migratie automatisch op (geen Prisma-modelwijziging maar wel een nieuwe migratie); typecheck blijft groen omdat we geen Prisma Client-wijziging hebben + +## Risico's en mitigaties + +| Risico | Mitigatie | +|---|---| +| Vercel sluit Node-route na maxDuration | Hard-close server-side bij 240s + automatische client-reconnect; gebruiker merkt dit niet | +| Echo van eigen optimistic mutation | `markPending`/`clearPending` in solo-store; skip als `pendingOps[taskId]` set is | +| Connection leaks (open `pg.Client`'s) | `req.signal.addEventListener('abort')` cleanup; bij Edge cold-start sluit Vercel zelf | +| Trigger overhead op writes | Triggers zijn lichtgewicht (één pg_notify call); meet bij rollout | +| Oude pg_notify payloads >8kb | Zorg dat we alleen primitives (id, status, sort_order, etc.) sturen — geen description/implementation_plan in de payload, daar is een refetch voor | +| Test-DB heeft geen triggers | Migratie automatisch toegepast in CI (Prisma migrate deploy); bestaande tests blijven groen | +| MCP-server schema-sync detecteert migratie als drift | False alarm — wekelijkse cron rapporteert "schema-prisma diff", maar typecheck blijft groen omdat het alleen migratie-SQL is. Beoordeel handmatig bij rapport | + +## Wat dit NIET oplost + +- Realtime in Sprint Backlog of Product Backlog — alleen Solo Paneel +- Conflict-merge bij gelijktijdige updates van twee gebruikers (last-write-wins blijft) +- Mobile pagina (out of scope desktop-first MVP) +- Audit-trail van wie wat wanneer veranderde (bestaat al via StoryLog) + +## Volgorde van uitvoering + +1. Branch `feat/m8-realtime-solo` van main +2. ST-801 (migratie + trigger) — commit, lokaal verifiëren met `psql LISTEN` +3. ST-802 (SSE-route) — commit, `curl -N` lokaal testen tegen lokale UI-mutatie +4. ST-803 (client hook) — commit +5. ST-804 (store-uitbreiding) — commit, met unit-test +6. ST-805 (wire-up + UI-indicator) — commit +7. ST-806 (docs + acceptatie) — commit +8. PR openen — Vercel preview-deploy laat realtime werken op preview-DB (mits trigger via `migrate deploy` mee) +9. Na review: merge + +## Geschatte size + +- ~6 stories, ~12–18 commits +- 1 migratie, 1 nieuwe route, 1 nieuwe hook, kleine store-uitbreiding, UI-indicator +- ~400 regels code + ~80 regels docs +- 1 PR