3.1 KiB
| title | status | audience | language | last_updated | applies_to | |||
|---|---|---|---|---|---|---|---|---|
| ST-1111 — Voer uit-knop met Claude Code job queue | active |
|
nl | 2026-05-03 |
|
ST-1111 — 'Voer uit'-knop met Claude Code job queue
Story: Als developer wil ik op het solo-scherm per task een 'Voer uit'-knop, zodat ik mijn lokale Claude Code-sessie kan inschakelen om de taak uit te voeren.
Branch: feat/M13-claude-job-queue
Sub-tasks en commits
| Task | Commit |
|---|---|
| ST-1111.1 DB: ClaudeJob model + enum + migration | 5274e1e |
| ST-1111.2 API: ClaudeJob status mappers | a1b1f69 |
| ST-1111.3 Server actions: enqueue + cancel | 9d9fb4b |
| ST-1111.4 SSE: ClaudeJob events op solo-stream + initial state | ece0aa9 |
| ST-1111.5 MCP-tools (mcp repo — aparte PR) | — |
| ST-1111.6 UI: 'Voer uit' + cancel in TaskDetailDialog | b9c65eb |
| ST-1111.7 UI: status-pill op SoloTaskCard | dace427 |
| ST-1111.8 Tests: mappers + actions | 2c2a246 |
| ST-1111.9 Docs | dit bestand |
Architectuur
State machine
QUEUED → CLAIMED → RUNNING → DONE
→ FAILED
→ CANCELLED (cancel-knop of server action)
CLAIMED → QUEUED (stale cleanup, >30min, via wait_for_job)
NOTIFY-pijplijn
Omdat claude_jobs geen row-trigger heeft (zoals tasks en stories), stuurt de server action zelf pg_notify via prisma.$executeRaw:
await prisma.$executeRaw`SELECT pg_notify('scrum4me_changes', ${JSON.stringify(payload)}::text)`
Voordeel: expliciete controle over het payload-shape (met type i.p.v. entity). Nadeel: MCP-tools in de mcp-repo moeten hun eigen NOTIFY-aanroep hebben bij update_job_status.
SSE-routing
De bestaande /api/realtime/solo-route herkent nu twee payload-shapes:
entity: 'task'|'story'— bestaande trigger-eventstype: 'claude_job_enqueued'|'claude_job_status'— nieuwe job-events
Job-events worden gefilterd op user_id + product_id. Bij connect stuurt de route een claude_jobs_initial-event met alle actieve + recente (vandaag) jobs.
Idempotency
enqueueClaudeJobAction weigert als claude_jobs WHERE task_id=X AND status IN (QUEUED, CLAIMED, RUNNING) bestaat. De client ontvangt { error, jobId } zodat de UI naar de actieve job kan linken in plaats van een nieuw venstertje te openen.
Beslissingen
Waarom geen DB-trigger voor NOTIFY?
De MCP-server claimt jobs via raw SQL (FOR UPDATE SKIP LOCKED); die schrijft ook direct naar de DB. Een trigger zou clean zijn, maar de MCP-tools moeten hoe dan ook hun eigen NOTIFY-payload bouwen voor update_job_status. Applicatie-NOTIFY houdt de payloads consistent en expliciet.
Waarom cancelled verwijderd uit de store?
Geannuleerde jobs zijn terminaal; het pill-element zou "Geannuleerd" tonen tot de gebruiker een refresh doet. In plaats daarvan wist handleJobEvent de entry bij status === 'cancelled' zodat de kaart teruggaat naar de "Voer uit"-staat.
Auto-clear DONE/FAILED? Niet geïmplementeerd in v1. De pill blijft staan totdat de SSE-connectie herstart (refresh, tab-hidden+visible). Acceptabel voor de eerste iteratie.