feat(eoi): in-app pathway fills the same source PDF as Documenso

When the in-app pathway is used for EOI templates, we now load the same
source PDF that the Documenso template uploads and fill its AcroForm
fields with values from EoiContext via pdf-lib. Field names mirror the
Documenso template's formValues keys exactly (Name, Email, Address,
Yacht Name, Length, Width, Draft, Berth Number + Lease_10 / Purchase
checkboxes), so both pathways produce equivalent legal documents — only
the renderer differs.

The form is left interactive (not flattened) so a recipient can still
adjust values before signing. Non-EOI templates (welcome letters,
acknowledgments, etc.) keep using the existing HTML→pdfme path.

Adds:
- pdf-lib direct dep
- src/lib/pdf/fill-eoi-form.ts — load + fill helpers, EOI_TEMPLATE_PDF_PATH
  env override
- assets/ + README documenting the expected source PDF
- next.config outputFileTracingIncludes so the asset is bundled in the
  standalone build

Tests: 8 new (4 fill-form unit + 2 source-PDF route + 2 fallback);
645/645 green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matt Ciaccio
2026-04-26 13:38:02 +02:00
parent f8255cedb8
commit 2ff24a7132
8 changed files with 536 additions and 9 deletions

48
assets/README.md Normal file
View File

@@ -0,0 +1,48 @@
# `assets/`
Server-side runtime assets bundled by Next.js (via `outputFileTracingIncludes`
in `next.config.ts`). These files are read with `fs.readFile` from
`process.cwd()` at runtime, so they are NOT served as public URLs — use
`public/` for that.
## `eoi-template.pdf`
The source PDF used by the in-app EOI generation pathway
(`src/lib/pdf/fill-eoi-form.ts`). It must be the **same** PDF that the
Documenso EOI template uploads, so both pathways produce equivalent
documents.
The PDF must contain AcroForm fields with these exact names (mirroring the
Documenso template's `formValues` keys — see
`docs/eoi-documenso-field-mapping.md`):
| Field name | Type | Filled with |
| -------------- | -------- | ----------------------------------------------------- |
| `Name` | Text | `EoiContext.client.fullName` |
| `Email` | Text | `EoiContext.client.primaryEmail` |
| `Address` | Text | `street, city, country` |
| `Yacht Name` | Text | `EoiContext.yacht.name` |
| `Length` | Text | `EoiContext.yacht.lengthFt` |
| `Width` | Text | `EoiContext.yacht.widthFt` |
| `Draft` | Text | `EoiContext.yacht.draftFt` |
| `Berth Number` | Text | `EoiContext.berth.mooringNumber` |
| `Lease_10` | Checkbox | always `false` (legacy default — Purchase, not Lease) |
| `Purchase` | Checkbox | always `true` |
Form fields stay interactive after generation (not flattened), so the
recipient can still tweak values before signing if the in-app pathway is
followed by a Documenso send.
### Override path
In dev/test, set `EOI_TEMPLATE_PDF_PATH=/abs/path/to/your/template.pdf` to
point at a different file (e.g. a fixture).
### How to extract this PDF
The legacy flow uploads this PDF to Documenso template ID 8. To get the
exact bytes:
1. In Documenso, open the EOI template.
2. Download the source PDF.
3. Drop it here as `eoi-template.pdf`.