---
phase: 10-expanded-field-types-end-to-end
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
  - teressa-copeland-homes/src/lib/pdf/prepare-document.ts
  - teressa-copeland-homes/src/app/api/sign/[token]/route.ts
autonomous: true
requirements:
  - FIELD-02
  - FIELD-04

must_haves:
  truths:
    - "Checkbox fields are embedded in the prepared PDF as a bordered box with X diagonals"
    - "Date fields get a light placeholder rectangle in the prepared PDF (not 'Sign Here')"
    - "Initials fields get a placeholder rectangle labeled 'Initials' in the prepared PDF"
    - "Text fields get a light background rectangle (no label) in the prepared PDF"
    - "Client-signature fields continue to show a blue 'Sign Here' rectangle (unchanged)"
    - "Date fields are stamped with the actual signing date at POST submission time, not prepare time"
    - "POST handler no longer throws 500 for text/checkbox/date fields after client submits"
  artifacts:
    - path: "teressa-copeland-homes/src/lib/pdf/prepare-document.ts"
      provides: "Type-branched field rendering: checkbox X-mark, date placeholder, initials placeholder, text background, sig placeholder"
      contains: "getFieldType"
    - path: "teressa-copeland-homes/src/app/api/sign/[token]/route.ts"
      provides: "POST handler filters to signable fields only; stamps date text at sign time before embed"
      contains: "signableFields.*filter"
  key_links:
    - from: "preparePdf() sigFields loop"
      to: "@cantoo/pdf-lib drawLine/drawRectangle/drawText"
      via: "getFieldType() branch dispatch"
      pattern: "getFieldType.*checkbox|date|initials|text"
    - from: "POST handler signaturesWithCoords"
      to: "embedSignatureInPdf()"
      via: "signableFields filter then map — only client-signature and initials"
      pattern: "signableFields.*filter.*client-signature.*initials"
    - from: "POST handler date stamp"
      to: "preparedAbsPath PDF bytes"
      via: "pdf-lib load/drawText at date field coordinates before embedSignatureInPdf"
      pattern: "date.*drawText.*toLocaleDateString"
---

<objective>
Extend `preparePdf()` to render each field type distinctly rather than treating all fields as "Sign Here" signature placeholders. Fix the POST handler in `/api/sign/[token]/route.ts` to: (1) only require signatures for `client-signature` and `initials` fields (not text/checkbox/date), and (2) stamp the actual signing date onto any `date` fields at submission time before calling `embedSignatureInPdf()`.

Purpose: Without these changes, the prepare pipeline paints all fields blue with "Sign Here", and the POST handler throws 500 for documents containing checkbox/text/date fields. This plan makes the pipeline correct for all four new field types end-to-end.
Output: Updated `prepare-document.ts` with type-branched rendering and updated `route.ts` with signable field filter and date stamping.
</objective>

<execution_context>
@/Users/ccopeland/.claude/get-shit-done/workflows/execute-plan.md
@/Users/ccopeland/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/10-expanded-field-types-end-to-end/10-RESEARCH.md

<interfaces>
<!-- Key types and current implementation. Executor must use these directly. -->

From teressa-copeland-homes/src/lib/db/schema.ts:
```typescript
export type SignatureFieldType =
  | 'client-signature' | 'initials' | 'text' | 'checkbox' | 'date' | 'agent-signature';

export interface SignatureFieldData {
  id: string;
  page: number;
  x: number; y: number; width: number; height: number;
  type?: SignatureFieldType;
}

export function getFieldType(field: SignatureFieldData): SignatureFieldType {
  return field.type ?? 'client-signature';
}
export function isClientVisibleField(field: SignatureFieldData): boolean {
  return getFieldType(field) !== 'agent-signature';
}
```

Current prepare-document.ts field loop (lines 91-110) — to be replaced:
```typescript
// Current: ALL fields get identical blue rectangle + "Sign Here"
for (const field of sigFields) {
  const page = pages[field.page - 1];
  if (!page) continue;
  page.drawRectangle({ x: field.x, y: field.y, width: field.width, height: field.height,
    borderColor: rgb(0.15, 0.39, 0.92), borderWidth: 1.5, color: rgb(0.90, 0.94, 0.99) });
  page.drawText('Sign Here', { x: field.x + 4, y: field.y + 4, size: 8, font: helvetica,
    color: rgb(0.15, 0.39, 0.92) });
}
```

