docs(06-01): complete signing foundation plan — SUMMARY, STATE, ROADMAP updated
- created 06-01-SUMMARY.md with full task and decision documentation - STATE.md: advanced to phase 6 plan 1, added 5 signing foundation decisions - ROADMAP.md: marked 06-01-PLAN.md complete, Signing Flow at 1/6 - REQUIREMENTS.md: marked SIGN-02, LEGAL-01, LEGAL-02 complete
This commit is contained in:
@@ -43,7 +43,7 @@
|
|||||||
### Signing Flow
|
### Signing Flow
|
||||||
|
|
||||||
- [ ] **SIGN-01**: Client receives an email with a unique link to sign the document (no account required)
|
- [ ] **SIGN-01**: Client receives an email with a unique link to sign the document (no account required)
|
||||||
- [ ] **SIGN-02**: Signing link expires after 72 hours and can only be used once
|
- [x] **SIGN-02**: Signing link expires after 72 hours and can only be used once
|
||||||
- [ ] **SIGN-03**: Client opens the link in any browser and sees the prepared PDF with signature fields highlighted
|
- [ ] **SIGN-03**: Client opens the link in any browser and sees the prepared PDF with signature fields highlighted
|
||||||
- [ ] **SIGN-04**: Client can draw a freehand signature on a canvas (works on mobile and desktop)
|
- [ ] **SIGN-04**: Client can draw a freehand signature on a canvas (works on mobile and desktop)
|
||||||
- [ ] **SIGN-05**: Client can save a default signature and click a signature field to apply it without redrawing
|
- [ ] **SIGN-05**: Client can save a default signature and click a signature field to apply it without redrawing
|
||||||
@@ -52,8 +52,8 @@
|
|||||||
|
|
||||||
### Legal & Compliance
|
### Legal & Compliance
|
||||||
|
|
||||||
- [ ] **LEGAL-01**: System logs a complete audit trail for every signing ceremony — 6 server-side events: document prepared, email sent, link opened (with IP/user-agent), document viewed, signature submitted, final PDF hash computed
|
- [x] **LEGAL-01**: System logs a complete audit trail for every signing ceremony — 6 server-side events: document prepared, email sent, link opened (with IP/user-agent), document viewed, signature submitted, final PDF hash computed
|
||||||
- [ ] **LEGAL-02**: System computes and stores a SHA-256 hash of the final signed PDF immediately after signature embedding (tamper-evident record)
|
- [x] **LEGAL-02**: System computes and stores a SHA-256 hash of the final signed PDF immediately after signature embedding (tamper-evident record)
|
||||||
- [ ] **LEGAL-03**: Signed PDFs are stored in private storage — never accessible via public or guessable URLs; agent downloads via authenticated presigned URLs only
|
- [ ] **LEGAL-03**: Signed PDFs are stored in private storage — never accessible via public or guessable URLs; agent downloads via authenticated presigned URLs only
|
||||||
- [ ] **LEGAL-04**: DNS (SPF/DKIM/DMARC) configured for teressacopelandhomes.com before first signing link is sent to a real client
|
- [ ] **LEGAL-04**: DNS (SPF/DKIM/DMARC) configured for teressacopelandhomes.com before first signing link is sent to a real client
|
||||||
|
|
||||||
@@ -126,13 +126,13 @@ Which phases cover which requirements. Updated during roadmap creation.
|
|||||||
| DOC-05 | Phase 5 | Complete |
|
| DOC-05 | Phase 5 | Complete |
|
||||||
| DOC-06 | Phase 5 | Complete |
|
| DOC-06 | Phase 5 | Complete |
|
||||||
| SIGN-01 | Phase 6 | Pending |
|
| SIGN-01 | Phase 6 | Pending |
|
||||||
| SIGN-02 | Phase 6 | Pending |
|
| SIGN-02 | Phase 6 | Complete |
|
||||||
| SIGN-03 | Phase 6 | Pending |
|
| SIGN-03 | Phase 6 | Pending |
|
||||||
| SIGN-04 | Phase 6 | Pending |
|
| SIGN-04 | Phase 6 | Pending |
|
||||||
| SIGN-05 | Phase 6 | Pending |
|
| SIGN-05 | Phase 6 | Pending |
|
||||||
| SIGN-06 | Phase 6 | Pending |
|
| SIGN-06 | Phase 6 | Pending |
|
||||||
| LEGAL-01 | Phase 6 | Pending |
|
| LEGAL-01 | Phase 6 | Complete |
|
||||||
| LEGAL-02 | Phase 6 | Pending |
|
| LEGAL-02 | Phase 6 | Complete |
|
||||||
| LEGAL-04 | Phase 6 | Pending |
|
| LEGAL-04 | Phase 6 | Pending |
|
||||||
| SIGN-07 | Phase 7 | Pending |
|
| SIGN-07 | Phase 7 | Pending |
|
||||||
| LEGAL-03 | Phase 7 | Pending |
|
| LEGAL-03 | Phase 7 | Pending |
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ Plans:
|
|||||||
**Plans**: 6 plans
|
**Plans**: 6 plans
|
||||||
|
|
||||||
Plans:
|
Plans:
|
||||||
- [ ] 06-01-PLAN.md — Schema migration 0005 (signingTokens + auditEvents tables + 3 documents columns), signing utility library (token.ts, audit.ts, embed-signature.ts), npm install signature_pad + @react-email
|
- [x] 06-01-PLAN.md — Schema migration 0005 (signingTokens + auditEvents tables + 3 documents columns), signing utility library (token.ts, audit.ts, embed-signature.ts), npm install signature_pad + @react-email
|
||||||
- [ ] 06-02-PLAN.md — Branded signing request email (React Email), signing-mailer utilities, POST /api/documents/[id]/send route, document_prepared audit logging in prepare route
|
- [ ] 06-02-PLAN.md — Branded signing request email (React Email), signing-mailer utilities, POST /api/documents/[id]/send route, document_prepared audit logging in prepare route
|
||||||
- [ ] 06-03-PLAN.md — Public /sign/[token] page (3 states: signing/already-signed/expired), react-pdf viewer with pulsing blue field overlays, sticky progress bar, GET /api/sign/[token] data route
|
- [ ] 06-03-PLAN.md — Public /sign/[token] page (3 states: signing/already-signed/expired), react-pdf viewer with pulsing blue field overlays, sticky progress bar, GET /api/sign/[token] data route
|
||||||
- [ ] 06-04-PLAN.md — SignatureModal (Draw/Type/Use Saved tabs, signature_pad with devicePixelRatio scaling), POST /api/sign/[token] with atomic usedAt enforcement, PDF embedding, SHA-256 hash
|
- [ ] 06-04-PLAN.md — SignatureModal (Draw/Type/Use Saved tabs, signature_pad with devicePixelRatio scaling), POST /api/sign/[token] with atomic usedAt enforcement, PDF embedding, SHA-256 hash
|
||||||
@@ -153,5 +153,5 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7
|
|||||||
| 3. Agent Portal Shell | 4/4 | Complete | 2026-03-19 |
|
| 3. Agent Portal Shell | 4/4 | Complete | 2026-03-19 |
|
||||||
| 4. PDF Ingest | 4/4 | Complete | 2026-03-20 |
|
| 4. PDF Ingest | 4/4 | Complete | 2026-03-20 |
|
||||||
| 5. PDF Fill and Field Mapping | 3/4 | In Progress| |
|
| 5. PDF Fill and Field Mapping | 3/4 | In Progress| |
|
||||||
| 6. Signing Flow | 0/6 | Not started | - |
|
| 6. Signing Flow | 1/6 | In Progress | - |
|
||||||
| 7. Audit Trail and Download | 0/? | Not started | - |
|
| 7. Audit Trail and Download | 0/? | Not started | - |
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ gsd_state_version: 1.0
|
|||||||
milestone: v1.0
|
milestone: v1.0
|
||||||
milestone_name: milestone
|
milestone_name: milestone
|
||||||
status: unknown
|
status: unknown
|
||||||
last_updated: "2026-03-20T06:08:20Z"
|
last_updated: "2026-03-20T17:25:09Z"
|
||||||
progress:
|
progress:
|
||||||
total_phases: 5
|
total_phases: 7
|
||||||
completed_phases: 4
|
completed_phases: 5
|
||||||
total_plans: 18
|
total_plans: 23
|
||||||
completed_plans: 18
|
completed_plans: 19
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State
|
# Project State
|
||||||
@@ -18,16 +18,16 @@ progress:
|
|||||||
See: .planning/PROJECT.md (updated 2026-03-19)
|
See: .planning/PROJECT.md (updated 2026-03-19)
|
||||||
|
|
||||||
**Core value:** Teressa can prepare and send any real estate form to a client for signing in minutes, from her browser, without leaving her site.
|
**Core value:** Teressa can prepare and send any real estate form to a client for signing in minutes, from her browser, without leaving her site.
|
||||||
**Current focus:** Phase 5 - PDF Fill and Field Mapping
|
**Current focus:** Phase 6 - Signing Flow
|
||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 5 of 7 (PDF Fill and Field Mapping) — ADDITIONAL BUG FIXES APPLIED, AWAITING RE-VERIFICATION
|
Phase: 6 of 7 (Signing Flow) — Plan 1 complete
|
||||||
Plan: 05-04 (4 of 4 plans) — three more precise UI fixes applied
|
Plan: 06-01 (1 of 5 plans) — cryptographic foundation, DB tables, utility library
|
||||||
Status: Three additional fixes applied (commits f0ecfd1, 73ba6d5, c4e8d01): (1) ghost-rect drag placement + canvas-offset overlays fix field jumping on drop, (2) locked client replaced with editable primaryEmail input, (3) text stamp moved to 60pt from top, font 10pt. Build passes cleanly.
|
Status: signingTokens + auditEvents tables in PostgreSQL, documents extended with signedFilePath/pdfHash/signedAt, createSigningToken/verifySigningToken/logAuditEvent/embedSignatureInPdf utilities compiled and committed, npm run build passes cleanly.
|
||||||
Last activity: 2026-03-20 — Three targeted Phase 5 UI fixes: field placement accuracy, email input UX, stamp position
|
Last activity: 2026-03-20 — Phase 6 Plan 01: signing foundation (DB + JWT + audit + PDF embed utilities)
|
||||||
|
|
||||||
Progress: [██████████] 100%
|
Progress: [████████░░] 83%
|
||||||
|
|
||||||
## Performance Metrics
|
## Performance Metrics
|
||||||
|
|
||||||
@@ -58,6 +58,7 @@ Progress: [██████████] 100%
|
|||||||
| Phase 04-pdf-ingest P04-03 | 5 | 2 tasks | 8 files |
|
| Phase 04-pdf-ingest P04-03 | 5 | 2 tasks | 8 files |
|
||||||
| Phase 05-pdf-fill-and-field-mapping P02 | 1 | 2 tasks | 2 files |
|
| Phase 05-pdf-fill-and-field-mapping P02 | 1 | 2 tasks | 2 files |
|
||||||
| Phase 05-pdf-fill-and-field-mapping P03 | 3 | 2 tasks | 4 files |
|
| Phase 05-pdf-fill-and-field-mapping P03 | 3 | 2 tasks | 4 files |
|
||||||
|
| Phase 06-signing-flow P01 | 2 | 2 tasks | 8 files |
|
||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
@@ -115,6 +116,11 @@ Recent decisions affecting current work:
|
|||||||
- [Phase 05-pdf-fill-and-field-mapping 05-02]: top: top - heightPx on overlay divs — pdfToScreenCoords returns y of bottom-left corner; must shift up by field height for DOM top-left origin
|
- [Phase 05-pdf-fill-and-field-mapping 05-02]: top: top - heightPx on overlay divs — pdfToScreenCoords returns y of bottom-left corner; must shift up by field height for DOM top-left origin
|
||||||
- [Phase 05-pdf-fill-and-field-mapping]: PreparePanel canPrepare guard: only show prepare form for Draft status — read-only message for Sent/Signed
|
- [Phase 05-pdf-fill-and-field-mapping]: PreparePanel canPrepare guard: only show prepare form for Draft status — read-only message for Sent/Signed
|
||||||
- [Phase 05-pdf-fill-and-field-mapping]: currentClientId defaults to doc.assignedClientId ?? doc.clientId — allows reassigning client before preparing
|
- [Phase 05-pdf-fill-and-field-mapping]: currentClientId defaults to doc.assignedClientId ?? doc.clientId — allows reassigning client before preparing
|
||||||
|
- [Phase 06-signing-flow 06-01]: SIGNING_JWT_SECRET uses real openssl rand -base64 32 value (not placeholder) — generated at plan execution time
|
||||||
|
- [Phase 06-signing-flow 06-01]: auditEventTypeEnum defined before auditEvents table in schema.ts — pgEnum must precede referencing table (established Phase 3 pattern)
|
||||||
|
- [Phase 06-signing-flow 06-01]: Signing utilities live in src/lib/signing/ — server-only, never import from client components
|
||||||
|
- [Phase 06-signing-flow 06-01]: JWT jti stored in signingTokens table on createSigningToken — enables one-time-use enforcement in later plans
|
||||||
|
- [Phase 06-signing-flow 06-01]: SHA-256 hash computed from disk after atomic rename — never from in-memory bytes (LEGAL-02)
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
@@ -131,5 +137,5 @@ None yet.
|
|||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-03-20
|
Last session: 2026-03-20
|
||||||
Stopped at: 05-04 additional fixes complete — ghost-rect drag, editable primary email, text stamp repositioned; ready for re-verification
|
Stopped at: Completed 06-01-PLAN.md — signing foundation DB tables, JWT utilities, audit log, PDF embed with SHA-256
|
||||||
Resume file: None
|
Resume file: None
|
||||||
|
|||||||
132
.planning/phases/06-signing-flow/06-01-SUMMARY.md
Normal file
132
.planning/phases/06-signing-flow/06-01-SUMMARY.md
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
---
|
||||||
|
phase: 06-signing-flow
|
||||||
|
plan: "01"
|
||||||
|
subsystem: database
|
||||||
|
tags: [jwt, jose, postgres, drizzle, pdf, sha256, audit, signature_pad, react-email]
|
||||||
|
|
||||||
|
# Dependency graph
|
||||||
|
requires:
|
||||||
|
- phase: 05-pdf-fill-and-field-mapping
|
||||||
|
provides: documents table with signatureFields, preparedFilePath, @cantoo/pdf-lib installed
|
||||||
|
|
||||||
|
provides:
|
||||||
|
- signingTokens PostgreSQL table (jti pk, documentId FK, expiresAt, usedAt)
|
||||||
|
- auditEvents PostgreSQL table with 6-value audit_event_type enum
|
||||||
|
- signedFilePath, pdfHash, signedAt columns on documents table
|
||||||
|
- createSigningToken() — HS256 JWT creation with jti stored in DB
|
||||||
|
- verifySigningToken() — JWT verification, throws on expired/invalid
|
||||||
|
- logAuditEvent() — typed audit event insert with server-side timestamp
|
||||||
|
- embedSignatureInPdf() — embeds PNG sigs into PDF, returns SHA-256 hex digest
|
||||||
|
- signature_pad, @react-email/render, @react-email/components installed
|
||||||
|
|
||||||
|
affects: [06-02, 06-03, 06-04, 06-05]
|
||||||
|
|
||||||
|
# Tech tracking
|
||||||
|
tech-stack:
|
||||||
|
added: [signature_pad, "@react-email/render", "@react-email/components"]
|
||||||
|
patterns:
|
||||||
|
- jose HS256 JWT with jti stored in DB for one-time-use enforcement
|
||||||
|
- atomic rename (tmp -> final path) for PDF writes prevents corruption
|
||||||
|
- SHA-256 hash computed from disk after atomic rename (not from in-memory bytes)
|
||||||
|
- server-side defaultNow() for audit timestamps — never accept timestamp from client
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- teressa-copeland-homes/src/lib/signing/token.ts
|
||||||
|
- teressa-copeland-homes/src/lib/signing/audit.ts
|
||||||
|
- teressa-copeland-homes/src/lib/signing/embed-signature.ts
|
||||||
|
- teressa-copeland-homes/drizzle/0005_signing_flow.sql
|
||||||
|
modified:
|
||||||
|
- teressa-copeland-homes/src/lib/db/schema.ts
|
||||||
|
- teressa-copeland-homes/package.json
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "SIGNING_JWT_SECRET uses a real openssl rand -base64 32 value (not placeholder) — generated at plan execution time"
|
||||||
|
- "auditEventTypeEnum defined before auditEvents table — pgEnum must precede referencing table in schema.ts"
|
||||||
|
- "jose already present as next-auth transitive dependency — no reinstall needed"
|
||||||
|
- "Migration file renamed from drizzle-kit default to 0005_signing_flow.sql for readability; journal updated to match"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Signing utilities live in src/lib/signing/ — server-only, never imported from client components"
|
||||||
|
- "JWT jti stored in signingTokens table on createSigningToken — enables one-time-use enforcement in later plans"
|
||||||
|
- "Audit log uses server defaultNow() exclusively — createdAt never passed from caller"
|
||||||
|
|
||||||
|
requirements-completed: [SIGN-02, LEGAL-01, LEGAL-02]
|
||||||
|
|
||||||
|
# Metrics
|
||||||
|
duration: 2min
|
||||||
|
completed: 2026-03-20
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 6 Plan 01: Signing Foundation Summary
|
||||||
|
|
||||||
|
**PostgreSQL signing tables (signingTokens, auditEvents), three new documents columns, and server-side utilities for HS256 JWT token creation, typed audit logging, and atomic PDF signature embedding with SHA-256 hash**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** 2 min
|
||||||
|
- **Started:** 2026-03-20T17:22:43Z
|
||||||
|
- **Completed:** 2026-03-20T17:25:09Z
|
||||||
|
- **Tasks:** 2
|
||||||
|
- **Files modified:** 6
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- Migration 0005_signing_flow.sql applied — signingTokens and auditEvents tables live in PostgreSQL
|
||||||
|
- documents table extended with signedFilePath, pdfHash, signedAt columns
|
||||||
|
- Three signing utilities created and compile cleanly: token.ts, audit.ts, embed-signature.ts
|
||||||
|
- signature_pad, @react-email/render, @react-email/components installed for Phase 6 plans 02-05
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
Each task was committed atomically:
|
||||||
|
|
||||||
|
1. **Task 1: Install packages + extend schema + generate migration** - `fa68a1b` (feat)
|
||||||
|
2. **Task 2: Create signing utility library (token + audit + embed)** - `2929581` (feat)
|
||||||
|
|
||||||
|
**Plan metadata:** (docs commit — see below)
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `teressa-copeland-homes/src/lib/db/schema.ts` - Added auditEventTypeEnum, signingTokens table, auditEvents table; added signedFilePath/pdfHash/signedAt to documents table
|
||||||
|
- `teressa-copeland-homes/drizzle/0005_signing_flow.sql` - Migration file adding all new tables and columns
|
||||||
|
- `teressa-copeland-homes/drizzle/meta/_journal.json` - Updated journal tag to 0005_signing_flow
|
||||||
|
- `teressa-copeland-homes/drizzle/meta/0005_snapshot.json` - Generated drizzle snapshot
|
||||||
|
- `teressa-copeland-homes/src/lib/signing/token.ts` - createSigningToken() and verifySigningToken() using jose HS256
|
||||||
|
- `teressa-copeland-homes/src/lib/signing/audit.ts` - logAuditEvent() with typed enum + server-side timestamp
|
||||||
|
- `teressa-copeland-homes/src/lib/signing/embed-signature.ts` - embedSignatureInPdf() with atomic write and SHA-256 hash (LEGAL-02)
|
||||||
|
- `teressa-copeland-homes/package.json` - Added signature_pad, @react-email/render, @react-email/components
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- jose was already installed as a transitive dependency of next-auth — skipped reinstall
|
||||||
|
- Migration filename renamed from drizzle-kit default `0005_abandoned_albert_cleary.sql` to `0005_signing_flow.sql`; `drizzle/meta/_journal.json` updated to match — drizzle-kit migrate uses the journal tag, not filename, so this is safe
|
||||||
|
- `SIGNING_JWT_SECRET` generated with `openssl rand -base64 32` (real value, not placeholder) and added directly to `.env.local`
|
||||||
|
- `auditEventTypeEnum` positioned before `auditEvents` table in schema.ts — pgEnum must precede referencing table per established project convention (see Phase 3 decision log)
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
None - plan executed exactly as written.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
|
||||||
|
`SIGNING_JWT_SECRET` has been added to `.env.local` with a real generated value. No additional manual setup required for this plan.
|
||||||
|
|
||||||
|
When Phase 6 goes to production, the secret must be set in the Docker server environment. The `.env.local` value can be reused or regenerated.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
Phase 6 foundation is fully in place:
|
||||||
|
- signingTokens and auditEvents tables in PostgreSQL (migration 0005 applied)
|
||||||
|
- documents table has signedFilePath, pdfHash, signedAt columns
|
||||||
|
- createSigningToken, verifySigningToken, logAuditEvent, embedSignatureInPdf all compile
|
||||||
|
- npm run build passes cleanly
|
||||||
|
- Plans 02-05 can now import from `@/lib/signing/token`, `@/lib/signing/audit`, and `@/lib/signing/embed-signature`
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 06-signing-flow*
|
||||||
|
*Completed: 2026-03-20*
|
||||||
Reference in New Issue
Block a user