ST-1243: F1 schema + propagateStatusUpwards-helper voor sprint-flow

Schema-uitbreidingen voor de sprint-niveau jobflow (PBI-46):
- TaskStatus, StoryStatus, PbiStatus, SprintStatus krijgen FAILED
- Nieuwe enums: SprintRunStatus, PrStrategy
- Nieuw SprintRun-model dat per-task ClaudeJobs groepeert
- ClaudeJob.sprint_run_id koppeling + index
- Product.pr_strategy (default SPRINT)
- Bijhorende Prisma-migratie

propagateStatusUpwards vervangt updateTaskStatusWithStoryPromotion en
herevalueert de keten Task → Story → PBI → Sprint → SprintRun bij elke
task-statuswijziging. Bij FAILED cancelt het sibling-jobs in dezelfde
SprintRun. PBI-status BLOCKED blijft handmatig en wordt niet overschreven.

Status-mappers + theme krijgen failed-token + label-uitbreidingen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-05-06 13:56:26 +02:00
commit 3eaaacaeb8
15 changed files with 795 additions and 146 deletions

View file

@ -1,13 +1,20 @@
// Bidirectionele case-mappers voor de REST API-boundary.
// DB houdt UPPER_SNAKE; API exposeert lowercase.
import type { TaskStatus, StoryStatus, PbiStatus } from '@prisma/client'
import type {
TaskStatus,
StoryStatus,
PbiStatus,
SprintStatus,
SprintRunStatus,
} from '@prisma/client'
const TASK_DB_TO_API = {
TO_DO: 'todo',
IN_PROGRESS: 'in_progress',
REVIEW: 'review',
DONE: 'done',
FAILED: 'failed',
} as const satisfies Record<TaskStatus, string>
const TASK_API_TO_DB: Record<string, TaskStatus> = {
@ -15,35 +22,72 @@ const TASK_API_TO_DB: Record<string, TaskStatus> = {
in_progress: 'IN_PROGRESS',
review: 'REVIEW',
done: 'DONE',
failed: 'FAILED',
}
const STORY_DB_TO_API = {
OPEN: 'open',
IN_SPRINT: 'in_sprint',
DONE: 'done',
FAILED: 'failed',
} as const satisfies Record<StoryStatus, string>
const STORY_API_TO_DB: Record<string, StoryStatus> = {
open: 'OPEN',
in_sprint: 'IN_SPRINT',
done: 'DONE',
failed: 'FAILED',
}
const PBI_DB_TO_API = {
READY: 'ready',
BLOCKED: 'blocked',
FAILED: 'failed',
DONE: 'done',
} as const satisfies Record<PbiStatus, string>
const PBI_API_TO_DB: Record<string, PbiStatus> = {
ready: 'READY',
blocked: 'BLOCKED',
failed: 'FAILED',
done: 'DONE',
}
const SPRINT_DB_TO_API = {
ACTIVE: 'active',
COMPLETED: 'completed',
FAILED: 'failed',
} as const satisfies Record<SprintStatus, string>
const SPRINT_API_TO_DB: Record<string, SprintStatus> = {
active: 'ACTIVE',
completed: 'COMPLETED',
failed: 'FAILED',
}
const SPRINT_RUN_DB_TO_API = {
QUEUED: 'queued',
RUNNING: 'running',
PAUSED: 'paused',
DONE: 'done',
FAILED: 'failed',
CANCELLED: 'cancelled',
} as const satisfies Record<SprintRunStatus, string>
const SPRINT_RUN_API_TO_DB: Record<string, SprintRunStatus> = {
queued: 'QUEUED',
running: 'RUNNING',
paused: 'PAUSED',
done: 'DONE',
failed: 'FAILED',
cancelled: 'CANCELLED',
}
export type TaskStatusApi = typeof TASK_DB_TO_API[TaskStatus]
export type StoryStatusApi = typeof STORY_DB_TO_API[StoryStatus]
export type PbiStatusApi = typeof PBI_DB_TO_API[PbiStatus]
export type SprintStatusApi = typeof SPRINT_DB_TO_API[SprintStatus]
export type SprintRunStatusApi = typeof SPRINT_RUN_DB_TO_API[SprintRunStatus]
export function taskStatusToApi(s: TaskStatus): TaskStatusApi {
return TASK_DB_TO_API[s]
@ -69,6 +113,24 @@ export function pbiStatusFromApi(s: string): PbiStatus | null {
return PBI_API_TO_DB[s.toLowerCase()] ?? null
}
export function sprintStatusToApi(s: SprintStatus): SprintStatusApi {
return SPRINT_DB_TO_API[s]
}
export function sprintStatusFromApi(s: string): SprintStatus | null {
return SPRINT_API_TO_DB[s.toLowerCase()] ?? null
}
export function sprintRunStatusToApi(s: SprintRunStatus): SprintRunStatusApi {
return SPRINT_RUN_DB_TO_API[s]
}
export function sprintRunStatusFromApi(s: string): SprintRunStatus | null {
return SPRINT_RUN_API_TO_DB[s.toLowerCase()] ?? null
}
export const TASK_STATUS_API_VALUES = Object.values(TASK_DB_TO_API)
export const STORY_STATUS_API_VALUES = Object.values(STORY_DB_TO_API)
export const PBI_STATUS_API_VALUES = Object.values(PBI_DB_TO_API)
export const SPRINT_STATUS_API_VALUES = Object.values(SPRINT_DB_TO_API)
export const SPRINT_RUN_STATUS_API_VALUES = Object.values(SPRINT_RUN_DB_TO_API)