From 12a74fcf4ace8fdadd6b26455569445ed209611f Mon Sep 17 00:00:00 2001 From: Chandler Copeland Date: Mon, 6 Apr 2026 12:17:39 -0600 Subject: [PATCH] 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 --- .../src/app/api/templates/[id]/route.ts | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 teressa-copeland-homes/src/app/api/templates/[id]/route.ts diff --git a/teressa-copeland-homes/src/app/api/templates/[id]/route.ts b/teressa-copeland-homes/src/app/api/templates/[id]/route.ts new file mode 100644 index 0000000..07edf97 --- /dev/null +++ b/teressa-copeland-homes/src/app/api/templates/[id]/route.ts @@ -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 = { + 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 }); +}