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.
Uploaded .docx files are converted to PDF on the server using a
Gotenberg
sidecar before entering the normal envelope pipeline. The feature is
opt-in via NEXT_PRIVATE_DOCUMENT_CONVERSION_URL; when unset, only PDF
uploads are accepted.
A per-process circuit breaker opens for 30s after a conversion failure
to shed load.
Ships a dev Dockerfile that layers Microsoft Core Fonts and additional
language fonts
onto the upstream Gotenberg image for better fidelity.
Co-authored-by: Ephraim Duncan
<55143799+ephraimduncan@users.noreply.github.com>
Co-authored-by: Ephraim Duncan <55143799+ephraimduncan@users.noreply.github.com>
Platform-plan organisations and teams can now customise non-embed
signing pages with six brand colour tokens, a border-radius, and
a free-text custom CSS block (up to 256 KB).
- Stored on OrganisationGlobalSettings / TeamGlobalSettings;
teams inherit from the org via brandingEnabled === null.
- CSS is sanitised on save (PostCSS) so we can inline it at SSR
with no per-render parsing.
- Rendered via a nonce'd <style> scoped under .documenso-branded,
using native CSS nesting so user selectors don't need scoping.
- Gated on the existing embedSigningWhiteLabel claim (or
self-hosted) — reuses the embed white-label decision.
## Description
- Add a new team page showing team details, global settings, members,
and pending invites
- Update the organisation page to display organisation usage and global
settings
- Show the role and ID of each organisation member, with navigation to
their teams
## Checklist
<!--- Please check the boxes that apply to this pull request. -->
<!--- You can add or remove items as needed. -->
- [ ] I have tested these changes locally and they work as expected.
- [ ] I have added/updated tests that prove the effectiveness of these
changes.
- [ ] I have updated the documentation to reflect these changes, if
applicable.
- [ ] I have followed the project's coding style guidelines.
- [ ] I have addressed the code review feedback from the previous
submission, if applicable.
Webhook URLs were being fetched without validating whether they
resolved to private/loopback addresses, exposing the server to SSRF.
Current SSRF is best effort and fail open, you should never host
services that
you cant risk exposure of.
This extracts webhook execution into a shared module that validates
URLs against private IP ranges (including DNS resolution), enforces
timeouts, and disables redirect following. The resend route now
queues through the job system instead of calling fetch inline.
Configure default transaction options (5s maxWait, 10s timeout) on the
PrismaClient instead of per-transaction overrides. Move side effects
like email sending, webhook triggers, and job dispatches out of
$transaction blocks to avoid holding database connections open during
network I/O.
Also extracts the direct template email into a background job and fixes
a bug where prisma was used instead of tx inside a transaction.
- Allow admins to update recipient role from document detail page
- Add download button to export audit logs as PDF
- Display recipient status details in accordion
- Add LocalTime component with hover popover for timestamps
- Added function to handle template searches based on user input
- Introduced in the TRPC router to facilitate authenticated template
searches
- Updated to include template search results alongside document search
results
- Enhanced query handling by enabling searches only when the input is
valid
- Created corresponding Zod schemas for request and response validation
in
## Description
Add envelopes V2 embedded support
---------
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
## Description
Replace the PDF renderer with an custom image renderer.
This allows us to remove the "react-pdf" dependency and allows us to use
a virtual list to improve performance.
## Summary
- Adds a new admin action to move a subscription (and Stripe customerId)
from one organisation to another owned by the same user
- The target organisation must be on the free plan (no active
subscription) — enforces paid → free only
- The source organisation's claim is reset to the free plan after the
move
## How it works
A "Move Subscription" option appears in the actions dropdown of the
organisations table (on the admin user detail page) for any org with an
active or past-due subscription. Clicking it opens a dialog where the
admin selects a target org from a filtered list of eligible (free-plan)
orgs owned by the same user.
The backend performs the swap atomically in a single Prisma transaction:
1. Deletes any stale inactive subscription on the target org
2. Moves the `customerId` from source to target org
3. Reassigns the `Subscription` record to the target org
4. Copies claim entitlements to the target org
5. Resets the source org's claim to FREE
No Stripe API calls are made — the Stripe subscription and customer
remain unchanged; only the DB-level org association is updated.
## Files changed
- **New:**
`packages/trpc/server/admin-router/swap-organisation-subscription.types.ts`
— Zod schemas
- **New:**
`packages/trpc/server/admin-router/swap-organisation-subscription.ts` —
Admin mutation
- **New:**
`apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx` —
Dialog component
- **Modified:** `packages/trpc/server/admin-router/router.ts` — Register
route
- **Modified:**
`apps/remix/app/components/tables/admin-organisations-table.tsx` — Add
action menu item