diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 3f7f081..eef584c 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -44,7 +44,7 @@ - [x] **SIGN-01**: Client receives an email with a unique link to sign the document (no account required) - [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 +- [x] **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-05**: Client can save a default signature and click a signature field to apply it without redrawing - [ ] **SIGN-06**: Client sees a confirmation screen after successfully signing @@ -127,7 +127,7 @@ Which phases cover which requirements. Updated during roadmap creation. | DOC-06 | Phase 5 | Complete | | SIGN-01 | Phase 6 | Complete | | SIGN-02 | Phase 6 | Complete | -| SIGN-03 | Phase 6 | Pending | +| SIGN-03 | Phase 6 | Complete | | SIGN-04 | Phase 6 | Pending | | SIGN-05 | Phase 6 | Pending | | SIGN-06 | Phase 6 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 2c450ea..4e46241 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -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 | | 4. PDF Ingest | 4/4 | Complete | 2026-03-20 | | 5. PDF Fill and Field Mapping | 3/4 | In Progress| | -| 6. Signing Flow | 2/6 | In Progress| | +| 6. Signing Flow | 3/6 | In Progress| | | 7. Audit Trail and Download | 0/? | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 107b398..586ccde 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,12 +3,12 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: unknown -last_updated: "2026-03-20T17:30:55.130Z" +last_updated: "2026-03-20T17:32:09.418Z" progress: total_phases: 6 completed_phases: 5 total_plans: 24 - completed_plans: 20 + completed_plans: 21 --- # Project State @@ -22,10 +22,10 @@ See: .planning/PROJECT.md (updated 2026-03-19) ## Current Position -Phase: 6 of 7 (Signing Flow) — Plan 2 complete -Plan: 06-02 (2 of 5 plans) — email delivery layer, signing request email, send API route -Status: SigningRequestEmail.tsx + signing-mailer.tsx created, POST /api/documents/[id]/send live, document_prepared audit log wired in prepare route, npm run build passes cleanly. -Last activity: 2026-03-20 — Phase 6 Plan 02: email delivery layer (React Email + nodemailer + send route) +Phase: 6 of 7 (Signing Flow) — Plan 3 complete +Plan: 06-03 (3 of 5 plans) — public signing page, PDF viewer, field overlays, audit route +Status: /sign/[token] public route with server-side token validation (expired/used/pending states), react-pdf full-scroll PDF viewer with pulsing blue field overlays, sticky progress bar, GET /api/sign/[token] audit route, GET /api/sign/[token]/pdf streaming route — npm run build passes cleanly. +Last activity: 2026-03-20 — Phase 6 Plan 03: signing page (server component + PDF viewer + progress bar) Progress: [████████░░] 87% @@ -60,6 +60,7 @@ Progress: [████████░░] 87% | Phase 05-pdf-fill-and-field-mapping P03 | 3 | 2 tasks | 4 files | | Phase 06-signing-flow P01 | 2 | 2 tasks | 8 files | | Phase 06-signing-flow P02 | 2 | 2 tasks | 4 files | +| Phase 06-signing-flow P03 | 3 | 2 tasks | 6 files | ## Accumulated Context @@ -125,6 +126,8 @@ Recent decisions affecting current work: - [Phase 06-signing-flow]: Sender address hardcoded as teressa@teressacopelandhomes.com — matches brand identity requirement in CONTEXT.md - [Phase 06-signing-flow]: sendMail failure triggers 502 without DB status update — document stays in current state if email delivery fails - [Phase 06-signing-flow]: Status update in send/route.ts guarded by status=Draft — prevents downgrading Sent/Signed documents +- [Phase 06-signing-flow]: SigningPageClientWrapper uses dynamic import (ssr:false) — react-pdf requires browser APIs that cannot run server-side +- [Phase 06-signing-flow]: PDF served via /api/sign/[token]/pdf (token-authenticated) not /api/documents/[id]/file (agent-authenticated) — signing page is public ### Pending Todos @@ -141,5 +144,5 @@ None yet. ## Session Continuity Last session: 2026-03-20 -Stopped at: Completed 06-02-PLAN.md — branded email component, signing mailer, send API route, document_prepared audit logging +Stopped at: Completed 06-03-PLAN.md — signing page, PDF viewer, field overlays, progress bar, audit route Resume file: None diff --git a/.planning/phases/06-signing-flow/06-03-SUMMARY.md b/.planning/phases/06-signing-flow/06-03-SUMMARY.md new file mode 100644 index 0000000..51584b5 --- /dev/null +++ b/.planning/phases/06-signing-flow/06-03-SUMMARY.md @@ -0,0 +1,142 @@ +--- +phase: 06-signing-flow +plan: "03" +subsystem: ui +tags: [react-pdf, pdfjs, signing, jwt, audit, overlay, animation, next-app-router] + +# Dependency graph +requires: + - phase: 06-signing-flow/06-01 + provides: verifySigningToken(), logAuditEvent(), signingTokens table, SignatureFieldData schema + +provides: + - /sign/[token] public route with three states (expired/used/pending) + - Server component token validation before any UI renders + - SigningPageClient: full-scroll react-pdf viewer + pulsing blue field overlays + sticky progress bar + - SigningProgressBar: sticky bottom bar with X/Y count + jump-to-next + submit button + - GET /api/sign/[token]: token validation data route + audit event logging + - GET /api/sign/[token]/pdf: token-authenticated PDF streaming route + +affects: [06-04, 06-05] + +# Tech tracking +tech-stack: + added: [] + patterns: + - react-pdf used with dynamic import (ssr:false) via SigningPageClientWrapper — prevents SSR crashes from browser-only canvas/worker APIs + - PDF coordinate conversion: screenTop = renderedH - (field.y * scaleY) - (field.height * scaleY); origin flip from PDF bottom-left to screen top-left + - CSS keyframes injected via