fix(documenso): expired event, real signer emails, query invalidation, double-fire

- Wire the `DOCUMENT_EXPIRED` webhook event to `handleDocumentExpired`.
  Previously the handler existed but was never called, leaving expired
  EOIs stuck in `sent` / `partially_signed` forever.
- `sendForSigning` now resolves real port-configured signer emails via
  `getPortEoiSigners(portId)` instead of fabricating
  `developer@{slug}.com` / `sales@{slug}.com`. The Documenso-template
  pathway was already using these; the upload-PDF pathway now matches.
- `handleRecipientSigned` logs a warning when the email match returns
  zero rows so a misconfigured signer isn't a silent no-op.
- `handleDocumentCompleted` skips berth-rule re-evaluation when the
  interest is already at or past `eoi_signed`, preventing a double-fire
  when `DOCUMENT_SIGNED` and `DOCUMENT_COMPLETED` arrive close together.
- EOI generate dialog now invalidates by predicate (any queryKey
  starting with `'documents'`) so the Documents tab and hub counts
  refresh after generation, instead of missing because the actual
  query key shape didn't match the targeted invalidation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matt Ciaccio
2026-05-02 23:00:58 +02:00
parent 6af2ac9680
commit e3e0e69c04
3 changed files with 61 additions and 9 deletions

View File

@@ -6,6 +6,7 @@ import { verifyDocumensoSecret } from '@/lib/services/documenso-webhook';
import {
handleRecipientSigned,
handleDocumentCompleted,
handleDocumentExpired,
handleDocumentOpened,
handleDocumentRejected,
handleDocumentCancelled,
@@ -139,6 +140,10 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
await handleDocumentCancelled({ documentId: documensoId, signatureHash });
break;
case 'DOCUMENT_EXPIRED':
await handleDocumentExpired({ documentId: documensoId });
break;
default:
logger.info({ event }, 'Unhandled Documenso webhook event type');
}