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>
2026-04-26 13:38:02 +02:00
|
|
|
# `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` |
|
|
|
|
|
|
2026-05-13 12:07:57 +02:00
|
|
|
The fill path **flattens** the AcroForm after writing values, so the
|
|
|
|
|
recipient can't edit pre-filled values (yacht dimensions, address, berth
|
|
|
|
|
number) after the fact. Documenso pathway flattens server-side; the
|
|
|
|
|
in-app pathway brings the artifact to parity.
|
|
|
|
|
|
|
|
|
|
### Expected sha256
|
|
|
|
|
|
|
|
|
|
The source PDF's sha256 is pinned to guard against silent template swaps
|
|
|
|
|
(an unreviewed asset swap would change legal output without a code diff):
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
ba495fd88d99ebe4b7f61acbe397fb2f1cd116e1e1f1b217de93106915c7c44b
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`scripts/check-eoi-template-sha.ts` verifies this at boot of the in-app
|
|
|
|
|
pathway; the function exposes the expected hash via `EXPECTED_EOI_SHA256`
|
|
|
|
|
so tests can re-check after a deliberate template revision.
|
|
|
|
|
|
|
|
|
|
To intentionally update the template:
|
|
|
|
|
|
|
|
|
|
1. Drop the new PDF as `eoi-template.pdf`.
|
|
|
|
|
2. Run `shasum -a 256 assets/eoi-template.pdf`.
|
|
|
|
|
3. Update the hash in this README **and** in
|
|
|
|
|
`src/lib/pdf/fill-eoi-form.ts` (search for `EXPECTED_EOI_SHA256`).
|
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>
2026-04-26 13:38:02 +02:00
|
|
|
|
|
|
|
|
### 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`.
|