← back to Homesonspec
apps/admin/src/app/api/review/route.ts
49 lines
import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { prisma } from "@homesonspec/database";
import { publishStagedRecord } from "@homesonspec/publisher";
const actionSchema = z.object({
reviewItemId: z.string(),
stagedRecordId: z.string(),
action: z.enum(["approve", "reject"]),
});
/**
* Human review resolution. Approve = staged record becomes APPROVED and the
* publish stage (the only published-tables writer) runs. Reject = REJECTED,
* never published. Either way the ReviewItem records who/when.
*/
export async function POST(request: NextRequest) {
const parsed = actionSchema.safeParse(await request.json().catch(() => null));
if (!parsed.success) return NextResponse.json({ error: "invalid request" }, { status: 400 });
const { reviewItemId, stagedRecordId, action } = parsed.data;
const item = await prisma.reviewItem.findUnique({ where: { id: reviewItemId } });
if (!item || item.status !== "OPEN") {
return NextResponse.json({ error: "review item not open" }, { status: 409 });
}
if (action === "approve") {
await prisma.stagedRecord.update({ where: { id: stagedRecordId }, data: { status: "APPROVED" } });
try {
await publishStagedRecord(stagedRecordId);
} catch (error) {
return NextResponse.json({ error: `publish failed: ${String(error)}` }, { status: 500 });
}
} else {
await prisma.stagedRecord.update({ where: { id: stagedRecordId }, data: { status: "REJECTED" } });
}
await prisma.reviewItem.update({
where: { id: reviewItemId },
data: {
status: action === "approve" ? "APPROVED" : "REJECTED",
reviewer: "admin",
resolvedAt: new Date(),
},
});
return NextResponse.json({ ok: true });
}