docs(junk-cleanup): archive .Plans/ to docs/plans/archive/
This commit is contained in:
parent
0982640ade
commit
83262e20bb
4 changed files with 429 additions and 1 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -52,7 +52,6 @@ next-env.d.ts
|
|||
.claude/settings.local.json
|
||||
|
||||
# Local plan/scratch files (per-developer, not shared)
|
||||
.Plans/
|
||||
|
||||
# Editor
|
||||
.vscode/
|
||||
|
|
|
|||
141
docs/plans/archive/2026-04-27-claude-md-workflow-update.md
Normal file
141
docs/plans/archive/2026-04-27-claude-md-workflow-update.md
Normal file
|
|
@ -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
|
||||
102
docs/plans/archive/2026-04-27-insert-milestone-tool.md
Normal file
102
docs/plans/archive/2026-04-27-insert-milestone-tool.md
Normal file
|
|
@ -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/<datum>-<slug>.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/<naam>.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: <header-title>`. 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 <milestone-key> [--product <code>] [--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 <key> 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
|
||||
186
docs/plans/archive/2026-04-27-m8-realtime-solo.md
Normal file
186
docs/plans/archive/2026-04-27-m8-realtime-solo.md
Normal file
|
|
@ -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/<ts>_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
|
||||
Loading…
Add table
Add a link
Reference in a new issue