Commit Graph

335 Commits

Author SHA1 Message Date
Chandler Copeland
e17b2655f1 docs(phase-16): complete phase execution — 4/4 plans, human UAT deferred 2026-04-03 16:36:55 -06:00
Chandler Copeland
fd08e4e63c docs(phase-16): verification passed — 11/11 must-haves, 4 human UAT items 2026-04-03 16:36:48 -06:00
Chandler Copeland
64c1b5b8ae docs(16-04): complete dashboard N/M signed badge plan
- Add 16-04-SUMMARY.md
- Update STATE.md: advance plan, update progress, record metrics and session
2026-04-03 16:32:42 -06:00
Chandler Copeland
29557f06e0 feat(16-04): render N/M signed badge in DocumentsTable Status column
- Extend DocumentRow type with optional signedCount, totalSigners, hasMultipleSigners
- Render badge after StatusBadge only for multi-signer Sent documents (D-11, D-12, D-13)
- Badge: inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-50 text-blue-700 ml-1.5
- Shows '{N}/{M} signed' text from server-computed token counts
- No badge for single-signer or fully-signed documents
2026-04-03 16:31:04 -06:00
Chandler Copeland
ad4e27af42 feat(16-04): enrich dashboard rows with signedCount, totalSigners, hasMultipleSigners
- Import signingTokens and sql from drizzle-orm
- Add documents.signers to main select
- Fetch token counts per document in single grouped query (avoids N+1)
- Build tokenMap for O(1) lookup per row
- Produce enrichedRows with signedCount, totalSigners, hasMultipleSigners fields
- Pass enrichedRows to DocumentsTable instead of filteredRows
2026-04-03 16:29:17 -06:00
Chandler Copeland
377133074b docs(16-02): complete PreparePanel signer list plan 2026-04-03 16:27:13 -06:00
Chandler Copeland
1c8551c30d feat(16-02): PreparePanel signer list UI, send-block validation, persist signers to DB 2026-04-03 16:26:53 -06:00
Chandler Copeland
25576c0d1b docs(16-03): complete FieldPlacer signer selector plan 2026-04-03 16:26:04 -06:00
Chandler Copeland
d768fc6aae feat(16-03): active signer selector, per-signer field coloring, unassigned field red highlight 2026-04-03 16:25:39 -06:00
Chandler Copeland
4e9d373e1d docs(16-01): complete multi-signer state wiring plan
- SUMMARY.md created for 16-01 plan
- STATE.md updated: plan advanced to 16-02, progress bar updated, decisions logged
- ROADMAP.md updated: phase 16 shows 1/4 plans complete
- REQUIREMENTS.md: MSIGN-01, MSIGN-02, MSIGN-03 marked complete

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 16:22:39 -06:00
Chandler Copeland
9da2cc67fd feat(16-01): thread signers and unassignedFieldIds through PdfViewer chain to FieldPlacer
- PdfViewerWrapper accepts and passes signers/unassignedFieldIds to PdfViewer
- PdfViewer accepts and passes both props to FieldPlacer
- FieldPlacer adds signers/unassignedFieldIds to FieldPlacerProps (optional, defaulted to []/ new Set())
- No rendering changes — prop tunnel only for Wave 2 consumers

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 16:21:20 -06:00
Chandler Copeland
ac1f1d6cec feat(16-01): thread signers state through DocumentPageClient
- Server page passes doc.signers as initialSigners to DocumentPageClient
- DocumentPageClient adds signers + unassignedFieldIds state (initialized from server)
- Props threaded to PdfViewerWrapper (signers, unassignedFieldIds) and PreparePanel (signers, onSignersChange, unassignedFieldIds, onUnassignedFieldIdsChange)
- PreparePanel interface extended to accept new optional multi-signer props

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 16:21:13 -06:00
Chandler Copeland
0ca698925f docs(16): create phase plan — 4 plans in 3 waves 2026-04-03 16:16:07 -06:00
Chandler Copeland
3ab49004cf docs(16): fix spacing violations flagged by ui-checker
- Replace gap-1.5 (6px) with gap-2 (8px) in signer row
- Replace padding 6px 8px with py-1 px-2 (4px/8px) in signer row
- Raise touch target exception from 28px to 32px, name override as touch-target-compact-remove with rationale
- Rename "Add" button to "Add Signer" (verb+noun CTA per Dimension 1)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 16:07:45 -06:00
Chandler Copeland
f62354e628 docs(16): UI design contract 2026-04-03 16:04:20 -06:00
Chandler Copeland
7311d30ad6 docs(phase-16): gather context for multi-signer UI phase 2026-04-03 15:59:46 -06:00
Chandler Copeland
9dc6b27174 docs(phase-15): complete phase execution — 3/3 plans, human UAT deferred 2026-04-03 15:56:22 -06:00
Chandler Copeland
163de9f162 docs(phase-15): verification passed — 17/17 must-haves, 3 human UAT items 2026-04-03 15:52:40 -06:00
Chandler Copeland
db868aebb5 docs(15-03): complete signer-aware sign route plan — atomic completion, accumulate PDF 2026-04-03 15:49:09 -06:00
Chandler Copeland
a19163855b 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
2026-04-03 15:48:01 -06:00
Chandler Copeland
1749e10e9c feat(15-03): signer-aware POST handler with accumulate PDF and atomic completion
- Step 3.5: fetch signerEmail from tokenRow after atomic claim
- Step 7: accumulate pattern — read from signedFilePath or preparedFilePath as working PDF
- Step 7: write to JTI-keyed _partial_ path to prevent concurrent signer collisions
- Step 8a: date stamps scoped to this signer's date fields (D-09)
- Step 8b: signable fields scoped to this signer's fields (Pitfall 4)
- Step 9.5: JTI-keyed datestamped temp file to prevent collision
- Step 10.5: update signedFilePath to this signer's partial after each signing
- Step 11: remaining-token count check before completion attempt
- Step 11: completionTriggeredAt atomic guard (UPDATE WHERE IS NULL RETURNING)
- Step 12: status='Signed' only in completion winner block (fixes first-signer-wins bug)
- Step 13: agent notification + signer completion emails only at completion
- Legacy null-signerEmail tokens fall through all signer filters unchanged
2026-04-03 15:47:37 -06:00
Chandler Copeland
7a04a4f617 feat(15-02): rewrite send route with multi-signer token loop and legacy fallback
- Loop over doc.signers when populated: one createSigningToken per signer with signerEmail
- Dispatch all signing emails in parallel via Promise.all
- Preserve legacy single-signer path unchanged when signers is null/empty
- Replace NEXT_PUBLIC_BASE_URL with APP_BASE_URL for signing URLs
- Add audit event with metadata.signerEmail for each signer in multi-signer path
- Import DocumentSigner from schema for type casting
2026-04-03 15:46:44 -06:00
Chandler Copeland
0f97c4233f feat(15-03): signer-aware GET field filter and updated imports
- Filter signatureFields by tokenRow.signerEmail for multi-signer tokens (D-04)
- Legacy null-signerEmail tokens return all isClientVisibleField fields (D-05)
- Added imports: createSignerDownloadToken, sendSignerCompletionEmail, DocumentSigner, sql
2026-04-03 15:45:59 -06:00
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
Chandler Copeland
14efa1dce4 feat(15-01): create public signer download route GET /api/sign/download/[token]
- Public route — no auth session required
- Validates signer-download JWT via verifySignerDownloadToken
- Guards: expired/invalid token (401), incomplete doc (404), path traversal (403)
- Serves signed PDF with Content-Disposition attachment header
2026-04-03 15:43:40 -06:00
Chandler Copeland
e1cdfe9b7b feat(15-01): add sendSignerCompletionEmail to signing-mailer
- Sends plain-text email with signed document download link to signer
- Follows established createTransporter() + sendMail() pattern
- Subject: 'Signed copy ready: {documentName}', 72h expiry in body text
2026-04-03 15:43:17 -06:00
Chandler Copeland
70c48cc377 feat(15-01): extend createSigningToken with signerEmail, add signer-download token pair
- createSigningToken now accepts optional signerEmail param and persists to DB
- Added createSignerDownloadToken (72h TTL, purpose: signer-download)
- Added verifySignerDownloadToken with purpose claim validation
2026-04-03 15:43:00 -06:00
Chandler Copeland
cdd4b8b38c docs(15): create phase plan — multi-signer backend (3 plans, 2 waves) 2026-04-03 15:39:09 -06:00
Chandler Copeland
89b4b13f8a docs(phase-15): add research and validation strategy 2026-04-03 15:32:47 -06:00
Chandler Copeland
4a3895f8a0 docs(15): research multi-signer backend phase 2026-04-03 15:31:57 -06:00
Chandler Copeland
817d53ae12 docs(phase-15): gather context for multi-signer backend phase 2026-04-03 15:26:34 -06:00
Chandler Copeland
71e1191dd1 docs(phase-14): verification passed — 6/6 must-haves, migration 0010 applied cleanly 2026-04-03 15:20:26 -06:00
Chandler Copeland
cdb1f4924e docs(14-01): complete multi-signer schema plan — migration 0010 applied
- SUMMARY.md: 2 tasks complete, schema.ts + migration 0010 committed
- STATE.md: advanced to plan 1 complete, decisions logged, 98% progress
- ROADMAP.md: phase 14 marked Complete (1/1 plans)
- REQUIREMENTS.md: MSIGN-08 marked complete
2026-04-03 15:17:25 -06:00
Chandler Copeland
363949124c feat(14-01): generate and apply Drizzle migration 0010 for multi-signer columns
- Migration 0010_sharp_archangel.sql adds signer_email to signing_tokens
- Migration adds signers JSONB column to documents
- Migration adds completion_triggered_at TIMESTAMP to documents
- Additive-only: no DROP columns, no ALTER TYPE, no backfills
- Applied successfully to local Neon/Postgres instance
2026-04-03 15:16:15 -06:00
Chandler Copeland
c658f13ea0 feat(14-01): add multi-signer types and columns to schema.ts
- Add signerEmail?: string to SignatureFieldData interface
- Add getSignerEmail() helper function with fallback pattern
- Add DocumentSigner interface { email, color }
- Add documents.signers JSONB column typed as DocumentSigner[]
- Add documents.completionTriggeredAt nullable TIMESTAMP column
- Add signingTokens.signerEmail nullable TEXT column
2026-04-03 15:15:32 -06:00
Chandler Copeland
07555ed6c5 docs(14): create phase plan 2026-04-03 15:11:27 -06:00
Chandler Copeland
ed6b8bce23 docs(phase-14): gather context for multi-signer schema phase 2026-04-03 15:04:08 -06:00
Chandler Copeland
4d69253a94 docs: create milestone v1.2 roadmap (4 phases) 2026-04-03 14:59:31 -06:00
Chandler Copeland
64ccb750fa docs: define milestone v1.2 requirements 2026-04-03 14:49:03 -06:00
Chandler Copeland
622ca3dc21 docs: complete project research 2026-04-03 14:47:06 -06:00
Chandler Copeland
6265a64a50 chore(13-04): remove debug console.log from classifyFieldsWithAI
- Remove 3 console.log statements that printed blank count, all blank descriptions, and AI classifications
- These were development debug statements; not appropriate for production code
- Tests pass (prepare-document.test.ts: 10/10), TypeScript clean
2026-04-03 14:31:15 -06:00
Chandler Copeland
b792971dac docs(13): re-research — text-extraction approach, coordinate system, plan-04 gap analysis 2026-04-03 14:29:08 -06:00
Chandler Copeland
34ee72004b docs: start milestone v1.2 Multi-Signer and Deployment Hardening 2026-04-03 13:48:53 -06:00
Chandler Copeland
7c1e480ef7 wip: phase-13 paused at 13-04 human verification — coordinate offset bug active 2026-03-21 17:57:39 -06:00
Chandler Copeland
c80133ea58 fix(13): stamp page numbers on rendered images, fix signature block pattern in prompt
- Red PAGE N label stamped on each image so GPT-4o correctly attributes fields to pages
- Prompt: add 'blank line above label' signature block pattern (common in real estate docs)
- Prompt: explicit rule — place field on blank underline, not on the (Label) text below it

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 17:52:31 -06:00
Chandler Copeland
8ac5acb486 fix(13): reduce field heights, nudge y-offset, tighten height prompt guidance
- Max heights reduced: text/date 16pt, initials 18pt, signature 26pt
- 0.5% y nudge pushes fields onto the underline instead of floating above it
- Prompt specifies 1.2% height for text/date, 1.8% for signatures

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 17:49:11 -06:00
Chandler Copeland
48788dea23 fix(13): use AI-estimated field sizes with type bounds, stricter no-inline-text rule
- Replace fixed 144x36 with AI widthPct/heightPct clamped to per-type min/max
  (signatures 100-250x20-40pt, initials 36-80x16-28pt, date 60-130x14-24pt, text 60-280x14-24pt)
