diff --git a/.planning/phases/19-template-editor-ui/.gitkeep b/.planning/phases/19-template-editor-ui/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/.planning/phases/19-template-editor-ui/19-CONTEXT.md b/.planning/phases/19-template-editor-ui/19-CONTEXT.md
new file mode 100644
index 0000000..73d5f41
--- /dev/null
+++ b/.planning/phases/19-template-editor-ui/19-CONTEXT.md
@@ -0,0 +1,133 @@
+# Phase 19: Template Editor UI - Context
+
+**Gathered:** 2026-04-06
+**Status:** Ready for planning
+
+
+## Phase Boundary
+
+UI-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:
+1. `FieldPlacer` — add optional `onPersist` callback prop (non-breaking)
+2. `/portal/templates` — list page (all active templates, click to open editor)
+3. `/portal/templates/[id]` — template editor page (PDF + FieldPlacer in template mode + role panel + save button)
+4. `POST /api/templates/[id]/ai-prepare` — AI auto-place for templates
+5. Top nav: "Templates" link
+
+
+
+
+## Implementation Decisions
+
+### FieldPlacer Abstraction
+
+- **D-01:** Add `onPersist?: (fields: SignatureFieldData[]) => Promise | void` prop to FieldPlacer. When provided, this replaces the internal `persistFields(docId, fields)` call. When absent (all existing consumers), falls back to the existing internal `persistFields` behavior — fully backwards compatible.
+- **D-02:** `persistFields` is called in 4 places in FieldPlacer. All 4 must be updated to call `onPersist(fields)` if provided, else `persistFields(docId, fields)`. The internal `persistFields` function stays for backwards compat.
+- **D-03:** FieldPlacer's `signers` prop accepts `DocumentSigner[]` where `email` carries 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.signatureFields` via `field.signerEmail`. When the template editor saves, it calls `PATCH /api/templates/[id]` with the full `signatureFields` array (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 `/edit` route.
+- **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` — reads `formTemplate.filename` to locate the PDF in `seeds/forms/`, calls existing `extractBlanks(filePath)` + `classifyFieldsWithAI(blanks, null)` (no client data for pre-fill in template mode), writes result to `documentTemplates.signatureFields` via `PATCH`.
+- **D-15:** No client name/address pre-fill in template AI mode — `classifyFieldsWithAI` receives `null` for 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 existing `aiPlacementKey` in 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 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 page
+- `teressa-copeland-homes/src/app/portal/(protected)/templates/[id]/page.tsx` — editor server component
+- `teressa-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 structure
+- `teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/FieldPlacer.tsx` — onPersist prop addition
+- `teressa-copeland-homes/src/app/api/documents/[id]/ai-prepare/route.ts` — AI route pattern to copy for templates
+- `teressa-copeland-homes/src/app/portal/(protected)/clients/page.tsx` — list page pattern
+- `teressa-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` — `documentTemplates` table + `documentTemplatesRelations`
+- `teressa-copeland-homes/src/app/api/templates/route.ts` — GET/POST
+- `teressa-copeland-homes/src/app/api/templates/[id]/route.ts` — PATCH/DELETE
+
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- `aiPlacementKey` + `setAiPlacementKey` pattern in DocumentPageClient — TemplatePageClient uses the same increment-to-reload mechanism
+- `SIGNER_COLORS` constant in PreparePanel — same palette for role colors in TemplatePanel
+- `isClientVisibleField()` — already imported in FieldPlacer; no changes needed
+- `PdfViewerWrapper` — passes through to FieldPlacer; reused as-is in template editor
+
+### Established Patterns
+- Server component page → `PageClient.tsx` state owner → child components (PreparePanel, FieldPlacer)
+- `db.query.documentTemplates.findFirst(...)` available via Drizzle relations from Phase 18
+- Field persistence: FieldPlacer calls `persistFields(id, fields)` internally; adding `onPersist` prop makes this injectable
+
+### Integration Points
+- `documentTemplates.signatureFields` (Phase 18) — written by template editor via PATCH
+- `PATCH /api/templates/[id]` (Phase 18) — accepts `{ signatureFields?: SignatureFieldData[] }` — used by TemplatePanel save and AI auto-place
+- Phase 20 reads `documentTemplates.signatureFields` to copy fields into a new document
+
+
+
+
+## Specific Ideas
+
+- The "Save" button in TemplatePanel calls `PATCH /api/templates/[id]` with the current `signatureFields` from FieldPlacer state.
+- AI Auto-place flow: button click → `POST /api/templates/[id]/ai-prepare` → route reads PDF → calls extractBlanks + classifyFieldsWithAI → writes to `documentTemplates.signatureFields` → returns fields → TemplatePageClient increments `aiPlacementKey` to reload FieldPlacer.
+- The `onPersist` callback in FieldPlacer: `async (fields) => await fetch('/api/templates/{id}', { method: 'PATCH', body: JSON.stringify({ signatureFields: fields }) })`
+
+
+
+
+## Deferred Ideas
+
+None — discussion stayed within phase scope.
+
+
+
+---
+
+*Phase: 19-template-editor-ui*
+*Context gathered: 2026-04-06*