feat(PBI-102): PBI ↔ ProductDoc-bron via immutable PbiDoc + revisions #13

Merged
janpeter merged 6 commits from feat/pbi-102-pbi-doc-linking into main 2026-05-17 02:45:21 +02:00
Owner

Wat verandert

Koppel PBI's relationeel aan hun bron-ProductDoc via een immutable revision-laag, zodat plan/grill-documenten reproduceerbaar getraceerd blijven (review-fix: PBI mag niet stilzwijgend mee-verschuiven bij latere doc-edits).

Plan: docs/plans/PBI-102-pbi-doc-linking-with-revisions.md (v2, na cross-model review).
Review-feedback: docs/recommendations/pbi-productdoc-linking-plan-review-2026-05-17.md.

Belangrijkste wijzigingen

Schema (74b32ed):

  • Nieuwe ProductDocRevision-tabel (immutable; SHA-256 content_hash)
  • Nieuwe PbiDoc(pbi_id, doc_revision_id, role) junction met PbiDocRole enum (PLAN/GRILL)
  • ProductDoc.current_revision_id pointer (SetNull-cascade)
  • Idea.plan_doc_id + grill_doc_id (1:1 FK's, dual-write tijdens transitie)
  • ProductDocFolder.GRILLS enum-waarde + GRILLS-toggle in UI
  • 2-step migratie (PG-constraint: ALTER TYPE ADD VALUE moet committed zijn vóór gebruik)

Shared write-laag (ca15dcf + 4880369):

  • lib/product-doc-write.ts: writeProductDoc(tx, input) — Next-vrij, hash + no-op skip + revision-increment binnen één tx
  • actions/product-docs.ts delegeert naar de shared laag
  • Gespiegeld in scrum4me-mcp/src/lib/ (mirror-pact, patroon zoals job-config.ts)

Data-migratie (f023346):

  • scripts/migrate-idea-md-to-product-docs.ts — idempotent, --dry-run, --only-idea=
  • Lokaal gerund: 75 ProductDocs aangemaakt, 58 PbiDoc-links, 0 collisions

UI (7c8efd2-incl):

  • Nieuwe page /products/[id]/backlog/[pbiId] toont gekoppelde source-docs met vN-badge + optionele "→ huidige versie" link
  • ProductDoc-viewer krijgt rechter-paneel "Versies" + ?rev=N query-param + banner bij oude revisie

Docs (7c8efd2):

  • docs/runbooks/plan-to-pbi-flow.md: nieuwe stap 0.5 (create_product_doc) + source_docs-param
  • docs/architecture/data-model.md: nieuwe secties product_doc_revisions + pbi_docs
  • docs/architecture/product-docs.md: GRILLS-folder + revision-model + PBI-koppeling

MCP-counterpart

Aparte PR op scrum4me-mcp (zelfde branchnaam) — zie compare https://git.jp-visser.nl/janpeter/scrum4me-mcp/compare/main...feat/pbi-102-pbi-doc-linking

Verificatie

  • npm run verify: 1040/1040 tests pass (lint + typecheck + vitest)
  • Pre-existing rood: __tests__/components/idea-timeline-merge.test.ts (DATABASE_URL via actions/questions.ts-import) — niet door PBI-102 veroorzaakt, geverifieerd via git stash zonder mijn wijzigingen
  • Lokale dev-DB migraties applied (20260516235117_add_grills_enum_value, 20260516235118_add_pbi_doc_junction_and_revisions)
  • Data-fill droogloop + echte run + 2e-run idempotency check geslaagd
  • Pre-existing broken doc-links in PBI-96/PBI-98 plans blijven; mijn nieuwe broken-links (migrate-user → insert-milestone) gefixt

Test plan

  • Merge → productie-migratie (zelfde 2-step volgorde nodig)
  • Productie-run van tsx scripts/migrate-idea-md-to-product-docs.ts --dry-run, daarna echte run
  • Vereist gemerged-en-deployed scrum4me-mcp-PR (zelfde branchnaam) — anders zien MCP-tools de nieuwe schema-velden niet
  • Smoke-test Idea-flow: nieuwe Idea → grill → plan → check ProductDoc(folder=GRILLS/PLANS) + revision + Idea-FK gevuld
  • Smoke-test Claude-Code-flow: create_product_doc → create_pbi(source_docs=[…]) → PBI-detail toont source-doc met vN-badge
  • Vervolg-PBI: drop Idea.grill_md / plan_md na wait-for-job-refactor groen in productie

🤖 Generated with Claude Code

## Wat verandert Koppel PBI's relationeel aan hun bron-`ProductDoc` via een **immutable revision-laag**, zodat plan/grill-documenten reproduceerbaar getraceerd blijven (review-fix: PBI mag niet stilzwijgend mee-verschuiven bij latere doc-edits). Plan: [docs/plans/PBI-102-pbi-doc-linking-with-revisions.md](docs/plans/PBI-102-pbi-doc-linking-with-revisions.md) (v2, na cross-model review). Review-feedback: [docs/recommendations/pbi-productdoc-linking-plan-review-2026-05-17.md](docs/recommendations/pbi-productdoc-linking-plan-review-2026-05-17.md). ## Belangrijkste wijzigingen **Schema** (`74b32ed`): - Nieuwe `ProductDocRevision`-tabel (immutable; SHA-256 content_hash) - Nieuwe `PbiDoc(pbi_id, doc_revision_id, role)` junction met `PbiDocRole` enum (PLAN/GRILL) - `ProductDoc.current_revision_id` pointer (`SetNull`-cascade) - `Idea.plan_doc_id` + `grill_doc_id` (1:1 FK's, dual-write tijdens transitie) - `ProductDocFolder.GRILLS` enum-waarde + GRILLS-toggle in UI - 2-step migratie (PG-constraint: `ALTER TYPE ADD VALUE` moet committed zijn vóór gebruik) **Shared write-laag** (`ca15dcf` + `4880369`): - `lib/product-doc-write.ts`: `writeProductDoc(tx, input)` — Next-vrij, hash + no-op skip + revision-increment binnen één tx - `actions/product-docs.ts` delegeert naar de shared laag - Gespiegeld in `scrum4me-mcp/src/lib/` (mirror-pact, patroon zoals `job-config.ts`) **Data-migratie** (`f023346`): - `scripts/migrate-idea-md-to-product-docs.ts` — idempotent, `--dry-run`, `--only-idea=` - Lokaal gerund: 75 ProductDocs aangemaakt, 58 PbiDoc-links, 0 collisions **UI** (`7c8efd2`-incl): - Nieuwe page `/products/[id]/backlog/[pbiId]` toont gekoppelde source-docs met `vN`-badge + optionele "→ huidige versie" link - ProductDoc-viewer krijgt rechter-paneel "Versies" + `?rev=N` query-param + banner bij oude revisie **Docs** (`7c8efd2`): - `docs/runbooks/plan-to-pbi-flow.md`: nieuwe stap 0.5 (`create_product_doc`) + `source_docs`-param - `docs/architecture/data-model.md`: nieuwe secties product_doc_revisions + pbi_docs - `docs/architecture/product-docs.md`: GRILLS-folder + revision-model + PBI-koppeling ## MCP-counterpart Aparte PR op `scrum4me-mcp` (zelfde branchnaam) — zie compare https://git.jp-visser.nl/janpeter/scrum4me-mcp/compare/main...feat/pbi-102-pbi-doc-linking ## Verificatie - `npm run verify`: **1040/1040 tests pass** (lint + typecheck + vitest) - Pre-existing rood: `__tests__/components/idea-timeline-merge.test.ts` (DATABASE_URL via `actions/questions.ts`-import) — **niet door PBI-102 veroorzaakt**, geverifieerd via `git stash` zonder mijn wijzigingen - Lokale dev-DB migraties applied (`20260516235117_add_grills_enum_value`, `20260516235118_add_pbi_doc_junction_and_revisions`) - Data-fill droogloop + echte run + 2e-run idempotency check geslaagd - Pre-existing broken doc-links in `PBI-96`/`PBI-98` plans blijven; mijn nieuwe broken-links (migrate-user → insert-milestone) gefixt ## Test plan - [ ] Merge → productie-migratie (zelfde 2-step volgorde nodig) - [ ] Productie-run van `tsx scripts/migrate-idea-md-to-product-docs.ts --dry-run`, daarna echte run - [ ] Vereist gemerged-en-deployed scrum4me-mcp-PR (zelfde branchnaam) — anders zien MCP-tools de nieuwe schema-velden niet - [ ] Smoke-test Idea-flow: nieuwe Idea → grill → plan → check ProductDoc(folder=GRILLS/PLANS) + revision + Idea-FK gevuld - [ ] Smoke-test Claude-Code-flow: `create_product_doc` → `create_pbi(source_docs=[…])` → PBI-detail toont source-doc met `vN`-badge - [ ] Vervolg-PBI: drop `Idea.grill_md` / `plan_md` na wait-for-job-refactor groen in productie 🤖 Generated with [Claude Code](https://claude.com/claude-code)
- ProductDocFolder enum krijgt GRILLS (alfabetisch ingevoegd)
- Immutable ProductDocRevision-model (per-save snapshot + SHA-256 hash)
- PbiDoc(pbi_id, doc_revision_id, role) junction met PbiDocRole-enum
- ProductDoc.current_revision_id pointer + revisions back-relation
- Idea.plan_doc_id + grill_doc_id (1:1 FK's, dual-write tijdens transitie)
- Migratie gesplitst in 2 (PG-constraint: enum ADD VALUE moet gecommit
  zijn voor gebruik): 20260516235117 = enum-add, 20260516235118 = DDL
- GRILLS-mapping in lib/schemas/product-doc.ts, lib/product-doc-folder.ts
  en beide product-docs UI-components (satisfies-gate dwingt af)
- Default frontmatter-template voor GRILLS-folder
- Idea-detail page selecteert plan_doc_id/grill_doc_id

Pre-existing: __tests__/components/idea-timeline-merge.test.ts faalt op
DATABASE_URL via actions/questions.ts import — niet door deze PBI
veroorzaakt (geverifieerd via git stash).

Tasks: T-1118, T-1121

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- writeProductDoc(tx, input) — Next-vrije module voor ProductDoc create/update
- SHA-256 content_hash + no-op skip (geen nieuwe revision bij identieke content)
- Revision-nummer = max(revision)+1 binnen tx
- ProductDocWriteError-class met code (422 voor parse-fouten)
- 6 unit-tests met mock-tx: create-flow, no-op skip, append-revision,
  invalid-frontmatter, stable hash

Wordt in T-1120 gebruikt door actions/product-docs.ts (server-action)
en in T-1123 gemirrord naar scrum4me-mcp/src/lib/.

Task: T-1119

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- createProductDocAction en updateProductDocAction roepen nu writeProductDoc
  binnen prisma.$transaction; inline content_md-parse + create/update +
  log-rij is daarmee uit de action verdwenen
- ProductDocWriteError uit de write-laag wordt vertaald naar 422-actions
- Return-shapes uitgebreid met revision + revision_id (+ noop voor update)
- Behouden: auth, demo-guard, rate-limit, zod, access-check,
  enabled_doc_folders-check, P2002-mapping, revalidatePath
- 5 tests gerefactord om writeProductDoc-mock te valideren ipv
  prisma-internals (oude inline-implementatie was niet meer aanwezig)

Task: T-1120

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- scripts/migrate-idea-md-to-product-docs.ts: voor elke Idea met
  grill_md/plan_md → ProductDoc (folder GRILLS/PLANS) + revision +
  Idea.{grill,plan}_doc_id + (indien pbi_id) PbiDoc-link
- ensureValidFrontmatter wrapt md zonder/met incomplete frontmatter
  in een minimaal {title, status} blok — geen data-verlies
- Slug: ${code.toLowerCase()}-${role.toLowerCase()} (bv "idea-079-plan")
- Idempotent via writeProductDoc.noop + pbiDoc.upsert op unique
- Flags: --dry-run, --only-idea=IDEA-NN

Lokaal gerund op dev-DB (Tailscale):
  Run 1: created=75 linked=58 repaired=75
  Run 2: created=0 reused=75 linked=58  (= idempotent ✓)

Productie-rollout volgt apart na PR-merge.

Task: T-1122

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
T-1130: PBI-detail page (nieuw onder /products/[id]/backlog/[pbiId]) toont
PBI-meta + gelinkte source docs (PLAN/GRILL) via PbiSourceDocs-component.
Bevroren revision-link (?rev=N) en optionele "→ huidige versie (vM)" link
als de doc nieuwere revisies heeft.

T-1131: ProductDoc-viewer krijgt een rechter-paneel "Versies" met de
revision-historie en per revisie de gelinkte PBI's. Optioneel ?rev=N in
URL renderert content uit die specifieke revision + banner. Edit-mode
werkt alleen op de current revision (Bewerken-knop strip ?rev).

Tasks: T-1130, T-1131

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
docs(PBI-102): runbook + arch-docs voor PbiDoc + ProductDocRevision
Some checks failed
CI / Lint, Typecheck, Test & Build (pull_request) Failing after 27s
CI / Deploy Manual (workflow_dispatch) (pull_request) Has been skipped
CI / Detect deploy-relevant changes (pull_request) Has been skipped
CI / Deploy Preview (PR) (pull_request) Has been skipped
CI / Deploy Production (main) (pull_request) Has been skipped
7c8efd2af8
- plan-to-pbi-flow.md: nieuwe stap 0.5 (create_product_doc), uitgebreide
  create_pbi sectie met source_docs, flow-diagram en voorbeeld-sessie
  bijgewerkt
- data-model.md: nieuwe secties product_doc_revisions + pbi_docs;
  Idea-tabel uitgebreid met plan_doc_id/grill_doc_id + dual-write note;
  PBI-bron-koppeling toegevoegd aan Pbi-sectie
- product-docs.md: GRILLS-folder + ProductDocRevision/PbiDoc datamodel
  + nieuwe sectie "PBI ↔ ProductDoc koppeling" met flow-diagram en
  pointers naar MCP-tools en UI
- docs/INDEX.md geregenereerd
- Plan-broken-link gefixt (migrate-user → insert-milestone)

Task: T-1132

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
janpeter/Scrum4Me!13
No description provided.