From 7311d30ad63fb7935d660459fc3e0852a3d0a5de Mon Sep 17 00:00:00 2001 From: Chandler Copeland Date: Fri, 3 Apr 2026 15:59:46 -0600 Subject: [PATCH] docs(phase-16): gather context for multi-signer UI phase --- .planning/phases/16-multi-signer-ui/.gitkeep | 0 .../phases/16-multi-signer-ui/16-CONTEXT.md | 126 ++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 .planning/phases/16-multi-signer-ui/.gitkeep create mode 100644 .planning/phases/16-multi-signer-ui/16-CONTEXT.md diff --git a/.planning/phases/16-multi-signer-ui/.gitkeep b/.planning/phases/16-multi-signer-ui/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.planning/phases/16-multi-signer-ui/16-CONTEXT.md b/.planning/phases/16-multi-signer-ui/16-CONTEXT.md new file mode 100644 index 0000000..7096173 --- /dev/null +++ b/.planning/phases/16-multi-signer-ui/16-CONTEXT.md @@ -0,0 +1,126 @@ +# 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 `