5.6 KiB
phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
| phase | plan | subsystem | tags | dependency_graph | tech_stack | key_files | decisions | metrics | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 20-apply-template-and-portal-nav | 01 | document-template-apply |
|
|
|
|
|
|
Phase 20 Plan 01: Apply Template and Portal Nav Summary
One-liner: Template apply branch in POST /api/documents copies fields with fresh UUIDs and maps signer roles to client contacts; AddDocumentModal gains a My Templates tab with lazy-loaded template list.
Tasks Completed
| # | Task | Commit | Files |
|---|---|---|---|
| 1 | Extend POST /api/documents with documentTemplateId branch | bdf0cb0 |
src/app/api/documents/route.ts |
| 2 | Add My Templates tab to AddDocumentModal | 2947fa5 |
src/app/portal/_components/AddDocumentModal.tsx |
What Was Built
Task 1 — POST /api/documents template branch
Extended the JSON body path of the POST handler to accept documentTemplateId. When provided:
- Fetches the
documentTemplatesrecord with itsformTemplaterelation (for the PDF filename) - Copies the PDF from
seeds/forms/using the form template's filename - Maps every field to a new object with a fresh
crypto.randomUUID()— template field IDs never appear in documents - Collects unique signer role labels (stored in
signerEmailon template fields) in order of first appearance - Fetches the client record and builds
clientEmails = [client.email, ...contacts[].email] - Maps roles to emails: role[0] → clientEmails[0], role[1] → clientEmails[1], etc.; falls back to the role label if no email at that index
- Inserts the document with
signatureFields: copiedFieldsandsigners: mappedSignersand returns 201
The existing custom-upload path and form-library path are completely unchanged.
Task 2 — AddDocumentModal My Templates tab
Added a two-tab UI (Forms Library | My Templates) to the AddDocumentModal:
- Tab bar uses underline-style active indicator matching project Tailwind conventions
- My Templates tab lazy-fetches
GET /api/templateson first click viadocTemplatesLoadedflag - Empty state shown when no templates exist; loading state shown while fetching
- Template rows show name, form name, and field count
- Selecting a template clears
selectedTemplateandcustomFile(mutual exclusivity) - Selecting a form or uploading a file clears
selectedDocTemplate handleSubmithas a new top branch: whenselectedDocTemplateis set, sendsdocumentTemplateIdto POST /api/documents as JSON- Guard condition and submit button disabled state both updated to include
selectedDocTemplate - All existing Forms Library and custom upload markup preserved exactly — only wrapped in
activeTab === 'forms'conditional
Verification
npx tsc --noEmit— zero type errors (both tasks)npm run build— production build succeedsdocumentTemplateIdpresent in route.ts (4 matches) and AddDocumentModal.tsx (1 match)crypto.randomUUIDpresent in route.ts (2 matches: docId + field copy)SIGNER_COLORSpresent in route.tsactiveTab(5 matches) andselectedDocTemplate(6 matches) in AddDocumentModal.tsx
Deviations from Plan
Auto-fixed Issues
None.
Plan Adjustments
handleFileChange also clears selectedDocTemplate — The plan specified mutual exclusivity in handleSelectTemplate and handleSelectDocTemplate, but handleFileChange (custom file picker) also needed to clear selectedDocTemplate to maintain full mutual exclusivity across all three selection paths. Added setSelectedDocTemplate(null) to handleFileChange. This is a completeness fix, not a deviation from intent.
resolvedFormTemplateId instead of reassigning formTemplateId — The plan showed formTemplateId = docTemplate.formTemplateId to override the let variable. Instead used a new const resolvedFormTemplateId to avoid modifying a shared variable that existing branches also read. Cleaner and avoids any unintended side effects.
Known Stubs
None — all data paths are fully wired. The template apply branch fetches real data from the database and inserts real documents with copied fields and mapped signers.
Self-Check: PASSED
Files exist:
- FOUND: teressa-copeland-homes/src/app/api/documents/route.ts
- FOUND: teressa-copeland-homes/src/app/portal/_components/AddDocumentModal.tsx
Commits exist: