From 6c5722fc61e30d54b280c97de56962f3b662906d Mon Sep 17 00:00:00 2001 From: Chandler Copeland Date: Mon, 6 Apr 2026 12:18:45 -0600 Subject: [PATCH] docs(18-02): complete template CRUD API plan - 18-02-SUMMARY.md: GET/POST/PATCH/DELETE routes with soft-delete and auth guard - STATE.md: advanced to plan 2/2, progress 98%, decisions recorded - ROADMAP.md: Phase 18 marked Complete (2/2 plans) --- .planning/ROADMAP.md | 6 +- .planning/STATE.md | 19 ++-- .../18-02-SUMMARY.md | 102 ++++++++++++++++++ 3 files changed, 116 insertions(+), 11 deletions(-) create mode 100644 .planning/phases/18-template-schema-and-crud-api/18-02-SUMMARY.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index b7e5ef3..8ad9326 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -186,7 +186,7 @@ Plans: **Milestone Goal:** Agent creates reusable document templates with pre-placed fields (including AI auto-placement) so the same PDF never needs to be field-mapped from scratch for every client. -- [ ] **Phase 18: Template Schema and CRUD API** - New `document_templates` table with Drizzle migration; list, create, rename, and soft-delete API routes +- [x] **Phase 18: Template Schema and CRUD API** - New `document_templates` table with Drizzle migration; list, create, rename, and soft-delete API routes (completed 2026-04-06) - [ ] **Phase 19: Template Editor UI** - FieldPlacer `onPersist` abstraction, template editor page at `/portal/templates/[id]`, AI auto-place wired to template context, signer role label support, save template - [ ] **Phase 20: Apply Template and Portal Nav** - "Start from template" option in AddDocumentModal, apply operation with field snapshot and role-to-email mapping, text hint quick-fill, Templates portal nav section and list page @@ -400,7 +400,7 @@ Plans: Plans: - [x] 18-01-PLAN.md — Drizzle schema: documentTemplates table definition + 0012 migration -- [ ] 18-02-PLAN.md — CRUD API routes: GET/POST /api/templates, PATCH/DELETE /api/templates/[id] +- [x] 18-02-PLAN.md — CRUD API routes: GET/POST /api/templates, PATCH/DELETE /api/templates/[id] **UI hint**: no ### Phase 19: Template Editor UI @@ -455,6 +455,6 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → | 15. Multi-Signer Backend | v1.2 | 3/3 | Complete | 2026-04-03 | | 16. Multi-Signer UI | v1.2 | 1/4 | Complete | 2026-04-03 | | 17. Docker Deployment | v1.2 | 2/2 | Complete | 2026-04-03 | -| 18. Template Schema and CRUD API | v1.3 | 1/2 | In Progress| | +| 18. Template Schema and CRUD API | v1.3 | 2/2 | Complete | 2026-04-06 | | 19. Template Editor UI | v1.3 | 0/TBD | Not started | - | | 20. Apply Template and Portal Nav | v1.3 | 0/TBD | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 6e85e0c..0ee9f0e 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,15 +2,15 @@ gsd_state_version: 1.0 milestone: v1.1 milestone_name: Smart Document Preparation -status: executing -stopped_at: Completed 18-01-PLAN.md — documentTemplates schema and migration 0012 -last_updated: "2026-04-06T18:15:59.504Z" +status: verifying +stopped_at: Completed 18-02-PLAN.md — template CRUD API routes (GET, POST, PATCH, DELETE) +last_updated: "2026-04-06T18:18:26.395Z" last_activity: 2026-04-06 progress: total_phases: 20 - completed_phases: 18 + completed_phases: 19 total_plans: 60 - completed_plans: 58 + completed_plans: 59 percent: 82 --- @@ -26,7 +26,7 @@ See: .planning/PROJECT.md (updated 2026-04-03) Phase: 18 (template-schema-and-crud-api) — EXECUTING Plan: 2 of 2 -Status: Ready to execute +Status: Phase complete — ready for verification Last activity: 2026-04-06 ## Note on v1.1 @@ -104,6 +104,7 @@ Progress: [████████████░░░] 82% (18/22 phases comp | Phase 17-docker-deployment P01 | 2 | 2 tasks | 4 files | | Phase 17 P02 | 3 | 3 tasks | 6 files | | Phase 18-template-schema-and-crud-api P01 | 4 | 2 tasks | 2 files | +| Phase 18-template-schema-and-crud-api P02 | 3 | 2 tasks | 2 files | ## Accumulated Context @@ -192,6 +193,8 @@ Recent decisions affecting v1.1 work: - [Phase 18-template-schema-and-crud-api]: signatureFields nullable JSONB: template starts empty; Phase 19 fills it via PATCH - [Phase 18-template-schema-and-crud-api]: formTemplateId FK has no onDelete cascade: archived templates remain even if form is removed - [Phase 18-template-schema-and-crud-api]: archivedAt nullable timestamp: NULL = active, soft-delete only +- [Phase 18-template-schema-and-crud-api]: fieldCount derived server-side as (signatureFields ?? []).length per D-12 — not stored in DB +- [Phase 18-template-schema-and-crud-api]: POST validates FK existence before INSERT to return 404 not 500 on bad formTemplateId ### v1.2 Pre-decisions (from research) @@ -227,6 +230,6 @@ None yet. ## Session Continuity -Last session: 2026-04-06T18:15:59.498Z -Stopped at: Completed 18-01-PLAN.md — documentTemplates schema and migration 0012 +Last session: 2026-04-06T18:18:26.391Z +Stopped at: Completed 18-02-PLAN.md — template CRUD API routes (GET, POST, PATCH, DELETE) Resume file: None diff --git a/.planning/phases/18-template-schema-and-crud-api/18-02-SUMMARY.md b/.planning/phases/18-template-schema-and-crud-api/18-02-SUMMARY.md new file mode 100644 index 0000000..afee0ab --- /dev/null +++ b/.planning/phases/18-template-schema-and-crud-api/18-02-SUMMARY.md @@ -0,0 +1,102 @@ +--- +phase: 18-template-schema-and-crud-api +plan: "02" +subsystem: api +tags: [drizzle, next-app-router, rest-api, soft-delete, postgresql] + +requires: + - phase: 18-01 + provides: documentTemplates Drizzle table + 0012 migration + +provides: + - GET /api/templates — list active templates with formName JOIN and computed fieldCount + - POST /api/templates — create template with name + formTemplateId FK validation + - PATCH /api/templates/[id] — rename and/or update signatureFields with explicit updatedAt + - DELETE /api/templates/[id] — soft-delete via archivedAt (no hard delete) + +affects: [Phase 19 template editor UI, Phase 20 apply-template endpoint] + +tech-stack: + added: [] + patterns: [soft-delete filter (isNull archivedAt), LEFT JOIN for computed field, explicit updatedAt on every UPDATE] + +key-files: + created: + - teressa-copeland-homes/src/app/api/templates/route.ts + - teressa-copeland-homes/src/app/api/templates/[id]/route.ts + modified: [] + +key-decisions: + - "fieldCount derived server-side as (signatureFields ?? []).length — not stored in DB per D-12" + - "PATCH guards against archived templates via isNull(archivedAt) before update — archived templates return 404" + - "DELETE sets archivedAt + updatedAt atomically in a single UPDATE statement, returns 204 No Content" + - "POST validates FK existence via db.query.formTemplates.findFirst before INSERT — returns 404 not 500 on bad FK" + +patterns-established: + - "Soft-delete list filter: .where(isNull(documentTemplates.archivedAt)) in GET handler" + - "Soft-delete guard in mutating handlers: findFirst with and(eq(id), isNull(archivedAt)) → 404 if missing/archived" + - "Explicit updatedAt: new Date() in every UPDATE per D-05 pattern" + +requirements-completed: [TMPL-01, TMPL-02, TMPL-03, TMPL-04] + +duration: 3min +completed: 2026-04-06 +--- + +# Phase 18 Plan 02: Template CRUD API Summary + +**Four REST handlers at /api/templates providing full CRUD with soft-delete, auth guard, FK validation, and computed fieldCount via LEFT JOIN on formTemplates.** + +## Performance + +- **Duration:** ~3 min +- **Started:** 2026-04-06T18:16:47Z +- **Completed:** 2026-04-06T18:19:30Z +- **Tasks:** 2 +- **Files modified:** 2 + +## Accomplishments + +- GET /api/templates lists active templates only (archivedAt IS NULL) with formName from joined formTemplates and computed fieldCount +- POST /api/templates validates name + formTemplateId, checks FK exists in formTemplates, inserts and returns 201 +- PATCH /api/templates/[id] handles rename and signatureFields update with explicit updatedAt, guards archived templates +- DELETE /api/templates/[id] soft-deletes via archivedAt = new Date() per D-07, returns 204 — never removes the row + +## Task Commits + +1. **Task 1: Create GET and POST routes at /api/templates** - `28c7773` (feat) +2. **Task 2: Create PATCH and DELETE routes at /api/templates/[id]** - `12a74fc` (feat) + +## Files Created/Modified + +- `teressa-copeland-homes/src/app/api/templates/route.ts` — GET (list active templates with JOIN) and POST (create with FK validation) +- `teressa-copeland-homes/src/app/api/templates/[id]/route.ts` — PATCH (rename/update fields, explicit updatedAt) and DELETE (soft-delete via archivedAt) + +## Decisions Made + +- PATCH returns 404 for archived templates (guards via `and(eq(id), isNull(archivedAt))`) — ensures mutating handlers do not resurrect archived templates accidentally +- POST verifies `formTemplateId` FK exists before INSERT, returning 404 with a clear error message rather than letting the DB constraint throw a 500 +- DELETE returns 204 No Content on success (no body) — matches REST convention for soft-delete confirmation + +## Deviations from Plan + +None - plan executed exactly as written. + +## Issues Encountered + +None. + +## User Setup Required + +None - no external service configuration required. + +## Next Phase Readiness + +- All four CRUD routes are ready for Phase 19 (template editor UI) +- Phase 19 will call GET to list templates, POST to create, PATCH with signatureFields to save field layout, and optionally DELETE +- Phase 20 (apply template) will call GET to pick a template, then read signatureFields to stamp fresh UUIDs at apply time +- No blockers. TypeScript compiles clean. + +--- +*Phase: 18-template-schema-and-crud-api* +*Completed: 2026-04-06*