// GET /api/projects/[id]/findings — returns the project's currently visible // findings (suggested + accepted + deprecated) // POST /api/projects/[id]/findings — runs detection, MERGES (no wipe), returns // the new set. Suggestions and deprecations // await user keep/discard via the // /findings/[findingId]/decision endpoint. import { NextResponse } from "next/server"; import { loadProject, listVisibleFindings, listDiscardedFindings, mergeFindingsSuggestion, } from "../../../../../lib/db/repo"; import { detectFindings } from "../../../../../lib/llm/detect"; function toApi(f: Awaited>[number]) { return { id: f.id, kind: f.kind, text: f.text, linkedElementIds: f.linkedElementIds, confidence: f.confidence, severity: f.severity, validationCode: f.validationCode, status: f.status, pinned: f.pinned, modelVersion: f.modelVersion, provider: f.provider, llmModel: f.llmModel, }; } export async function GET(req: Request, { params }: { params: Promise<{ projectId: string }> }) { const { projectId } = await params; // ?include=all merges in dismissed + resolved so the FindingsPane Discarded // drawer can render them. Default stays visible-only for back-compat. const url = new URL(req.url); const include = (url.searchParams.get("include") ?? "").toLowerCase(); if (include === "all") { const [visible, discarded] = await Promise.all([ listVisibleFindings(projectId), listDiscardedFindings(projectId), ]); return NextResponse.json({ findings: [...visible, ...discarded].map(toApi) }); } const findings = await listVisibleFindings(projectId); return NextResponse.json({ findings: findings.map(toApi) }); } export async function POST(_req: Request, { params }: { params: Promise<{ projectId: string }> }) { const { projectId } = await params; try { const { model, version } = await loadProject(projectId); const result = await detectFindings(model); const stored = await mergeFindingsSuggestion( projectId, result.findings, version, result.provider, result.model ); return NextResponse.json({ findings: stored.map(toApi), meta: { provider: result.provider, model: result.model, inputTokens: result.inputTokens, outputTokens: result.outputTokens, durationMs: result.durationMs, strippedRefs: result.strippedRefs, droppedFindings: result.droppedFindings, }, }); } catch (err) { return NextResponse.json({ error: (err as Error).message }, { status: 500 }); } }