feat(documenso): v2 coverage on getDocument/health + reminder webhook + admin UI benefits panel

- documenso-client.ts: getDocument now routes to /api/v2/envelope/{id} when port apiVersion=v2; checkDocumensoHealth surfaces resolved apiVersion for the admin Test button
- webhook route: handle DOCUMENT_REMINDER_SENT (structured log only, no audit-table noise) + DOCUMENT_CREATED / DOCUMENT_SENT (informational log)
- Admin Documenso page: prominent v1-vs-v2 explainer card listing v2-only capabilities the CRM already exploits (bulk fields, percent coords, richer fieldMeta, v2 webhook aliases, envelope endpoints) + amber roadmap callout for sequential signing / redirectUrl / template/use / envelope/update / non-SIGNER roles
- CLAUDE.md: idempotency + v2 webhook event list, berth-rules engine section, DOCUMENSO_API_URL gotcha, storage backend listByPrefix + timeout

Still v1-only (call out in admin UI roadmap): createDocument, generateDocumentFromTemplate, sendDocument, sendReminder, downloadSignedPdf. Migrating template/use to v2 requires per-template field-ID mapping in template config; deferred to a follow-up plan.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-11 14:24:40 +02:00
parent 1f41f8a8a0
commit ad312df8a4
4 changed files with 152 additions and 10 deletions

View File

@@ -229,7 +229,12 @@ export async function sendDocument(docId: string, portId?: string): Promise<Docu
}
export async function getDocument(docId: string, portId?: string): Promise<DocumensoDocument> {
return documensoFetch(`/api/v1/documents/${docId}`, undefined, portId).then(normalizeDocument);
const { apiVersion } = await resolveCreds(portId);
// v1: GET /api/v1/documents/{id}
// v2: GET /api/v2/envelope/{id} — same response normalizer (id ↔ documentId,
// recipientId ↔ id handled by normalizeDocument).
const path = apiVersion === 'v2' ? `/api/v2/envelope/${docId}` : `/api/v1/documents/${docId}`;
return documensoFetch(path, undefined, portId).then(normalizeDocument);
}
/**
@@ -295,13 +300,16 @@ export async function downloadSignedPdf(docId: string, portId?: string): Promise
/** Convenience health-check used by the admin "Test connection" button. */
export async function checkDocumensoHealth(
portId?: string,
): Promise<{ ok: boolean; status?: number; error?: string }> {
): Promise<{ ok: boolean; status?: number; error?: string; apiVersion?: DocumensoApiVersion }> {
try {
const { baseUrl, apiKey } = await resolveCreds(portId);
const { baseUrl, apiKey, apiVersion } = await resolveCreds(portId);
// Both v1 and v2 expose /api/v1/health (v2 keeps the v1 path for
// backward compat). If a v2 deployment ever moves this we'll add a
// v2 branch — but as of Documenso 2.x there isn't a v2 health path.
const res = await fetchWithTimeout(`${baseUrl}/api/v1/health`, {
headers: { Authorization: `Bearer ${apiKey}` },
});
return { ok: res.ok, status: res.status };
return { ok: res.ok, status: res.status, apiVersion };
} catch (err) {
return { ok: false, error: err instanceof Error ? err.message : 'Unknown error' };
}