Commit graph

551 commits

Author SHA1 Message Date
b2e26805b3 fix(PBI-96/T-1104): toon echte folder-totaal op docs-index i.p.v. preview-cap
Some checks are pending
CI / Lint, Typecheck, Test & Build (pull_request) Waiting to run
CI / Detect deploy-relevant changes (pull_request) Blocked by required conditions
CI / Deploy Preview (PR) (pull_request) Blocked by required conditions
CI / Deploy Production (main) (pull_request) Blocked by required conditions
CI / Deploy Manual (workflow_dispatch) (pull_request) Waiting to run
Page bouwde docsByFolder met max 3 docs per folder (voor preview-lijst),
en de card gebruikte docs.length als telling — dus folders met >3 docs
toonden altijd '3 docs'. Zichtbaar geworden door PBI-100 seed (vóór seed
had geen folder >3 docs).

Fix: page bouwt totalByFolder in dezelfde loop (geen extra query), geeft
door via ProductDocsIndex → ProductDocsFolderCard.totalCount.
2026-05-16 16:35:49 +02:00
a3bf6dbd4e feat(PBI-100/T-1101): seed Scrum4Me-docs migratie (82 inserts)
Some checks are pending
CI / Detect deploy-relevant changes (pull_request) Blocked by required conditions
CI / Deploy Preview (PR) (pull_request) Blocked by required conditions
CI / Lint, Typecheck, Test & Build (pull_request) Waiting to run
CI / Deploy Production (main) (pull_request) Blocked by required conditions
CI / Deploy Manual (workflow_dispatch) (pull_request) Waiting to run
Gegenereerd door scripts/generate-product-docs-migration.ts. Per-folder
counts: adr=11, architecture=9, patterns=17, plans=24, runbooks=11,
specs=2, manual=7, api=1. Idempotent via ON CONFLICT (product_id, folder,
slug) DO NOTHING.
2026-05-16 16:23:37 +02:00
8557cd1676 fix(PBI-100): normaliseer frontmatter voor productDocFrontmatterSchema
Bron-bestanden:
- 5 ADRs (0003/0005/0007/0008/0010): status 'accepted' → 'active'; 4 ervan
  krijgen ontbrekende title.
