Core hooks for regional compliance integrations: invoice.* events, delivery-failure alerting, webhook docs#162
Merged
Conversation
Regional tax integrations (e.g. NFS-e tax notes in Brazil) can now be built on core hooks: staff request a fiscal document on a folio (emits invoice.requested), an external integration performs the issuance against the government API and reports the official document number back (emits invoice.issued), with voiding supported (invoice.voided). Core stores only the reference and lifecycle; regional fields live in metadata jsonb. Requested in #159. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
A delivery that exhausts all 5 retry attempts (~7h) previously just marked the row failed — silent for operators. For mandatory-delivery subscribers (e.g. government reporting integrations, #159) that is not acceptable. WebhookDeliveryService now emits an in-process webhook.delivery_failed event on permanent failure (deliberately not fanned out to external subscribers — their endpoint is the thing failing), and StaffNotificationListener turns it into a critical staff notification. Failures of staff.notification_created deliveries are skipped to prevent an alert-on-alert loop. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
…ion patterns New docs/webhooks.md covers subscribing via the Connect API, HMAC signature verification, the lean-payload / fetch-by-entityId convention, retry and at-least-once semantics, the polling reconciliation fallback, the fiscal document (invoice.*) flow, and a worked government guest-registration example. Linked from the README webhook engine section. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
CI requires the badge and docs counts to match the suite (1129 tests / 136 files after the 18 new tests in this PR). Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
telivity-otaip
marked this pull request as ready for review
July 17, 2026 02:26
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Supports #159 (Brazilian government guest registration + tax invoice integrations). The existing webhook subscription system already covers the event-driven side; this PR adds the three core pieces that make external regional integrations clean to build, without putting any regional tax logic in core.
1. Fiscal document references +
invoice.*eventsJurisdictions like Brazil require official tax documents (NFS-e tax notes) per folio. Core now stores a reference to such documents and emits lifecycle events, while issuance stays in an external integration:
fiscal_documentstable (property-scoped, folio-linked,metadatajsonb for regional fields — series, verification codes, etc. Core never interprets them).invoice.requested,invoice.issued,invoice.voided.POST /folios/:id/fiscal-documents— request a document → emitsinvoice.requestedPOST /folios/:id/fiscal-documents/:documentId/issue— integration reports the issued document number → emitsinvoice.issuedPOST /folios/:id/fiscal-documents/:documentId/void— void/cancel → emitsinvoice.voidedGET /folios/:id/fiscal-documents— listpropertyIdper the multi-tenancy rules; migration added to bothpush-schema.tsandsrc/migrations/0007_fiscal_documents.sql.2. Staff alerting on permanent webhook delivery failure
A delivery that exhausted all 5 retries (~7h) previously went silent — unacceptable when the subscriber is a mandatory government-reporting integration.
WebhookDeliveryServicenow emits an in-processwebhook.delivery_failedevent on permanent failure, andStaffNotificationListenercreates a critical staff notification. The internal event is deliberately not fanned out to external subscribers (their endpoint is the thing failing), and failures ofstaff.notification_createddeliveries are skipped to prevent an alert-on-alert loop.3. Webhook integration guide (
docs/webhooks.md)Documents subscribing via the Connect API, HMAC signature verification (with code sample), the lean-payload / fetch-by-
entityIdconvention (keeps guest PII out of webhook bodies), retry + at-least-once semantics, the polling reconciliation fallback, the fiscal document flow, and a worked government guest-registration example. Linked from the README. README test counts synced to 1129 / 136.Testing
Notes for reviewers
documentTypeandmetadataare opaque to core.EventEmitter2is injected@Optional()intoWebhookDeliveryServiceso existing direct-construction tests remain valid.