Current route.ts POST handler field mapping (lines 171-187) — to be fixed:
```typescript
// CRITICAL BUG: throws for text/checkbox/date fields (Missing signature for field X)
const signaturesWithCoords = (doc.signatureFields ?? []).map((field) => {
  const clientSig = signatures.find((s) => s.fieldId === field.id);
  if (!clientSig) throw new Error(`Missing signature for field ${field.id}`);
  return { fieldId: field.id, dataURL: clientSig.dataURL,
    x: field.x, y: field.y, width: field.width, height: field.height, page: field.page };
});
```

@cantoo/pdf-lib drawing primitives (confirmed available):
- `page.drawRectangle({ x, y, width, height, borderColor, borderWidth, color })`
- `page.drawLine({ start: {x,y}, end: {x,y}, thickness, color })`
- `page.drawText(text, { x, y, size, font, color })`
- `rgb(r, g, b)` where r/g/b are 0.0-1.0
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: Type-branched field rendering in preparePdf()</name>
  <files>teressa-copeland-homes/src/lib/pdf/prepare-document.ts</files>
  <action>
Add import for `getFieldType` at the top of the file:
```typescript
import type { SignatureFieldData } from '@/lib/db/schema';
import { getFieldType } from '@/lib/db/schema';
```

(Note: `SignatureFieldData` is already imported — just add `getFieldType` to the named imports.)

Replace the entire field rendering loop (currently lines 91-110, starting with the comment "Draw signature field placeholders") with this type-branched version:

```typescript
// Draw field placeholders — rendering varies by field type
for (const field of sigFields) {
  const page = pages[field.page - 1]; // page is 1-indexed
  if (!page) continue;
  const fieldType = getFieldType(field);

  if (fieldType === 'client-signature') {
    // Blue "Sign Here" placeholder — client will sign at signing time
    page.drawRectangle({
      x: field.x, y: field.y, width: field.width, height: field.height,
      borderColor: rgb(0.15, 0.39, 0.92), borderWidth: 1.5,
      color: rgb(0.90, 0.94, 0.99),
    });
    page.drawText('Sign Here', {
      x: field.x + 4, y: field.y + 4, size: 8, font: helvetica,
      color: rgb(0.15, 0.39, 0.92),
    });

  } else if (fieldType === 'initials') {
    // Purple "Initials" placeholder — client will initial at signing time
    page.drawRectangle({
      x: field.x, y: field.y, width: field.width, height: field.height,
      borderColor: rgb(0.49, 0.23, 0.93), borderWidth: 1.5,
      color: rgb(0.95, 0.92, 1.0),
    });
    page.drawText('Initials', {
      x: field.x + 4, y: field.y + 4, size: 8, font: helvetica,
      color: rgb(0.49, 0.23, 0.93),
    });

  } else if (fieldType === 'checkbox') {
    // Checked box: light gray background + X crossing diagonals (embedded at prepare time)
    page.drawRectangle({
      x: field.x, y: field.y, width: field.width, height: field.height,
      borderColor: rgb(0.1, 0.1, 0.1), borderWidth: 1.5,
      color: rgb(0.95, 0.95, 0.95),
    });
    // X mark: two diagonals
    page.drawLine({
      start: { x: field.x + 2, y: field.y + 2 },
      end: { x: field.x + field.width - 2, y: field.y + field.height - 2 },
      thickness: 1.5, color: rgb(0.1, 0.1, 0.1),
    });
    page.drawLine({
      start: { x: field.x + field.width - 2, y: field.y + 2 },
      end: { x: field.x + 2, y: field.y + field.height - 2 },
      thickness: 1.5, color: rgb(0.1, 0.1, 0.1),
    });

  } else if (fieldType === 'date') {
    // Light placeholder rectangle — actual signing date stamped at POST time in route.ts
    page.drawRectangle({
      x: field.x, y: field.y, width: field.width, height: field.height,
      borderColor: rgb(0.85, 0.47, 0.04), borderWidth: 1,
      color: rgb(1.0, 0.97, 0.90),
    });
    page.drawText('Date', {
      x: field.x + 4, y: field.y + 4, size: 8, font: helvetica,
      color: rgb(0.85, 0.47, 0.04),
    });

  } else if (fieldType === 'text') {
    // Light background rectangle — text content is provided via textFillData (separate pipeline)
    // type='text' SignatureFieldData fields are visual position markers only
    page.drawRectangle({
      x: field.x, y: field.y, width: field.width, height: field.height,
      borderColor: rgb(0.39, 0.45, 0.55), borderWidth: 1,
      color: rgb(0.96, 0.97, 0.98),
    });

  } else if (fieldType === 'agent-signature') {
    // Skip — agent signature handled by Phase 11; no placeholder drawn here
  }
}
```

