Server Component met data-fetching via getSprintTokenHistory/getDayTokenData/
getPbiTokenAggregates. SprintTokenHistoryTable, TokenDayChart (Recharts LineChart),
PbiTokenTable en TokenSelectors (client, URL-params). Link toegevoegd in
insights/page.tsx.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drie functies via prisma.$queryRaw: getSprintTokenHistory (per-sprint
aggregaat), getDayTokenData (dag-totalen met guard op lege sprintId),
getPbiTokenAggregates (per-PBI met guard). Tests voor alle drie.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Voeg model_id, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens (nullable) toe aan ClaudeJob
- Voeg nieuw ModelPrice model toe met per-1M prijsvelden en currency default USD
- Migratie 20260506010013_add_token_usage_fields aangemaakt en toegepast
- Seed uitgebreid met standaardprijzen voor claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5-20251001
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Voegt server action toe die secondary_products voor een idee atomisch
vervangt: primair product gefilterd, toegankelijkheid gevalideerd via
productAccessFilter, deleteMany + createMany in één transactie.
Demo-geblokkeerd, Zod-gevalideerd.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Voegt IdeaProduct schema toe (dependency van story-qtkvz6ly), breidt
IdeaWithProduct type en IdeaDto interface uit met secondary_products array,
en laadt de relatie mee in findMany/findFirst in page.tsx en REST GET.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Voegt IdeaProduct model toe met idea_id/product_id/created_at,
unique constraint op (idea_id, product_id), cascade-deletes.
Breidt Product.idea_products en Idea.secondary_products relaties uit.
Migratie 20260506010000_add_idea_product_secondary aangemaakt en toegepast.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Beschrijft hoe agent-jobs met Product.auto_pr=true automatisch
commit → push → PR → auto-merge → deploy doorlopen. Documenteert
welke laag wat doet (worker, scrum4me-mcp, GitHub Actions, Vercel),
setup-vereisten per product, foutpaden en wanneer auto_pr UIT
laten.
Onderdeel van PBI-36 ST-1220. De auto-PR-implementatie zelf zit
in scrum4me-mcp; deze runbook documenteert de bestaande flow plus
de nieuwe auto-merge-stap (scrum4me-mcp PR #23).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- TabKey union uitgebreid met 'sync'.
- Sync-tab alleen zichtbaar als syncData !== null && idea.status === 'planned'
(M12 keuze 6: na Materialiseer-actie).
- page.tsx roept loadIdeaSyncData alleen aan bij PLANNED + pbi_id, anders
null doorgeven aan layout.
- showSync-flag bepaalt of de tab in TAB_KEYS array zit en in de UI
gerenderd wordt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Toont per Story onder de gekoppelde PBI: status-badge, taak-rij met
job-status (incl. SKIPPED), branch, pushed_at, pr_url, en bestaande
<StoryLog>-component voor activity-log. PBI-header met PR-link en
gemerged-badge.
Realtime: subscribed op /api/realtime/notifications. Bij story_log-
event waar story_id matcht, of claude_job_status voor dit idea →
router.refresh() (server-render levert nieuwe data).
MD3-tokens overal: bg-status-todo/in-progress/done, bg-surface-
container, bg-muted/60. Geen bg-blue-500.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Joint Idea → PBI → Stories → Tasks → ClaudeJobs + StoryLog in één
prisma.findFirst-call. user_id-scope conform M12-keuze 2 (strikt
user_id-only). Filtert ClaudeJob op kind=TASK_IMPLEMENTATION en
neemt laatste 20 story-logs per story.
Returns null als idea geen pbi_id heeft — caller render geen tab.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
StoryLogPayload type toegevoegd aan NotifyPayload union. In de
notification-handler: idea_id-pad checkt accessibleIdeaIds (M12
user-private), fallback op product_id check accessibleProductIds.
Consistent met question-payload-pattern.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AFTER INSERT op story_logs emit op scrum4me_changes channel met
entity:'story_log'. Trigger resolved product_id en idea_id via
story → pbi → product/idea zodat SSE-route kan filteren zonder
extra DB-call per event.
Migratie toegepast op Neon productie-DB.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dorny/paths-filter@v3 leest PR-changed-files via de GitHub API.
Default GITHUB_TOKEN heeft op deze repo geen pull-requests:read
permission, waardoor de action faalde met "Resource not accessible
by integration".
Workflow-level permissions toegevoegd: contents:read +
pull-requests:read. Geen andere wijzigingen aan jobs nodig.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drie samenhangende wijzigingen in ci.yml:
T-554: Nieuwe `changes` job met dorny/paths-filter@v3 die per push/PR
detecteert of er deploy-relevante paden zijn gewijzigd. Output `code`
boolean wordt door de deploy-jobs gelezen.
T-555: deploy-preview if-conditie checkt nu `needs.changes.outputs.code`
plus PR-labels: deployt als (code-changed AND niet skip-deploy) OR
force-deploy. deploy-production deployt alleen bij code-changed pushes
naar main (path-filter op productie).
T-556: workflow_dispatch trigger toegevoegd met `target: preview |
production` input + nieuwe deploy-manual job. Geeft handmatige
re-deploy via Actions-tab. CI-job slaat workflow_dispatch over (geen
nieuwe code, alleen redeploy).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Vercel's eigen Git-integratie uitzetten zodat de GitHub Actions
workflow de enige bron van deploy-truth wordt. Plus labels
skip-deploy en force-deploy aangemaakt voor selectieve controle
in volgende taken.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Beschrijft beslissingsboom verify_result × diff-staat × branch-staat
→ JobStatus, met SKIPPED gereserveerd voor al-gemergd werk en FAILED
voor échte fouten. Plus StoryLog-verplichting (log_implementation,
log_commit, log_test_result) en idempotency-protocol vóór schrijven.
PBI-33 batch (5-5 22:22) gedocumenteerd als case-study: drie
protocol-overtredingen die deze runbook + de nieuwe SKIPPED-status
aanpakken.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Italic, neutrale grijstint die SKIPPED visueel onderscheidt van
CANCELLED (zelfde grijstint, maar non-italic) en van FAILED (rood).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- lib/job-status.ts: SKIPPED ↔ 'skipped' mapping in beide richtingen
- components/shared/job-status.ts: label "Overgeslagen" + neutrale italic styling
- actions/admin/jobs.ts: cancel-guard erkent SKIPPED als eindstatus
- app/api/cron/cleanup-agent-artifacts: SKIPPED ook opruimen na 7d
- lib/insights/agent-throughput: SKIPPED telt mee als terminal
ACTIVE_JOB_STATUSES bewust ongewijzigd — SKIPPED is afgerond.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reactie op PBI-33 batch waar worker correct detecteerde dat werk al
gemerged was, maar geen passende status had om dat uit te drukken.
SKIPPED is bedoeld voor jobs met verify=EMPTY/DIVERGENT waar de
diff t.o.v. origin/main leeg is — geen FAILED (geen fout), geen DONE
(geen netto-output).
Migratie: ALTER TYPE ClaudeJobStatus ADD VALUE 'SKIPPED'.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Nav-label 'Ideeën' hernoemd naar 'Ideas'; breadcrumb idem
- Grill/Plan tabs disabled (grijs, cursor-not-allowed) zolang er geen
content is; groene stip zodra grill_md resp. plan_md beschikbaar is
- SSE hook roept router.refresh() aan bij job done/failed zodat de
Timeline automatisch de nieuwe GRILL_RESULT/PLAN_RESULT logs toont
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- /admin/jobs: overzicht van de laatste 100 Claude jobs met cancel/delete
- /admin/products: overzicht van alle producten met archive/delete
- JobsTable component met statusbadges en acties per job
- ProductsTable component met eigenaar, leden/PBI-telling en acties
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- requireAdmin() checkt nu de database i.p.v. session.isAdmin (was altijd undefined)
- loginAction stelt session.isAdmin in op basis van UserRole in de DB
- registerAction stelt session.isAdmin = false expliciet in
- NavBar toont 'Admin'-link conditioneel als roles.includes('ADMIN')
- UserMenu ROLE_LABELS uitgebreid met ADMIN → 'Admin'
- Tests aangepast: prismaUserRole.findFirst mock toegevoegd
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Nieuwe server action in actions/user-questions.ts
- Aanmaken UserQuestion + ClaudeJob PLAN_CHAT in transactie
- Blokkeert als idea.plan_md null is of product ontbreekt
- Idempotency-check: geen dubbele PLAN_CHAT per idee
- pg_notify claude_job_enqueued event voor SSE-realtime
- Rate-limit config uitgebreid met create-user-question
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Voeg PLAN_CHAT toe aan ClaudeJobKind enum
- Voeg UserQuestionStatus enum toe (pending, answered)
- Voeg UserQuestion model toe met idea_id, user_id, question, answer, status
- Koppel user_questions relatie aan Idea model
- Migratie: 20260505120000_add_user_question_plan_chat
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- app/(app)/admin/layout.tsx: admin-sidebar met links (Gebruikers/Claude Jobs/Producten)
- app/(app)/admin/page.tsx: redirect naar /admin/users
- app/(app)/admin/users/page.tsx: server component, query users+roles, geeft userId door
- components/admin/users-table.tsx: client component met UsersTable, RoleBadge,
RolesDialog (checkboxes, eigen ADMIN-rol geblokkeerd), DeleteDialog (confirm),
ResetToggle — alles via useTransition + server actions
- Maakt user aan als die niet bestaat, anders upgrade bestaande user
- Upsert ADMIN in user_roles (idempotent)
- Helder foutbericht als argumenten ontbreken (process.exit(1))
- package.json scripts: "create-admin": "tsx scripts/create-admin.ts"