- Prompt: explicit 'no inline body text' rule — if text is part of a sentence, skip it
- Prompt: widthPct should match visual underline width, heightPct kept thin (~2-2.5%)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 17:46:04 -06:00
Chandler Copeland
461abb0dc4 fix(13): mark @napi-rs/canvas as serverExternalPackages to prevent Turbopack bundling native .node binding
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 17:43:16 -06:00
Chandler Copeland
e7bf5abb9f fix(13): switch to GPT-4o vision — render PDF pages as images for accurate field placement
- extractPdfText now renders each page to JPEG via @napi-rs/canvas + pdfjs-dist (108dpi)
- field-placement.ts sends rendered page images to GPT-4o with vision (detail: high)
- AI can now visually identify underlines, signature blocks, date fields, initials boxes
- System prompt focuses on visual cues (blank lines, boxes) not text pattern matching
- Handles multi-field lines: separate fields for signature blank and date blank on same line

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 17:40:47 -06:00
Chandler Copeland
b5216a8542 fix(13): extract text with line positions for accurate AI field placement
- extractPdfText now returns TextLine[] with yPct/xPct per line instead of flat text blob
- AI can now see spatial layout (where blank lines/underscores actually are vs body text)
- Rewrote system prompt: explicit rules about blank lines/underscores/signature blocks,
  place ALL blanks even without prefill value, match field type to label pattern

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 17:35:02 -06:00