Do NOT touch the AcroForm strategy A/B text fill code above the loop — only replace the field loop.
  </action>
  <verify>TypeScript compiles: `cd /Users/ccopeland/temp/red/teressa-copeland-homes && npx tsc --noEmit 2>&1 | head -30`</verify>
  <done>TypeScript compiles clean; the field loop branches on getFieldType(); checkbox fields draw X diagonals; date fields draw amber placeholder; initials draw purple placeholder; client-signature behavior unchanged</done>
</task>

<task type="auto">
  <name>Task 2: Fix POST handler — signable field filter and date stamping at sign time</name>
  <files>teressa-copeland-homes/src/app/api/sign/[token]/route.ts</files>
  <action>
Add `getFieldType` to the import from `@/lib/db/schema`:
```typescript
import { signingTokens, documents, clients, isClientVisibleField, getFieldType } from '@/lib/db/schema';
```

Add `PDFDocument` and `rgb` to the file for date stamping at sign time. Add this import after the existing imports:
```typescript
import { PDFDocument, StandardFonts, rgb } from '@cantoo/pdf-lib';
```

Also add `readFile` and `writeFile` imports from Node.js (check if already imported — add if missing):
```typescript
import { readFile, writeFile, rename } from 'node:fs/promises';
```

Replace step 8 "Merge client-supplied dataURLs with server-stored field coordinates" (the `signaturesWithCoords` block at lines ~171-187) with this two-part replacement:

**Part A — Date stamping before embed:**
Before building `signaturesWithCoords`, stamp the actual signing date onto each `date` field in the prepared PDF. This modifies the prepared PDF bytes in-memory before passing them to `embedSignatureInPdf()`.

```typescript
// 8a. Stamp date text at each 'date' field coordinate (signing date = now, captured server-side)
const dateFields = (doc.signatureFields ?? []).filter(
  (f) => getFieldType(f) === 'date'
);

// Only load and modify PDF if there are date fields to stamp
let dateStampedPath = preparedAbsPath;
if (dateFields.length > 0) {
  const pdfBytes = await readFile(preparedAbsPath);
  const pdfDoc = await PDFDocument.load(pdfBytes);
  const helvetica = await pdfDoc.embedFont(StandardFonts.Helvetica);
  const pages = pdfDoc.getPages();
  const signingDateStr = now.toLocaleDateString('en-US', {
    month: '2-digit', day: '2-digit', year: 'numeric',
  });
  for (const field of dateFields) {
    const page = pages[field.page - 1];
    if (!page) continue;
    // Overwrite the amber placeholder rectangle with white background + date text
    page.drawRectangle({
      x: field.x, y: field.y, width: field.width, height: field.height,
      borderColor: rgb(0.39, 0.45, 0.55), borderWidth: 0.5,
      color: rgb(1.0, 1.0, 1.0),
    });
    page.drawText(signingDateStr, {
      x: field.x + 4,
      y: field.y + field.height / 2 - 4,  // vertically center
      size: 10, font: helvetica, color: rgb(0.05, 0.05, 0.55),
    });
  }
  const stampedBytes = await pdfDoc.save();
  // Write to a temporary date-stamped path; embedSignatureInPdf reads from this path
  dateStampedPath = `${preparedAbsPath}.datestamped.tmp`;
  await writeFile(dateStampedPath, stampedBytes);
}
```

Note: `now` is already defined later in the file (line ~208). Move the `const now = new Date();` declaration UP to before step 8, so it can be reused for both date stamping and the documents table update. Currently `now` is defined inside step 11 — hoist it to the top of the POST handler body (after payload verification but before any async DB work would be awkward; hoist it to just before step 8a).

