import { NextRequest, NextResponse } from "next/server"; import { withPermission } from "@/lib/middleware/authorize"; import { withTenantContext } from "@/lib/prisma-tenant"; import { transitionTicketStatus } from "@/lib/services/ticket-service"; import { TicketStatus } from "@prisma/client"; /** * POST /api/tickets/[id]/status * * Transition a ticket to a new status. * Enforces the guard map: OPEN->ASSIGNED|CLOSED, ASSIGNED->OPEN|RESOLVED, * RESOLVED->CLOSED|OPEN, CLOSED->(terminal). * * Accepts: { status: TicketStatus } * * Requires: update on Ticket subject. * * Response: * 200 OK — updated ticket with new status * 400 Bad Request — invalid or disallowed transition * 404 Not Found — ticket not found * 401 Unauthorized — no session * 403 Forbidden — insufficient role */ export function POST(req: NextRequest, { params }: { params: Promise<{ id: string }> }) { return withPermission("update", "Ticket")( async (req: NextRequest, { user }) => { if (!user.tenantId) { return NextResponse.json( { error: "No tenant context — super-admins must use the admin API" }, { status: 400 } ); } const { id } = await params; let body: unknown; try { body = await req.json(); } catch { return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 }); } const { status } = body as Record; if (!status || typeof status !== "string") { return NextResponse.json({ error: "status is required" }, { status: 400 }); } const validStatuses = Object.values(TicketStatus) as string[]; if (!validStatuses.includes(status)) { return NextResponse.json( { error: `Invalid status. Must be one of: ${validStatuses.join(", ")}` }, { status: 400 } ); } const tenantPrisma = withTenantContext(user.tenantId); try { const ticket = await transitionTicketStatus( tenantPrisma, id, status as TicketStatus ); return NextResponse.json(ticket); } catch (err) { const message = err instanceof Error ? err.message : "Failed to transition ticket status"; if (message.includes("not found")) { return NextResponse.json({ error: message }, { status: 404 }); } return NextResponse.json({ error: message }, { status: 400 }); } } )(req); }