# Event-Driven Architecture ## Envelope All events use `shared.events.EventEnvelope`: ```json { "event_id": "uuid", "event_type": "tenant.created", "aggregate_type": "tenant", "aggregate_id": "uuid", "tenant_id": "uuid|null", "source_service": "core-service", "payload": {}, "occurred_at": "ISO-8601" } ``` ## Outbox → Inbox ([ADR-006](adr/ADR-006.md)) 1. Producer writes business row + `outbox_events` in one transaction. 2. Worker (`process_outbox_events`) publishes pending rows. 3. Consumer inserts `inbox_events` keyed by `event_id` (idempotency) then handles payload. ## Naming `{aggregate}.{past_tense_verb}` — e.g. `tenant.created`, `subscription.updated`, `user.registered`. ## Catalog Canonical list → [event-catalog.md](../reference/event-catalog.md) ## Future Replace in-process/Celery-only publish with a real message bus without changing envelope or outbox ownership. ## Related Documents - [Services Contracts](../reference/services-contracts.md) - [Service Architecture](service-architecture.md) - [ADR-006](adr/ADR-006.md)