M12 / ST-1109: PBI krijgt een status (Ready / Blocked / Done) (#16)
* feat(ST-1109.2): add PbiStatus enum and status field to Pbi model - New PbiStatus enum (READY/BLOCKED/DONE) for PBI lifecycle tracking - Pbi.status PbiStatus @default(READY) - Index on (product_id, status) for filter queries - Migration: 20260429150643_add_pbi_status - ERD regenerated via prisma generate Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(ST-1109.3): add PBI status API mappers - pbiStatusToApi / pbiStatusFromApi following same pattern as task/story - PbiStatusApi type derived from PBI_DB_TO_API - PBI_STATUS_API_VALUES export for downstream Zod schemas - Lowercase API surface (ready/blocked/done), DB stays UPPER_SNAKE Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(ST-1109.4): support status in PBI create/update actions - Optional status field in Zod schemas (lowercase API: ready/blocked/done) - pbiStatusFromApi() maps to DB enum before persistence - Status omitted on create => Prisma @default(READY) takes effect - Update preserves existing status when not provided - Demo-check unchanged Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(ST-1109.5): auto-mark PBI as DONE when all its stories are DONE on sprint close Extends completeSprintAction's $transaction with PBI status cascade: - Pre-transaction: identify PBIs touched by this close (via stories.pbi_id), fetch each with all its stories - Skip PBIs already DONE; skip PBIs with 0 stories - Mark PBI DONE only when every story (post-decision) is DONE — stories outside the sprint are evaluated against their current DB status - Promote-only: never demotes a PBI that becomes "incomplete" again Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(ST-1109.6): add Popover primitive (base-ui wrapper) - Mirrors the Tooltip pattern: render-prop composition, data-slot attrs - Exports Popover (Root), PopoverTrigger, PopoverContent (Portal+Positioner+Popup) - MD3 popover/popover-foreground tokens, animated open/close states - Will be used to consolidate the backlog filter UI in ST-1109.8 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(ST-1109.7): add status select to PBI dialog - New components/shared/pbi-status-select.tsx mirrors PrioritySelect: PBI_STATUS_LABELS (NL), PBI_STATUS_COLORS, PbiStatusSelect component - Reuses existing --status-todo/blocked/done MD3 tokens - PbiDialog: status state with sync-on-open; default 'ready' for create, pbi.status for edit; hidden input submits lowercase API value - Priority + Status sit side-by-side in 2-col grid - PbiDialogPbi.status is optional; pbi-list.tsx will populate in ST-1109.8 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(ST-1109.8): show PBI status badge and consolidate filters into popover - Pbi.status (lowercase API) flows from page.tsx via pbiStatusToApi - Status badge rendered in BacklogCard's badge slot using PBI_STATUS_COLORS - Two old Select dropdowns replaced by single Popover with three pill-button sections (Sorteren, Prioriteit, Status) and a "Wis filters" footer - Filter trigger shows active count "(n)" badge in label - Active priority/status filters still surface as dismissable chips next to the trigger for at-a-glance feedback - onEdit passes the full Pbi (incl. status) so the dialog opens with the correct current status — closes the data flow loop opened in ST-1109.7 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(ST-1109.9): cover PBI status mappers and sprint-close cascade - __tests__/lib/task-status.test.ts: 11 cases incl. round-trip + invalid input for task/story/pbi mappers; verifies PBI_STATUS_API_VALUES shape - __tests__/actions/sprints-cascade.test.ts: 8 cases for completeSprintAction: promote on all-DONE, no promote on partial OPEN, respect out-of-sprint story status, skip already-DONE PBIs, multi-PBI cascade, 0-story guard, demo-user block - Full vitest run: 170/170 green across 21 files Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(ST-1109.10): document PbiStatus enum, sprint-close cascade, and filter UI - docs/scrum4me-architecture.md: pbis-table updated with status column + index; PbiStatus enum + Pbi model in the Prisma schema sample; cascade-on-sprint-close rule documented inline - docs/scrum4me-styling.md: short note pointing to PBI_STATUS_LABELS / PBI_STATUS_COLORS in components/shared/pbi-status-select.tsx so future components don't ad-hoc-copy the color map - docs/plans/ST-1109-pbi-status.md: in-repo mirror of the approved plan (per feedback_plan_location memory) with cascade pseudo-code and end-to-end verification checklist Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(ST-1109.11): persist backlog filters in localStorage Filters reset op reload was verwarrend. Nu net als sortMode: - scrum4me:pbi_filter_priority — 'all' | '1' | '2' | '3' | '4' - scrum4me:pbi_filter_status — 'all' | 'ready' | 'blocked' | 'done' useState-init met SSR-guard; ongeldige waarden vallen terug op 'all'. Wis filters reset alle drie de keys correct (sortMode -> 'priority', beide filters -> 'all'), waardoor de localStorage-staat consistent wordt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
50faebb82c
commit
8a9fb9d32b
16 changed files with 767 additions and 48 deletions
79
docs/plans/ST-1109-pbi-status.md
Normal file
79
docs/plans/ST-1109-pbi-status.md
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# Plan — ST-1109 · PBI krijgt een status (Ready / Blocked / Done)
|
||||
|
||||
> Spiegel van het goedgekeurde plan dat tijdens de sessie is opgesteld in
|
||||
> `~/.claude/plans/welke-rioriteiten-heeft-een-mighty-shell.md`. Vastgelegd
|
||||
> in deze repo per project-conventie (zie `MEMORY.md → feedback_plan_location`).
|
||||
|
||||
## Context
|
||||
|
||||
PBI's hadden alleen `priority` en `sort_order`; Story en Task hebben wél een status. Dit maakte het onmogelijk om in de Product Backlog te zien welke PBI's klaar staan, geblokkeerd zijn of al afgerond. Een derde filter naast prioriteit + sortering zou de bestaande UI te druk maken.
|
||||
|
||||
**Sprint-goal:** "Beter overzicht van openstaande PBI's"
|
||||
**Story:** als teamlid wil filteren op status van een PBI
|
||||
|
||||
## Doelen
|
||||
|
||||
1. Nieuwe enum `PbiStatus { READY BLOCKED DONE }`, default `READY`
|
||||
2. Status zichtbaar als badge in de Product Backlog cards
|
||||
3. Status manueel te zetten via PBI-dialog (alle drie de waarden)
|
||||
4. Auto-cascade: bij sprint-close → als alle stories van een PBI `DONE` zijn, PBI naar `DONE` (alleen-promote)
|
||||
5. Filter-UI consolideren in één shadcn `Popover` (priority + status + sort)
|
||||
|
||||
## Stappen (één commit per laag)
|
||||
|
||||
| ST-code | Laag | Bestand(en) |
|
||||
|---|---|---|
|
||||
| ST-1109.2 | DB | `prisma/schema.prisma` + migration |
|
||||
| ST-1109.3 | API mappers | `lib/task-status.ts` |
|
||||
| ST-1109.4 | Server actions | `actions/pbis.ts` |
|
||||
| ST-1109.5 | Sprint-close cascade | `actions/sprints.ts` |
|
||||
| ST-1109.6 | UI primitive | `components/ui/popover.tsx` (NIEUW) |
|
||||
| ST-1109.7 | Dialog | `components/backlog/pbi-dialog.tsx` + `components/shared/pbi-status-select.tsx` |
|
||||
| ST-1109.8 | Backlog UI | `components/backlog/pbi-list.tsx` + `app/(app)/products/[id]/page.tsx` |
|
||||
| ST-1109.9 | Tests | `__tests__/lib/task-status.test.ts` + `__tests__/actions/sprints-cascade.test.ts` |
|
||||
| ST-1109.10 | Docs | architecture, styling, plan-mirror |
|
||||
|
||||
Detail-implementatieplannen staan op de individuele MCP-tasks (`mcp__scrum4me__get_claude_context`).
|
||||
|
||||
## Cascade-regel (definitief)
|
||||
|
||||
```ts
|
||||
// In completeSprintAction's prisma.$transaction([...])
|
||||
const candidatePbis = await prisma.pbi.findMany({
|
||||
where: { id: { in: affectedPbiIds }, status: { not: 'DONE' } },
|
||||
select: { id: true, stories: { select: { id: true, status: true } } },
|
||||
})
|
||||
const decisionByStoryId = new Map(entries) // entries = Object.entries(decisions)
|
||||
const pbiIdsToMarkDone = candidatePbis
|
||||
.filter(pbi =>
|
||||
pbi.stories.length > 0 &&
|
||||
pbi.stories.every(s => (decisionByStoryId.get(s.id) ?? s.status) === 'DONE')
|
||||
)
|
||||
.map(p => p.id)
|
||||
```
|
||||
|
||||
**Regels:**
|
||||
- Promote-only: een PBI op DONE wordt nooit automatisch teruggezet
|
||||
- 0-story PBI's blijven READY (ondanks dat `[].every(...) === true`)
|
||||
- Stories buiten de Sprint worden meegerekend op hun huidige DB-status — een open PBL-story blokkeert de cascade
|
||||
|
||||
## Branch + PR
|
||||
|
||||
- Branch: `feat/M12-pbi-status`
|
||||
- Push + PR pas **na handmatige test door gebruiker** (per Branch & PR Strategy)
|
||||
- Verwachte commits: 9× `feat/test/docs(ST-1109.x)`
|
||||
|
||||
## Opvolgactie buiten deze repo
|
||||
|
||||
[`madhura68/scrum4me-mcp`](https://github.com/madhura68/scrum4me-mcp): de `create_pbi` tool kan straks optioneel `status` accepteren. Submodule (`vendor/scrum4me`) moet gesynced worden na merge zodat de drift-bewaking maandag groen blijft.
|
||||
|
||||
## Verificatie (end-to-end)
|
||||
|
||||
1. `npm run lint && npm test && npm run build` — alles groen
|
||||
2. `npm run dev` (port 3000)
|
||||
3. Maak nieuwe PBI → status default "Klaar voor sprint" (READY)
|
||||
4. Edit PBI → wijzig status naar "Geblokkeerd" → save → herlaad → badge toont oranje
|
||||
5. Sprint met PBI + 2 stories → close met beide DONE → PBI auto-DONE
|
||||
6. Idem maar 1 story OPEN → PBI blijft READY
|
||||
7. Filter-popover: open → status=Geblokkeerd → alleen blocked PBIs zichtbaar; (n)-badge klopt; "Wis filters" reset
|
||||
8. Demo-user: status-velden zijn read-only / save geblokkeerd
|
||||
Loading…
Add table
Add a link
Reference in a new issue