feat(PBI-63): meerdere sprints per product + EXCLUDED + sprint-switcher (#161)
- Sprint lifecycle: ACTIVE→OPEN, COMPLETED→CLOSED, +ARCHIVED (FAILED behouden) - TaskStatus: +EXCLUDED (overgeslagen door agent-loop via bestaande TO_DO filter) - Cookie-gebaseerde actieve sprint per product (lib/active-sprint.ts) - Route splitsen: /products/[id]/sprint/[sprintId] + /sprint redirect-page - NavBar: gestapelde product/sprint dropdowns + BUILDING-badge derivatie - Backlog selectie-modus + nieuwe-sprint-dialog (createSprintWithPbisAction) - Migratie 20260507210000_sprint_lifecycle: ALTER TYPE RENAME (geen data-rewrite) - Version bump 1.0.0 → 1.2.0 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d68aa1e5e6
commit
4a9db57e94
43 changed files with 966 additions and 290 deletions
|
|
@ -0,0 +1,19 @@
|
|||
-- PBI-63: Sprint-lifecycle migratie
|
||||
--
|
||||
-- 1. Hernoem SprintStatus ACTIVE → OPEN, COMPLETED → CLOSED (bestaande data behouden, geen rewrite)
|
||||
-- 2. Voeg ARCHIVED toe (FAILED blijft)
|
||||
-- 3. Pas Sprint.status default aan naar OPEN
|
||||
-- 4. Voeg EXCLUDED toe aan TaskStatus
|
||||
--
|
||||
-- ALTER TYPE ... RENAME VALUE werkt vanaf PostgreSQL 10 zonder data-rewrite.
|
||||
-- ALTER TYPE ... ADD VALUE moet buiten een transaction-block uitgevoerd worden;
|
||||
-- Prisma migrate runt elk SQL-bestand zonder impliciete BEGIN/COMMIT, dus
|
||||
-- losse statements zijn voldoende.
|
||||
|
||||
ALTER TYPE "SprintStatus" RENAME VALUE 'ACTIVE' TO 'OPEN';
|
||||
ALTER TYPE "SprintStatus" RENAME VALUE 'COMPLETED' TO 'CLOSED';
|
||||
ALTER TYPE "SprintStatus" ADD VALUE 'ARCHIVED';
|
||||
|
||||
ALTER TABLE "sprints" ALTER COLUMN "status" SET DEFAULT 'OPEN';
|
||||
|
||||
ALTER TYPE "TaskStatus" ADD VALUE 'EXCLUDED';
|
||||
|
|
@ -61,6 +61,7 @@ enum TaskStatus {
|
|||
REVIEW
|
||||
DONE
|
||||
FAILED
|
||||
EXCLUDED
|
||||
}
|
||||
|
||||
enum LogType {
|
||||
|
|
@ -75,8 +76,9 @@ enum TestStatus {
|
|||
}
|
||||
|
||||
enum SprintStatus {
|
||||
ACTIVE
|
||||
COMPLETED
|
||||
OPEN
|
||||
CLOSED
|
||||
ARCHIVED
|
||||
FAILED
|
||||
}
|
||||
|
||||
|
|
@ -302,7 +304,7 @@ model Sprint {
|
|||
product_id String
|
||||
code String @db.VarChar(30)
|
||||
sprint_goal String
|
||||
status SprintStatus @default(ACTIVE)
|
||||
status SprintStatus @default(OPEN)
|
||||
start_date DateTime? @db.Date
|
||||
end_date DateTime? @db.Date
|
||||
created_at DateTime @default(now())
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export type ParsedMilestone = {
|
|||
title: string
|
||||
goal: string
|
||||
priority: 1 | 2 | 3 | 4
|
||||
sprint_status: 'ACTIVE' | 'COMPLETED'
|
||||
sprint_status: 'OPEN' | 'CLOSED'
|
||||
sort_order: number
|
||||
stories: ParsedStory[]
|
||||
}
|
||||
|
|
@ -66,19 +66,19 @@ const MILESTONE_GOAL: Record<string, string> = {
|
|||
}
|
||||
|
||||
const MILESTONE_SPRINT_STATUS: Record<string, ParsedMilestone['sprint_status']> = {
|
||||
M0: 'COMPLETED',
|
||||
M1: 'COMPLETED',
|
||||
M2: 'COMPLETED',
|
||||
M3: 'COMPLETED',
|
||||
'M3.5': 'COMPLETED',
|
||||
M4: 'COMPLETED',
|
||||
M5: 'COMPLETED',
|
||||
M6: 'COMPLETED',
|
||||
M7: 'COMPLETED',
|
||||
M8: 'COMPLETED',
|
||||
M9: 'COMPLETED',
|
||||
M10: 'COMPLETED',
|
||||
M11: 'COMPLETED',
|
||||
M0: 'CLOSED',
|
||||
M1: 'CLOSED',
|
||||
M2: 'CLOSED',
|
||||
M3: 'CLOSED',
|
||||
'M3.5': 'CLOSED',
|
||||
M4: 'CLOSED',
|
||||
M5: 'CLOSED',
|
||||
M6: 'CLOSED',
|
||||
M7: 'CLOSED',
|
||||
M8: 'CLOSED',
|
||||
M9: 'CLOSED',
|
||||
M10: 'CLOSED',
|
||||
M11: 'CLOSED',
|
||||
}
|
||||
|
||||
const MILESTONE_KEY = /^(?:M[\d.]+|PBI-\d+)$/
|
||||
|
|
@ -154,7 +154,7 @@ export async function loadBacklog(
|
|||
title,
|
||||
goal: MILESTONE_GOAL[key] ?? title,
|
||||
priority: MILESTONE_PRIORITY[key] ?? 4,
|
||||
sprint_status: MILESTONE_SPRINT_STATUS[key] ?? 'COMPLETED',
|
||||
sprint_status: MILESTONE_SPRINT_STATUS[key] ?? 'CLOSED',
|
||||
sort_order: milestones.length + 1,
|
||||
stories: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ async function main() {
|
|||
const forceOpen = ms.key === 'M3.5'
|
||||
|
||||
for (const s of ms.stories) {
|
||||
const isActive = ms.sprint_status === 'ACTIVE'
|
||||
const isActive = ms.sprint_status === 'OPEN'
|
||||
const effectivelyDone = !forceOpen && s.status === 'DONE'
|
||||
const inSprint = isActive || effectivelyDone
|
||||
const storyStatus = effectivelyDone ? 'DONE' : isActive ? 'IN_SPRINT' : 'OPEN'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue