Edit-mode-only cross-link in de dialog-footer naar /products/[id]/docs/
settings. Layout: footer is nu flex justify-between met de link links en
de bestaande knoppen (Annuleren + Opslaan) rechts. Create-mode behoudt
right-aligned knoppen via placeholder-span.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- actions/products.ts: nieuwe owner-only deleteProductAction (demo-403,
scope-check via user_id, transaction: null active_product_id + delete).
Cascade-deletes voor PBI/Story/Task/Doc gebeuren via Prisma onDelete:
Cascade in schema.
- components/dashboard/delete-product-confirm.tsx: controlled AlertDialog
(open/onOpenChange) zodat dropdown-item kan triggeren. Bevestiging
roept deleteProductAction; success → toast + router.refresh.
- ProductRowActions: Verwijderen-item toegevoegd in dropdown (na
Separator), text-destructive styling. Opent DeleteProductConfirm via
lokale state.
- ProductsTable doorgeeft product.name aan ProductRowActions zodat de
confirm-dialog de naam kan tonen.
- 1028 tests blijven groen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- components/dashboard/products-table-toolbar.tsx: client met Input
search-veld (debounced 200ms via useEffect+setTimeout) en checkbox
"Inclusief gearchiveerd". State leeft in
useUserSettingsStore.views.productsTable (server-persisted via setPref).
- Lokale state voor input zodat typen vlot blijft; cleanup-functie in
useEffect voorkomt update na unmount.
- Archived-toggle schrijft direct (één klik = één call).
- 1028 tests blijven groen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- components/dashboard/products-table.tsx: client-component met shadcn
Table-primitives. Kolommen: Code (CodeBadge) · Naam (+Actief-badge bij
active product) · #PBI's (rechts, tabular-nums) · Status (alleen badge
bij archived) · Bijgewerkt (nl-NL date) · Acties (placeholder voor
T-1088).
- Filter/sort state via useUserSettingsStore.views.productsTable
(search, includeArchived, sort, sortDir met defaults via fallbacks).
- handleSort wisselt asc↔desc bij dezelfde kolom; nieuwe kolom → asc.
- Rij-klik opent <ProductDialog mode="edit">; acties-cell heeft
stopPropagation zodat klik op de cel niet dialog opent.
- ProductsTableRow shape = ProductDialogProduct + {archived, pbiCount,
updated_at}.
- Empty-filter-result toont info-text in tbody; volledig-empty-state
komt in T-1092.
- 1028 tests blijven groen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- components/shared/sort-header.tsx: generic <SortHeader<TKey>> met
active-state (ArrowUp/ArrowDown) en inactive (ArrowUpDown). Hergebruik
voor zowel /ideas als /dashboard products-tabel.
- components/ideas/idea-list.tsx: refactor; lokale SortHeader-helper +
ArrowUp/Down/UpDown imports vervangen door shared import.
- lib/user-settings.ts: nieuwe ProductsTablePrefs schema (search,
includeArchived, sort enum, sortDir) onder ViewsPrefs.productsTable.
Alle velden optional → defaults via component-fallbacks.
- __tests__/components/shared/sort-header.test.tsx: 6 tests (label,
click-callback, active/inactive classes, custom className, svg-icoon).
- 1028 tests groen totaal; geen regressie in Ideas-tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Audit-rapport in docs/recommendations/PBI-96-demo-audit-2026-05-16.md.
Bevestigt dat alle 3 lagen van de demo-policy volledig zijn:
- Laag 1 (proxy.ts): n.v.t. — geen REST-routes in v1
- Laag 2 (server-actions): alle 4 writes hebben isDemo-guard; list-action
bewust niet (demo MAG lezen volgens plan §B.4)
- Laag 3 (UI): alle write-knoppen DemoTooltip-wrapped + disabled in demo
Geen actie nodig. Manual e2e (stap 9 uit plan-verificatie) blijft als
beheerder-taak vóór merge.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- components/product-docs/disabled-folder-banner.tsx: server-component
banner met AlertTriangle, status-blocked-tokens, en link naar settings.
Tekst legt uit: "lezen mag, nieuwe/edit kan niet, delete wél (cleanup)".
- Integratie in folder-page: render banner als !isFolderEnabled; de
bestaande conditional verbergt de "Nieuwe doc"-knop al.
- Integratie in detail-page: render banner als !isFolderEnabled; de
bestaande conditional verbergt de Edit-knop al. Delete blijft
zichtbaar voor cleanup (zoals plan §C.4 voorschrijft).
- ST-D is hiermee compleet — alle 5 UI-tasks gereed. Directe URLs naar
disabled folders blijven leesbaar (P2-review-fix volledig).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- components/product-docs/new-product-doc-dialog.tsx: één client-component
dat trigger-knop + dialog combineert. Folder-select uit enabled folders,
title-input met auto-slug-suggestie (totdat user slug zelf bewerkt),
starter-template-knop per folder. Deep-link via ?new=1 → dialog opent
automatisch (initial state, geen useEffect setState).
- docs/specs/dialogs/product-doc.md: verplichte dialog-spec (volgt
docs/patterns/dialog.md), beschrijft modes (alleen create), velden,
UX-details (auto-slug, template, minimale frontmatter-wrap),
server-actions, foutmappings, drie-laagse demo-policy, deep-link
conventie, en niet-doelen (geen rich-text, geen template-picker UI).
- Folder-page hookt de dialog in als "Nieuwe doc"-knop bij enabled
folder (verborgen bij disabled folder — banner volgt in T-1071).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- app/(app)/products/[id]/docs/[folder]/[slug]/page.tsx: server-route
die doc laadt (scope-checked via productAccessFilter), frontmatter
parseert, en op basis van ?edit=1 viewer of editor toont. Fallback
voor unparseable frontmatter toont errors + raw content in <pre>.
- product-doc-viewer.tsx: server-component met frontmatter-kop
(title + status-badge + audience/applies_to/last_updated meta) en
body via <Markdown> (XSS-safe).
- product-doc-editor.tsx: client-wrapper rond MarkdownDocEditor met
parseProductDocMd validator + updateProductDocAction + cancelHref.
- delete-product-doc-button.tsx: AlertDialog confirm + delete-action
+ DemoTooltip + redirect-na-success. Disabled in demo.
- Edit-knop conditioneel verborgen bij disabled folder (T-1071 voegt
banner toe); delete blijft altijd zichtbaar voor cleanup.
- Button met `render={<Link/>}` ipv asChild (CLAUDE.md hardstop
base-ui pattern).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- app/(app)/products/[id]/docs/[folder]/page.tsx: server-route die
folder-segment valideert tegen ProductDocFolder-enum (404 anders),
docs sorteert op slug ASC, en de tabel + breadcrumb + "Nieuwe doc"-link
rendert. New-doc-link wordt in T-1070 functioneel via dialog.
- components/product-docs/product-docs-folder-list.tsx: server-tabel
(slug · title · status-badge · updated_at met nl-NL DateTimeFormat).
- components/product-docs/product-doc-status-badge.tsx: MD3-tokens
(bg-status-done/20, bg-status-blocked/20, bg-muted) per status.
Unknown statussen fallbacken naar 'muted'.
- "Nieuwe doc"-knop conditioneel verborgen bij disabled folder; banner
zelf komt in T-1071.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- app/(app)/products/[id]/docs/page.tsx: server-component die met één
prisma.findMany de 3 meest recent bijgewerkte docs per enabled folder
laadt en doorgeeft aan ProductDocsIndex.
- components/product-docs/product-docs-index.tsx: grid van enabled
folders (vaste FOLDER_ORDER), folder-labels, settings-link. Toont
empty-state als 0 folders aanstaan.
- components/product-docs/product-docs-folder-card.tsx: card per folder
met titel + omschrijving + count + 3 doc-links of CTA bij leeg.
- MD3-tokens (bg-surface-container-low, border-border, text-primary);
GEEN bg-blue-500 (CLAUDE.md hardstop).
- debugProps op alle root-divs (debug-id pattern).
- Disabled folders worden niet getoond in INDEX (verborgen) maar
blijven via directe URL bereikbaar — banner-flow in T-1071.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- toggleProductDocFolderAction: owner-only scope (where: id + user_id,
NIET productAccessFilter — folder-config is product-setting). Idempotent
(no-op + success als al in target-staat). Disabled folder verwijdert
GEEN docs uit DB; alleen flag in enabled_doc_folders. Log met doc_id:null
+ FOLDER_ENABLED/FOLDER_DISABLED.
- listProductDocsAction: read-only, scope via productAccessFilter (zonder
demo-403 — demo MAG lezen, zie plan §B.4). Geen rate-limit. Select
zonder content_md. OrderBy [folder, slug]. Mapt DB-enum naar API-string.
- Tests: 10 nieuwe (owner-only-check, idempotent, enable+disable-logs,
demo-read-OK, folder-filter, ontbreken content_md in select). Totaal
28 tests in product-docs actions; 1008 tests groen in monorepo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- actions/product-docs.ts: deleteProductDocAction haalt eerst metadata
op (folder/slug/title), schrijft dan log met doc_id:null + delete in
één $transaction. Geen SetNull-race, geen interactieve tx nodig.
- __tests__: 4 nieuwe tests (auth-paden + P1-coverage met expliciete
check op doc_id:null, type:'DELETED' en metadata-velden gevuld).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- lib/rate-limit.ts: 'create-product-doc' (30/min) + 'edit-product-doc'
(60/min) in eigen PBI-96-blok na M12-Ideas-keys.
- lib/product-docs-server.ts: loadAccessibleProduct + folderApiToDbOrThrow
als 'server-only' helpers. Wordt door create/update/list-actions
hergebruikt; folder-toggle gebruikt direct user_id-scope (owner-only).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- lib/product-doc-parser.ts: parseProductDocMd(md) → {ok, frontmatter, body}
| {ok:false, errors[]} met line-info bij YAML-fouten. Pattern gespiegeld
uit lib/idea-plan-parser.ts.
- lib/product-doc-frontmatter.ts: setProductDocFrontmatterFields(md, patch)
laat de server `last_updated` server-side normaliseren (P2-review-fix
uit docs/recommendations/product-docs-storage-system-review-2026-05-16).
Gebruikt yaml.parseDocument om field-ordering best-effort te behouden.
- todayIsoDate() helper voor 'yyyy-mm-dd' string.
- __tests__: 19 nieuwe tests groen — parse-success/fail-paden, en
expliciete P2-coverage (vervangen + toevoegen last_updated, behoud
overige velden + body).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Voegt twee enums (ProductDocFolder met 8 kern-folders + ProductDocLogType),
een Product-uitbreiding (enabled_doc_folders array met alle 8 als default)
en twee modellen toe (ProductDoc met @@unique(product_id, folder, slug) +
ProductDocLog met denormalized actor_user_id en doc_id nullable + SetNull).
Bestaande producten krijgen de 8-folder-default automatisch via de
ALTER TABLE DEFAULT — geen backfill nodig (zie plan §A.4).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extraheert mergeTimelineItems uit IdeaTimeline als exporteerbare functie
en voegt een vitest-test toe die de nieuwste-boven-sortering verifieert.
revalidatePath in user-questions action was al aanwezig.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Verplaats UserChatInput naar boven in IdeaTimeline en geef de wrapper
sticky top-0 z-10 bg-background border-b border-border — input blijft
zichtbaar terwijl de timeline-items eronder doorscrollt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
userQuestions waren als enige `asc` opgehaald terwijl logs en questions
`desc` gebruiken; het timeline-component sorteert toch client-side `desc`,
maar consistentie voorkomt verwarring bij toekomstige wijzigingen.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
URL-deel van markdown-links mag geen :lineNumber-suffix bevatten —
de check-doc-links.mjs (en standaard markdown) zoekt dan naar een
bestand `selectors.ts:166` dat niet bestaat. Label behoudt :N voor
leesbaarheid; alleen het URL-deel verwijst nu naar het werkelijke
bestand.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(user-settings): voeg IdeasListPrefs schema toe met filterStatuses
Nieuw IdeasListPrefs-subschema met filterStatuses (array van IdeaStatusApi-waarden),
ingehangen als views.ideasList in ViewsPrefs. Testdekking voor geldig, ongeldig en
leeg filterStatuses.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor: extraheer MultiFilterPills naar backlog-filter-popover
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ideas): voeg IdeasFilterPopover component toe
Nieuwe client-component met multi-select statusfilter popover voor het
Ideeënscherm; hergebruikt MultiFilterPills uit backlog-filter-popover.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ideas): vervang inline statuschips door IdeasFilterPopover met user-settings persistentie
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(ideas): voeg componenttests toe voor IdeasFilterPopover en persistentie
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ideas): voeg activeProductId-prop toe aan IdeaList
IdeaListProps uitgebreid met activeProductId: string | null.
Create-form initialiseert en reset naar het actieve product na aanmaken.
Tests en page.tsx bijgewerkt (page.tsx krijgt echte waarde in volgende taak).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ideas): resolve active_product_id en geef door aan IdeaList
Haalt active_product_id op via prisma.user.findUnique en resolveert
het tegen de al opgehaalde toegankelijke productenlijst (AC4). Geeft
het resultaat als prop door aan IdeaList in plaats van hardcoded null.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ideas): stuur activeProductId mee bij snel idee aanmaken
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(ideas): voeg component-tests toe voor activeProductId-voorvulling
AC1: "Nieuw idee"-select voorgevuld met activeProductId
AC2: "Nieuw idee"-select leeg bij activeProductId=null
AC3: "Snel idee" stuurt product_id=activeProductId mee bij createIdeaAction
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(notifications): toon textarea altijd in answer-modal naast opties
Vervang opties-XOR-textarea door twee onafhankelijke blokken: opties
alleen wanneer aanwezig, vrij tekstveld altijd zichtbaar. Bij opties
een visuele scheiding (border-t) en label 'Of typ een eigen antwoord'.
Verstuur-knop nu altijd in footer zichtbaar (was verborgen bij opties).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(notifications): gebruik question.options?.length als conditie
Gebruik de kortere optional chaining variant consistent, conform plan.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(notifications): voeg component-tests toe voor AnswerModal
Dekt: optieknoppen + textarea + Verstuur zichtbaar met opties,
submit via optieknop, submit via vrij tekstveld, disabled Verstuur
bij leeg veld, en demo-modus (textarea + Verstuur disabled).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(notifications): werk answer-modal spec bij voor vrije tekstveld naast opties
Beschrijft dat textarea + Verstuur altijd zichtbaar zijn in multiple-choice
mode. Corrigeert de Cmd/Ctrl+Enter-bullet: shortcut werkt nu ook daar.
Bijgewerkt naar 2026-05-15.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(ST-1369): plan PBI-91 — expliciete schermstaat + draft-zichtbaarheid
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(ST-1369): screen-state module — ScreenState + deriveScreenState()
Pure afleidingslaag die de verspreide schermstaat-derivatie van de Product
Backlog page consolideert tot één testbaar ScreenState-model. Nog geen
consumers — die volgen in T-1035/T-1036.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(ST-1369): unit-tests voor deriveScreenState()
Dekt alle vier de kinds (NO_SPRINT, DRAFT, ACTIVE, EDITING), de building-flag
en de draft-voorrang boven een actieve sprint.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(ST-1369): SprintSwitcher op deriveScreenState + draft op trigger (G5)
De trigger-knop toont nu de concept-sprint zodra er een sprint-draft loopt,
niet langer alleen de (disabled) dropdown-regel. Schermstaat-afleiding loopt
via de pure deriveScreenState() i.p.v. losse flags.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(ST-1369): NewSprintTrigger achter isActiveProduct-gate (G6)
De "Nieuwe sprint"-knop rendert niet langer op een niet-actief product —
een sprint-draft starten daar was verwarrend. page.tsx geeft de bestaande
isActiveProduct-flag door.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(ST-1369): component-tests voor draft-op-trigger (G5) en isActiveProduct-gate (G6)
sprint-switcher: trigger toont concept-sprint bij een pending draft, en geen
concept-label zonder draft. new-sprint-trigger: nieuw testbestand — rendert
niet op een niet-actief product, wel op een actief product zonder draft.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(jobs): extraheer job-mapper naar lib/jobs-mapper.ts + voeg breadcrumb-velden toe
Verplaatst JobWithRelations, JOB_INCLUDE, RawJob, PriceRow, pickDescription,
computeCost en mapJob naar lib/jobs-mapper.ts (zonder 'use server'). Voegt
buildPriceMap helper toe en breidt de types uit met productCode, storyCode en
pbiCode via task->story->pbi en product.code includes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(jobs): voeg GET /api/jobs/[id] route toe + tests
* feat(jobs): useJobsRealtime fetch-on-unknown met dedup-Set
Wanneer een SSE-event een onbekend job_id bevat, haalt de hook de volledige
job op via GET /api/jobs/[id] en upsert die in de store. Een inFlight-Set
voorkomt gelijktijdige dubbele fetches voor hetzelfde job_id. Bekende jobs
blijven de bestaande partial-upsert gebruiken. Zelfde logica in jobs_initial.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(jobs): JobCard breadcrumb + datum-fallback per kind
Voeg productCode/pbiCode/storyCode/startedAt/finishedAt toe aan
JobCardProps; bouw breadcrumb per job-kind en toon finishedAt → startedAt
→ createdAt als datum. JobsColumn geeft de nieuwe velden door.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(jobs): JobCard breadcrumb + datum-fallback tests
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(T-1014): PB-workflow doc — skelet + as-is architectuur-lagen en stores
Eerste laag van het Product Backlog page workflow-doc (PBI-88 / ST-1363):
frontmatter, Context & scope, de architectuur-lagen (PG-triggers -> SSE ->
Zustand -> React) en de drie voedende Zustand-stores.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(T-1015): PB-workflow doc — as-is workflow-states, transitions en diagram
Tweede laag van het Product Backlog page workflow-doc (PBI-88 / ST-1363):
de zeven impliciete workflow-states met preconditie en UI-gedrag, de
transition-tabel, en een Mermaid stateDiagram-v2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(T-1016): PB-workflow doc — to-be expliciete state machine
Derde laag van het Product Backlog page workflow-doc (PBI-88 / ST-1363):
canonieke state-set met mapping op de as-is werkelijkheid, transitietabel,
en het ontwerp van een dunne deriveScreenState()-afleidingslaag bovenop de
bestaande PBI-74 stores (geen nieuwe store).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(T-1017): PB-workflow doc — gap-analyse, aanbevelingen en docs-wiring
Slotlaag van het Product Backlog page workflow-doc (PBI-88 / ST-1363):
gap-analyse (G1-G6, incl. de oorspronkelijke switcher-FOUT), niet-bindende
aanbevelingen, en verwante-docs sectie. Haakt het doc in via de
architecture.md breadcrumb en een cross-link vanuit functional.md F-04.
npm run docs groen: INDEX geregenereerd, alle doc-links valide.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(PBI-ll): voeg lib/product-switch-path.ts toe met resolveProductSwitchTarget
Pure helper die doel-URL bij product-wissel bepaalt; unit-tests dekken alle pad-gevallen.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(product-switch-path): dek alle pad-categorieën en null-terugval af
* feat(nav-bar): gebruik resolveProductSwitchTarget bij product-wissel
Vervang router.refresh() door gerichte navigatie via resolveProductSwitchTarget,
zodat product/sprint/solo-pagina's direct naar het nieuwe product navigeren.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(nav-bar): voeg navigatie-assertions toe voor product-wissel
Voeg 4 tests toe die verifiëren dat NavBar na product-wissel naar de
juiste URL navigeert: /products/B, /products/B/sprint, /products/B/solo,
en router.refresh() op niet-product-pagina's.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(jobs): voeg lib/jobs-time-filter.ts toe met tijdvenster-predikaat
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(user-settings): voeg views.jobs.timeFilter toe aan UserSettingsSchema
Breidt ViewsPrefs uit met een jobs-object (JobsViewPrefs) dat timeFilter
accepteert met waarden '1h' | '24h' | 'all'. ViewsPrefs blijft .strict().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(jobs-time-filter): voeg unit-tests toe voor isWithinTimeWindow en UserSettings-schema
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(jobs-time-filter): voeg JobsTimeFilterControl component toe
Nieuw client-component dat views.jobs.timeFilter leest/schrijft
via useUserSettingsStore met pill-stijl (MD3-tokens).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(jobs): wire JobsTimeFilter in jobs page header
Plaatst het tijdfilter-component rechts van de Jobs-kop via justify-between op de header-div.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(jobs): pas tijdvenster-filter toe in JobsColumn
Lees views.jobs.timeFilter uit de store en filter jobs op createdAt via isWithinTimeWindow, als eerste check vóór de bestaande kind/status-filters.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
schema.prisma declareert IdeaLogType.PLAN_REVIEW_RESULT, maar geen
migratie voegde de enum-waarde toe aan de DB — de migratie
20260514000000_add_review_plan_support deed alleen IdeaStatus +
ClaudeJobKind. Schema-drift: prisma migrate status ziet het niet (die
checkt alleen of migratie-files zijn toegepast, niet schema-vs-DB).
Gevolg: de scrum4me-mcp tool update_idea_plan_reviewed crasht runtime
op prisma.ideaLog.create({ type: 'PLAN_REVIEW_RESULT' }) met
"invalid input value for enum IdeaLogType" — geverifieerd op de
zelf-gehoste DB (pg_enum mist de waarde).
Deze migratie voegt de waarde alsnog toe (ALTER TYPE ADD VALUE),
zelfde stijl als 20260514000000.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ST-1359): docs-index generator indexeert alleen git-tracked bestanden
scripts/generate-docs-index.mjs walkte de docs/-map op schijf en
indexeerde elk .md-bestand — ook ongetrackte scratch-bestanden. Daardoor
kon een tijdelijk review-bestand van een Claude-worktree-sessie een link
in de gegenereerde INDEX.md krijgen die dood achterbleef nadat de
worktree was opgeruimd.
Vervangen door een `git ls-files -z docs`-listing: alleen getrackte (en
gestagede) .md-bestanden komen nog in de index. EXCLUDE_PATTERNS en de
archived-filter blijven ongewijzigd erbovenop werken; git ls-files is
recursief en werkt correct binnen git-worktrees.
Verificatie: npm run lint groen; regressietest met een ongetrackt
docs/-bestand bevestigt dat het niet meer in INDEX.md belandt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(ST-1359): regenereer INDEX.md — verwijder dode reviews-link
npm run docs:check-links faalde op een dode link naar
docs/reviews/onderzoek-wat-er-gedaan-quirky-mist-review.md — een
review-bestand dat nooit in git is gecommit. INDEX.md is geregenereerd
met de geharde generator uit de vorige commit; de stale regel valt
daardoor vanzelf weg (1 regel verwijderd, verder geen wijzigingen).
Verificatie: npm run docs → docs:check-links ✓ All doc links valid
(119 files checked).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(code): add parseCodeNumber helper to lib/code.ts
Pure helper that extracts the trailing numeric sequence from a code string
(ST-007 → 7, T-42 → 42). Non-conforming codes fall back to Number.MAX_SAFE_INTEGER
so they sort to the end. Includes 5 unit tests.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(tasks): add code field to BacklogTask type and all task selects
Adds `code: string | null` to BacklogTask interface and includes it in
all Prisma task.findMany selects (backlog API, stories tasks API, page
hydration routes). Updates coerceTaskPayload and test fixtures to match.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(sort-order): derive story/task sort_order from parseCodeNumber(code)
All create paths (createStoryAction, saveTask, createTaskAction,
materializeIdeaPlanAction) and code-edit paths (updateStoryAction, saveTask
update) now set sort_order = parseCodeNumber(code) instead of last+1.
Removes stale last-record queries from create paths.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(sort-order): decouple sprint membership actions from sort_order
createSprintAction and addStoryToSprintAction no longer write sort_order
when adding stories to a sprint. sort_order is derived from code via
parseCodeNumber, so membership should only set sprint_id + status.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(ordering): remove priority from all story/task orderBy
Story- en taak-ordering is nu puur sort_order asc (created_at als
tiebreaker). PBI-ordering (priority + sort_order) blijft ongewijzigd.
Gewijzigd: backlog/route, pbis/stories/route, claude-context/route,
next-story/route, workspace/route, tasks/route, sprint-runs (query +
in-memory sort), solo-workspace-server, page.tsx (app + mobile + sprint),
store compareStory, actions/sprints story-query, next-story test.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(dnd): remove drag-and-drop reorder for stories and tasks
- Remove reorderStoriesAction, reorderTasksAction, reorderSprintStoriesAction
- Delete REST route app/api/stories/[id]/tasks/reorder/route.ts
- Remove DnD from backlog story-panel and task-panel (flat list)
- Remove reorder-within-sprint branch from sprint-board-client handleDragEnd
- Switch SortableSprintRow to plain SprintRow using useDraggable (membership drag kept)
- Remove all DnD from task-list (status toggle + edit kept)
- Remove story-order/task-order/sprint-story-order/sprint-task-order mutation types and store handlers
- Remove related tests for deleted reorder route; fix sprint store tests
* feat(backlog): toon code-badge op backlog-taakkaarten
Geeft code={task.code} door aan <BacklogCard> in TaskCard (task-panel.tsx).
BacklogCard rendert de CodeBadge al conditionally — alleen de prop ontbrak.
* feat(migration): backfill story/task sort_order from code numeric suffix
One-time Prisma migration that sets sort_order = trailing numeric part
of code for all existing stories and tasks, consistent with
parseCodeNumber (fallback = Number.MAX_SAFE_INTEGER for non-conforming
codes). PBIs are intentionally excluded.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs+tests(sort-order): update for code-binding order on stories/tasks
- Rewrite docs/patterns/sort-order.md: float-insertion PBI only; story/task
sort_order = parseCodeNumber(code), never drag/membership mutated
- Update plan-to-pbi-flow.md: sort_order auto, sprint_id param, priority=label
- Update make-plan.md: priority=label, array order = execution order
- Update rest-contract.md: fix sprint-tasks ordering, remove reorder endpoint
- Add ADR-0011: code is bindende volgordesleutel voor stories/taken
- Regenerate docs/INDEX.md via npm run docs
- Remove reorderStoriesAction/reorderTasksAction mocks from backlog tests
- Remove dnd-kit mocks from task-panel test (panel no longer uses dnd)
- Extend materializeIdeaPlanAction test: assert sort_order=parseCodeNumber(code)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ci): docs:check-links groen — exclude docs/old/ + archiveer stale plans
CI faalde sinds #191 (docs cleanup) op pre-existing broken links:
- docs/old/ bevat archief-docs met by-design stale paden
- docs/plans/PBI-79*, M9*, M11* hadden geprojecteerde paden naar
../backlog/index.md (verplaatst naar docs/old/backlog/) en naar
app-bestanden die nooit met de juiste relatieve prefix waren geschreven
- docs/adr/0000* verwees naar docs-restructure-ai-lookup.md (verplaatst)
- docs/glossary.md verwees naar /docs/backlog/index.md (verplaatst)
Fixes:
- scripts/check-doc-links.mjs: skip docs/old/ recursief
- Move docs/plans/{PBI-79,M9,M11}*.md → docs/old/plans/ (allemaal merged PBIs;
plans waren historisch)
- docs/adr/0000-record-architecture-decisions.md: update pad naar archief
- docs/glossary.md: verwijder dode "backlog index"-link
Verificatie: `npm run docs:check-links` → ✓ All doc links valid (105 files)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(sprint-conflicts): stories uit CLOSED/ARCHIVED/FAILED sprints zijn weer eligible
Bug: bij sprint-aanmaken (en story-toevoegen aan een actieve sprint) gaf de
backend "Geen eligible stories voor deze sprint" zodra je stories aanvinkte
die ooit in een sprint hadden gezeten — ook als die sprint allang gesloten
of gearchiveerd was. partitionByEligibility checkte alleen story.sprint_id,
nooit sprint.status, terwijl getBlockingSprintMap in dezelfde file wél al
filterde op sprint: { status: 'OPEN' }. Inconsistent.
Fix: partitionByEligibility en isEligibleForSprint wegen nu sprint.status
mee. Een story blokkeert alleen als hij in een ANDERE sprint zit DIE NOG
OPEN is. Stories uit CLOSED/ARCHIVED/FAILED sprints worden weer vrij voor
planning — story.sprint_id blijft als historische referentie staan tot de
volgende updateMany hem overschrijft naar de nieuwe sprint.
Neveneffect: een DONE story in een gesloten sprint krijgt nu reason='DONE'
i.p.v. het misleidende reason='IN_OTHER_SPRINT'.
Tests: 3 nieuwe scenario's in __tests__/lib/sprint-conflicts.test.ts
(CLOSED/ARCHIVED/FAILED → eligible, DONE-in-CLOSED → reason=DONE).
De oude test 'does NOT mark crossSprint for stories in CLOSED other sprint'
is vervangen omdat hij het bug-gedrag vastlegde.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(sprint-switcher): repareer mock om CI te unblocken
Twee pre-existing mock-bugs die op main al rood waren maar geen gevolgen
hadden tot de CI-monitor erop sloeg in deze PR:
1. Mock-state miste `entities.settings`. Sinds PBI-79 (commit d587be2)
selecteert SprintSwitcher ook `s.entities.settings.workflow?.pendingSprintDraft?.[productId]?.goal`,
maar de testmock leverde alleen `{ context }`. → undefined-crash op
`entities.settings` reading.
2. Mock factory exporteerde alleen `setActiveSprintAction`, maar de
productie roept `switchActiveSprintAction` aan. Door `vi.mock` werden
alle andere exports `undefined`, waardoor `actionMock` nooit kon
triggeren.
Out-of-scope-fix t.o.v. de sprint-eligibility-fix in dit PR — apart commit
zodat reviewer dit als losse cleanup kan zien. CI is nu groen lokaal:
3/3 sprint-switcher tests + 839/839 full suite.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(ideas): upload-plan knop — short-circuit van Make-Plan AI-flow
Voegt een 'Upload plan' knop toe in idea-row-actions (verschijnt in zowel
list als idea-detail). Klik → file picker → kies .md → server-side parse +
opslaan; idea-status springt naar PLAN_READY. Vandaaruit de bestaande
'Maak PBI' knop voor materialize.
Server (uploadPlanMdAction):
- Toegestaan vanuit DRAFT, GRILLED, PLAN_FAILED, PLAN_READY
- DRAFT → skip-grill: status gaat direct naar PLAN_READY
- PLAN_READY overschrijft het bestaande plan (consistent met
updatePlanMdAction, geen confirmation)
- Geblokkeerd in GRILLING/PLANNING (job loopt), PLANNED (al gematerialiseerd)
- Parse-failure → 422 + details (NIET opslaan, zodat een onparseerbaar plan
nooit in de DB belandt)
- Empty / >100k chars → 422
- Schrijft IdeaLog NOTE met from_status + length
- Rate-limit + demo-guard + ownership-check via loadOwnedIdea (zelfde
patroon als updatePlanMdAction)
UI (idea-row-actions.tsx):
- Hidden <input type=file accept=".md,.markdown,text/markdown,text/plain">
- FileReader → text → action
- Toast bij success + router.refresh()
- Blocked-tooltip in andere statussen
Tests: 10 nieuwe in __tests__/actions/ideas-crud.test.ts dekkend voor:
happy paths (DRAFT/GRILLED/PLAN_READY-overwrite/PLAN_FAILED), blocks
(PLANNED/GRILLING), validation (empty/oversized/parse-fail), 404.
Full suite groen: 849/849.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Add reviews for Bootstrap-wizard plans v3.2 to v3.4
- Review v3.2: Addressed executor model, fire-and-forget issues, and PAT handling.
- Review v3.3: Improved transaction handling, stale recovery, and ID generation.
- Review v3.4: Finalized GitHub permissions, catalog versioning, and E2E verification queries.
- Updated recommendations for each version to enhance implementation readiness.
* fix(ideas): respecteer YAML-volgorde bij plan-materialize
Tasks erven nu story-priority i.p.v. eigen task.priority bij
materializeIdeaPlanAction. Worker sorteert op `priority ASC, sort_order ASC`;
gemixte task-priorities binnen één story zouden anders de YAML-volgorde
verstoren (e.g. tasks met priority 1/1/1/2/1/2 → worker-volgorde 1,2,3,5,4,6
i.p.v. 1,2,3,4,5,6).
- actions/ideas.ts: priority = s.priority bij task-create
- lib/schemas/idea.ts: task.priority optional (geaccepteerd, genegeerd)
- lib/idea-prompts/make-plan.md: documenteer dat task.priority genegeerd wordt
- __tests__/lib/idea-schemas.test.ts: test dat omitted task.priority slaagt
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(make-plan): documenteer backtick-format voor implementation_plan-paden
verify_task_against_plan extraheert paden uit implementation_plan via twee
regex-patronen (backticks + bullet). Paden inline in genummerde tekst-stappen
worden niet herkend → planPaths.length=0 → bij diff >50 regels DIVERGENT.
Voeg sectie "Bestandspaden in implementation_plan — verplicht format" toe
die uitlegt welke formats werken (backticks, bullets) en welke niet (inline).
Plus verband met verify_required-keuze: default ALIGNED_OR_PARTIAL behouden
voor ADR-stubs en multi-file edits.
Voorkomt herhaling van T-963 cancelled_by_self-symptoom waar implementatie
slaagde maar verifier DIVERGENT teruggaf.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(plans): M8 bootstrap-wizard upload-variant v1.4 — backtick-paden
Upload-variant van het volledige technische plan (docs/plans/M8-bootstrap-wizard.md),
bedoeld voor de "Upload plan"-functie. Genereert 1 PBI + 4 Stories + 22 Tasks
via materializeIdeaPlanAction.
v1.4-aanpassingen tov eerdere generatie-iteratie:
- Alle bestandspaden in implementation_plan in backticks (path-extractor matchen)
- Expliciete "Bestanden:" blok per task vóór de stappen
- Alle tasks op verify_required: ALIGNED_OR_PARTIAL (was deels ALIGNED — te strict
voor ADR-stubs en multi-file edits)
Fixt forward-only: T-963 cancelled_by_self door DIVERGENT verifier-verdict.
Re-upload van dit bestand produceert tasks die door verify_task_against_plan
als ALIGNED of PARTIAL geclassificeerd kunnen worden.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* PBI-67: Add review-plan support to Idea model and job config
- Add plan_review_log and reviewed_at fields to Idea model
- Add REVIEWING_PLAN, PLAN_REVIEW_FAILED, PLAN_REVIEWED to IdeaStatus enum
- Add IDEA_REVIEW_PLAN to ClaudeJobKind enum
- Add IDEA_REVIEW_PLAN config to job-config.ts with model=opus, thinking_budget=6000
- Create migration record for schema changes (applied via db push)
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
* PBI-67 Phase 2: Add update-idea-plan-reviewed MCP tool
- Create src/tools/update-idea-plan-reviewed.ts: saves review-log and transitions idea status to PLAN_REVIEWED
- Add PLAN_REVIEW_RESULT to IdeaLogType enum (both repos)
- Register tool in src/index.ts
- Update Prisma schemas (both repos): add plan_review_log and reviewed_at fields to Idea model
- Add REVIEWING_PLAN, PLAN_REVIEW_FAILED, PLAN_REVIEWED to IdeaStatus enum (MCP schema)
- Add IDEA_REVIEW_PLAN to ClaudeJobKind enum (MCP schema)
- Tool includes transaction safety and convergence metrics logging
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
* feat(PBI-67): IDEA_REVIEW_PLAN Phases 3-6 — server actions, UI components, prompt & tests
- Phase 3: startReviewPlanJobAction, cancelIdeaJobAction, status transitions
(REVIEWING_PLAN / PLAN_REVIEWED / PLAN_REVIEW_FAILED), status colors,
job-card/jobs-column filters, idea-list status tabs
- Phase 4: review-plan-job.md prompt (multi-model orchestration with codex
injection + active plan revision via update_idea_plan_md after each round),
runbook, 13 unit tests
- Phase 5: ReviewLogViewer component (rounds, convergence, approval, issues),
idea-detail integration, proper ReviewLog TypeScript types exported from component
- Phase 6.1: wait-for-job discriminator wired (IDEA_REVIEW_PLAN), plan-revision
step made mandatory in prompt (was previously optional/missing)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Goedgekeurd plan voor PBI-84: code wordt de bindende sorteersleutel voor
stories/taken, drag-and-drop herordening verdwijnt. Herzien na multi-model
review (P0/P1/P2) + onderzoek van het plan->onderdelen-mechanisme.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fixes a P2002 unique constraint crash on (user_id, code) when
idea_code_counter on the User is behind the actual codes in the ideas
table (e.g. after direct DB inserts during development).
After incrementing the counter the function now queries
MAX(CAST(SUBSTRING(code FROM 6) AS INTEGER)) via raw SQL and takes
max(counter, maxExisting + 1) as the next code. String MAX was not
safe above IDEA-999, hence the numeric cast. If the counter lagged it
is updated in-place to stay in sync.
No schema change, no migration, no changes outside idea-code-server.ts.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ideas): upload-plan knop — short-circuit van Make-Plan AI-flow
Voegt een 'Upload plan' knop toe in idea-row-actions (verschijnt in zowel
list als idea-detail). Klik → file picker → kies .md → server-side parse +
opslaan; idea-status springt naar PLAN_READY. Vandaaruit de bestaande
'Maak PBI' knop voor materialize.
Server (uploadPlanMdAction):
- Toegestaan vanuit DRAFT, GRILLED, PLAN_FAILED, PLAN_READY
- DRAFT → skip-grill: status gaat direct naar PLAN_READY
- PLAN_READY overschrijft het bestaande plan (consistent met
updatePlanMdAction, geen confirmation)
- Geblokkeerd in GRILLING/PLANNING (job loopt), PLANNED (al gematerialiseerd)
- Parse-failure → 422 + details (NIET opslaan, zodat een onparseerbaar plan
nooit in de DB belandt)
- Empty / >100k chars → 422
- Schrijft IdeaLog NOTE met from_status + length
- Rate-limit + demo-guard + ownership-check via loadOwnedIdea (zelfde
patroon als updatePlanMdAction)
UI (idea-row-actions.tsx):
- Hidden <input type=file accept=".md,.markdown,text/markdown,text/plain">
- FileReader → text → action
- Toast bij success + router.refresh()
- Blocked-tooltip in andere statussen
Tests: 10 nieuwe in __tests__/actions/ideas-crud.test.ts dekkend voor:
happy paths (DRAFT/GRILLED/PLAN_READY-overwrite/PLAN_FAILED), blocks
(PLANNED/GRILLING), validation (empty/oversized/parse-fail), 404.
Full suite groen: 849/849.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Add reviews for Bootstrap-wizard plans v3.2 to v3.4
- Review v3.2: Addressed executor model, fire-and-forget issues, and PAT handling.
- Review v3.3: Improved transaction handling, stale recovery, and ID generation.
- Review v3.4: Finalized GitHub permissions, catalog versioning, and E2E verification queries.
- Updated recommendations for each version to enhance implementation readiness.
* docs(plans): M8 bootstrap-wizard upload-variant v1.4 — backtick-paden
Upload-variant van het volledige technische plan (docs/plans/M8-bootstrap-wizard.md),
bedoeld voor de "Upload plan"-functie. Genereert 1 PBI + 4 Stories + 22 Tasks
via materializeIdeaPlanAction.
v1.4-aanpassingen tov eerdere generatie-iteratie:
- Alle bestandspaden in implementation_plan in backticks (path-extractor matchen)
- Expliciete "Bestanden:" blok per task vóór de stappen
- Alle tasks op verify_required: ALIGNED_OR_PARTIAL (was deels ALIGNED — te strict
voor ADR-stubs en multi-file edits)
Fixt forward-only: T-963 cancelled_by_self door DIVERGENT verifier-verdict.
Re-upload van dit bestand produceert tasks die door verify_task_against_plan
als ALIGNED of PARTIAL geclassificeerd kunnen worden.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* PBI-67: Add review-plan support to Idea model and job config
- Add plan_review_log and reviewed_at fields to Idea model
- Add REVIEWING_PLAN, PLAN_REVIEW_FAILED, PLAN_REVIEWED to IdeaStatus enum
- Add IDEA_REVIEW_PLAN to ClaudeJobKind enum
- Add IDEA_REVIEW_PLAN config to job-config.ts with model=opus, thinking_budget=6000
- Create migration record for schema changes (applied via db push)
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
* PBI-67 Phase 2: Add update-idea-plan-reviewed MCP tool
- Create src/tools/update-idea-plan-reviewed.ts: saves review-log and transitions idea status to PLAN_REVIEWED
- Add PLAN_REVIEW_RESULT to IdeaLogType enum (both repos)
- Register tool in src/index.ts
- Update Prisma schemas (both repos): add plan_review_log and reviewed_at fields to Idea model
- Add REVIEWING_PLAN, PLAN_REVIEW_FAILED, PLAN_REVIEWED to IdeaStatus enum (MCP schema)
- Add IDEA_REVIEW_PLAN to ClaudeJobKind enum (MCP schema)
- Tool includes transaction safety and convergence metrics logging
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
* feat(PBI-67): IDEA_REVIEW_PLAN Phases 3-6 — server actions, UI components, prompt & tests
- Phase 3: startReviewPlanJobAction, cancelIdeaJobAction, status transitions
(REVIEWING_PLAN / PLAN_REVIEWED / PLAN_REVIEW_FAILED), status colors,
job-card/jobs-column filters, idea-list status tabs
- Phase 4: review-plan-job.md prompt (multi-model orchestration with codex
injection + active plan revision via update_idea_plan_md after each round),
runbook, 13 unit tests
- Phase 5: ReviewLogViewer component (rounds, convergence, approval, issues),
idea-detail integration, proper ReviewLog TypeScript types exported from component
- Phase 6.1: wait-for-job discriminator wired (IDEA_REVIEW_PLAN), plan-revision
step made mandatory in prompt (was previously optional/missing)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ideas): respecteer YAML-volgorde bij plan-materialize
Tasks erven nu story-priority i.p.v. eigen task.priority bij
materializeIdeaPlanAction. Worker sorteert op `priority ASC, sort_order ASC`;
gemixte task-priorities binnen één story zouden anders de YAML-volgorde
verstoren (e.g. tasks met priority 1/1/1/2/1/2 → worker-volgorde 1,2,3,5,4,6
i.p.v. 1,2,3,4,5,6).
- actions/ideas.ts: priority = s.priority bij task-create
- lib/schemas/idea.ts: task.priority optional (geaccepteerd, genegeerd)
- lib/idea-prompts/make-plan.md: documenteer dat task.priority genegeerd wordt
- __tests__/lib/idea-schemas.test.ts: test dat omitted task.priority slaagt
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(make-plan): documenteer backtick-format voor implementation_plan-paden
verify_task_against_plan extraheert paden uit implementation_plan via twee
regex-patronen (backticks + bullet). Paden inline in genummerde tekst-stappen
worden niet herkend → planPaths.length=0 → bij diff >50 regels DIVERGENT.
Voeg sectie "Bestandspaden in implementation_plan — verplicht format" toe
die uitlegt welke formats werken (backticks, bullets) en welke niet (inline).
Plus verband met verify_required-keuze: default ALIGNED_OR_PARTIAL behouden
voor ADR-stubs en multi-file edits.
Voorkomt herhaling van T-963 cancelled_by_self-symptoom waar implementatie
slaagde maar verifier DIVERGENT teruggaf.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Voegt een 'Upload plan' knop toe in idea-row-actions (verschijnt in zowel
list als idea-detail). Klik → file picker → kies .md → server-side parse +
opslaan; idea-status springt naar PLAN_READY. Vandaaruit de bestaande
'Maak PBI' knop voor materialize.
Server (uploadPlanMdAction):
- Toegestaan vanuit DRAFT, GRILLED, PLAN_FAILED, PLAN_READY
- DRAFT → skip-grill: status gaat direct naar PLAN_READY
- PLAN_READY overschrijft het bestaande plan (consistent met
updatePlanMdAction, geen confirmation)
- Geblokkeerd in GRILLING/PLANNING (job loopt), PLANNED (al gematerialiseerd)
- Parse-failure → 422 + details (NIET opslaan, zodat een onparseerbaar plan
nooit in de DB belandt)
- Empty / >100k chars → 422
- Schrijft IdeaLog NOTE met from_status + length
- Rate-limit + demo-guard + ownership-check via loadOwnedIdea (zelfde
patroon als updatePlanMdAction)
UI (idea-row-actions.tsx):
- Hidden <input type=file accept=".md,.markdown,text/markdown,text/plain">
- FileReader → text → action
- Toast bij success + router.refresh()
- Blocked-tooltip in andere statussen
Tests: 10 nieuwe in __tests__/actions/ideas-crud.test.ts dekkend voor:
happy paths (DRAFT/GRILLED/PLAN_READY-overwrite/PLAN_FAILED), blocks
(PLANNED/GRILLING), validation (empty/oversized/parse-fail), 404.
Full suite groen: 849/849.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(sprint-conflicts): stories uit CLOSED/ARCHIVED/FAILED sprints zijn weer eligible
Bug: bij sprint-aanmaken (en story-toevoegen aan een actieve sprint) gaf de
backend "Geen eligible stories voor deze sprint" zodra je stories aanvinkte
die ooit in een sprint hadden gezeten — ook als die sprint allang gesloten
of gearchiveerd was. partitionByEligibility checkte alleen story.sprint_id,
nooit sprint.status, terwijl getBlockingSprintMap in dezelfde file wél al
filterde op sprint: { status: 'OPEN' }. Inconsistent.
Fix: partitionByEligibility en isEligibleForSprint wegen nu sprint.status
mee. Een story blokkeert alleen als hij in een ANDERE sprint zit DIE NOG
OPEN is. Stories uit CLOSED/ARCHIVED/FAILED sprints worden weer vrij voor
planning — story.sprint_id blijft als historische referentie staan tot de
volgende updateMany hem overschrijft naar de nieuwe sprint.
Neveneffect: een DONE story in een gesloten sprint krijgt nu reason='DONE'
i.p.v. het misleidende reason='IN_OTHER_SPRINT'.
Tests: 3 nieuwe scenario's in __tests__/lib/sprint-conflicts.test.ts
(CLOSED/ARCHIVED/FAILED → eligible, DONE-in-CLOSED → reason=DONE).
De oude test 'does NOT mark crossSprint for stories in CLOSED other sprint'
is vervangen omdat hij het bug-gedrag vastlegde.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(sprint-switcher): repareer mock om CI te unblocken
Twee pre-existing mock-bugs die op main al rood waren maar geen gevolgen
hadden tot de CI-monitor erop sloeg in deze PR:
1. Mock-state miste `entities.settings`. Sinds PBI-79 (commit d587be2)
selecteert SprintSwitcher ook `s.entities.settings.workflow?.pendingSprintDraft?.[productId]?.goal`,
maar de testmock leverde alleen `{ context }`. → undefined-crash op
`entities.settings` reading.
2. Mock factory exporteerde alleen `setActiveSprintAction`, maar de
productie roept `switchActiveSprintAction` aan. Door `vi.mock` werden
alle andere exports `undefined`, waardoor `actionMock` nooit kon
triggeren.
Out-of-scope-fix t.o.v. de sprint-eligibility-fix in dit PR — apart commit
zodat reviewer dit als losse cleanup kan zien. CI is nu groen lokaal:
3/3 sprint-switcher tests + 839/839 full suite.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>