Files
Chandler Copeland 00c5e5df33 docs(15-01): complete multi-signer utility building blocks plan
- SUMMARY.md created for 15-01
- STATE.md: plan advanced to 01/02, progress 94%, decisions added
- ROADMAP.md: phase 15 progress updated (1/3 plans)
- REQUIREMENTS.md: MSIGN-10, MSIGN-11 marked complete
2026-04-03 15:44:37 -06:00

3.6 KiB

phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
phase plan subsystem tags dependency_graph tech_stack key_files decisions metrics
15-multi-signer-backend 01 signing
multi-signer
jwt
email
download-route
requires provides affects
14-multi-signer-schema
signer-download-token
signer-completion-email
public-download-route
15-02-send-route
15-03-sign-handler
added patterns
jose-jwt
nodemailer-plain-text
nextjs-app-router-route-handler
created modified
teressa-copeland-homes/src/app/api/sign/download/[token]/route.ts
teressa-copeland-homes/src/lib/signing/token.ts
teressa-copeland-homes/src/lib/signing/signing-mailer.tsx
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
duration completed tasks_completed files_modified
2 min 2026-04-03 3 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

  • teressa-copeland-homes/src/lib/signing/token.ts — modified, committed 70c48cc
  • teressa-copeland-homes/src/lib/signing/signing-mailer.tsx — modified, committed e1cdfe9
  • teressa-copeland-homes/src/app/api/sign/download/[token]/route.ts — created, committed 14efa1d
  • All three commits confirmed in git log