feat(ST-512): extend REST API with code, description and implementation_plan
- GET /api/products returns code, description and definition_of_done - GET /api/products/:id/next-story returns story.code and per-task code + implementation_plan - GET /api/sprints/:id/tasks returns description, implementation_plan, story_code and derived per-task code - POST /api/todos accepts and returns optional description (max 2000) All changes are additive — existing clients ignore unknown keys. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
80d1f30615
commit
03fda05be3
4 changed files with 60 additions and 7 deletions
|
|
@ -25,8 +25,16 @@ export async function GET(
|
|||
orderBy: [{ priority: 'asc' }, { sort_order: 'asc' }],
|
||||
include: {
|
||||
tasks: {
|
||||
orderBy: [{ priority: 'asc' }, { sort_order: 'asc' }],
|
||||
select: { id: true, title: true, description: true, priority: true, sort_order: true, status: true },
|
||||
orderBy: { sort_order: 'asc' },
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
description: true,
|
||||
implementation_plan: true,
|
||||
priority: true,
|
||||
sort_order: true,
|
||||
status: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
@ -35,11 +43,17 @@ export async function GET(
|
|||
return Response.json({ error: 'Geen open stories in de Sprint' }, { status: 404 })
|
||||
}
|
||||
|
||||
const tasks = story.tasks.map((t, idx) => ({
|
||||
...t,
|
||||
code: story.code ? `${story.code}.${idx + 1}` : null,
|
||||
}))
|
||||
|
||||
return Response.json({
|
||||
id: story.id,
|
||||
code: story.code,
|
||||
title: story.title,
|
||||
description: story.description,
|
||||
acceptance_criteria: story.acceptance_criteria,
|
||||
tasks: story.tasks,
|
||||
tasks,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export async function GET(request: Request) {
|
|||
const products = await prisma.product.findMany({
|
||||
where: { archived: false, ...productAccessFilter(auth.userId) },
|
||||
orderBy: { created_at: 'desc' },
|
||||
select: { id: true, name: true, repo_url: true },
|
||||
select: { id: true, code: true, name: true, description: true, repo_url: true, definition_of_done: true },
|
||||
})
|
||||
|
||||
return Response.json(products)
|
||||
|
|
|
|||
|
|
@ -31,8 +31,40 @@ export async function GET(
|
|||
{ sort_order: 'asc' },
|
||||
],
|
||||
take: limit,
|
||||
select: { id: true, title: true, story_id: true, priority: true, sort_order: true, status: true },
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
description: true,
|
||||
implementation_plan: true,
|
||||
story_id: true,
|
||||
priority: true,
|
||||
sort_order: true,
|
||||
status: true,
|
||||
story: {
|
||||
select: {
|
||||
code: true,
|
||||
tasks: { select: { id: true }, orderBy: { sort_order: 'asc' } },
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return Response.json(tasks)
|
||||
const enriched = tasks.map((t) => {
|
||||
const positionInStory = t.story.tasks.findIndex((st) => st.id === t.id)
|
||||
const code = t.story.code && positionInStory >= 0 ? `${t.story.code}.${positionInStory + 1}` : null
|
||||
return {
|
||||
id: t.id,
|
||||
code,
|
||||
title: t.title,
|
||||
description: t.description,
|
||||
implementation_plan: t.implementation_plan,
|
||||
story_id: t.story_id,
|
||||
story_code: t.story.code,
|
||||
priority: t.priority,
|
||||
sort_order: t.sort_order,
|
||||
status: t.status,
|
||||
}
|
||||
})
|
||||
|
||||
return Response.json(enriched)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { z } from 'zod'
|
|||
|
||||
const bodySchema = z.object({
|
||||
title: z.string().min(1, 'Titel is verplicht').max(500),
|
||||
description: z.string().max(2000, 'Beschrijving mag maximaal 2000 tekens bevatten').optional(),
|
||||
product_id: z.string().min(1, 'Product is verplicht'),
|
||||
})
|
||||
|
||||
|
|
@ -29,13 +30,19 @@ export async function POST(request: Request) {
|
|||
return Response.json({ error: 'Product niet gevonden' }, { status: 404 })
|
||||
}
|
||||
|
||||
const description = parsed.data.description?.trim() || null
|
||||
|
||||
const todo = await prisma.todo.create({
|
||||
data: {
|
||||
user_id: auth.userId,
|
||||
product_id: parsed.data.product_id,
|
||||
title: parsed.data.title,
|
||||
description,
|
||||
},
|
||||
})
|
||||
|
||||
return Response.json({ id: todo.id, title: todo.title, created_at: todo.created_at }, { status: 201 })
|
||||
return Response.json(
|
||||
{ id: todo.id, title: todo.title, description: todo.description, created_at: todo.created_at },
|
||||
{ status: 201 },
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue