Per-product direction: AcroForm widget to Documenso field creation
should not happen automatically on upload. It must be a deliberate,
opt-in action on a draft envelope.
- Revert AcroForm extraction from create-envelope (route) and
create-envelope-items upload paths. They no longer thread
acroFormFields into envelope items or run the extractor.
- Stop flattening on upload (flattenForm: false) so widgets survive
in the stored PDF until the user opts in.
- New tRPC mutation envelope.field.importFromPdf is the single entry
point. It loads each item's stored PDF, extracts widgets, creates
Field rows assigned to the first signable recipient (creating a
placeholder Recipient 1 SIGNER when none exist), flattens the PDF
in place, swaps documentDataId, and emits FIELD_CREATED audit log
entries on DOCUMENT envelopes.
- Editor fields panel gains an "Import from PDF form" button next to
"Detect with AI", gated to DRAFT envelopes. Success toasts the
count and revalidates the editor.
- Rewrite acroform-import.spec.ts e2e to the new flow: upload
preserves widgets and creates zero fields; service call creates
fields, flattens PDF, audits, and cleans up old DocumentData.
- Invert four DOCUMENT-upload assertions in form-flattening.spec.ts
to match the new preserve-widgets, no-auto-flatten contract.
Template and template-to-doc flatten behavior is unchanged.
Detect AcroForm widgets (text, checkbox, radio, dropdown, signature) at upload
time and reuse their geometry as Documenso fields instead of stripping them via
form.flatten(). Imported fields land in the editor as ordinary Field rows
assigned to the first signable recipient, removing the manual re-placement step
users hit when preparing PDFs in Adobe Acrobat.
Extraction runs before normalizePdf so widget geometry is still readable.
Text fields go through a name+format heuristic that maps DATE/NUMBER/EMAIL/
NAME/INITIALS/TEXT, with AcroForm /AA format actions taking precedence over
name tokens. Coordinates are converted via per-rotation transforms (0/90/180/
270) against the rendered page dimensions; widgets fully off-page are
dropped, partial overlap is clamped. Signed signatures (SignatureField.
isSigned()) are detected and skip both the import and the form flatten so
the signature stays valid. Encrypted PDFs, XFA hybrids, malformed PDFs, and
internal extractor errors all return an empty result with skipReason set so
the upload proceeds untouched.
Every imported field carries fieldMeta.source = 'acroform' (new optional on
ZBaseFieldMeta) for future provenance queries. DOCUMENT envelopes emit a
per-field FIELD_CREATED audit entry matching create-envelope-fields.ts.
Recipient assignment picks the first Recipient with role SIGNER or APPROVER
sorted by (signingOrder asc nulls last, id asc); when no signable recipient
exists, a placeholder Recipient 1 SIGNER is created mirroring the
placeholder-pipeline behaviour.
## Description
Add envelopes V2 embedded support
---------
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>