---
id: WF-MBR-MEM-025
title: State and deliver a business event
trigger: A Membership writer states a business event inside its transaction.
product_area: membership
module: memberships
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
inference: []
source_sha:
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
  - CAP-MBR-MEM-020
moves:
  - STATE-MBR-MEM-013
crosses:
  - SVC-MBR-MEM-events
  - SVC-MBR-MEM-memberships
  - SVC-MBR-MEM-commerce-participant
idempotency: >-
  The published event identifier remains stable through transport retries.
  Receiver deduplication is required; Membership does not provide exactly-once
  delivery.
concurrency: >-
  Dispatch claiming coordinates work, but transport and receiver retries can
  duplicate delivery and can arrive out of order.
hops:
  - 'n': 1
    actor_or_service: The writing module
    action: Validate and insert the business event only inside a transaction.
    anchor: >-
      services-membership:modules/events/services/publishing/publish-business-event.ts:publishBusinessEvent
    seam: sync
    on_failure: Reject the source transaction before its business change commits.
    left_inconsistent: No partial local change remains.
    observer: Writer-visible operation result
    provenance: test
    source: >-
      services-membership:modules/events/tests/integration/business-events.integration.spec.ts#leaves
      no event when the operation that stated it rolls back
  - 'n': 2
    actor_or_service: Database at commit
    action: Capture the inserted event on the published-event transport stream.
    anchor: 'services-membership:modules/events/db/published-event-stream.ts'
    seam: sync
    on_failure: Capture failure also rolls back the source change.
    left_inconsistent: No partial local change remains.
    observer: Published-event log
    provenance: observed
    source: >-
      services-membership:modules/events/services/publishing/publish-business-event.ts
      (header)
  - 'n': 3
    actor_or_service: Change-events dispatcher
    action: >-
      On dispatch passes, queue matched handler work and discard transport
      events with no receiver.
    anchor: 'services-membership:modules/events/aws/lambda/CHANGE_EVENTS_DISPATCHER.ts'
    seam: schedule
    on_failure: A failed claim is available to a later dispatch pass.
    left_inconsistent: Partner reactions can lag behind the committed event.
    observer: Dispatch execution logs
    provenance: test
    source: >-
      services-membership:modules/events/tests/unit/change-event-registry.spec.ts#registers
      no handler without the ARN
  - 'n': 4
    actor_or_service: Change-events consumer
    action: >-
      Deliver configured termination events to Committees in bounded batches and
      report per-event success or failure.
    anchor: >-
      services-membership:modules/events/services/handlers/remote-business-event-handler.ts:defineRemoteBusinessEventHandler
    seam: queue
    on_failure: >-
      Report receiver failure for queue retry; exhausted receives reach the
      alarmed dead-letter queue.
    left_inconsistent: >-
      Appointments may retain their prior state until the configured receiver
      processes termination.
    observer: Queue dead-letter alarm
    provenance: test
    source: >-
      services-membership:modules/events/tests/integration/change-events-dispatch.integration.spec.ts#reports
      a failure on the queue’s last receive too
branches:
  - >-
    Import, correction trimming and void release of never-effective coverage do
    not publish separate domain events.
waits:
  - >-
    Polling every minute does not bound receiver completion after failures or
    missing configuration.
evidence:
  - >-
    services-membership at 5994c270: modules/events/**;
    aws/membership.change-events.ts; docs/migrations/events/README.md
controls: [TC-AVL-002, TC-AVL-003, TC-AVL-004, TC-AZ-001, TC-AZ-003, TC-AZ-004, TC-CHG-001, TC-CHG-002, TC-CHG-003, TC-CHG-004, TC-CRY-001, TC-CRY-002, TC-CRY-003, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-007, TC-IAM-006, TC-LOG-002, TC-LOG-003, TC-LOG-005, TC-MON-001, TC-MON-002, TC-MON-004, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-PRV-001, TC-PRV-002, TC-SEC-001, TC-SEC-004, TC-TEN-001, TC-TEN-002, TC-TEN-003]
---

# State and deliver a business event

## What It Does

Business-event publication records a partner message in the same transaction as its source change. Dispatch later routes captured transport rows to configured handlers.

## The Flow

```mermaid
flowchart TD
  H1["Validate and insert the business event only inside a transaction"]
  H2["Capture the inserted event on the published-event transport stream"]
  H1 --> H2
  H3["On dispatch passes, queue matched handler work and discard transport events with no receiver"]
  H2 --> H3
  H4["Deliver configured termination events to Committees in bounded batches and report per-event success or failure"]
  H3 --> H4
```

## When Something Fails

Invalid payloads fail the source write before commit. Configured receiver failures retry and eventually enter the dead-letter queue. Events without a matching handler have their transport rows discarded, while their published log remains; no later automatic delivery is promised.

## Open Design Questions

Catalogue ownership and retention remain open with the integration platform owner.
