diff --git a/docs/patterns/realtime-notify-payload.md b/docs/patterns/realtime-notify-payload.md new file mode 100644 index 0000000..f954f4c --- /dev/null +++ b/docs/patterns/realtime-notify-payload.md @@ -0,0 +1,149 @@ +--- +title: "Realtime NOTIFY payload — veldnaam-contract" +status: active +audience: [ai-agent, developer] +last_updated: 2026-05-03 +--- + +# Realtime NOTIFY payload — veldnaam-contract + +Dit document beschrijft welke veldnamen de Postgres-triggers emitteren, +welke client-bestanden die velden consumeren, en het gekozen rename-pad. + +--- + +## Huidige trigger-payload (voor rename) + +### `notify_task_change` (migratie 20260427000216) +```json +{ + "op": "I|U|D", + "entity": "task", + "id": "...", + "story_id": "...", + "product_id": "...", + "sprint_id": "...", + "assignee_id": "...", + "task_status": "TO_DO", + "task_sort_order": 1, + "task_title": "...", + "changed_fields": ["status"] // alleen bij U +} +``` + +### `notify_story_change` (migratie 20260427000216) +```json +{ + "op": "I|U|D", + "entity": "story", + "id": "...", + "product_id": "...", + "sprint_id": "...", + "assignee_id": "...", + "story_status": "OPEN", + "story_sort_order": 1, + "story_title": "...", + "story_code": "SC-1", + "changed_fields": ["status"] // alleen bij U +} +``` + +**Ontbrekende velden (voor INSERT-rendering in backlog-paneel):** +- story: `pbi_id`, `priority`, `created_at`, `description` +- task: `priority`, `created_at`, `description`, `story_id` ✓ (al aanwezig) + +--- + +## Consumers per veld + +| Veld (huidig) | Bestanden die dit lezen | +|---|---| +| `task_status` | `stores/solo-store.ts` (RealtimeEvent + applyChange), `app/debug-realtime/debug-store.ts` | +| `task_sort_order` | `stores/solo-store.ts` | +| `task_title` | `stores/solo-store.ts`, `app/debug-realtime/debug-store.ts` | +| `story_status` | `stores/solo-store.ts` | +| `story_sort_order` | `stores/solo-store.ts` | +| `story_title` | `stores/solo-store.ts`, `stores/notifications-store.ts`* | +| `story_code` | `stores/solo-store.ts`, `stores/notifications-store.ts`* | + +\* `notifications-store.ts` leest `story_title`/`story_code` uit een **andere** SSE-stream +(`/api/realtime/notifications`), niet uit de `pg_notify`-stroom. Dat pad +blijft onveranderd — de notificatie-route bouwt zijn payload zelf op +(`app/api/realtime/notifications/route.ts:158-159`). + +**`stores/backlog-store.ts`** leest de prefixed velden NIET expliciet — +het doet `{ ...p, ...(data as Partial) }`. Daarmee landt +`story_title` als los veld op het object i.p.v. `title` te vullen → +INSERT-events produceren records zonder `title`, `status`, `sort_order`, +`pbi_id`, `priority`, `created_at`. + +--- + +## Gekozen rename-pad: harde rename + store-update in één migratie-set + +**Aanpak A — harde rename** (gekozen, conform story-beslissing): + +1. **Trigger-migratie**: verander `task_status → status`, `task_sort_order → sort_order`, + `task_title → title`; idem voor story (`story_status → status`, etc.). + Voeg ontbrekende velden toe: `pbi_id`, `priority`, `created_at`, `description`. + +2. **`stores/solo-store.ts`**: verander `RealtimeEvent`-interface en alle + `applyChange`-lees-expressies naar de nieuwe namen + (`event.status`, `event.sort_order`, `event.title`). + Let op: `SoloTask` slaat de story-context op als `story_title`/`story_code` + → dat zijn eigenschappen van `SoloTask`, niet van het event; die mapping + (`event.title → story_title op de task`) blijft expliciet. + +3. **`app/debug-realtime/debug-store.ts`**: update `task_status → status`, + `task_title → title`. + +**Niet kiezen voor aanpak B (dual-emit alias):** maakt payload groter en +het aliaspad moet later toch worden opgeruimd — twee commits voor één rename. + +--- + +## Na de rename — verwacht payload-contract + +### `notify_task_change` (na migratie) +```json +{ + "op": "I|U|D", + "entity": "task", + "id": "...", + "story_id": "...", + "product_id": "...", + "sprint_id": "...", + "assignee_id": "...", + "title": "...", + "status": "TO_DO", + "sort_order": 1, + "priority": 1, + "description": null, + "created_at": "2026-05-03T00:00:00Z", + "changed_fields": ["status"] +} +``` + +### `notify_story_change` (na migratie) +```json +{ + "op": "I|U|D", + "entity": "story", + "id": "...", + "pbi_id": "...", + "product_id": "...", + "sprint_id": "...", + "assignee_id": "...", + "title": "...", + "code": "SC-1", + "status": "OPEN", + "sort_order": 1, + "priority": 1, + "description": null, + "created_at": "2026-05-03T00:00:00Z", + "changed_fields": ["status"] +} +``` + +Dit contract laat `backlog-store.applyChange` de payload direct spreaden +in `BacklogStory`/`BacklogTask` zonder adapter.