feat(18-02): PATCH and DELETE handlers at /api/templates/[id]

- PATCH accepts name and signatureFields for rename and field save per D-10
- PATCH sets updatedAt: new Date() explicitly per D-05
- PATCH returns 404 for archived or missing templates
- DELETE soft-deletes by setting archivedAt: new Date() per D-07 (no hard delete)
- DELETE sets updatedAt: new Date() per D-05, returns 204 No Content
- Both handlers auth-gated with auth() per D-11
This commit is contained in:
Chandler Copeland
2026-04-06 12:17:39 -06:00
parent 28c7773b40
commit 12a74fcf4a

View File

@@ -0,0 +1,69 @@
import { auth } from '@/lib/auth';
import { db } from '@/lib/db';
import { documentTemplates } from '@/lib/db/schema';
import type { SignatureFieldData } from '@/lib/db/schema';
import { and, eq, isNull } from 'drizzle-orm';
export async function PATCH(
req: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const session = await auth();
if (!session) return new Response('Unauthorized', { status: 401 });
const { id } = await params;
const body = await req.json() as {
name?: string;
signatureFields?: SignatureFieldData[];
};
// Only update non-archived templates
const existing = await db.query.documentTemplates.findFirst({
where: and(eq(documentTemplates.id, id), isNull(documentTemplates.archivedAt)),
});
if (!existing) {
return Response.json({ error: 'Not found' }, { status: 404 });
}
const updates: Partial<typeof documentTemplates.$inferInsert> = {
updatedAt: new Date(), // per D-05: explicit updatedAt on every UPDATE
};
if (body.name !== undefined) updates.name = body.name;
if (body.signatureFields !== undefined) updates.signatureFields = body.signatureFields;
const [updated] = await db
.update(documentTemplates)
.set(updates)
.where(eq(documentTemplates.id, id))
.returning();
return Response.json(updated);
}
export async function DELETE(
_req: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const session = await auth();
if (!session) return new Response('Unauthorized', { status: 401 });
const { id } = await params;
// Only soft-delete non-archived templates (idempotent)
const existing = await db.query.documentTemplates.findFirst({
where: and(eq(documentTemplates.id, id), isNull(documentTemplates.archivedAt)),
});
if (!existing) {
return Response.json({ error: 'Not found' }, { status: 404 });
}
await db
.update(documentTemplates)
.set({
archivedAt: new Date(), // per D-07: soft-delete sets archivedAt
updatedAt: new Date(), // per D-05: explicit updatedAt
})
.where(eq(documentTemplates.id, id));
return new Response(null, { status: 204 });
}