Files
esign/.agents/plans/clear-amber-light-validate-signer-fields-on-distribute.md
zeekay d3e091aa97 Serve and call every route under /v1
The resource API is /v1/rest and the operation API is /v1/rpc: named
for what they are, so neither shadows the other, and the v2-beta alias
is gone. Hanzo IAM returns to /auth/callback, the callback path IAM
already derives for this host, so sign-in needs no IAM change.

Claude-Session: https://claude.ai/code/session_01TUxvfuta1Z44KVNYuAz71F
2026-09-24 14:52:07 -07:00

3.2 KiB

date, title
date title
2026-01-26 Validate Signer Fields On Distribute

Summary

Validate that signers have at least one signature field before allowing document/envelope distribution via API, matching the existing UI behavior.

Background

The API originally allowed distributing documents/envelopes without validating that signers had signature fields assigned. This was intentional - we thought API users might have specific flows where this flexibility was needed.

However, after running it this way for a while, we've observed that more often than not, API users inadvertently send documents without fields assigned. This causes confusion for their recipients (who receive a document with nothing to sign) and breaks their own systems expecting a completed signing flow.

Problem

The API allowed distributing documents/envelopes even when signers had no signature fields assigned. This was inconsistent with the UI which validates this condition before allowing distribution.

Solution

1. Create centralized validation helper

File: packages/lib/utils/recipients.ts

  • Added RECIPIENT_ROLES_THAT_REQUIRE_FIELDS constant (currently only SIGNER)
  • Added getRecipientsWithMissingFields() function that returns recipients missing required fields
  • Uses existing isSignatureFieldType guard from packages/prisma/guards/is-signature-field.ts

2. Add server-side validation

File: packages/lib/server-only/document/send-document.ts

  • Added validation check that throws AppError with INVALID_REQUEST code when signers are missing signature fields
  • This blocks both v1 and v2 API distribution endpoints since they both use sendDocument()

3. Fix v1 API error handling

File: packages/v1/rest/implementation.ts

  • Changed sendDocument endpoint to use AppError.toRestAPIError(err) instead of always returning 500
  • Now returns 400 for validation errors

4. Update UI to use shared helper

Files:

  • apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx
  • packages/ui/primitives/document-flow/add-fields.tsx

5. Consolidate hasSignatureField checks

Updated to use isSignatureFieldType guard (checks both SIGNATURE and FREE_SIGNATURE):

  • apps/remix/app/components/general/document-signing/document-signing-form.tsx
  • apps/remix/app/components/general/envelope-signing/envelope-signer-form.tsx
  • apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx
  • apps/remix/app/components/embed/embed-direct-template-client-page.tsx
  • apps/remix/app/components/embed/embed-document-signing-page-v1.tsx

6. Add E2E tests

Files:

  • packages/app-tests/e2e/v1/rest/document-sending.spec.ts - 5 new tests
  • packages/app-tests/e2e/v1/rpc/distribute-validation.spec.ts - 8 new tests

Test Coverage

  • Distribution fails when signer has no fields
  • Distribution fails when signer has only non-signature fields
  • Distribution succeeds with SIGNATURE field
  • Distribution succeeds with FREE_SIGNATURE field (v1 only via Prisma)
  • Distribution succeeds when VIEWER/CC/APPROVER have no fields
  • Distribution fails when one of multiple signers is missing signature field
  • Distribution succeeds when all signers have signature fields