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
|
|
@ -77,7 +77,7 @@ const mockPrisma = prisma as unknown as Mocked
|
|||
|
||||
const SPRINT_OK = {
|
||||
id: 'sprint-1',
|
||||
status: 'ACTIVE',
|
||||
status: 'OPEN',
|
||||
product_id: 'prod-1',
|
||||
product: { id: 'prod-1', pr_strategy: 'SPRINT' },
|
||||
}
|
||||
|
|
@ -303,7 +303,7 @@ describe('startSprintRunAction — SPRINT_BATCH', () => {
|
|||
|
||||
describe('startSprintRunAction — guards', () => {
|
||||
it('weigert wanneer Sprint niet ACTIVE is', async () => {
|
||||
mockPrisma.sprint.findUnique.mockResolvedValue({ ...SPRINT_OK, status: 'COMPLETED' })
|
||||
mockPrisma.sprint.findUnique.mockResolvedValue({ ...SPRINT_OK, status: 'CLOSED' })
|
||||
|
||||
const result = await startSprintRunAction({ sprint_id: 'sprint-1' })
|
||||
expect(result).toMatchObject({ ok: false, error: 'SPRINT_NOT_ACTIVE' })
|
||||
|
|
@ -346,7 +346,7 @@ describe('resumeSprintAction', () => {
|
|||
expect(result).toMatchObject({ ok: true, sprint_run_id: 'run-2' })
|
||||
expect(mockPrisma.sprint.update).toHaveBeenCalledWith({
|
||||
where: { id: 'sprint-1' },
|
||||
data: { status: 'ACTIVE', completed_at: null },
|
||||
data: { status: 'OPEN', completed_at: null },
|
||||
})
|
||||
expect(mockPrisma.story.updateMany).toHaveBeenCalledWith({
|
||||
where: { sprint_id: 'sprint-1', status: 'FAILED' },
|
||||
|
|
@ -359,7 +359,7 @@ describe('resumeSprintAction', () => {
|
|||
})
|
||||
|
||||
it('weigert als sprint niet FAILED is', async () => {
|
||||
mockPrisma.sprint.findUnique.mockResolvedValue({ ...SPRINT_OK, status: 'ACTIVE' })
|
||||
mockPrisma.sprint.findUnique.mockResolvedValue({ ...SPRINT_OK, status: 'OPEN' })
|
||||
|
||||
const result = await resumeSprintAction({ sprint_id: 'sprint-1' })
|
||||
expect(result).toMatchObject({ ok: false, error: 'SPRINT_NOT_FAILED' })
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ const mockPrisma = prisma as unknown as {
|
|||
$transaction: ReturnType<typeof vi.fn>
|
||||
}
|
||||
|
||||
const SPRINT = { id: 'sprint-1', product_id: 'product-1', status: 'ACTIVE' }
|
||||
const SPRINT = { id: 'sprint-1', product_id: 'product-1', status: 'OPEN' }
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ const mockRequireProductWriter = requireProductWriter as ReturnType<typeof vi.fn
|
|||
const mockGetIronSession = getIronSession as ReturnType<typeof vi.fn>
|
||||
|
||||
const STORY = { id: 'story-1', product_id: 'product-1', assignee_id: null }
|
||||
const SPRINT = { id: 'sprint-1', product_id: 'product-1', status: 'ACTIVE' }
|
||||
const SPRINT = { id: 'sprint-1', product_id: 'product-1', status: 'OPEN' }
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue