7.7 KiB
7.7 KiB
Phase 16: Multi-Signer UI - Context
Gathered: 2026-04-03 Status: Ready for planning
## Phase BoundaryUI-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:
- PreparePanel signer list — add/remove signers by email; signers saved to
documents.signersvia existing document update API - FieldPlacer signer assignment — active-signer selector + per-signer field coloring; fields tagged with
signerEmailvia existing field placement API - Send-block validation + dashboard — pre-send check for unassigned fields;
N/M signedbadge on dashboard
Signer Color Palette
- D-01: Colors are auto-assigned when a signer is added — no agent choice needed. Fixed palette in order:
#6366f1(indigo)#f43f5e(rose)#10b981(emerald)#f59e0b(amber)
- If more than 4 signers, cycle the palette. The color is stored in
documents.signers[].colorwhen 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.signersis 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.signershas 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
signerEmailset to that signer's email. The field box is colored using the signer's color (fromdocuments.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 nosignerEmail. If count > 0:- Show red outline on each unassigned field in FieldPlacer (pass a
validationErrorsprop or similar from DocumentPageClient) - Show inline error below the Send button: "X field(s) need a signer assigned before sending."
- Block the API call.
- Show red outline on each unassigned field in FieldPlacer (pass a
- 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.signersis non-empty AND status is "Sent" (partially signed): showN/M signedbadge (e.g.,1/2 signed). Computed from countingsigningTokens WHERE documentId = X AND usedAt IS NOT NULLvs 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_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/PreparePanel.tsx— Add signer list UI + send-block validationteressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/FieldPlacer.tsx— Active signer selector + per-signer field coloringteressa-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—DocumentSignerinterface{ email, color },documents.signersJSONB,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)
</canonical_refs>
<code_context>
Existing Code Insights
Reusable Assets
PALETTE_TOKENSinFieldPlacer.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 colorisClientVisibleField()inschema.ts— already used in FieldPlacer; reuse for send-block validation checkDocumentSignerinterface — already in schema.ts from Phase 14- Existing field-click-to-select UX in FieldPlacer — the
selectedFieldIdandonFieldSelectprops are already threaded through; the active signer selector builds alongside this
Established Patterns
- PreparePanel receives document state as props from DocumentPageClient (
DocumentPageClient.tsxis the state owner) - FieldPlacer uses
onFieldsChangedcallback 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 modifiedSignatureFieldData.signerEmail?(Phase 14) — written when field is placed with active signer; read in FieldPlacer for color lookup and in PreparePanel for send-block validationsigningTokens— read (count query) in dashboard server component for N/M badge
</code_context>
## 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
<select>or styled dropdown showing signer email with a colored dot. It appears only whensigners.length > 0. - Red highlight for unassigned fields: add a CSS border/box-shadow override (e.g.,
border: 2px solid #ef4444) when a field ID is in theunassignedFieldIdsset passed from DocumentPageClient.
None — discussion stayed within phase scope.
Phase: 16-multi-signer-ui Context gathered: 2026-04-03