Commit Graph

307 Commits

Author SHA1 Message Date
Chandler Copeland
e2bda51d91 feat: per-signer status panel with Resend button on sent documents, fix sign page field filter 2026-04-03 18:21:07 -06:00
Chandler Copeland
bc0495dea9 fix(signing): filter fields by signer on sign page — was passing all fields unfiltered 2026-04-03 18:14:46 -06:00
Chandler Copeland
4fe7913d7e fix(email): switch to SMTP port 587 STARTTLS — port 465 SSL blocked in Docker 2026-04-03 18:06:33 -06:00
Chandler Copeland
2d2a43a3c9 fix(docker): polyfill DOMMatrix/ImageData/Path2D for pdfjs-dist in linux/amd64 container via NODE_OPTIONS --require 2026-04-03 18:02:39 -06:00
Chandler Copeland
f15e538f5c fix(ui): uniform card heights, tinted bottom section on client cards 2026-04-03 17:51:44 -06:00
Chandler Copeland
ac42fa1fc7 fix: show additional contacts on client profile page 2026-04-03 17:49:13 -06:00
Chandler Copeland
47bc0f4cfa fix: remove redundant recipients field — signers system handles all email dispatch 2026-04-03 17:46:30 -06:00
Chandler Copeland
a00d52216e feat(clients): show contacts on client cards, auto-persist seeded signers to DB 2026-04-03 17:41:51 -06:00
Chandler Copeland
81ce0b9ab0 feat(clients): multi-contact support — co-buyers, auto-seed document signers from client contacts 2026-04-03 17:37:39 -06:00
Chandler Copeland
4f25a8c124 fix(signers): show invalid email error, persist signers immediately via PATCH, add PATCH /api/documents/[id] 2026-04-03 17:29:27 -06:00
Chandler Copeland
07cfaf0511 fix(docker): add credentials fields to auth provider, postgres service, expose port 5433, AUTH_URL/AUTH_TRUST_HOST in env example 2026-04-03 17:21:01 -06:00
Chandler Copeland
3da9610c6f docs(phase-17): verification passed — 9/9 must-haves, 3 human UAT items 2026-04-03 17:01:25 -06:00
Chandler Copeland
4a7605bbb9 docs(17-02): complete docker deployment files plan — SUMMARY.md, STATE.md, ROADMAP.md, REQUIREMENTS.md 2026-04-03 16:58:26 -06:00
Chandler Copeland
72c23f8bba feat(17-02): DEPLOYMENT.md with env setup, migration from host, docker compose up, health check
- Step-by-step guide: configure .env.production, run drizzle-kit migrate from host
- docker compose up -d --build to build and start
- curl /api/health verification step
- Update workflow: git pull, optional migration, compose up --build
2026-04-03 16:56:43 -06:00
Chandler Copeland
a107970269 feat(17-02): docker-compose.yml with env_file secrets, DNS fix, named volume; update .gitignore
- env_file: .env.production — secrets injected at runtime, not baked into image
- dns array [8.8.8.8, 1.1.1.1] + NODE_OPTIONS=--dns-result-order=ipv4first for SMTP EAI_AGAIN fix
- Named volume uploads:/app/uploads persists PDFs across container restarts
- restart: unless-stopped, port 3000:3000
- .gitignore: added /uploads/ entry for production Docker volume path
2026-04-03 16:56:25 -06:00
Chandler Copeland
e83ced580d feat(17-02): Dockerfile three-stage build, .dockerignore, .env.production.example
- Three-stage node:20-slim Dockerfile with --platform=linux/amd64 on all 3 FROM lines
- Non-root nextjs:nodejs user, seeds/ copied for form library, uploads/ dir pre-created
- HEALTHCHECK via wget pointing to /api/health, CMD node server.js
- .dockerignore excludes node_modules, .next, .git, .env*, uploads/, *.md
- .env.production.example with exactly 11 required vars (template, no real secrets, force-added past .env* glob)
2026-04-03 16:56:09 -06:00
Chandler Copeland
aa1d8d48fe docs(17-01): complete docker deployment prep plan
- SUMMARY.md: standalone output, pool limit, health endpoint
- STATE.md: advanced to plan 2, updated progress to 97%, added decisions
- ROADMAP.md: phase 17 progress updated (1/2 plans complete)
- REQUIREMENTS.md: DEPLOY-01, DEPLOY-02, DEPLOY-04 marked complete
2026-04-03 16:54:55 -06:00
Chandler Copeland
57326d77e7 feat(17-01): add GET /api/health endpoint with DB connectivity check
- Runs SELECT 1 via Drizzle db client
- Returns { ok: true, db: 'connected' } with status 200 on success
- Returns { ok: false, error: message } with status 503 on DB failure
- No auth check — intentionally public for Docker HEALTHCHECK
2026-04-03 16:53:42 -06:00
Chandler Copeland
fa7d6a9636 feat(17-01): enable standalone output, limit DB pool to 5, remove @vercel/blob
- Add output: 'standalone' to next.config.ts for Docker three-stage build
- Change postgres(url) to postgres(url, { max: 5 }) to avoid Neon free tier exhaustion
- Remove dead @vercel/blob dependency (imported nowhere in codebase)
2026-04-03 16:53:18 -06:00
Chandler Copeland
62a216fccf fix(17): add DEPLOYMENT.md task to 17-02 per checker feedback 2026-04-03 16:50:31 -06:00
Chandler Copeland
86e43d442c docs(17): create phase plan for Docker deployment
Two plans in 2 waves:
- Plan 01 (Wave 1): standalone output, DB pool limit, remove @vercel/blob, health endpoint
- Plan 02 (Wave 2): Dockerfile, docker-compose.yml, .dockerignore, .env.production.example

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 16:46:24 -06:00
Chandler Copeland
5e6b50a1e1 docs(phase-17): gather context for Docker deployment phase 2026-04-03 16:41:12 -06:00
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