Event-driven side effects
A business transaction commits state and an outbox row together. After commit, the relay publishes an IntegrationEventEnvelope to a Redis Stream. Consumers in other services record an inbox row and handle it asynchronously.
Why this shape
- The user request does not wait for push, email, or another service's projection.
- A crash after commit cannot lose the fact: the row is still pending.
- A crash after Redis publish but before the mark causes a redelivery. Consumers dedupe on
event_id.
Transport history
Phase 1 dual-wrote Pub/Sub and Streams (ADR 0002). Phase 2 turned stream consumers on by default (ADR 0003). Phase 3 made auth publish only through the outbox and set runtime transport to STREAMS (ADR 0004). The relay process moved out of auth in ADR 0006. Current default is SHARED_EVENTS_TRANSPORT=STREAMS.
Stream key pattern: splick.streams.<context>.<name>. Group env vars look like SHARED_EVENTS_GROUP_SOCIAL_USER_REGISTERED=social-service.user-registered.