// REST endpoints voor de Idee-entity (M12). // - Strikt user_id-only — geen productAccessFilter. // - Auth via session OF API-token (zelfde patroon als /api/todos). // - Demo blokkeert POST/PATCH/DELETE (proxy.ts laag + 403 hier als second-line). import { authenticateApiRequest } from '@/lib/api-auth' import { prisma } from '@/lib/prisma' import { ideaCreateSchema } from '@/lib/schemas/idea' import { ideaStatusFromApi, ideaStatusToApi } from '@/lib/idea-status' import { nextIdeaCode } from '@/lib/idea-code-server' import { ideaToDto } from '@/lib/idea-dto' export async function GET(request: Request) { const auth = await authenticateApiRequest(request) if ('error' in auth) { return Response.json({ error: auth.error }, { status: auth.status }) } const url = new URL(request.url) const archivedParam = url.searchParams.get('archived') const productIdParam = url.searchParams.get('product_id') const statusParam = url.searchParams.get('status') const archived = archivedParam === 'true' ? true : archivedParam === 'false' ? false : undefined const status = statusParam ? ideaStatusFromApi(statusParam) ?? undefined : undefined const ideas = await prisma.idea.findMany({ where: { user_id: auth.userId, ...(archived !== undefined ? { archived } : {}), ...(productIdParam ? { product_id: productIdParam } : {}), ...(status ? { status } : {}), }, include: { product: { select: { id: true, name: true, repo_url: true } }, secondary_products: { include: { product: { select: { id: true, name: true } } } }, }, orderBy: { created_at: 'desc' }, take: 200, }) return Response.json({ ideas: ideas.map(ideaToDto) }) } export async function POST(request: Request) { const auth = await authenticateApiRequest(request) if ('error' in auth) { return Response.json({ error: auth.error }, { status: auth.status }) } if (auth.isDemo) { return Response.json({ error: 'Niet beschikbaar in demo-modus' }, { status: 403 }) } let body: unknown try { body = await request.json() } catch { return Response.json({ error: 'Malformed JSON' }, { status: 400 }) } const parsed = ideaCreateSchema.safeParse(body) if (!parsed.success) { return Response.json({ error: parsed.error.flatten() }, { status: 422 }) } // Optionele product-binding: alleen toelaten als gebruiker eigenaar/member is. if (parsed.data.product_id) { const product = await prisma.product.findFirst({ where: { id: parsed.data.product_id, user_id: auth.userId, archived: false }, select: { id: true }, }) if (!product) { return Response.json({ error: 'Product niet gevonden' }, { status: 404 }) } } const userId = auth.userId const idea = await prisma.$transaction(async (tx) => { const code = await nextIdeaCode(userId, tx) return tx.idea.create({ data: { user_id: userId, product_id: parsed.data.product_id ?? null, code, title: parsed.data.title, description: parsed.data.description ?? null, status: 'DRAFT', }, include: { product: { select: { id: true, name: true, repo_url: true } } }, }) }) return Response.json( { idea: { ...ideaToDto(idea), status: ideaStatusToApi(idea.status) } }, { status: 201 }, ) }