feat(documenso): full v2 endpoint coverage + sequential signing + redirectUrl

Wire up the remaining version-aware paths so a port pointed at Documenso 2.x
takes the v2 endpoint on every CRUD operation, with two new v2-only settings
exposed in admin UI.

documenso-client.ts:
- createDocument: v2 multipart /envelope/create + getDocument follow-up to
  return the full doc shape (v1 path unchanged)
- sendDocument: v2 /envelope/distribute (returns per-recipient signingUrl in
  the same response — eliminates the v1 separate-GET round-trip)
- sendReminder: v2 /envelope/redistribute with recipientIds filter
- downloadSignedPdf: v2 /envelope/{id}/download
- CreateDocumentMeta type: { subject, message, redirectUrl, signingOrder }
  threaded through v1 + v2 paths (v1 ignores signingOrder)

port-config.ts:
- New settings: documenso_signing_order (PARALLEL/SEQUENTIAL, v2-only),
  documenso_redirect_url (both versions honour)
- PortDocumensoConfig gains signingOrder + redirectUrl

documenso-payload.ts:
- DocumensoTemplatePayload.meta gains signingOrder
- buildDocumensoPayload reads from options.signingOrder, omits when null

document-templates.ts (EOI template flow):
- Pass docCfg.signingOrder + docCfg.redirectUrl into buildDocumensoPayload

documents.service.ts (sendForSigning uploaded-doc flow):
- Pass portId to documensoCreate + documensoSend (was missing)
- Thread signingOrder + redirectUrl via the new meta param

Admin Documenso settings page:
- v2 benefits card updated: now lists envelope CRUD, one-call send,
  sequential enforcement, post-sign redirect as wired (was roadmap)
- Roadmap callout pruned to the three remaining deferred items:
  template/use migration, /envelope/update, non-SIGNER recipient roles
- New "v2 signing behaviour" SettingsFormCard with the two new settings

Template flow stays on /api/v1/templates/{id}/generate-document by design —
Documenso 2.x accepts v1 endpoints via backward compat; full migration to
v2 /template/use requires per-template field-ID capture (admin schema work,
deferred).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-11 14:38:45 +02:00
parent ad312df8a4
commit d597e158fe
8 changed files with 365 additions and 58 deletions

View File

@@ -34,6 +34,7 @@ import {
voidDocument as documensoVoid,
} from '@/lib/services/documenso-client';
import { getPortEoiSigners } from '@/lib/services/documenso-payload';
import { getPortDocumensoConfig } from '@/lib/services/port-config';
import {
listTree,
collectDescendantIds,
@@ -699,24 +700,39 @@ export async function sendForSigning(documentId: string, portId: string, meta: A
const pdfBuffer = Buffer.concat(chunks);
const pdfBase64 = pdfBuffer.toString('base64');
// Create document in Documenso + send
const documensoDoc = await documensoCreate(doc.title, pdfBase64, [
{ name: client.fullName, email: emailContact.value, role: 'SIGNER', signingOrder: 1 },
{
name: eoiSigners.developer.name,
email: eoiSigners.developer.email,
role: 'SIGNER',
signingOrder: 2,
},
{
name: eoiSigners.approver.name,
email: eoiSigners.approver.email,
role: 'SIGNER',
signingOrder: 3,
},
]);
// Read per-port v2 signing settings (PARALLEL/SEQUENTIAL + redirect URL).
// Both are optional — passing undefined yields v1's legacy behavior.
const docCfg = await getPortDocumensoConfig(portId);
await documensoSend(documensoDoc.id);
// Create document in Documenso + send. portId is required for the v2
// envelope/create code path (which routes by per-port apiVersion);
// meta.signingOrder is honoured only on v2 instances.
const documensoDoc = await documensoCreate(
doc.title,
pdfBase64,
[
{ name: client.fullName, email: emailContact.value, role: 'SIGNER', signingOrder: 1 },
{
name: eoiSigners.developer.name,
email: eoiSigners.developer.email,
role: 'SIGNER',
signingOrder: 2,
},
{
name: eoiSigners.approver.name,
email: eoiSigners.approver.email,
role: 'SIGNER',
signingOrder: 3,
},
],
portId,
{
...(docCfg.signingOrder ? { signingOrder: docCfg.signingOrder } : {}),
...(docCfg.redirectUrl ? { redirectUrl: docCfg.redirectUrl } : {}),
},
);
await documensoSend(documensoDoc.id, portId);
// Update signer records with signing URLs from Documenso response
for (const docSigner of documensoDoc.recipients) {