Files
red/.planning/phases/05-pdf-fill-and-field-mapping/05-04-SUMMARY.md
Chandler Copeland 13cdd150f1 docs(05-04): complete pdf-fill-and-field-mapping plan 04 bug fixes
Four post-testing bugs fixed: signature field placement coordinate math,
delete button clickability, client selector pre-selection with manual
email entry, and text fill fallback to drawText for flat PDFs.
SUMMARY.md updated with full bug fix documentation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 00:24:50 -06:00

7.5 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
05-pdf-fill-and-field-mapping 04 documents/pdf-fill
human-verify
checkpoint
bug-fix
dnd-kit
pdf-lib
coordinate-math
form-prepare
phase provides
05-02-pdf-fill-and-field-mapping Drag-and-drop FieldPlacer component on PDF pages with DB persistence
phase provides
05-03-pdf-fill-and-field-mapping TextFillForm and PreparePanel components wired to /api/documents/[id]/prepare
phase provides
05-01-pdf-fill-and-field-mapping POST /api/documents/[id]/prepare endpoint that writes prepared PDF and transitions status to Sent
Human sign-off on Phase 5 end-to-end workflow (DOC-04, DOC-05, DOC-06)
06-signing-flow
added patterns
email_addresses jsonb column in documents table (migration 0004)
pageInfo.width/height as authoritative rendered canvas size (not getBoundingClientRect)
dnd-kit MouseSensor/TouchSensor with activationConstraint.distance to guard click targets
onPointerDown e.stopPropagation() on buttons inside DndContext to prevent drag capture
useLayoutEffect for tracking container dimensions in state
preparePdf Strategy A (AcroForm) + Strategy B (drawText fallback) for text fill
email_addresses jsonb column in documents table for Phase 6 signing
created modified
teressa-copeland-homes/drizzle/0004_military_maximus.sql
teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/FieldPlacer.tsx
teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/_components/PreparePanel.tsx
teressa-copeland-homes/src/app/portal/(protected)/documents/[docId]/page.tsx
teressa-copeland-homes/src/app/api/documents/[id]/prepare/route.ts
teressa-copeland-homes/src/lib/pdf/prepare-document.ts
teressa-copeland-homes/src/lib/db/schema.ts
Use pageInfo.width/height (from react-pdf page load callback) not containerRect.width/height for coordinate math
dnd-kit sensor activationConstraint distance:5 prevents buttons inside DndContext from triggering drag
onPointerDown e.stopPropagation() on delete button as safe guard for dnd-kit sensor capture
preparePdf Strategy B stamps un-matched text fields as 'key: value' lines at top of page 1
emailAddresses stored as jsonb array in documents.email_addresses ready for Phase 6; no email sent in Phase 5
assignedClientId locked (read-only) when already set; defaults to document owner but changeable when null
pageInfo.width/height pattern for PDF canvas coordinate math in FieldPlacer
preparePdf dual-strategy text fill: AcroForm + drawText fallback
DOC-04
DOC-05
DOC-06
30min 2026-03-20

Phase 5 Plan 04: Human Verification Checkpoint + Bug Fixes Summary

Four bugs found during human testing were fixed: signature field misplacement, unclickable delete button, client selector pre-selection with manual email entry, and text fill data silently dropped from output PDF.

Performance

  • Duration: ~30 min (bug fixes after checkpoint)
  • Completed: 2026-03-20
  • Bugs fixed: 4
  • Commits: 3 (Bugs 1+2 in same file, Bugs 3 and 4 separate)
  • Files modified: 6 + 1 migration created

Accomplishments

Bug 1 — Signature field placement lands in wrong position (FIXED)

Root cause: renderFields() called containerRef.current?.getBoundingClientRect() during React render to obtain canvas dimensions. containerRect.width/height could differ from the actual PDF canvas size if the wrapper div had any extra decoration. Also, calling getBoundingClientRect() during render is unreliable.

Fix: Used pageInfo.width/height (set from react-pdf's page.onLoadSuccess) as the authoritative rendered canvas dimensions. Added containerSize state updated via useLayoutEffect(pageInfo) so renderFields() reads from stable state. getBoundingClientRect() is still called in handleDragEnd (event handler) to get the container's viewport origin for offset calculation only.

Commit: 126e10d

Bug 2 — Cannot click the x button to delete a signature field (FIXED)

Root cause: dnd-kit's default sensor captured all pointerdown events inside DndContext, including on the delete button.

Fix (two-part):

  1. Configured MouseSensor + TouchSensor with activationConstraint: { distance: 5 } — drag only activates after 5px movement, so a button click does not start a drag.
  2. Added onPointerDown={(e) => e.stopPropagation()} to the delete button — prevents dnd-kit sensors from seeing the pointerdown from the button.

Field overlay divs now have zIndex: 10 and the button zIndex: 11.

Commit: 126e10d (same file as Bug 1)

Bug 3 — Client selector should default to document's client; allow manual email entry (FIXED)

Root cause: PreparePanel received a single currentClientId prop (resolved assignedClientId ?? clientId) so it could not distinguish "explicitly assigned" from "default owner". No email input existed.

Fix:

  • page.tsx now passes assignedClientId (nullable) and defaultClientId separately.
  • PreparePanel shows locked read-only display when assignedClientId is non-null; unlocked dropdown (defaulting to defaultClientId) when null.
  • Textarea added for additional/CC email addresses (comma or newline separated), always visible.
  • buildEmailAddresses() merges client email + manual entries, deduplicates, validates.
  • POST /api/documents/[id]/prepare accepts and stores emailAddresses: string[].
  • Added email_addresses jsonb column via migration 0004_military_maximus.sql (applied).

Commit: 05915aa

Bug 4 — Text fill fields do nothing in the prepared PDF (FIXED)

Root cause: preparePdf() silently caught all AcroForm errors with no fallback. Text fill data was discarded when the PDF had no AcroForm or no matching field names.

Fix: Added Strategy B: after Strategy A (AcroForm), any un-filled entries are drawn as key: value text lines near the top of page 1 using @cantoo/pdf-lib's drawText(). acroFilledKeys Set tracks Strategy A successes so Strategy B only stamps the remainder.

Commit: ef10dd5

Task Commits

Commit Description Bugs
126e10d fix(05-04): fix signature field placement coordinate math 1, 2
05915aa fix(05-04): pre-select document client and add manual email entry 3
ef10dd5 fix(05-04): always stamp text fill data into prepared PDF 4

Files Created/Modified

File Change
FieldPlacer.tsx Coordinate math, sensor config, delete button guard
PreparePanel.tsx Locked client, manual email textarea, emailAddresses
page.tsx Pass assignedClientId and defaultClientId separately
prepare/route.ts Accept and store emailAddresses array
prepare-document.ts Strategy B drawText fallback for text fill
schema.ts Added emailAddresses jsonb field
0004_military_maximus.sql New migration: email_addresses column

Deviations from Plan

None — these were continuation bug fixes from human testing, not plan deviations.

Self-Check: PASSED

  • All 6 source files exist and TypeScript compiles clean (tsc --noEmit)
  • Migration 0004 generated and applied to local DB
  • Commits 126e10d, 05915aa, ef10dd5 confirmed in git log