Commit graph

492 commits

Author SHA1 Message Date
Scrum4Me Agent
68a2439b72 feat(PBI-49): add BEM sub-element data-debug-id to admin, auth, dialogs, entity-dialog, mobile, split-pane 2026-05-09 22:35:56 +02:00
Scrum4Me Agent
c11b5f3b4c feat(PBI-49): add BEM sub-element data-debug-id to components/settings/*
- leave-product-button: root only (single-button component)
- min-quota-editor: __input (number input), __save (save button)
- profile-editor: __username (bio/short-description input), __save (submit)
- role-manager: __roles (checkbox list), __add (save button)
- token-manager: __tokens (active tokens list), __generate (create button)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 22:30:28 +02:00
Scrum4Me Agent
924a31b89a feat(PBI-49): add BEM sub-element data-debug-id to components/notifications/*
- answer-modal: __content (scroll area), __submit (footer)
- notifications-bridge: skip comment (bridge, non-rendering wrapper)
- notifications-realtime-mount: skip comment (returns null)
- notifications-sheet: __header, __items (questions list)
- push-toggle: __switch (button), __label (button text) on subscribed/unsubscribed states
2026-05-09 22:27:23 +02:00
Scrum4Me Agent
d34793d7a9 feat(PBI-49): add BEM sub-element data-debug-id to components/products/* 2026-05-09 22:21:36 +02:00
Scrum4Me Agent
29e05d831e feat(PBI-49): add BEM sub-element data-debug-id to components/jobs/*
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 22:18:32 +02:00
Scrum4Me Agent
59d2d44a64 feat(PBI-49): add BEM sub-elements to nav-status-indicators
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 22:13:44 +02:00
Scrum4Me Agent
eb6ace62c8 feat(PBI-49): add BEM sub-element data-debug-id to components/solo/*
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 22:12:15 +02:00
Scrum4Me Agent
e8537cc3f1 feat(PBI-49): add BEM sub-element data-debug-id to new-product-button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 22:06:02 +02:00
Scrum4Me Agent
c01b1aeb83 feat(PBI-49): add BEM sub-element data-debug-id to components/dashboard/* + components/markdown.tsx
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 22:04:51 +02:00
Scrum4Me Agent
0b9f8708ab feat(PBI-49): add BEM sub-element data-debug-id to components/ideas/* 2026-05-09 21:54:25 +02:00
Scrum4Me Agent
82c0341ff3 feat(PBI-49): add BEM sub-element data-debug-id to components/backlog/* 2026-05-09 21:48:56 +02:00
Scrum4Me Agent
a7ed817c6c feat(PBI-49): add BEM sub-element data-debug-id to components/sprint/*
- new-sprint-dialog: __submit on submit button
- sprint-backlog: __list on SprintBacklogLeft + SprintBacklogRight scroll areas
- sprint-board-client: root wrapper div (display:contents) + __drag-overlay
- sprint-header: __title on goal button, __dates on dates button, __actions on action cluster
- sprint-run-controls: root on controls div, __start/__cancel on action buttons; __blockers-dialog on dialog content
- start-sprint-button: root on trigger button, __dialog on dialog content, __submit on submit button
- sync-active-sprint-cookie: no debug-id (returns null, side-effect only), comment added

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 21:42:42 +02:00
Scrum4Me Agent
e60de10777 feat(PBI-49): add BEM sub-element data-debug-id to StatusBar, NavBar, PanelNavBar
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 21:35:48 +02:00
Scrum4Me Agent
7ceefd4409 refactor(PBI-49): strip unused component/file args from debugProps in shared/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 21:33:03 +02:00
Scrum4Me Agent
f7a44f85a8 refactor(PBI-49): remove data-debug-label from debugProps helper + test
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 21:32:09 +02:00
Scrum4Me Agent
898de87d71 fix(PBI-49): use attr(data-debug-id) for debug tooltip in globals.css 2026-05-09 21:28:26 +02:00
Scrum4Me Agent
c2295241c0 feat(PBI-49): add debugProps to admin/ + dashboard/ + dialogs/ + mobile/ + split-pane/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 21:16:20 +02:00
Scrum4Me Agent
ebac8e5827 feat(PBI-49): add debugProps to products/ + settings/ + notifications/ components 2026-05-09 21:10:27 +02:00
Scrum4Me Agent
c9f0e65a3d feat(PBI-49): add debugProps to jobs/ + ideas/ components 2026-05-09 21:03:49 +02:00
Scrum4Me Agent
6c004ffc74 feat(PBI-49): add debugProps to backlog/, sprint/, solo/ components 2026-05-09 20:57:56 +02:00
Scrum4Me Agent
f555cb547b refactor(PBI-49): migrate 17 shared/ components to debugProps helper
Replace hardcoded data-debug-id + data-debug-label attribute pairs with
{...debugProps(id, component, file)} spread in all 17 components/shared/
files. Existing debug-ids preserved unchanged.
2026-05-09 20:47:51 +02:00
Scrum4Me Agent
a7cc48a230 docs(PBI-49): add debug-id pattern doc + CLAUDE.md reference
Adds docs/patterns/debug-id.md documenting the named-component boundary
rule (6 punten), helper-voorbeeld, skip-criteria en motivatie voor
handmatige pad-argumenten. Voegt verwijzing toe aan CLAUDE.md
patterns-tabel.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 20:42:20 +02:00
Scrum4Me Agent
82b23a9c84 feat(PBI-49): add debugProps helper + Vitest test
Adds lib/debug.ts with debugProps(id, component, file) that returns
data-debug-id and data-debug-label attrs in dev mode, empty object in
production. Adds __tests__/lib/debug.test.ts covering both modes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 20:40:09 +02:00
Janpeter Visser
ce43f7720a
chore: bump 1.3.1 → 1.3.2 (#177)
* chore: bump 1.3.0 → 1.3.1 (force Vercel-redeploy)

Triggert Vercel-rebuild zodat lib/job-config.ts (KIND_DEFAULTS uit #171
en permission_mode-fix uit #172) actief wordt in de live webapp. De
enqueue-laag (lib/job-config-snapshot.ts) snapshot dan correct
permission_mode='acceptEdits' voor idea-kinds + PLAN_CHAT.

Symptoom dat dit oplost: in een lokale smoke-test (na merge van #171
en #172) bleek dat een vers enqueued IDEA_MAKE_PLAN-job nog
requested_permission_mode='plan' kreeg — wat duidt op een Vercel-deploy
die nog op de oude bundle stond. Met deze bump wordt de redeploy
geforceerd.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: bump 1.3.1 → 1.3.2

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 17:22:32 +02:00
Janpeter Visser
6756450131
Sprint: rerun jobs (#176)
* feat(PBI-jobs): voeg isDemo-prop door aan JobsBoard en JobDetailPane

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(PBI-jobs): voeg 'Opnieuw starten'-knop toe aan JobDetailPane

Toont een restart-knop voor jobs met status FAILED, CANCELLED of SKIPPED.
Gebruikt useTransition voor loading-state en DemoTooltip voor demo-modus.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(PBI-jobs): voeg component-test toe voor JobDetailPane restart-knop

Test: knop zichtbaar voor FAILED, verborgen voor DONE, aanroep met juist id, disabled in demo-modus.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(PBI-jobs): voeg F-14 restart-acceptatiecriteria toe aan functional.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 17:19:47 +02:00
Janpeter Visser
71319e629d
feat(PBI-71): UX-fix 'lege sprint' + sprint-switch data-refresh (#175)
- StartSprintButton dialog toont 3-state banner: info met accurate vrije-
  stories count + PBI-context, of waarschuwing als geen PBI geselecteerd
  is, of waarschuwing als de geselecteerde PBI 0 vrije stories heeft
- Voeg sprint_id toe aan BacklogStory/Story/SprintStory + select in PB-
  pagina's en sprint-board mappings, zodat de banner accuraat kan tellen
- createSprintAction: revalidatePath met 'layout' flag voor consistency
  met createSprintWithPbisAction (top-nav 'Sprint' link ververst direct)

Sprint-switch data-refresh op alle relevante pagina's:

- BacklogHydrationWrapper: fingerprint-based re-hydratie zodat PB-data
  na router.refresh opnieuw uit nieuwe initialData komt (was: useEffect
  met lege deps draaide alleen 1x)
- SprintBoardClient: key={sprint.id} forceert remount bij sprint-switch
  zodat lokale sprintStories/sprintStoryIds-state vers ge-init wordt
- Solo (desktop + mobile): gebruik resolveActiveSprint(id) ipv eerste
  OPEN-sprint, plus key={sprint.id} op SoloBoard voor remount

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 16:27:24 +02:00
Janpeter Visser
35e37dac09
feat(ST-006): voeg restartClaudeJobAction toe aan actions/claude-jobs.ts (#174)
- Exporteert restartClaudeJobAction(jobId) die FAILED/CANCELLED/SKIPPED jobs atomair reset naar QUEUED
- Valideert auth, demo-blokkade, ownership en restartbare status
- Gebruikt prisma.$transaction: claudeJob.updateMany + conditionale sprintTaskExecution.updateMany reset
- Verstuurt pg_notify claude_job_status zodat Jobs-pagina via SSE ververst
- Unit-tests: happy-path (FAILED/CANCELLED/SKIPPED), demo-blokkade, not-found, niet-restartbare status, race-conditie en sprint sub-task reset
2026-05-09 13:59:06 +02:00
Janpeter Visser
3c773421da
chore: bump 1.3.0 → 1.3.1 (force Vercel-redeploy) (#173)
Triggert Vercel-rebuild zodat lib/job-config.ts (KIND_DEFAULTS uit #171
en permission_mode-fix uit #172) actief wordt in de live webapp. De
enqueue-laag (lib/job-config-snapshot.ts) snapshot dan correct
permission_mode='acceptEdits' voor idea-kinds + PLAN_CHAT.

Symptoom dat dit oplost: in een lokale smoke-test (na merge van #171
en #172) bleek dat een vers enqueued IDEA_MAKE_PLAN-job nog
requested_permission_mode='plan' kreeg — wat duidt op een Vercel-deploy
die nog op de oude bundle stond. Met deze bump wordt de redeploy
geforceerd.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 12:47:38 +02:00
Janpeter Visser
c2633695d2
fix(KIND_DEFAULTS): permission_mode acceptEdits voor idea-kinds + PLAN_CHAT (#172)
* fix(KIND_DEFAULTS): permission_mode acceptEdits voor idea-kinds + PLAN_CHAT

Spiegel van scrum4me-mcp PR #40. Symptoom: IDEA_GRILL job IDEA-047 werd
3x geclaimd, Claude liep telkens succesvol (exit 0 na 600-900s) maar
deed nooit update_job_status('done'). Lease verliep, retry_count >= 2 →
status FAILED met "agent did not complete job within 2 attempts".

Root cause: KIND_DEFAULTS.permission_mode='plan' voor idea-kinds en
PLAN_CHAT. In autonome batch-mode wacht plan-mode op een human "go" na
elke planning-fase — geen mens in de loop in deze runner-context.

Fix:
- IDEA_GRILL.permission_mode: plan → acceptEdits
- IDEA_MAKE_PLAN.permission_mode: plan → acceptEdits
- PLAN_CHAT.permission_mode: plan → acceptEdits
- PLAN_CHAT.allowed_tools krijgt mcp__scrum4me__update_job_status (ontbrak)

De allowed_tools-lijsten doen de echte sandboxing (geen Bash, geen Edit
voor IDEA_GRILL/PLAN_CHAT). Plan-mode's "veiligheid" wordt al door
tool-allowlists geleverd; acceptEdits is hier puur om Claude door zijn
eigen update_job_status loop te laten lopen zonder approval-wachttijd.

Plus: docs/runbooks/{job-model-selection,worker-idempotency}.md tabellen
bijgewerkt. last_updated note in job-model-selection.md.

Verify: 587 tests in 78 files passed (incl. nieuwe lib/job-config tests).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: remove .claude/scheduled_tasks.lock per ongeluk meegecommit

Lokale tooling-lock-file van de cowork-skills, hoort niet in de repo.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 11:33:03 +02:00
Janpeter Visser
00c5045558
feat(PBI-4/ST-006): mirror job-config naar webapp + runbook-fix CLI-flags (#171)
Spiegelt de scrum4me-mcp wijzigingen naar de Scrum4Me web-app zodat
enqueue-laag (lib/job-config-snapshot.ts) en claim-laag dezelfde
defaults gebruiken. Plus runbook-correctie van een eerder gedocumenteerde
maar niet-bestaande Claude CLI-flag.

- T-25: lib/job-config.ts — mapBudgetToEffort export + KIND_DEFAULTS
  .allowed_tools voor TASK/SPRINT/IDEA_GRILL/IDEA_MAKE_PLAN omgezet
  naar expliciete lijsten zonder wait_for_job/check_queue_empty/
  get_idea_context. Comment-block over CLI-flag-mapping en sync met
  scrum4me-mcp.
- T-26: docs/runbooks/worker-idempotency.md sectie "Config doorgeven aan
  Claude Code (PBI-67)" herschreven. --thinking-budget vervangen door
  --effort (mapping-tabel toegevoegd); --max-turns geschrapt (CLI heeft
  die flag niet — audit-only). Sectie "Wie doet wat in de runner-
  architectuur" toegevoegd.
- T-27: docs/runbooks/job-model-selection.md — notes over max_turns,
  thinking_budget en allowed_tools onder de matrix. Nieuwe sectie
  "Runner-architectuur" met verwijzing naar plan + worker-idempotency.
- T-28: __tests__/lib/job-config.test.ts (nieuw) — 22 tests:
  mapBudgetToEffort grenswaarden + KIND_DEFAULTS.allowed_tools structurele
  checks + cascade regression.

Plus: docs/plans/queue-loop-extraction.md (geschreven in plan-mode,
nu gepubliceerd in repo).

Verify: lint OK, typecheck OK, 587 tests in 78 files passed.
Build niet lokaal uitgevoerd (vereist DATABASE_URL voor "Collecting page
data" — diff raakt geen API-route).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 07:11:52 +02:00
10c52e8b8f chore: remove prisma-erd-generator and stale erd refs
Vercel detecteert @prisma/client en runt automatisch `prisma generate`
zonder --generator filter. Daardoor probeerde de erd-generator op Vercel
te draaien en faalde op libnss3.so (puppeteer/Chrome niet beschikbaar in
de build container). Cascading: de Prisma-client werd niet ge-update,
runtime kreeg oude enum-waarden (ACTIVE i.p.v. OPEN).

ERD is dev-only documentatie en niet meer in productie nodig. Generator
+ dependency + npm scripts + de gegenereerde svg verwijderd. README,
prisma-client pattern en architecture docs bijgewerkt.

Build script blijft `prisma generate && next build` zodat de client ook
bij Vercel build-cache-hits opnieuw wordt gegenereerd.
2026-05-08 14:45:39 +02:00
Janpeter Visser
79005dc777
Sprint: regril (#170)
* ST-cmowjelb1: Parser: bestand-relatieve regel + hint-detectie in YAMLParseError-tak

- Voeg `hint?: string` toe aan PlanParseError type
- Bereken bestand-relatief regelnummer (yamlLine + 1 voor de openings-`---`)
- Detecteer markdown-patronen (numbered/bullet lijst) op de offending regel
- Zet Nederlandstalige hint bij markdown-match
- Render hint als "Tip: …" onder het foutbericht in IdeaMdEditor

* ST-cmowjeq3q: UI: render hint apart onder error-message in IdeaMdEditor

Vervang <span block mt-0.5 text-status-blocked/80> door <div mt-1 text-foreground/80>
voor de Tip-hint per plan-spec (MD3-token, geen status-kleur).

* ST-cmowjewfg: Test: parser geeft hint bij markdown-in-frontmatter

Voeg twee Vitest-cases toe:
- hints when markdown sneaks into frontmatter: fixture met [unclosed op
  een genummerde markdown-regel triggert YAMLParseError op die regel
  (plain lijst zonder unclosed flow parset als geldig YAML)
- omits hint for non-markdown yaml errors: unclosed bracket zonder
  markdown-patroon geeft geen hint
2026-05-08 13:22:10 +02:00
Janpeter Visser
8c63ba377d
feat(PBI-67): model + mode-selectie per ClaudeJob-kind (#169)
* feat(PBI-67/ST-1297): datamodel-velden voor job-model-selectie

Voegt 8 nieuwe optionele velden toe verspreid over Product, Task en
ClaudeJob ten dienste van de override-cascade:

  task.requires_opus → job.requested_* → product.preferred_* → kind-default

Bestaande rijen krijgen NULL (Product/ClaudeJob) of false (Task) en
vallen daarmee terug op de kind-defaults uit de resolver (ST-1298).

Migration is additief: alleen ALTER TABLE ADD COLUMN, geen RENAME of
DROP. Bestaande factories en seed-script blijven werken zonder
aanpassing omdat alle nieuwe velden default-waardes hebben.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(PBI-67/ST-1299): job-config snapshot bij enqueue + worker-flag-runbook

T-789: Snapshot van resolved JobConfig in ClaudeJob.requested_*
bij elke job-creatie. Helper in lib/job-config-snapshot.ts laadt
product (preferred_*) en task (requires_opus) en draait de resolver
uit lib/job-config.ts (mirror van scrum4me-mcp/src/lib/job-config.ts —
zelfde matrix, sync-comment in bestand). Toegepast op alle 5
enqueue-locaties:

  - actions/user-questions.ts          (PLAN_CHAT)
  - actions/sprint-runs.ts × 3         (SPRINT_IMPLEMENTATION x2,
                                        TASK_IMPLEMENTATION loop)
  - actions/ideas.ts                   (IDEA_GRILL / IDEA_MAKE_PLAN)

Test-mocks uitgebreid met product.findUnique en task.findUnique zodat
de helper bij unit tests veilig terugvalt op kind-defaults (alle 563
tests groen).

T-790: Sectie 'Config doorgeven aan Claude Code' toegevoegd aan
docs/runbooks/worker-idempotency.md met CLI-flag-mapping en de
verwachte aanroep per kind. Forward-link naar
docs/runbooks/job-model-selection.md (volgt in T-794).

Plus: docs/plans/job-model-selection.md (de approved plan-doc).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(PBI-67/ST-1300): cost-attribution voor thinking-tokens + admin UI

T-792: token-stats + token-history rekenen actual_thinking_tokens nu
mee in de totale kosten (tegen input-rate, conform Anthropic billing).
COALESCE-veilig zodat oude rijen 0 bijdragen i.p.v. NaN. Nieuwe export
`getTokenStatsByKind` aggregeert tokens en kosten per ClaudeJob.kind
zodat we relatieve uitgaven van IDEA_GRILL/IDEA_MAKE_PLAN/PLAN_CHAT/
TASK_IMPLEMENTATION/SPRINT_IMPLEMENTATION kunnen zien.

T-793: admin/jobs Kosten-tabel toont:
  - Nieuwe kolom 'Thinking' (aantal verbruikte thinking-tokens)
  - Mismatch-marker (rood) als requested_model afwijkt van actuele
    model_id — duidt op een worker die de CLI-flag niet doorgaf.
    Tooltip toont aangevraagd model. Geen Sentry/log-noise.

Page-level cost-berekening volgt dezelfde formule (input_price ×
thinking_tokens). 563 tests groen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(PBI-67/ST-1301): runbook + CLAUDE.md updates voor model/mode-selectie

T-794: Nieuwe runbook docs/runbooks/job-model-selection.md met
override-cascade, kind-default-matrix, override-voorbeelden,
auditspoor en cost-attribution-formule. 107 regels.

T-795: CLAUDE.md hardstop-bullet voor 'Model/mode per ClaudeJob'
(verwijst naar nieuwe runbook) + patterns-quickref-rij voor
job-config resolver. CLAUDE.md blijft 139 regels (≤ 150).

T-796: docs:check-links groen — 108 files, geen broken links. Twee
externe-repo verwijzingen (scrum4me-mcp/...) ge-de-linked tot plain
text omdat de check-links script de zustertree niet traverseert; de
referenties blijven leesbaar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 11:20:10 +02:00
Janpeter Visser
f233dd815e
docs: CLAUDE.md gap-fixes — adr/manual/architecture refs, npm run verify, MCP & cron sectie (#168)
Why: bij /init bleek CLAUDE.md ~95% accuraat maar miste verwijzingen naar docs/adr,
docs/manual en docs/architecture; verify-command was incompleet (typecheck ontbrak);
worker/job-systeem en cron-schedule waren niet zichtbaar zonder config-files te lezen.

- Orientatie: 3 nieuwe pointers (adr/manual/architecture)
- Hoe werk vinden + Verificatie + Deployment: `npm run verify && npm run build`
- Stack: Vitest-rij toegevoegd
- Hardstop: ClaudeJob queue lifecycle bullet
- Patterns quickref: realtime-notify-payload, story-with-ui-component, web-push
- Nieuwe sectie 'MCP & cron': externe MCP-server, cron-schedules, realtime-kanaal
- Env vars: verwijzing naar VAPID/Sentry/Anthropic in .env.example
- Frontmatter last_updated -> 2026-05-08

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 10:07:58 +02:00
Janpeter Visser
eaabec8471
feat(PBI-66): wekelijkse sync van model_prices via Anthropic /v1/models (#167)
Nieuw script `npm run db:sync-model-prices` haalt de actuele Claude 4.x
modellijst op bij de Anthropic API en upsert prijzen in `model_prices`.
Anthropic biedt geen prijs-API, dus prijzen blijven onderhouden in een
PRICE_TABLE constante in het script. Cache-tier-prijzen worden afgeleid
via vaste multipliers (read 0.1x, write 1.25x). Nieuwe Claude 4.x modellen
worden gedetecteerd en gelogd als warning zodat duidelijk is wanneer de
tabel handmatig moet worden bijgewerkt.

- scripts/sync-model-prices.ts: idempotent upsert, --dry-run, retry op 5xx
- ANTHROPIC_API_KEY als optional env-var (.env.example, lib/env.ts)
- scripts/README.md: gebruiksinstructies + edge cases
- docs/plans/sync-model-prices.md: ontwerpdocument

Verificatie: `npm run lint`, `vitest` (563/563), TypeScript clean.
Echt gedraaid tegen DB: 3 created (eerste run) -> 3 unchanged (tweede run).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 09:38:33 +02:00
Janpeter Visser
8a6b2d2cb3
chore: ignore .claude/worktrees in git (#166)
Voorkomt dat lokale worktree-mappen per ongeluk als submodule-pointers
worden gecommit (gebeurde in 4ff5b64).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 09:29:59 +02:00
Janpeter Visser
a16988b957
Sprint: debug, zichtbaarheid componenten (#165)
* feat(debug-store): Zustand store met hydration-flag voor debug-modus

* feat(status-bar): dev-only debug-toggle via geïsoleerde sub-component

* feat(globals.css): debug-mode overlay CSS voor data-debug-id elementen

* feat(shared): data-debug-id+label op navigatie-componenten

* feat(shared): data-debug-id+label op form/select-componenten

* feat(shared): data-debug-id+label op display-componenten
2026-05-08 08:55:43 +02:00
Janpeter Visser
f7464db837
docs: sync data-model, glossary en specs met huidig schema (#164)
Brengt de docs gelijk met de werkelijkheid na PBI-46/47/50/58/59/61/63
en M12. Belangrijkste fixes:

- data-model.md herschreven naar prisma/schema.prisma: nieuwe entiteiten
  (Idea, IdeaLog, IdeaProduct, UserQuestion, ClaudeQuestion, ClaudeJob,
  SprintRun, SprintTaskExecution, ClaudeWorker, LoginPairing,
  PushSubscription, ModelPrice, ProductMember), nieuwe enums
  (FAILED/EXCLUDED, OPEN/CLOSED/ARCHIVED, ADMIN, etc.) en codes
  (PBI/ST/T/SP-N) toegevoegd; verwijderde todos-tabel verwijderd.
- glossary.md: Sprint zonder "max 1 actief" (PBI-63), Story/Task incl.
  FAILED/EXCLUDED, Todo verwijderd, Idea/SprintRun/ClaudeJob/
  verify_result toegevoegd.
- project-structure.md: app/(app)/todos vervangen door
  ideas/insights/jobs/manual/admin/solo; api-tree volledig.
- overview.md: "geen realtime in v1" en Docker-rationale herschreven —
  Postgres LISTEN/NOTIFY + SSE, claude_jobs als queue, opt-in
  Docker-deploy-flow.
- functional.md: F-08 Todo-lijst -> Ideeen-laag, F-09 multi-sprint,
  F-10 Task-status incl. FAILED/EXCLUDED, F-11 endpoint-lijst,
  navigatiestructuur, datamodel-schets en Flow 3 bijgewerkt.
- README.md API-tabel: /api/todos weg, ideas/jobs/users/profile/health
  toegevoegd, kort over realtime/auth-pair/internal/cron.
- patterns + mcp-integration runbook: Todo-/ACTIVE-references vervangen
  door Idea/OPEN; create_todo MCP-tool note over verwijdering.

Linkcheck groen (105 files), INDEX hergegenereerd (98 docs).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 08:16:44 +02:00
Janpeter Visser
3842c05ae9
feat: sprint-switcher overal + PBI auto-toevoeging + cleanups (#163)
* refactor: verplaats sprint-switcher van NavBar naar product-header

Sprint-pulldown zit nu in de bestaande balk op de product backlog
(naast Sprint starten / Instellingen) i.p.v. in het midden van de
NavBar. Alleen zichtbaar wanneer het product ook het actieve product
van de gebruiker is.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: sync package-lock.json version naar 1.2.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor: centreer sprint-switcher en verwijder badges uit dropdown items

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor: vervang sprint-status badge door subtle tekst

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: toon code + titel + status in sprint-switcher dropdown items

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: cookie-write uit Server Component (Next.js 16 verbiedt dit)

setActiveSprintCookie werd direct aangeroepen in app/(app)/products/[id]/sprint/[sprintId]/page.tsx,
wat in Next.js 16 een runtime-error oplevert ('Cookies can only be modified in a Server Action
or Route Handler'). Vervangen door een client-side bridge die syncActiveSprintCookieAction
aanroept na mount, zodat de active-sprint cookie nog steeds gesynced blijft met de URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: filter 'toon afgeronde sprints' in sprint-switcher dropdown

Default verbergt de switcher gesloten/gearchiveerde/mislukte sprints
(toont alleen open + de huidige actieve sprint). Toggle bovenaan de
lijst om alle sprints te tonen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: nieuwe sprint wordt direct geselecteerd zonder redirect

createSprintAction zet nu de active-sprint cookie naar de zojuist
aangemaakte sprint, en de StartSprintButton refresht de huidige
pagina i.p.v. te redirecten naar /sprint. Resultaat: gebruiker blijft
op de product backlog en ziet de nieuwe sprint direct geselecteerd
in de sprint-pulldown.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor: verplaats Manual en Admin naar user-menu dropdown

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: voeg geselecteerde PBI automatisch toe aan nieuwe sprint

Bij sprint-aanmaak wordt de pbi_id uit de selection-store als hidden
form-field meegestuurd. Server-side worden alle stories van die PBI
(zonder sprint) en hun taken aan de nieuwe sprint gekoppeld; stories
krijgen status IN_SPRINT met incrementele sort_order.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: sprint-switcher op solo- en sprint-board pagina's

Sprint-switcher is nu beschikbaar op de drie hoofdpagina's: product
backlog, solo board en sprint board. Allen renderen 'm in een
gecentreerde balk net onder de NavBar. Sprint-data via gedeelde helper
getSprintSwitcherData.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 02:32:50 +02:00
Janpeter Visser
a4a7ef9b8b
refactor: sprint-switcher van NavBar naar product-header (#162)
* refactor: verplaats sprint-switcher van NavBar naar product-header

Sprint-pulldown zit nu in de bestaande balk op de product backlog
(naast Sprint starten / Instellingen) i.p.v. in het midden van de
NavBar. Alleen zichtbaar wanneer het product ook het actieve product
van de gebruiker is.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: sync package-lock.json version naar 1.2.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 01:05:39 +02:00
Janpeter Visser
4a9db57e94
feat(PBI-63): meerdere sprints per product + EXCLUDED + sprint-switcher (#161)
- Sprint lifecycle: ACTIVE→OPEN, COMPLETED→CLOSED, +ARCHIVED (FAILED behouden)
- TaskStatus: +EXCLUDED (overgeslagen door agent-loop via bestaande TO_DO filter)
- Cookie-gebaseerde actieve sprint per product (lib/active-sprint.ts)
- Route splitsen: /products/[id]/sprint/[sprintId] + /sprint redirect-page
- NavBar: gestapelde product/sprint dropdowns + BUILDING-badge derivatie
- Backlog selectie-modus + nieuwe-sprint-dialog (createSprintWithPbisAction)
- Migratie 20260507210000_sprint_lifecycle: ALTER TYPE RENAME (geen data-rewrite)
- Version bump 1.0.0 → 1.2.0

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 00:15:04 +02:00
Janpeter Visser
d68aa1e5e6
Sprint: pbi-55 (#160)
* fix(input): border-border bg-input-background voor light-mode zichtbaarheid

* fix(select): border-border bg-input-background voor light-mode zichtbaarheid
2026-05-07 22:57:57 +02:00
Janpeter Visser
10bf25dadd
feat(PBI-61): multi-select op kind- en status-filter (#159)
- Filter-pills zijn nu toggle-knoppen; meerdere waardes per dimensie selecteerbaar
- "Alle"-pill wist de selectie binnen die dimensie
- Eén active-badge per geselecteerde waarde, klikbaar om losse selectie te wissen
- localStorage formaat is nu CSV met whitelist-validatie (oude 'all'-waarde valt vanzelf weg → leeg = geen filter)
- Filtercount in trigger toont som van actieve selecties

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 22:21:09 +02:00
Janpeter Visser
e8371b9f95
feat(PBI-61): filter popover + created_at op job-kaart (#158)
- Nieuwe JobsColumn met Kind/Status filter-popover per kolom (Actief/Klaar)
- Filterstate persistent in localStorage (whitelist-validatie tegen corrupte waardes)
- Active-filter badges in kolomheader, klikbaar om te wissen
- Aanmaakdatum + tijd rechtsonder op elke JobCard (nl-NL short formaat)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 21:52:27 +02:00
Janpeter Visser
7ae8a24372
Sprint: pbi-55 (#156)
* ST-cmovs79lt: Schema + migratie PushSubscription model

Voeg PushSubscription model toe aan prisma/schema.prisma met
snake_case-conventie, relation field op User, en bijbehorende
migratie (push_subscriptions tabel, FK + index op user_id).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ST-cmovs7e3o: web-push dependency + VAPID env vars feature-gated

Voeg web-push + @types/web-push toe aan package.json.
Registreer NEXT_PUBLIC_VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY,
VAPID_SUBJECT en INTERNAL_PUSH_SECRET als .optional() in lib/env.ts.
Documenteer alle vier in .env.example en README.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ST-cmovs7jgr: lib/push-server.ts met sendPushToUser + stale-cleanup

Server-only push-lib met VAPID feature-gate, send naar alle
subscriptions van een user, en automatische cleanup bij 404/410.
Unit tests: success-pad, 410 verwijdert sub, 404 verwijdert sub,
andere errors loggen zonder delete.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ST-cmovs7ouz: lib/push-client.ts client-side push helpers + stub actions/push.ts

Client-side helpers: isPushSupported, isIOSSafari, isStandalonePWA,
urlBase64ToUint8Array, subscribeToPush, unsubscribeFromPush.
Stub actions/push.ts zodat imports resolven (implementatie volgt
in volgende taak). Unit tests voor urlBase64ToUint8Array.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ST-cmovs7ut4: actions/push.ts subscribeToPushAction + unsubscribeFromPushAction

Vervangt stub met volledige implementatie: requireUser via getSession,
demo-block, Zod-validatie, upsert met user_id-scoping en user-scoped
deleteMany. Tests (8): idempotentie, demo-block, unauthenticated, invalid input.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ST-cmovs80c1: POST /api/internal/push/send met constant-time Bearer check

Route: 503 als INTERNAL_PUSH_SECRET uitstaat, 401 bij verkeerd secret
(timingSafeEqual), 400 bij invalid JSON, 422 bij Zod-fout, 204 bij succes.
push-server.ts: env-import vervangen door process.env om SESSION_SECRET
validatie tijdens build te omzeilen. Tests aangepast.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ST-cmovs862j: Admin test-send route + public/sw.js service worker

POST /api/internal/push/test-send: requireAdmin check (redirect bij
niet-admin), optioneel body met defaults, roept sendPushToUser aan, 204.
public/sw.js: push-handler met showNotification, notificationclick met
same-origin guard, focus bestaand venster of openWindow.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ST-cmovs8jvq: PushToggle component met 3 states + iOS-banner

Client component met states loading/unsupported/ios-needs-install/
denied/subscribed/unsubscribed. useEffect detecteert initial status,
permission-prompt alleen via user-click. iOS-banner NL, denied-uitleg,
subscribe/unsubscribe knoppen met sonner-toasts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ST-cmovs8psg: notifications-sheet + iOS meta-tags in layout

notifications-sheet.tsx: PushToggle onderin met sectie
'Notificatie-instellingen' en visuele scheidslijn.
app/layout.tsx: appleWebApp.capable, statusBarStyle en
mobile-web-app-capable meta-tags toegevoegd via Next.js Metadata API.
manifest.json had al display: standalone.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ST-cmovs8vxj: docs/patterns/web-push.md pattern-documentatie

Architectuur-diagram, payload-shape, foutcodes, VAPID-config,
iOS-quirks, demo-users blokkade, trigger-voorbeelden (server +
HTTP) en admin-testroute curl-voorbeeld.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 21:46:01 +02:00
Janpeter Visser
25bd59c0b9
fix(PBI-59): jobs sorted newest-first, unified on created_at (#157)
- actions/jobs-page.ts: beide kolommen orderBy created_at desc
- stores/jobs-store.ts: nieuwe actieve jobs unshift (top) i.p.v. push (bottom)

Hiermee komen nieuw aangemaakte QUEUED/CLAIMED jobs bovenaan in de
linker kolom, in plaats van onderaan waar ze buiten het scrollbare deel
kunnen vallen.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:58:27 +02:00
Janpeter Visser
883534a521
fix(PBI-59): map jobs_initial SSE payload by job_id, not id (#155)
De server-route stuurt JobPayload[] (met `job_id`), maar de client deed
`initJobs(jobs, ...)` waardoor alle entries in activeJobs `id: undefined`
kregen — wat React-key warnings opleverde:

  Each child in a list should have a unique "key" prop.

Fix: SSE jobs_initial niet meer als overwrite gebruiken; SSR-fetch heeft
de volledige JobWithRelations al in de store gezet. We reconcileren nu
per job met upsertJob (status/branch/error/summary updaten van bekende
jobs, onbekende jobs als partials toevoegen — zelfde gedrag als gewone
'message' SSE events).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:22:07 +02:00
Janpeter Visser
00dbbb4f94
chore(ci): gate auto-deploy behind AUTO_DEPLOY_ENABLED repo-variable (#154)
Voorkomt automatische Vercel-deploys op PR-preview en push-naar-main
zolang \`vars.AUTO_DEPLOY_ENABLED == 'true'\` ontbreekt. Default-staat:
auto-deploy UIT, scheelt Actions-minuten op het free-plan.

Handmatig deployen blijft werken via workflow_dispatch (Actions tab →
"Run workflow" → kies preview of production). Die job (\`deploy-manual\`)
is niet aan de flag gebonden.

Aanzetten van auto-deploy: Settings → Secrets and variables → Actions
→ Variables → New repository variable: \`AUTO_DEPLOY_ENABLED\` = \`true\`.

\`changes\` job (path-filter) staat ook achter de flag — die wordt alleen
gebruikt door de twee auto-deploy jobs.

Runbook bijgewerkt met de nieuwe default + uitleg.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:17:15 +02:00
Janpeter Visser
a268df3680
feat(PBI-59): Sprint.code (SP-N sequentieel per product) (#153)
Voegt een verplicht code-veld toe aan Sprint, sequentieel per product
(consistent met PBI-N, ST-NNN, T-N).

- **Schema** — `Sprint.code String @db.VarChar(30)` + `@@unique([product_id, code])`
- **Migratie** — voegt kolom toe als nullable, backfillt bestaande sprints
  via `ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY created_at)`
  als `SP-N`, en zet daarna NOT NULL + UNIQUE.
- **Generator** — `generateNextSprintCode(productId)` in lib/code-server.ts
  volgt het patroon van story/pbi/task; createSprintAction gebruikt
  `createWithCodeRetry` voor race-bescherming.
- **Seed** — sprint-counter per product (`SP-1`, `SP-2`, ...).

Zichtbaar in:
- Sprint-header (`Product › Sprint actief · SP-3`)
- JobCard + JobDetailPane voor SPRINT_IMPLEMENTATION jobs
- Insights: VelocityChart x-axis (compacter dan goal-truncated),
  AlignmentTrend tooltip, SprintInfoStrip
- actions/jobs-page.ts: `sprintCode` is weer een echte code i.p.v. null

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:10:16 +02:00
Janpeter Visser
16f01283ef
feat(PBI-59): add Detail/Usage view-switch on /jobs (#152)
Splits het middenpaneel van de jobs-pagina in twee views (zoals admin/jobs):

- **Detail** — alle metadata (status, kind, product, branch, PR, dates,
  errors, summary, verify-result) plus een kind-aware beschrijving:
  TASK → implementation_plan, IDEA_GRILL → grill_md, IDEA_MAKE_PLAN →
  plan_md, PLAN_CHAT → idea.description.
- **Usage** — model, tokens (in/uit/cache/totaal), berekende kosten in
  USD via ModelPrice-tabel, en duur (started→finished).

SprintSubTasksPane blijft als sticky header boven beide views.

Server action `fetchJobsPageData` haalt nu ook ModelPrices op en
selecteert task.{description,implementation_plan} +
idea.{description,grill_md,plan_md} zodat de description en costUsd in
JobWithRelations gevuld kunnen worden.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 19:51:53 +02:00