**Part B — Filter signaturesWithCoords to signable fields only:**
```typescript
// 8b. Build signaturesWithCoords for client-signable fields only (client-signature + initials)
// text/checkbox/date are embedded at prepare time; the client was never shown these as interactive fields
const signableFields = (doc.signatureFields ?? []).filter((f) => {
  const t = getFieldType(f);
  return t === 'client-signature' || t === 'initials';
});

const signaturesWithCoords = signableFields.map((field) => {
  const clientSig = signatures.find((s) => s.fieldId === field.id);
  if (!clientSig) throw new Error(`Missing signature for field ${field.id}`);
  return {
    fieldId: field.id,
    dataURL: clientSig.dataURL,
    x: field.x, y: field.y, width: field.width, height: field.height, page: field.page,
  };
});
```

**Update the embedSignatureInPdf call (step 9)** to read from `dateStampedPath` instead of `preparedAbsPath`:
```typescript
pdfHash = await embedSignatureInPdf(dateStampedPath, signedAbsPath, signaturesWithCoords);
```

**Add cleanup of the temporary date-stamped file after embed** (fire-and-forget, non-fatal):
```typescript
// Clean up temporary date-stamped file if it was created
if (dateStampedPath !== preparedAbsPath) {
  import('node:fs/promises').then(({ unlink }) => unlink(dateStampedPath).catch(() => {}));
}
```

Actually — `readFile`, `writeFile` are already being imported at the top of the file since it already imports from `node:path`. Check the existing imports and add only what is missing. The `rename` import from `node:fs/promises` is NOT yet in route.ts (it's in prepare-document.ts). Add `readFile`, `writeFile`, and `unlink` to a new import:
```typescript
import { readFile, writeFile, unlink } from 'node:fs/promises';
```

Do NOT use dynamic imports for the cleanup — use the statically imported `unlink` instead.

Summary of all changes to route.ts:
1. Add `getFieldType` to the schema import
2. Add `import { PDFDocument, StandardFonts, rgb } from '@cantoo/pdf-lib'`
3. Add `import { readFile, writeFile, unlink } from 'node:fs/promises'`
4. Hoist `const now = new Date()` to before step 8 (remove it from step 11 where it currently lives)
5. Insert step 8a (date field stamping) after building absolute paths (step 7) and before signaturesWithCoords
6. Replace step 8 signaturesWithCoords block with the signableFields filter + map (Part B)
7. Update step 9 embedSignatureInPdf call to use `dateStampedPath`
8. Add unlink cleanup after embed
  </action>
  <verify>TypeScript compiles: `cd /Users/ccopeland/temp/red/teressa-copeland-homes && npx tsc --noEmit 2>&1 | head -30`</verify>
  <done>TypeScript compiles clean; POST handler no longer maps all signatureFields; only client-signature and initials fields are in signaturesWithCoords; date fields are stamped with the signing date at submission time</done>
</task>

</tasks>

<verification>
1. TypeScript: `cd /Users/ccopeland/temp/red/teressa-copeland-homes && npx tsc --noEmit`
2. Verify prepare-document.ts renders different field types by manual inspection or a quick Node script that creates a test PDF with all field types and checks the output.
3. Verify route.ts POST handler filter: `grep -n "signableFields\|getFieldType" /Users/ccopeland/temp/red/teressa-copeland-homes/src/app/api/sign/\[token\]/route.ts` — should show the filter on signable fields.
4. Verify date stamping code is present: `grep -n "toLocaleDateString\|datestamped" /Users/ccopeland/temp/red/teressa-copeland-homes/src/app/api/sign/\[token\]/route.ts`
</verification>

<success_criteria>
- `preparePdf()` field loop branches on `getFieldType()` for all six field types
- Checkbox fields produce an X-mark in the prepared PDF
- Date fields produce an amber placeholder rectangle labeled "Date" in the prepared PDF
- Initials fields produce a purple placeholder rectangle labeled "Initials" in the prepared PDF
- Text fields produce a light background rectangle with no label
- Client-signature behavior is unchanged (blue rectangle + "Sign Here")
- POST handler `signaturesWithCoords` only contains `client-signature` and `initials` entries
- Date fields are stamped with `now.toLocaleDateString('en-US', { month: '2-digit', day: '2-digit', year: 'numeric' })` at POST time
- TypeScript compiles without errors
</success_criteria>

<output>
After completion, create `.planning/phases/10-expanded-field-types-end-to-end/10-02-SUMMARY.md` following the summary template.
</output>
