Skip to content

ADR-0011: Outbox event catalogue, no relay yet

Status: Accepted · Date: 2026-10-19 · Resolves: OQ-5 · Refines: ADR-0004

Context

No consumer of payment events is known (OQ-5). The outbox must still be written correctly now, so a relay can be added later without a backfill. Implementers need fixed event names and payloads.

Decision

  • Working assumption A13: no consumer needs these events within milestones M1–M3. The relay (Kafka via Debezium or a polling publisher) is deferred until a consumer exists. Until then published_at stays NULL and the outbox is the audit trail.
  • Event row: aggregate_id = paymentId, event_type from the catalogue below, and a payload with this shape: {"schemaVersion":1,"paymentId","accountNo","amount":{"minorUnits","currency"},"decisionMode","state","declineReason"?,"occurredAt"}. Events may add fields. They never rename or remove them.
event_type Written when Task
PaymentApproved Decision APPROVED (debit, hold, or lookup found) M1-T4
PaymentDeclined Decision DECLINED, including WALLET_TIMEOUT and the stale sweeper M1-T4
PaymentReversalRequested An approved payment moves to REVERSAL_PENDING because of a till reversal M1-T5
PaymentReversed → REVERSED M1-T7
StandInApproved → STANDIN_APPROVED M2-T2
StandInDebitPosted / StandInUnrecovered Post-recovery debit result M2-T3
ReconciliationDriftDetected The reconciler finds a contradiction or an orphan it cannot repair M2-T4
PaymentCaptured / PaymentCaptureFailed Capture result, or the hold reaper's finding M3-T3, M3-T4

Consequences

  • + The relay later is pure plumbing, with no schema or backfill work.
  • − The outbox table grows unbounded until the relay or archival exists (deferred, roadmap). Revisit trigger: a consumer is named, or the outbox exceeds 50 M rows.