- 8 architecture/*.md: verwijder 'related:' veld dat als YAML niet
  parseerde (markdown-link-syntax binnen YAML).
- 9 plans: status mapping naar enum-waarden (planned→draft, done→archived,
  proposal→draft, reviewed→active, ready-to-execute→active, in-progress→active);
  2 M8-plans krijgen ontbrekende title/status.

Generator-script:
- Lowercase slug (mixed-case filenames als PBI-100/ST-1109/M8 worden
  lowercase in DB; bron-bestanden blijven leesbaar).
2026-05-16 16:23:31 +02:00
4010e8c296 feat(PBI-100/T-1100): generator-script voor product-docs migratie
Leest docs/{adr,architecture,patterns,plans,runbooks,specs,api,manual}/*.md
en produceert prisma/migrations/<ts>_seed_scrum4me_product_docs/migration.sql
met dollar-quoted INSERTs + ON CONFLICT DO NOTHING. Hergebruikt
parseProductDocMd en setProductDocFrontmatterFields voor frontmatter-
normalisatie. CUID-generatie via crypto.randomUUID() (geen extra dep nodig).
2026-05-16 16:20:39 +02:00
a71ea6f380 feat(PBI-100/T-1099): frontmatter aanvullen in 13 bron-bestanden
ADRs (6), plans (6), runbooks (1) krijgen YAML-frontmatter zodat
parseProductDocMd ze accepteert voor de product-docs seed (T-1100/T-1101).
2026-05-16 16:19:45 +02:00
0cf238b52a docs(PBI-100): implementatieplan seed-Scrum4Me-docs 2026-05-16 16:19:37 +02:00
4b4e52d11e refactor(UnassignedStoriesSheet): simplify story claiming logic by removing local state management
Some checks are pending
CI / Lint, Typecheck, Test & Build (push) Waiting to run
CI / Detect deploy-relevant changes (push) Blocked by required conditions
CI / Deploy Preview (PR) (push) Blocked by required conditions
CI / Deploy Production (main) (push) Blocked by required conditions
CI / Deploy Manual (workflow_dispatch) (push) Waiting to run
2026-05-16 15:57:15 +02:00
03eb1432ab Merge pull request 'feat/PBI-98-products-table' (#5) from feat/PBI-98-products-table into main
Some checks are pending
CI / Lint, Typecheck, Test & Build (push) Waiting to run
CI / Detect deploy-relevant changes (push) Blocked by required conditions
CI / Deploy Preview (PR) (push) Blocked by required conditions
CI / Deploy Production (main) (push) Blocked by required conditions
CI / Deploy Manual (workflow_dispatch) (push) Waiting to run
Reviewed-on: #5
2026-05-16 15:54:02 +02:00
92775cfcf4 Merge pull request 'docs(PBI-98): voeg implementatieplan dashboard-products-tabel toe' (#4) from docs/PBI-98-plan into main
Some checks are pending
CI / Lint, Typecheck, Test & Build (push) Waiting to run
CI / Detect deploy-relevant changes (push) Blocked by required conditions
CI / Deploy Preview (PR) (push) Blocked by required conditions
CI / Deploy Production (main) (push) Blocked by required conditions
CI / Deploy Manual (workflow_dispatch) (push) Waiting to run
Reviewed-on: #4
2026-05-16 15:53:42 +02:00
2fc7bec3ad feat(PBI-98/T-1095): Docs-link op /products/[id] page-header
Some checks are pending
CI / Lint, Typecheck, Test & Build (pull_request) Waiting to run
CI / Detect deploy-relevant changes (pull_request) Blocked by required conditions
CI / Deploy Preview (PR) (pull_request) Blocked by required conditions
CI / Deploy Production (main) (pull_request) Blocked by required conditions
CI / Deploy Manual (workflow_dispatch) (pull_request) Waiting to run
Voegt een "Docs"-link toe vóór de bestaande "Instellingen"-link in de
product-backlog-page-header (regel 154). Zelfde styling (text-xs
text-muted-foreground hover:text-foreground). Vervangt navigatie die
voorheen via ProductSubNav verliep (T-1094).

Geen wijziging in docs/architecture/product-docs.md nodig — bevat geen
ProductSubNav-mention (grep gaf 0 hits). ST-F hiermee compleet.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 15:44:29 +02:00
e66a4e979c feat(PBI-98/T-1094): verwijder ProductSubNav + layout-cleanup
- components/products/product-subnav.tsx: verwijderd. Sub-nav-laag
  (Backlog/Sprint/Solo/Docs/Instellingen) bleek overbodig — navigatie
  tussen sub-pages gebeurt al via page-headers en top-nav.
- app/(app)/products/[id]/layout.tsx: terug naar minimale layout
  (SetCurrentProduct + children). showDocs-berekening en import van
  ProductSubNav weg.
- Defensieve guard `(product.enabled_doc_folders ?? []).length > 0`
  in fix/product-layout-enabled-docs-guard branch wordt obsolete door
  deze cleanup — sluit die PR ongemerged na PBI-98 merge.
- 1035 tests blijven groen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 15:43:44 +02:00
bee15014c8 docs(PBI-98/T-1093): update F-03 + product-dialog spec
- docs/specs/functional.md §F-03: vervang oude grid-acceptance door
  twee blokken: 'CRUD via dialog' (incl. cross-link, delete-confirm,
  cascade-delete) en 'tabel /dashboard' (kolommen, sort, search,
  archived-toggle, rij-klik, acties-kolom, demo-policy, empty-state).
  Data-sectie verwijst naar nieuwe enabled_doc_folders en
  users.settings.views.productsTable.
- docs/specs/dialogs/product.md: nieuwe sectie "Cross-link 'Naar
  docs-instellingen' (PBI-98)" beschrijft layout + gedrag. "Bewust NIET
  in v1"-sectie: archiveProductAction → deleteProductAction.
- ST-E hiermee compleet.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 15:42:54 +02:00
27728296ff feat(PBI-98/T-1092): empty-state + component-tests
- components/dashboard/products-empty-state.tsx: nieuwe component met
  rounded-xl container, NL-tekst, en NewProductButton (verborgen in demo).
- ProductsTable: vroege return ProductsEmptyState bij products.length===0.
- __tests__/components/dashboard/products-empty-state.test.tsx: 4 tests
  (tekst, NewProductButton zichtbaar/verborgen op demo, container-styling).
- __tests__/components/dashboard/product-row-actions.test.tsx: 7 tests
  (Activeer/Actief-badge zichtbaarheid per state, Docs/Backlog aria-labels,
  Meer-acties-knop disabled in demo). Mocks: next/navigation, sonner,
  actions/products + actions/active-product.
- 1035 tests groen totaal.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 15:41:48 +02:00
a6fcfe685a feat(PBI-98/T-1091): ProductDialog cross-link "Naar docs-instellingen"
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>
2026-05-16 15:40:17 +02:00
2c6d356acf feat(PBI-98/T-1090): /dashboard rendert ProductsTable; ProductList weg
- app/(app)/dashboard/page.tsx: vervang ProductList-grid door
  ProductsTable + ProductsTableToolbar. Data-fetch met
  include: { _count: { select: { pbis: true } } } — geen N+1 voor
  #PBI's-kolom. Geen archived-searchParam meer; filter zit nu
  client-side in useUserSettingsStore via toolbar.
- max-w-4xl → max-w-6xl voor de bredere tabel.
- Verwijderd:
  - components/dashboard/product-list.tsx (grid, obsolete)
  - __tests__/components/dashboard/product-list.test.tsx
- 1024 tests blijven groen (1028 → 1024 door obsolete ProductList-tests).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 15:39:21 +02:00
98526f9f20 feat(PBI-98/T-1089): deleteProductAction + DeleteProductConfirm
- 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>
2026-05-16 15:38:19 +02:00
972e415fc9 feat(PBI-98/T-1088): ProductRowActions (Activeer/Docs/Backlog + dropdown Archive)
- components/dashboard/product-row-actions.tsx: inline knoppen
  Activeer (via ActivateProductButton) of "Actief"-badge,
  Docs (BookOpen-icon → /docs), Open backlog (ArrowRight-icon →
  /products/[id]). Dropdown (•••) met Archiveer/Herstel toggle.
- Archive: archiveProductAction (redirect /dashboard) of
  restoreProductAction (success + router.refresh).
- Verwijderen-item komt in T-1089 zodra deleteProductAction bestaat.
- DemoTooltip op dropdown-trigger (writes blokkeren); Docs/Backlog
  blijven klikbaar voor demo.
- Wires ProductRowActions in ProductsTable acties-kolom.
- 1028 tests blijven groen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 15:37:12 +02:00
ba37c8e8f2 feat(PBI-98/T-1087): ProductsTableToolbar (search + archived-toggle)
- 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>
2026-05-16 15:35:51 +02:00
d1df1f6cc4 feat(PBI-98/T-1086): ProductsTable component (6 kolommen + sort + rij-klik)
- 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>
2026-05-16 15:34:45 +02:00
6a0f18c16c feat(PBI-98/T-1085): extract SortHeader + ProductsTablePrefs in user-settings
- 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>
2026-05-16 15:33:12 +02:00
9a3a243ddf docs(PBI-98): voeg implementatieplan dashboard-products-tabel toe
Some checks are pending
CI / Lint, Typecheck, Test & Build (pull_request) Waiting to run
CI / Detect deploy-relevant changes (pull_request) Blocked by required conditions
CI / Deploy Preview (PR) (pull_request) Blocked by required conditions
CI / Deploy Production (main) (pull_request) Blocked by required conditions
CI / Deploy Manual (workflow_dispatch) (pull_request) Waiting to run
Plan-doc met 6 stories (ST-1386 t/m ST-1391) en 11 taken (T-1085 t/m
T-1095). Vervangt /dashboard grid door Ideas-stijl tabel (sort, search,
archived-toggle, rij-klik=edit-dialog, acties-kolom met Activeer/Docs/
Backlog + Archive/Delete dropdown). Cleanup ST-F verwijdert
ProductSubNav uit PBI-96 en voegt Docs-link toe op product-page-header.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 15:30:44 +02:00
4e3df2d425 Merge pull request 'docs: leg Forgejo-als-leidende-forge vast; vervang gh CLI referenties' (#2) from docs/forgejo-pr-rule into main
Some checks are pending
CI / Lint, Typecheck, Test & Build (push) Waiting to run
CI / Detect deploy-relevant changes (push) Blocked by required conditions
CI / Deploy Preview (PR) (push) Blocked by required conditions
CI / Deploy Production (main) (push) Blocked by required conditions
CI / Deploy Manual (workflow_dispatch) (push) Waiting to run
Reviewed-on: #2
2026-05-16 14:52:17 +02:00
9fc15f279a Merge pull request 'claude/friendly-williamson-02ff6b' (#3) from claude/friendly-williamson-02ff6b into main
Some checks are pending
CI / Lint, Typecheck, Test & Build (push) Waiting to run
CI / Detect deploy-relevant changes (push) Blocked by required conditions
CI / Deploy Preview (PR) (push) Blocked by required conditions
CI / Deploy Production (main) (push) Blocked by required conditions
CI / Deploy Manual (workflow_dispatch) (push) Waiting to run
Reviewed-on: #3
2026-05-16 14:52:02 +02:00
0b4cb511d6 docs: leg Forgejo-als-leidende-forge vast; vervang gh CLI referenties
Some checks are pending
CI / Lint, Typecheck, Test & Build (pull_request) Waiting to run
CI / Detect deploy-relevant changes (pull_request) Blocked by required conditions
CI / Deploy Preview (PR) (pull_request) Blocked by required conditions
CI / Deploy Production (main) (pull_request) Blocked by required conditions
CI / Deploy Manual (workflow_dispatch) (pull_request) Waiting to run
- CLAUDE.md: nieuwe hardstop "Forge" — Forgejo (git.jp-visser.nl) is
  leidend, gh CLI verboden, PRs via Forgejo compare-URL of tea CLI.
  "Hoe werk vinden" stap 8 verwijst nu naar Forgejo compare-URL ipv
  gh pr create.
- docs/runbooks/branch-and-commit.md: agent-batch-tabel verbod-kolom
  "PR aanmaken" generic; nieuwe sectie "Forgejo is leidend — PR-flow"
  beschrijft 4-staps PR-flow (push → compare-URL → user klikt of tea
  CLI → optionele github-mirror push). GitHub-checks → Forgejo-checks.
  Merge-conflict-mitigatie's "vóór gh pr create" → "vóór het aanmaken
  van de Forgejo-PR".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 14:44:47 +02:00
d32b39f62f docs(PBI-96/T-1076): architecture breadcrumb + F-15 functional spec
Some checks are pending
CI / Lint, Typecheck, Test & Build (pull_request) Waiting to run
CI / Detect deploy-relevant changes (pull_request) Blocked by required conditions
CI / Deploy Preview (PR) (pull_request) Blocked by required conditions
CI / Deploy Production (main) (pull_request) Blocked by required conditions
CI / Deploy Manual (workflow_dispatch) (pull_request) Waiting to run
- docs/architecture/product-docs.md: nieuw topical doc met folder-set,
  datamodel, P1/P2 review-fixes, server-actions tabel, UI-routes en
  editor-extractie. Verwijst naar plan + recommendations + relevante
  bestanden.
- docs/architecture.md: breadcrumb-rij naar product-docs.md.
- docs/specs/functional.md: F-15-sectie "Per-product documentatie
  (Product Docs)" met acceptatiecriteria voor overzicht/aanmaken/
  bewerken/verwijderen/folder-config/demo-policy/toegang + randgevallen.
- INDEX.md regen automatisch via pre-commit hook.

ST-F is hiermee compleet — ALLE 18 PBI-96 taken klaar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 14:38:15 +02:00
9cbbabe469 docs(PBI-96/T-1075): demo-policy audit — drie lagen volledig
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>
2026-05-16 14:36:50 +02:00
23cce4f35b feat(PBI-96/T-1074): ProductSubNav + layout-integratie
- components/products/product-subnav.tsx: client-component met tabs
  (Backlog · Sprint · Solo · Docs · Instellingen). Active-state via
  usePathname; patroon gespiegeld uit components/shared/nav-bar.tsx
  navLink-helper. Docs-tab conditioneel verborgen wanneer 0 folders
  enabled.
- app/(app)/products/[id]/layout.tsx: hookt <ProductSubNav> in na
  <SetCurrentProduct>; geeft showDocs = product.enabled_doc_folders
  .length > 0 mee. ST-E hiermee compleet — folder-config beheert
  zichtbaarheid van Docs-tab end-to-end.

(Geautomatiseerde smoke-test voor disabled-folder route blijft buiten
scope; de banner-rendering wordt impliciet door T-1071 gevalideerd.
Manual e2e in T-1075.)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 14:36:07 +02:00
e32ae45eb7 feat(PBI-96/T-1072): /docs/settings page + folder-toggle
- app/(app)/products/[id]/docs/settings/page.tsx: server-route met
  breadcrumb + intro, geeft isOwner door aan toggle-component.
- components/product-docs/product-doc-folder-toggle.tsx: client met
  8 checkboxes (één per ProductDocFolder enum-lid). Owner kan
  toggelen → toggleProductDocFolderAction (optimistic update +
  rollback bij error). ProductMember (niet-owner) krijgt waarschuwing
  en disabled checkboxes. DemoTooltip-wrapped, demo kan niets togglen.
- Voetnoot legt anti-data-loss uit: "Folders uitzetten verwijdert
  geen bestaande docs".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 14:35:01 +02:00
a892ff83ca feat(PBI-96/T-1071): DisabledFolderBanner + integratie (P2-fix)
- 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>
2026-05-16 14:34:03 +02:00
a59c35b9ae feat(PBI-96/T-1070): NewProductDocDialog + dialog-spec
- 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>
2026-05-16 14:33:07 +02:00
bb4a71eafa feat(PBI-96/T-1069): doc viewer/editor + delete-button
- 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>
2026-05-16 14:30:13 +02:00
3c8699f8e7 feat(PBI-96/T-1068): folder-listing page + folder-list + status-badge
- 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>
2026-05-16 14:27:55 +02:00
628857873e feat(PBI-96/T-1067): Product Docs INDEX-page + grid + folder-card
- 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>
2026-05-16 14:26:52 +02:00
7212192544 refactor(PBI-96/T-1066): idea-md-editor → wrapper around MarkdownDocEditor
Reduceert components/ideas/idea-md-editor.tsx van ~170 regels naar ~55:
- planValidator hoist naar module-scope (geen useMemo nodig)
- alle state, draft-persist, keyboard-shortcut, error-rendering komt
  uit MarkdownDocEditor (T-1065)
- wrapper injecteert alleen: storageKey, validator (plan-only), onSave
  (grill/plan-action), placeholder, validationErrorsHeader, onSaved
  (router.refresh)

Geen functioneel verschil; 1022 tests blijven groen (geen regressie).
ST-C is hiermee compleet — beide editors gebruiken nu dezelfde stack.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 11:51:45 +02:00
7332420914 feat(PBI-96/T-1065): extract MarkdownDocEditor as shared component
- components/shared/markdown-doc-editor.tsx: geëxtraheerd uit
  components/ideas/idea-md-editor.tsx zodat Ideas (grill/plan) en
  Product Docs dezelfde editor-stack delen (CLAUDE.md dialog-discipline:
  "twee keer kopieren = promote 'm meteen").
- Props: storageKey + initialValue + validate? + onSave + onSaved? +
  onCancel + rows? + placeholder? + saveLabel? + validationErrorsHeader?
  + debug-attrs. Component bevat geen entity-specifieke logica.
- 14 nieuwe tests groen (rendering/dirty-state, localStorage persist+
  restore+clear, Cmd+S/Ctrl+S save, success-clear+onSaved+onCancel,
  error-rendering, validation blocks submit, cancel-button).
- T-1066 (volgende) refactort idea-md-editor naar wrapper rond deze.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 11:50:50 +02:00
4539de1fff feat(PBI-96/T-1064): toggleProductDocFolderAction + listProductDocsAction
- 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>
2026-05-16 11:48:24 +02:00
1d116c44ff feat(PBI-96/T-1063): deleteProductDocAction with P1-fix (no FK race)
- 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>
2026-05-16 11:47:09 +02:00
ca301b5792 feat(PBI-96/T-1062): createProductDocAction + updateProductDocAction (P2)
- actions/product-docs.ts: create+update volgens server-action.md pattern
  (auth → demo → rate-limit → zod → parse-md → scope → folder-enabled →
  normalize last_updated → tx(create+log) → revalidatePath).
- P2-coverage volledig:
  • title/status uit parsed.frontmatter naar gerepliceerde kolommen
  • last_updated server-side overschreven via setProductDocFrontmatterFields
  • frontmatter-parse-fail → 422 zonder DB-write
  • slug-conflict (P2002) → 422 met heldere foutmelding
  • folder uitgeschakeld → 422 'staat uit'
- update logt UPDATED met prev_status + new_status in metadata.
- 14 nieuwe tests groen (auth-paden, P2-create, P2-last_updated,
  conflict-mapping, update-sync).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 11:46:24 +02:00
5ae78ff872 feat(PBI-96/T-1061): add rate-limit keys + server-only helpers
- 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>
2026-05-16 11:44:21 +02:00
afafbca855 feat(PBI-96/T-1060): add frontmatter parser + serializer (P2-fix)
- 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>
2026-05-16 11:42:03 +02:00
55781e463a feat(PBI-96/T-1059): add Zod schemas, folder-mapping, slug helpers
- lib/schemas/product-doc.ts: PRODUCT_DOC_FOLDERS/STATUSES + create/update/
  toggle/frontmatter schemas (MAX_PRODUCT_DOC_CONTENT_LEN=100k)
- lib/product-doc-folder.ts: DB UPPER_SNAKE ↔ API lowercase mapper
  (spiegel van lib/task-status.ts)
- lib/product-doc-slug.ts: pure slugify + suggestSlug (dedupe-suffix) +
  ADR-sequence helpers (nextAdrPrefix, parseAdrNumber, suggestAdrSlug)
- lib/schemas/product-doc-frontmatter-defaults.ts: per-folder UI-templates
  voor "Nieuwe doc"-dialog (last_updated weggelaten — server normaliseert
  bij save, zie T-1060)
- __tests__: 37 tests groen (Zod-schemas + slug-helpers); de pre-existing
  worktree-env fail in idea-timeline-merge.test.ts blijft buiten scope

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 11:40:30 +02:00
667be61334 feat(PBI-96/T-1058): add ProductDoc + ProductDocLog schema + migration
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>
2026-05-16 11:38:00 +02:00
73cb61d3a2 docs(PBI-96): voeg implementatieplan product-docs toe
Plan v2 (post-review) met PBI/Story/Task-referenties (PBI-96, 6 stories,
18 taken). Verwerkt review-punten P1 (delete-audit FK), P2 (title/status
sync, last_updated normalisatie, disabled-folder semantiek) en P3
(denormalized actor-velden).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 11:34:02 +02:00
410cd7c123 Merge pull request 'feat(sprint-73): sticky chat-invoerveld + reverse-chronologische idee-timeline' (#1) from feat/sprint-tzw3dt4h into main
Some checks are pending
CI / Lint, Typecheck, Test & Build (push) Waiting to run
CI / Detect deploy-relevant changes (push) Blocked by required conditions
CI / Deploy Preview (PR) (push) Blocked by required conditions
CI / Deploy Production (main) (push) Blocked by required conditions
CI / Deploy Manual (workflow_dispatch) (push) Waiting to run
Reviewed-on: #1
2026-05-15 21:40:59 +02:00
Scrum4Me Agent
c9d4122b3a feat(timeline): reverse-chronologische volgorde + unit-test merge/sort
Some checks are pending
CI / Lint, Typecheck, Test & Build (pull_request) Waiting to run
CI / Detect deploy-relevant changes (pull_request) Blocked by required conditions
CI / Deploy Preview (PR) (pull_request) Blocked by required conditions
CI / Deploy Production (main) (pull_request) Blocked by required conditions
CI / Deploy Manual (workflow_dispatch) (pull_request) Waiting to run
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>
2026-05-15 20:08:42 +02:00
Scrum4Me Agent
22781365e6 feat(timeline): sticky chat-input bovenaan timeline-sectie
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>
2026-05-15 19:57:01 +02:00
Scrum4Me Agent
a3303a605b fix(ideas): consistent desc orderBy for userQuestions in timeline page
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>
2026-05-15 19:49:15 +02:00
Janpeter Visser
973ff93d0c
docs(PBI-91): fix broken file:line links in hergebruik-sectie (#212)
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>
2026-05-15 11:09:11 +02:00
Janpeter Visser
00af559726
Sprint: ideeen aanpassen (#211)
* 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>
2026-05-15 07:28:36 +02:00
Janpeter Visser
3d5c22382c
feat(PBI-91): expliciete schermstaat + draft-zichtbaarheid PB-page (#210)
* 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>
2026-05-15 01:45:35 +02:00