diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 37e43ef..fe3848d 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -113,8 +113,8 @@ - [ ] **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) -- [ ] **MSIGN-10**: When all signers complete, agent receives a notification email -- [ ] **MSIGN-11**: When all signers complete, all parties (each signer + agent) receive the final merged PDF via email link +- [x] **MSIGN-10**: When all signers complete, agent receives a notification email +- [x] **MSIGN-11**: When all signers complete, all parties (each signer + agent) receive the final merged PDF via email link ### Deployment @@ -228,8 +228,8 @@ Which phases cover which requirements. Updated during roadmap creation. | MSIGN-05 | Phase 15 | Pending | | MSIGN-06 | Phase 15 | Pending | | MSIGN-07 | Phase 15 | Pending | -| MSIGN-10 | Phase 15 | Pending | -| MSIGN-11 | Phase 15 | Pending | +| MSIGN-10 | Phase 15 | Complete | +| MSIGN-11 | Phase 15 | Complete | | MSIGN-01 | Phase 16 | Pending | | MSIGN-02 | Phase 16 | Pending | | MSIGN-03 | Phase 16 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 49d4a4e..1205b4f 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -336,7 +336,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**: no @@ -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 | 0/3 | Not started | - | +| 15. Multi-Signer Backend | v1.2 | 1/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 e7ddc8d..3e1cb0d 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,15 +2,15 @@ gsd_state_version: 1.0 milestone: v1.1 milestone_name: Smart Document Preparation -status: verifying -stopped_at: "Completed 14-01-PLAN.md — Multi-signer schema: signerEmail on SignatureFieldData/signingTokens, signers JSONB + completionTriggeredAt on documents, migration 0010" -last_updated: "2026-04-03T21:17:15.201Z" +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" last_activity: 2026-04-03 progress: - total_phases: 16 + total_phases: 17 completed_phases: 15 - total_plans: 49 - completed_plans: 48 + total_plans: 52 + completed_plans: 49 percent: 100 --- @@ -24,9 +24,9 @@ See: .planning/PROJECT.md (updated 2026-04-03) ## Current Position -Phase: 14 (multi-signer-schema) — EXECUTING -Plan: 1 of 1 -Status: Phase complete — ready for verification +Phase: 15 (multi-signer-backend) — EXECUTING +Plan: 2 of 3 +Status: Ready to execute Last activity: 2026-04-03 ## Note on v1.1 @@ -86,6 +86,7 @@ Progress: [█████████████] 100% (13/13 phases complete | Phase 13-ai-field-placement-and-pre-fill P01 | 2 | 2 tasks | 5 files | | 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 | ## Accumulated Context @@ -156,6 +157,8 @@ Recent decisions affecting v1.1 work: - [Phase 14-multi-signer-schema]: documents.signers JSONB shape is { email, color }[] so Phase 16 can retrieve consistent per-signer colors from DB without recalculating - [Phase 14-multi-signer-schema]: completionTriggeredAt nullable TIMESTAMP used as atomic completion guard — Phase 14 adds column; Phase 15 owns write logic - [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 ### v1.2 Pre-decisions (from research) @@ -179,6 +182,6 @@ None yet. ## Session Continuity -Last session: 2026-04-03T21:17:15.198Z -Stopped at: Completed 14-01-PLAN.md — Multi-signer schema: signerEmail on SignatureFieldData/signingTokens, signers JSONB + completionTriggeredAt on documents, migration 0010 +Last session: 2026-04-03T21:44:28.030Z +Stopped at: Completed 15-01-PLAN.md — signer-download token pair, sendSignerCompletionEmail, public download route Resume file: None diff --git a/.planning/phases/15-multi-signer-backend/15-01-SUMMARY.md b/.planning/phases/15-multi-signer-backend/15-01-SUMMARY.md new file mode 100644 index 0000000..46126f8 --- /dev/null +++ b/.planning/phases/15-multi-signer-backend/15-01-SUMMARY.md @@ -0,0 +1,78 @@ +--- +phase: 15-multi-signer-backend +plan: "01" +subsystem: signing +tags: [multi-signer, jwt, email, download-route] +dependency_graph: + requires: [14-multi-signer-schema] + provides: [signer-download-token, signer-completion-email, public-download-route] + affects: [15-02-send-route, 15-03-sign-handler] +tech_stack: + added: [] + patterns: [jose-jwt, nodemailer-plain-text, nextjs-app-router-route-handler] +key_files: + created: + - teressa-copeland-homes/src/app/api/sign/download/[token]/route.ts + modified: + - teressa-copeland-homes/src/lib/signing/token.ts + - teressa-copeland-homes/src/lib/signing/signing-mailer.tsx +decisions: + - "signerEmail stored in DB only (not JWT) — keeps JWT payload minimal, consistent with D-03" + - "signer-download token is 72h with no DB record — same pattern as agent-download, longer TTL for signer latency" + - "public download route guards on doc.status === Signed AND signedFilePath — prevents serving partial accumulation files" +metrics: + duration: "2 min" + completed: "2026-04-03" + tasks_completed: 3 + files_modified: 3 +--- + +# Phase 15 Plan 01: Multi-Signer Utility Building Blocks Summary + +**One-liner:** Extended createSigningToken with optional signerEmail, added signer-download JWT pair (72h), sendSignerCompletionEmail mailer, and public GET /api/sign/download/[token] route. + +## Tasks Completed + +| Task | Name | Commit | Files | +|------|------|--------|-------| +| 1 | Extend token.ts with signerEmail param and signer-download token pair | 70c48cc | src/lib/signing/token.ts | +| 2 | Add sendSignerCompletionEmail to signing-mailer.tsx | e1cdfe9 | src/lib/signing/signing-mailer.tsx | +| 3 | Create public signer download route GET /api/sign/download/[token] | 14efa1d | src/app/api/sign/download/[token]/route.ts | + +## What Was Built + +### token.ts changes +- `createSigningToken` now accepts optional `signerEmail?: string` — persists to `signingTokens.signerEmail` column (written as `null` if absent, preserving all existing call sites) +- `createSignerDownloadToken(documentId)` — 72h JWT with `purpose: 'signer-download'` claim, no DB record +- `verifySignerDownloadToken(token)` — validates purpose claim, returns `{ documentId }` + +### signing-mailer.tsx changes +- `sendSignerCompletionEmail({ to, documentName, downloadUrl })` — plain-text email "All parties have signed...", subject "Signed copy ready: {name}", 72h expiry noted in body + +### New route: GET /api/sign/download/[token] +- Public (no auth session) +- App Router async params pattern: `{ params }: { params: Promise<{ token: string }> }` +- Guards: invalid/expired token → 401, doc not Signed or no signedFilePath → 404, path traversal → 403 +- Serves PDF with `Content-Type: application/pdf` and `Content-Disposition: attachment` + +## Verification + +- `npx tsc --noEmit` passes with zero errors +- Token utility now has 4 token types: sign, download, agent-download, signer-download +- Mailer now has 3 email functions: sendSigningRequestEmail, sendAgentNotificationEmail, sendSignerCompletionEmail +- Download route file exists at correct App Router path and imports from token.ts + +## Deviations from Plan + +None — plan executed exactly as written. + +## Known Stubs + +None — all functionality is fully implemented. Plans 02 and 03 will wire these utilities into the send route and sign handler. + +## Self-Check: PASSED + +- [x] teressa-copeland-homes/src/lib/signing/token.ts — modified, committed 70c48cc +- [x] teressa-copeland-homes/src/lib/signing/signing-mailer.tsx — modified, committed e1cdfe9 +- [x] teressa-copeland-homes/src/app/api/sign/download/[token]/route.ts — created, committed 14efa1d +- [x] All three commits confirmed in git log