8.2 KiB
8.2 KiB
Phase 19: Template Editor UI - Context
Gathered: 2026-04-06 Status: Ready for planning
## Phase BoundaryUI-only phase (plus one new API route for AI auto-place). Builds the template editor page at /portal/templates/[id] and the supporting infrastructure.
Deliverables:
FieldPlacer— add optionalonPersistcallback prop (non-breaking)/portal/templates— list page (all active templates, click to open editor)/portal/templates/[id]— template editor page (PDF + FieldPlacer in template mode + role panel + save button)POST /api/templates/[id]/ai-prepare— AI auto-place for templates- Top nav: "Templates" link
FieldPlacer Abstraction
- D-01: Add
onPersist?: (fields: SignatureFieldData[]) => Promise<void> | voidprop to FieldPlacer. When provided, this replaces the internalpersistFields(docId, fields)call. When absent (all existing consumers), falls back to the existing internalpersistFieldsbehavior — fully backwards compatible. - D-02:
persistFieldsis called in 4 places in FieldPlacer. All 4 must be updated to callonPersist(fields)if provided, elsepersistFields(docId, fields). The internalpersistFieldsfunction stays for backwards compat. - D-03: FieldPlacer's
signersprop acceptsDocumentSigner[]whereemailcarries either a real email (document mode) OR a role label (template mode). No type change needed — the slot already accepts any string.
Role Labels in Template Editor
- D-04: Role labels are free-form strings that the agent types OR picks from presets. Preset list: "Buyer", "Co-Buyer", "Seller", "Co-Seller". Agent can type any string (e.g. "Lender", "Trustee").
- D-05: Template editor starts with two default role labels pre-configured: "Buyer" (color #6366f1 indigo) and "Seller" (color #f43f5e rose). Agent can add, remove, or rename these.
- D-06: Role colors: same palette as document signers —
['#6366f1', '#f43f5e', '#10b981', '#f59e0b']cycling by index. - D-07: Role labels are stored in
documentTemplates.signatureFieldsviafield.signerEmail. When the template editor saves, it callsPATCH /api/templates/[id]with the fullsignatureFieldsarray (same route as Phase 18 D-10). - D-08: The "Active role" selector in the template editor is identical in behavior to the "Active signer" selector in the document FieldPlacer — it's the same component, just with role label strings instead of emails. No new component needed.
Template Editor Page
- D-09: Route:
/portal/templates/[id]— single page view + edit (same pattern as/portal/clients/[id]). No separate/editroute. - D-10: Templates list page at
/portal/templates— shows all active templates (name, form name, field count, last updated). Click a row to open the editor. - D-11: "Templates" appears in the portal top nav (alongside Dashboard, Clients, Profile).
- D-12: Template editor page layout: PDF viewer on the left (full FieldPlacer), slim right panel (TemplatePanel) with: template name (editable), role list (add/remove/rename), AI Auto-place button, Save button.
- D-13: TemplatePanel is a new component (separate from PreparePanel). PreparePanel is document-specific (prepare/send/preview). TemplatePanel is template-specific (roles, save).
AI Auto-place for Templates
- D-14: New route
POST /api/templates/[id]/ai-prepare— readsformTemplate.filenameto locate the PDF inseeds/forms/, calls existingextractBlanks(filePath)+classifyFieldsWithAI(blanks, null)(no client data for pre-fill in template mode), writes result todocumentTemplates.signatureFieldsviaPATCH. - D-15: No client name/address pre-fill in template AI mode —
classifyFieldsWithAIreceivesnullfor client context. Fields are placed by type only. - D-16: AI Auto-place button in TemplatePanel triggers
POST /api/templates/[id]/ai-prepare, then reloads the FieldPlacer via a key increment (same pattern as existingaiPlacementKeyin DocumentPageClient).
Navigation
- D-17: Portal nav: add "Templates" between "Clients" and "Profile" in the top nav.
- D-18: Templates list page is a server component that fetches from the database directly (same pattern as the clients list page).
Claude's Discretion
- Exact TemplatePanel layout details (spacing, button order)
- Whether to show field count on the editor page header
- Loading states for AI auto-place and save operations
<canonical_refs>
Canonical References
Downstream agents MUST read these before planning or implementing.
Files Being Modified
teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/FieldPlacer.tsx(822 lines — add onPersist prop)teressa-copeland-homes/src/app/portal/_components/SiteNav.tsx— add Templates nav link
New Files
teressa-copeland-homes/src/app/portal/(protected)/templates/page.tsx— list pageteressa-copeland-homes/src/app/portal/(protected)/templates/[id]/page.tsx— editor server componentteressa-copeland-homes/src/app/portal/(protected)/templates/[id]/_components/TemplatePageClient.tsx— state owner (like DocumentPageClient)teressa-copeland-homes/src/app/portal/(protected)/templates/[id]/_components/TemplatePanel.tsx— right panel (roles, AI, save)teressa-copeland-homes/src/app/api/templates/[id]/ai-prepare/route.ts— AI auto-place route
Existing Patterns to Reuse
teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/DocumentPageClient.tsx— state owner pattern; TemplatePageClient follows same structureteressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/FieldPlacer.tsx— onPersist prop additionteressa-copeland-homes/src/app/api/documents/[id]/ai-prepare/route.ts— AI route pattern to copy for templatesteressa-copeland-homes/src/app/portal/(protected)/clients/page.tsx— list page patternteressa-copeland-homes/src/lib/ai/extract-text.ts+field-placement.ts— reused as-is for template AI
Phase 18 Output
teressa-copeland-homes/src/lib/db/schema.ts—documentTemplatestable +documentTemplatesRelationsteressa-copeland-homes/src/app/api/templates/route.ts— GET/POSTteressa-copeland-homes/src/app/api/templates/[id]/route.ts— PATCH/DELETE
</canonical_refs>
<code_context>
Existing Code Insights
Reusable Assets
aiPlacementKey+setAiPlacementKeypattern in DocumentPageClient — TemplatePageClient uses the same increment-to-reload mechanismSIGNER_COLORSconstant in PreparePanel — same palette for role colors in TemplatePanelisClientVisibleField()— already imported in FieldPlacer; no changes neededPdfViewerWrapper— passes through to FieldPlacer; reused as-is in template editor
Established Patterns
- Server component page →
PageClient.tsxstate owner → child components (PreparePanel, FieldPlacer) db.query.documentTemplates.findFirst(...)available via Drizzle relations from Phase 18- Field persistence: FieldPlacer calls
persistFields(id, fields)internally; addingonPersistprop makes this injectable
Integration Points
documentTemplates.signatureFields(Phase 18) — written by template editor via PATCHPATCH /api/templates/[id](Phase 18) — accepts{ signatureFields?: SignatureFieldData[] }— used by TemplatePanel save and AI auto-place- Phase 20 reads
documentTemplates.signatureFieldsto copy fields into a new document
</code_context>
## Specific Ideas- The "Save" button in TemplatePanel calls
PATCH /api/templates/[id]with the currentsignatureFieldsfrom FieldPlacer state. - AI Auto-place flow: button click →
POST /api/templates/[id]/ai-prepare→ route reads PDF → calls extractBlanks + classifyFieldsWithAI → writes todocumentTemplates.signatureFields→ returns fields → TemplatePageClient incrementsaiPlacementKeyto reload FieldPlacer. - The
onPersistcallback in FieldPlacer:async (fields) => await fetch('/api/templates/{id}', { method: 'PATCH', body: JSON.stringify({ signatureFields: fields }) })
None — discussion stayed within phase scope.
Phase: 19-template-editor-ui Context gathered: 2026-04-06