Domain Events Catalog β
Canonical registry of all cross-context domain events in the Busflow modular monolith. For architectural principles governing event communication, see domain-driven-design.md Β§4.
Event Registry β
| Event | Emitter | Consumer | Trigger |
|---|---|---|---|
PriceMatrixPublished | Backoffice | Commerce | price_matrices.status β PUBLISHED |
SeasonPricingFinalized | Backoffice | Commerce | Batch completion β all PriceMatrices in a season published |
TripPublished | Backoffice | Commerce | TourDeparture.status β PUBLISHED |
TripAssigned | Backoffice | Operations | LegAssignment created for a ServiceLeg |
CrewScheduleUpdated | Backoffice | Operations | LegAssignment modified |
CrewMemberStatusChanged | Backoffice | Operations | crew_members.status mutated |
CrewAbsenceApproved | Backoffice | Operations | crew_absences.status β APPROVED |
VehicleStatusChanged | Backoffice | Operations | vehicles.status mutated |
VehicleSwapped | Operations | Communications | leg_assignments.vehicle_id updated via SwapVehicle action |
BookingConfirmed | Commerce | Backoffice, Communications | bookings.status β DEPOSIT_PAID (ADR-009). Communications sends deposit confirmation (EMAIL + WHATSAPP). |
BookingFullyPaid | Commerce | Communications | bookings.status β FULLY_PAID (Mollie payment.paid for FINAL_PAYMENT). Note: InvoiceService.generateInvoice() + issueInvoice() are co-located in the same webhook handler (see invoice-service-protocol.md Β§Invoice Trigger), not a separate async consumer. |
BookingCancelled | Commerce | Communications | bookings.status β CANCELLED (dispatcher or passenger cancels). Operations manifest updates flow via PassengerCancelled events (fired per-passenger by the cancellation handler). |
BookingRefunded | Commerce | Communications | bookings.status β REFUNDED (Mollie refund.settled webhook) |
BookingCompleted | Commerce | Communications | bookings.status β COMPLETED (Hasura Scheduled Trigger: end_date + 24h) |
BookingNoShow | Commerce | Communications | bookings.status β NO_SHOW (Hasura Scheduled Trigger: end_date + 48h, no BoardingEvent) |
CheckoutAbandoned | Commerce | Communications | checkout_sessions.status β EXPIRED (Hasura Scheduled Trigger: checkout_abandoned_sweep) |
FinalPaymentDue | Commerce (Scheduled) | Communications | departure_date - reminder_days_before_start for bookings in DEPOSIT_PAID (operator-configurable) |
FinalPaymentOverdue | Commerce (Scheduled) | Communications, Backoffice (dispatcher notification) | departure_date - flag_days_before_start β€ now() for DEPOSIT_PAID bookings with no FINAL_PAYMENT |
SeatHoldExpired | Commerce (Scheduled) | Commerce (self) | hold_expires_at < now() for HELD reservations (seat_hold_cleanup trigger) |
PassengerCancelled | Commerce | Commerce (seat release, ticket void, refund), Communications | Passenger removed from active booking |
AncillaryCancelled | Commerce | Communications | Ancillary removed from active booking |
PassengerAdded | Commerce | Commerce (supplementary payment), Communications, Operations (manifest) | New passenger added to active booking |
PassengerUpdated | Commerce | Operations (manifest) | Passenger details changed on active booking |
PaymentReceived | Commerce | Commerce (FinancialLedger), Backoffice | Mollie webhook β payment captured |
InvoiceIssued | Commerce (InvoiceService) | DATEV Export Service, Communications | invoices.status β ISSUED (see invoice-service-protocol.md Β§issueInvoice) |
FinancialLedgerClosed | Commerce | DATEV Export Service, Communications | financial_ledgers.status β CLOSED |
VehicleMaintenanceRequired | Operations | Backoffice | issue_reports.maintenance_urgency = IMMEDIATE |
IncidentCreated | Operations | Communications, Backoffice (dispatch board) | incidents row INSERT. Payload includes severity and type. Communications consumer routes uniformly: CRITICAL (any type: DELAY, BREAKDOWN, PASSENGER_ISSUE) β WhatsApp broadcast (with dispatcher approval); LOW/MEDIUM β dispatch board alert only. DELAY incidents are auto-created by the system when ServiceLegDelayed fires and no driver-reported Incident exists. See event-contracts-operations.md Β§Incident. |
IncidentResolved | Operations | Communications | incidents.status β RESOLVED |
IssueReportCreated | Operations | Backoffice (dispatch board feed) | issue_reports row INSERT |
BoardingConflictDetected | Operations (sync handler) | Communications (dispatcher notification) | Server-side validation overrides client-side check_in_status on sync (stale ticket, cancelled booking, duplicate QR across legs). See schema-operations.md Β§Server-Side Boarding Sync Handler. |
VehicleInspectionScheduled | Backoffice | Operations | vehicle_inspections row INSERT in response to VehicleMaintenanceRequired. Operations consumer sets linked IssueReport.status β IN_PROGRESS. |
VehicleInspectionCompleted | Backoffice | Operations | vehicle_inspections.status β COMPLETED. Operations consumer sets linked IssueReport.status β RESOLVED. |
ServiceLegStarted | Operations | Communications, Backoffice (dispatch board) | service_legs.status β ACTIVE |
ServiceLegCompleted | Operations | Commerce (NoShow window), Communications, Backoffice | service_legs.status β COMPLETED |
ServiceLegDelayed | Operations | Backoffice (dispatch board) | service_legs.status β DELAYED. Auto-creates a system DELAY Incident if no driver-reported one exists β IncidentCreated fires β Communications broadcasts. |
ServiceLegDelayResolved | Operations | Backoffice (dispatch board) | service_legs.status DELAYED β ACTIVE (ETA recovery). Auto-resolves linked system-created DELAY Incident β IncidentResolved fires β Communications sends all-clear. |
ServiceLegCancelled | Operations | Commerce (seat release), Communications (passenger notification), Backoffice | service_legs.status β CANCELLED |
OnboardSaleRecorded | Operations | Commerce (FinancialLedger) | onboard_sales INSERT/UPDATE with sale_status = ACTIVE AND payment_status = PAID |
OnboardSaleVoided | Operations | Commerce (FinancialLedger) | onboard_sales UPDATE where sale_status β VOIDED. Carries original amount as negative so FinancialLedger subtracts from realized_expense. |
OnboardSaleRefunded | Operations | Commerce (FinancialLedger) | onboard_sales UPDATE where sale_status β REFUNDED. For PAYMENT_LINK/CARD_READER sales, Commerce initiates Mollie refund API. For CASH, bookkeeping correction only. |
ExpenseSubmitted | Operations | Commerce (FinancialLedger) | expense_receipts.ocr_status β VERIFIED |
OnboardPaymentCompleted | Commerce | Operations | Mollie webhook payment.paid for a CheckoutSession linked to an OnboardSale (checkout_session_id) |
OnboardPaymentExpired | Commerce | Operations | checkout_abandoned_sweep expires an OnboardSale-linked CheckoutSession (status β EXPIRED where metadata.payment_type = 'ONBOARD_SALE'). Operations sets payment_status β FAILED, notifies driver. |
OnboardPaymentOrphaned | Operations | Backoffice (dispatch board) | OnboardPaymentCompleted received for a VOIDED OnboardSale. Payload: { onboard_sale_id, checkout_session_id, amount_paid, auto_refund_initiated: boolean }. Dispatcher alert β money received for voided sale. |
QualificationExpiring | Backoffice (Scheduled) | Communications | crew_qualifications.expiry_date within threshold |
VehicleInspectionOverdue | Backoffice (Scheduled) | Communications | vehicle_inspections.due_date < now() AND completed_date IS NULL |
TenantProvisioned | Backoffice | Backoffice (async workers) | operators row inserted with status = ONBOARDING (ADR-003) |
TenantActivated | Backoffice | β (logging only, MVP) | operators.status β ACTIVE (first login, via Nhost last_seen) |
TenantSuspended | Backoffice | Commerce | operators.status β SUSPENDED. Payload: { operator_id, reason } |
TenantReactivated | Backoffice | Commerce | operators.status SUSPENDED β ACTIVE. Payload: { operator_id } |
TenantChurned | Backoffice | Commerce | operators.status β CHURNED. Payload: { operator_id, reason } |
Payload Contracts β
Dedicated protocol documents specify the formal payload schemas, delivery mechanisms, and idempotency contracts:
| Events | Contract Document |
|---|---|
PriceMatrixPublished, SeasonPricingFinalized, BookingConfirmed | event-contracts-pricing.md |
BookingConfirmedΒΉ, BookingFullyPaid, BookingCancelled, BookingRefunded, BookingCompleted, BookingNoShow, PaymentReceived, CheckoutAbandoned, FinalPaymentDue, FinalPaymentOverdue, SeatHoldExpired, PassengerCancelled, AncillaryCancelled, PassengerAdded, PassengerUpdated, FinancialLedgerClosed, InvoiceIssued | event-contracts-commerce.md |
VehicleSwapped | vehicle-swap-protocol.md |
ServiceLegStarted, ServiceLegCompleted, ServiceLegDelayed, ServiceLegDelayResolved, ServiceLegCancelled, IncidentCreated, IncidentResolved | event-contracts-operations.md |
VehicleMaintenanceRequired, IssueReportCreated, VehicleInspectionScheduled, VehicleInspectionCompleted | event-contracts-operations.md Β§IssueReport Lifecycle Events |
QualificationExpiring | crew-qualification-protocol.md |
OnboardSaleRecorded, OnboardSaleVoided, OnboardSaleRefunded, ExpenseSubmitted, OnboardPaymentCompleted, OnboardPaymentExpired | Standard Hasura Event Trigger pattern (see note below) |
OnboardPaymentOrphaned | Handler-emitted (see note below) |
NOTE
Events without a dedicated contract document use the standard Hasura Event Trigger delivery pattern defined in domain-driven-design.md Β§4. All consumers implement at-least-once processing with event_id-based deduplication.
NOTE
Handler-emitted events fire programmatically from within a NestJS event handler, not from a Hasura Event Trigger on a table mutation. OnboardPaymentOrphaned fires inside the OnboardPaymentCompleted handler (Operations consumer) when the handler detects sale_status = VOIDED. The system dispatches the event via the NestJS EventEmitter (or equivalent async bus), not via a database trigger. Same at-least-once / event_id deduplication contract applies.
ΒΉ Both event-contracts-pricing.md and event-contracts-commerce.md document the BookingConfirmed payload.