- lib/code.ts: rename VALID_CODE_RE naar geexporteerde CODE_REGEX, verwijder ongebruikte deriveTaskCode - lib/code-server.ts: generateNextTaskCode(productId) — flat per-product T-N teller, hergebruikt nextSequential helper. Export isCodeUniqueConflict zodat callers P2002 op code-veld kunnen detecteren - Zod schemas (pbi/story/task): codeField met trim + max-length + regex, optional input (server vult bij ontbreken). Task krijgt voor het eerst een codeField Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
32 lines
979 B
TypeScript
32 lines
979 B
TypeScript
import { z } from 'zod'
|
|
import { CODE_REGEX, MAX_CODE_LENGTH } from '@/lib/code'
|
|
|
|
const codeField = z
|
|
.string()
|
|
.trim()
|
|
.max(MAX_CODE_LENGTH)
|
|
.regex(CODE_REGEX, 'Ongeldige code')
|
|
.optional()
|
|
.or(z.literal(''))
|
|
|
|
export const createStorySchema = z.object({
|
|
pbiId: z.string(),
|
|
productId: z.string(),
|
|
code: codeField,
|
|
title: z.string().min(1, 'Titel is verplicht').max(200),
|
|
description: z.string().max(2000).optional(),
|
|
acceptance_criteria: z.string().max(2000).optional(),
|
|
priority: z.coerce.number().int().min(1).max(4),
|
|
})
|
|
|
|
export const updateStorySchema = z.object({
|
|
id: z.string(),
|
|
code: codeField,
|
|
title: z.string().min(1, 'Titel is verplicht').max(200),
|
|
description: z.string().max(2000).optional(),
|
|
acceptance_criteria: z.string().max(2000).optional(),
|
|
priority: z.coerce.number().int().min(1).max(4),
|
|
})
|
|
|
|
export type CreateStoryInput = z.infer<typeof createStorySchema>
|
|
export type UpdateStoryInput = z.infer<typeof updateStorySchema>
|