# Phase 16: Multi-Signer UI - Context **Gathered:** 2026-04-03 **Status:** Ready for planning ## Phase Boundary UI-only changes. No new API routes. No schema migrations. Phase 16 wires the Phase 15 backend into the agent's PreparePanel/FieldPlacer workflow and adds per-signer status to the dashboard. Three UI areas: 1. **PreparePanel signer list** — add/remove signers by email; signers saved to `documents.signers` via existing document update API 2. **FieldPlacer signer assignment** — active-signer selector + per-signer field coloring; fields tagged with `signerEmail` via existing field placement API 3. **Send-block validation + dashboard** — pre-send check for unassigned fields; `N/M signed` badge on dashboard ## Implementation Decisions ### Signer Color Palette - **D-01:** Colors are auto-assigned when a signer is added — no agent choice needed. Fixed palette in order: 1. `#6366f1` (indigo) 2. `#f43f5e` (rose) 3. `#10b981` (emerald) 4. `#f59e0b` (amber) - If more than 4 signers, cycle the palette. The color is stored in `documents.signers[].color` when saved to DB. ### PreparePanel Signer List - **D-02:** Signer list UI lives inside PreparePanel — between the existing "AI Auto-place" button section and the "Prepare and Send" button. It appears only for Draft documents (same gate as the rest of PreparePanel). - **D-03:** UI: an email input + "Add" button. Below it, a list of added signers showing a colored dot (their color), their email, and a remove (×) button. Signers are saved to the document record immediately when added/removed (PATCH to document update API, or inline save on "Prepare and Send" click — planner decides which is simpler). - **D-04:** Agent must add at least one signer before sending. If `documents.signers` is empty AND the document has client-visible fields, the send is blocked with a message: "Add at least one signer before sending." ### FieldPlacer Active Signer Selector - **D-05:** An "Active signer" dropdown appears at the top of FieldPlacer (above the field palette), but ONLY when `documents.signers` has at least one signer. When no signers are configured, FieldPlacer behaves exactly as today. - **D-06:** All fields dragged onto the canvas while a signer is selected automatically get `signerEmail` set to that signer's email. The field box is colored using the signer's color (from `documents.signers`) instead of the field-type color. - **D-07:** Fields with no `signerEmail` (agent-signature, agent-initials, OR client fields placed before signers were configured) use the existing type-based color (unchanged behavior). - **D-08:** The active signer selector defaults to the first signer in `documents.signers[]` when the component loads. Agent can switch before dragging fields. ### Send-Block Validation - **D-09:** Before calling `/api/documents/[id]/send`, PreparePanel checks: count of client-visible fields (`isClientVisibleField`) with no `signerEmail`. If count > 0: - Show red outline on each unassigned field in FieldPlacer (pass a `validationErrors` prop or similar from DocumentPageClient) - Show inline error below the Send button: "X field(s) need a signer assigned before sending." - Block the API call. - **D-10:** The red highlight is a validation state, not permanent — it clears as soon as the agent assigns signers to those fields. ### Dashboard Per-Signer Status - **D-11:** The documents dashboard table gains a "Signers" column (or augments the existing Status column). For documents where `documents.signers` is non-empty AND status is "Sent" (partially signed): show `N/M signed` badge (e.g., `1/2 signed`). Computed from counting `signingTokens WHERE documentId = X AND usedAt IS NOT NULL` vs total tokens for that document. - **D-12:** For single-signer documents (no `documents.signers`), this column shows nothing — status badge is unchanged. - **D-13:** For fully-signed documents (status = "Signed"), the existing "Signed" badge is sufficient — no N/M badge needed. ### Claude's Discretion - Whether to save signers on every add/remove vs on "Prepare and Send" click (planner picks simpler approach) - Exact placement of "Active signer" selector within FieldPlacer layout - Whether the N/M badge appears in its own column or appended to the existing Status column - Email validation UX for the signer input (prevent duplicate emails, basic format check) ## Canonical References **Downstream agents MUST read these before planning or implementing.** ### Files Being Modified - `teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/PreparePanel.tsx` — Add signer list UI + send-block validation - `teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/FieldPlacer.tsx` — Active signer selector + per-signer field coloring - `teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/DocumentPageClient.tsx` — Thread signers state between PreparePanel and FieldPlacer - Dashboard document table (find exact file via grep for "DocumentsTable" or similar) ### Schema (Phase 14 output) - `teressa-copeland-homes/src/lib/db/schema.ts` — `DocumentSigner` interface `{ email, color }`, `documents.signers` JSONB, `isClientVisibleField()` ### Phase Context - `.planning/phases/14-multi-signer-schema/14-CONTEXT.md` — Schema decisions - `.planning/phases/15-multi-signer-backend/15-CONTEXT.md` — Backend decisions (send route, field filtering) ## Existing Code Insights ### Reusable Assets - `PALETTE_TOKENS` in `FieldPlacer.tsx` — existing per-type color palette (lines 70-78); signer colors augment this, not replace it — fields with a signer use signer color, fields without use type color - `isClientVisibleField()` in `schema.ts` — already used in FieldPlacer; reuse for send-block validation check - `DocumentSigner` interface — already in schema.ts from Phase 14 - Existing field-click-to-select UX in FieldPlacer — the `selectedFieldId` and `onFieldSelect` props are already threaded through; the active signer selector builds alongside this ### Established Patterns - PreparePanel receives document state as props from DocumentPageClient (`DocumentPageClient.tsx` is the state owner) - FieldPlacer uses `onFieldsChanged` callback to bubble field changes up — signer assignment changes follow same pattern - Field colors computed inline in FieldPlacer at render time from `PALETTE_TOKENS.find(t => t.id === fieldType)` — signerEmail check added before this lookup - Dashboard uses Drizzle queries in a server component — adding a token count join follows same pattern ### Integration Points - `documents.signers` (nullable JSONB) — read in PreparePanel to seed the signer list; written via document update call when signers are modified - `SignatureFieldData.signerEmail?` (Phase 14) — written when field is placed with active signer; read in FieldPlacer for color lookup and in PreparePanel for send-block validation - `signingTokens` — read (count query) in dashboard server component for N/M badge ## Specific Ideas - Signer color palette order: indigo → rose → emerald → amber (D-01). These contrast well against each other and against the existing type colors. - The "Active signer" selector is a simple `