Files
red/.planning/phases/20-apply-template-and-portal-nav/20-01-SUMMARY.md
2026-04-06 14:52:31 -06:00

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
templates
documents
modal
api
requires provides affects
phase-18-template-schema-and-crud-api
phase-19-template-editor-ui
template-apply-to-document
my-templates-tab
AddDocumentModal
POST /api/documents
added patterns
snapshot-copy-with-fresh-uuids
role-to-email-mapping
lazy-fetch-on-tab-switch
created modified
teressa-copeland-homes/src/app/api/documents/route.ts
teressa-copeland-homes/src/app/portal/_components/AddDocumentModal.tsx
documentTemplateId branch placed before fileBuffer and formTemplateId branches — returns early so existing paths are fully unchanged
SIGNER_COLORS constant extracted at module level for reuse in role-to-email mapping
resolvedFormTemplateId used (not reassigning formTemplateId let var) to avoid confusion with the existing library branch variable
handleSwitchToTemplates lazy-fetches only on first click — docTemplatesLoaded flag prevents repeated fetches on tab toggle
handleSelectDocTemplate clears selectedTemplate and customFile for mutual exclusivity; handleSelectTemplate now also clears selectedDocTemplate
duration_minutes completed_date tasks_completed files_modified
2 2026-04-06 2 2

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:

  1. Fetches the documentTemplates record with its formTemplate relation (for the PDF filename)
  2. Copies the PDF from seeds/forms/ using the form template's filename
  3. Maps every field to a new object with a fresh crypto.randomUUID() — template field IDs never appear in documents
  4. Collects unique signer role labels (stored in signerEmail on template fields) in order of first appearance
  5. Fetches the client record and builds clientEmails = [client.email, ...contacts[].email]
  6. 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
  7. Inserts the document with signatureFields: copiedFields and signers: mappedSigners and 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/templates on first click via docTemplatesLoaded flag
  • 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 selectedTemplate and customFile (mutual exclusivity)
  • Selecting a form or uploading a file clears selectedDocTemplate
  • handleSubmit has a new top branch: when selectedDocTemplate is set, sends documentTemplateId to 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 succeeds
  • documentTemplateId present in route.ts (4 matches) and AddDocumentModal.tsx (1 match)
  • crypto.randomUUID present in route.ts (2 matches: docId + field copy)
  • SIGNER_COLORS present in route.ts
  • activeTab (5 matches) and selectedDocTemplate (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:

  • bdf0cb0 — feat(20-01): extend POST /api/documents with documentTemplateId branch
  • 2947fa5 — feat(20-01): add My Templates tab to AddDocumentModal