From a19163855b79354af27b432618348838cc9ae959 Mon Sep 17 00:00:00 2001 From: Chandler Copeland Date: Fri, 3 Apr 2026 15:48:01 -0600 Subject: [PATCH] docs(15-02): complete multi-signer send route plan - SUMMARY.md: multi-signer token loop + legacy fallback route rewrite - STATE.md: advance to plan 3, record metrics, add decisions - ROADMAP.md: update phase 15 progress (2/3 plans complete) - REQUIREMENTS.md: mark MSIGN-05, MSIGN-06 complete --- .planning/REQUIREMENTS.md | 8 +- .planning/ROADMAP.md | 6 +- .planning/STATE.md | 15 ++- .../15-multi-signer-backend/15-02-SUMMARY.md | 110 ++++++++++++++++++ 4 files changed, 126 insertions(+), 13 deletions(-) create mode 100644 .planning/phases/15-multi-signer-backend/15-02-SUMMARY.md diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index fe3848d..0fcd7f9 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -108,8 +108,8 @@ - [ ] **MSIGN-02**: Agent can tag each signature, initials, and date field to a specific signer when placing in FieldPlacer - [ ] **MSIGN-03**: Fields in FieldPlacer are color-coded by assigned signer for visual distinction - [ ] **MSIGN-04**: Agent cannot send a document if any client-facing field (signature, initials, date, text) has no signer assigned — send is blocked with a clear error -- [ ] **MSIGN-05**: Document recipients list is built automatically from unique signer emails on placed fields (no separate manual entry) -- [ ] **MSIGN-06**: All signers receive their unique signing links simultaneously when agent sends +- [x] **MSIGN-05**: Document recipients list is built automatically from unique signer emails on placed fields (no separate manual entry) +- [x] **MSIGN-06**: All signers receive their unique signing links simultaneously when agent sends - [ ] **MSIGN-07**: Each signer's signing page shows only their own assigned fields — other signers' fields are not visible - [x] **MSIGN-08**: Server enforces field ownership — a signer can only submit fields assigned to them - [ ] **MSIGN-09**: Dashboard shows per-signer completion status (who has signed, who hasn't) @@ -225,8 +225,8 @@ Which phases cover which requirements. Updated during roadmap creation. | AI-01 | Phase 13 | In Progress | | AI-02 | Phase 13 | In Progress | | MSIGN-08 | Phase 14 | Complete | -| MSIGN-05 | Phase 15 | Pending | -| MSIGN-06 | Phase 15 | Pending | +| MSIGN-05 | Phase 15 | Complete | +| MSIGN-06 | Phase 15 | Complete | | MSIGN-07 | Phase 15 | Pending | | MSIGN-10 | Phase 15 | Complete | | MSIGN-11 | Phase 15 | Complete | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 1205b4f..aaa3d17 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -337,7 +337,7 @@ Plans: Plans: - [x] 15-01-PLAN.md — Token utility extensions (signerEmail param, signer-download JWT), sendSignerCompletionEmail mailer, public signer download route -- [ ] 15-02-PLAN.md — Send route rewrite: multi-signer token loop with Promise.all dispatch, legacy single-signer fallback, APP_BASE_URL rename +- [x] 15-02-PLAN.md — Send route rewrite: multi-signer token loop with Promise.all dispatch, legacy single-signer fallback, APP_BASE_URL rename - [ ] 15-03-PLAN.md — Sign handler rewrite: GET signer-filtered fields, POST signer-scoped operations + accumulate PDF + atomic completion + notifications **UI hint**: no @@ -353,7 +353,7 @@ Plans: **Plans**: 3 plans Plans: -- [ ] 15-01-PLAN.md — Token utility extensions (signerEmail param, signer-download JWT), sendSignerCompletionEmail mailer, public signer download route +- [x] 15-01-PLAN.md — Token utility extensions (signerEmail param, signer-download JWT), sendSignerCompletionEmail mailer, public signer download route - [ ] 15-02-PLAN.md — Send route rewrite: multi-signer token loop with Promise.all dispatch, legacy single-signer fallback, APP_BASE_URL rename - [ ] 15-03-PLAN.md — Sign handler rewrite: GET signer-filtered fields, POST signer-scoped operations + accumulate PDF + atomic completion + notifications **UI hint**: yes @@ -399,6 +399,6 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → | 12.1. Per-Field Text Editing and Quick-Fill (INSERTED) | v1.1 | 2/2 | Complete | 2026-03-21 | | 13. AI Field Placement and Pre-fill | v1.1 | 3/4 | In Progress | - | | 14. Multi-Signer Schema | v1.2 | 1/1 | Complete | 2026-04-03 | -| 15. Multi-Signer Backend | v1.2 | 1/3 | In Progress| | +| 15. Multi-Signer Backend | v1.2 | 2/3 | In Progress| | | 16. Multi-Signer UI | v1.2 | 0/TBD | Not started | - | | 17. Docker Deployment | v1.2 | 0/TBD | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 3e1cb0d..d13aff6 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,14 +3,14 @@ gsd_state_version: 1.0 milestone: v1.1 milestone_name: Smart Document Preparation status: executing -stopped_at: Completed 15-01-PLAN.md — signer-download token pair, sendSignerCompletionEmail, public download route -last_updated: "2026-04-03T21:44:28.033Z" +stopped_at: Completed 15-02-PLAN.md — Multi-signer send route with token loop and legacy fallback +last_updated: "2026-04-03T21:47:51.565Z" last_activity: 2026-04-03 progress: total_phases: 17 completed_phases: 15 total_plans: 52 - completed_plans: 49 + completed_plans: 50 percent: 100 --- @@ -25,7 +25,7 @@ See: .planning/PROJECT.md (updated 2026-04-03) ## Current Position Phase: 15 (multi-signer-backend) — EXECUTING -Plan: 2 of 3 +Plan: 3 of 3 Status: Ready to execute Last activity: 2026-04-03 @@ -87,6 +87,7 @@ Progress: [█████████████] 100% (13/13 phases complete | Phase 13-ai-field-placement-and-pre-fill P03 | 2 | 2 tasks | 5 files | | Phase 14-multi-signer-schema P01 | 5 | 2 tasks | 3 files | | Phase 15 P01 | 2 | 3 tasks | 3 files | +| Phase 15-multi-signer-backend P02 | 5 | 1 tasks | 1 files | ## Accumulated Context @@ -159,6 +160,8 @@ Recent decisions affecting v1.1 work: - [Phase 14-multi-signer-schema]: No Partially Signed enum added — partial state computed dynamically by counting usedAt IS NOT NULL tokens in Phase 16 - [Phase 15]: signer-download token is 72h with no DB record — same pattern as agent-download, longer TTL for signer latency - [Phase 15]: signerEmail stored in DB only (not JWT payload) — keeps token minimal, consistent with D-03 +- [Phase 15-multi-signer-backend]: Promise.all fail-fast for multi-signer send: one email failure rolls back entire send, agent retries — consistent with legacy single-signer behavior +- [Phase 15-multi-signer-backend]: APP_BASE_URL replaces NEXT_PUBLIC_BASE_URL for signing URLs — server-side env var correct for API routes ### v1.2 Pre-decisions (from research) @@ -182,6 +185,6 @@ None yet. ## Session Continuity -Last session: 2026-04-03T21:44:28.030Z -Stopped at: Completed 15-01-PLAN.md — signer-download token pair, sendSignerCompletionEmail, public download route +Last session: 2026-04-03T21:47:51.561Z +Stopped at: Completed 15-02-PLAN.md — Multi-signer send route with token loop and legacy fallback Resume file: None diff --git a/.planning/phases/15-multi-signer-backend/15-02-SUMMARY.md b/.planning/phases/15-multi-signer-backend/15-02-SUMMARY.md new file mode 100644 index 0000000..6f93874 --- /dev/null +++ b/.planning/phases/15-multi-signer-backend/15-02-SUMMARY.md @@ -0,0 +1,110 @@ +--- +phase: 15-multi-signer-backend +plan: 02 +subsystem: api +tags: [multi-signer, signing, email, jwt, drizzle, nextjs] + +# Dependency graph +requires: + - phase: 15-01 + provides: createSigningToken with signerEmail param, DocumentSigner type, signingTokens.signerEmail column + - phase: 14-multi-signer-schema + provides: documents.signers JSONB column, DocumentSigner interface +provides: + - Multi-signer send route with one token per signer and parallel email dispatch + - Legacy single-signer fallback preserved when doc.signers is null/empty + - APP_BASE_URL used for all signing URLs (not NEXT_PUBLIC_BASE_URL) + - Audit event with metadata.signerEmail per signer in multi-signer path +affects: [15-03, 16-multi-signer-ui] + +# Tech tracking +tech-stack: + added: [] + patterns: + - "Promise.all over signers array for parallel token creation and email dispatch" + - "Branch on doc.signers?.length > 0 for multi vs. legacy path" + - "APP_BASE_URL (server-side env) instead of NEXT_PUBLIC_BASE_URL for signing URLs" + +key-files: + created: [] + modified: + - teressa-copeland-homes/src/app/api/documents/[id]/send/route.ts + +key-decisions: + - "Kept Promise.all fail-fast behavior: if one signer email fails, entire send fails and agent retries (consistent with legacy behavior)" + - "clientName omitted for multi-signer emails (DocumentSigner has email+color only); email template handles gracefully" + - "Return NextResponse.json({ ok: true }) without expiresAt in multi-signer path (all tokens same 72h TTL anyway)" + +patterns-established: + - "Multi-signer branch: doc.signers && (doc.signers as DocumentSigner[]).length > 0" + - "Legacy fallback: resolve clientId = doc.assignedClientId ?? doc.clientId, same as before" + +requirements-completed: [MSIGN-05, MSIGN-06] + +# Metrics +duration: 5min +completed: 2026-04-03 +--- + +# Phase 15 Plan 02: Multi-Signer Send Route Summary + +**Send route rewritten to loop over doc.signers, create one JWT per signer with signerEmail, and dispatch all emails in parallel via Promise.all — with full legacy fallback when signers is null.** + +## Performance + +- **Duration:** ~5 min +- **Started:** 2026-04-03T00:00:00Z +- **Completed:** 2026-04-03T00:05:00Z +- **Tasks:** 1 +- **Files modified:** 1 + +## Accomplishments + +- Multi-signer path: `doc.signers` loop calls `createSigningToken(doc.id, signer.email)` for each signer, dispatches all emails in parallel via `Promise.all` +- Legacy single-signer path preserved exactly: resolves `assignedClientId ?? clientId`, creates token without signerEmail, sends to client.name +- `NEXT_PUBLIC_BASE_URL` replaced with `APP_BASE_URL` (server-side env var) across both paths +- Per-signer audit events with `metadata.signerEmail` in multi-signer path +- `DocumentSigner` imported from schema for proper type casting + +## Task Commits + +1. **Task 1: Rewrite send route with multi-signer token loop and legacy fallback** - `7a04a4f` (feat) + +**Plan metadata:** (pending) + +## Files Created/Modified + +- `teressa-copeland-homes/src/app/api/documents/[id]/send/route.ts` - Multi-signer token loop + legacy fallback, APP_BASE_URL, parallel email dispatch + +## Decisions Made + +- Kept `Promise.all` fail-fast: if one signer's email fails, entire send rolls back; agent retries. Consistent with existing single-signer pattern. +- Omitted `clientName` in multi-signer path — `DocumentSigner` only has `{ email, color }`, and the email template already handles undefined clientName gracefully. +- Returned `{ ok: true }` without `expiresAt` in multi-signer response (all tokens share the same 72h TTL). + +## Deviations from Plan + +None - plan executed exactly as written. + +## Issues Encountered + +None. + +## User Setup Required + +None — no new environment variables introduced. `APP_BASE_URL` was already referenced in Phase 15 context (Pitfall 5); update `.env` to add it if not already present. + +## Next Phase Readiness + +- Send route is ready; Plan 15-03 (GET/POST sign handler rewrites) can proceed +- `signingTokens.signerEmail` is now written at send time — GET handler can filter fields by it in 15-03 + +## Self-Check: PASSED + +- `teressa-copeland-homes/src/app/api/documents/[id]/send/route.ts` — FOUND +- `.planning/phases/15-multi-signer-backend/15-02-SUMMARY.md` — FOUND +- Commit `7a04a4f` — FOUND + +--- +*Phase: 15-multi-signer-backend* +*Completed: 2026-04-03*