Skip to content

Event catalog

Audience: backend
Status: specced
Owns: backend
Depends on: System architecture, Coding standards, Architecture handover

Living catalog of every RabbitMQ event: name, producer, consumers, payload schema, version. Payload JSON Schemas live under contracts/events/ and are browsable at Contracts — Events.

Every outbox row and RabbitMQ message uses this envelope:

{
"eventId": "01hz...",
"eventType": "payment.completed",
"version": 1,
"occurredAt": "2026-07-28T10:00:00Z",
"producedBy": "orchestrator",
"correlationId": "req_01hz...",
"data": { }
}
Field Rule
eventId Dedupe key for at-least-once delivery (ULID)
version Lets payload shape evolve without breaking existing consumers
correlationId Ties the event back to the originating request’s trace
Naming resource.past_tense_verb

Schema: event-envelope.v1.json.

  • Producers write via transactional outbox, then publish.
  • Consumers are idempotent (dedupe on eventId).
  • Version payloads; keep emitting the previous shape for at least one release when breaking.
  • Per-event JSON Schemas describe the data object only.
Event Producer Consumers Trigger Key data fields Schema
user.created Orchestrator CAP, LMS, WorkMasters Registration / OTP-verify complete userId, email, intents[] v1
user.deleted Orchestrator CAP POST /auth/delete-account userId v1
payment.completed Orchestrator CAP, LMS Webhook processed referenceType, referenceId, paymentId, amount, paidAt, provider? v1
payment.failed Orchestrator CAP, LMS Webhook reports failure referenceType, referenceId, paymentId, … v1
notification.requested Any business service Orchestrator (Notification) A service decides a user needs notifying userId, channel, template, data, platform v1
application.stage_changed CAP Audit service Workflow engine advances a stage applicationId, fromStage, toStage, outcome v1
application.evaluation_inconclusive CAP LMS Assessment outcome unsuccessful (recommendation flow) applicationId, candidateId, failedUnitIds[] v1
application.certified CAP WorkMasters, LMS Certificate issued applicationId, candidateId, certificateAssetId, issuedAt v1
lms.enrollment.activated LMS Notify / analytics Entitlement active enrollmentId, courseId, learnerUserId, source v1
lms.course.completed LMS CAP, WorkMasters later Completion policy satisfied enrollmentId, courseId, learnerUserId, certificateId?, capApplicationId? v1
lms.certificate.issued LMS WorkMasters later LMS certificate issued certificateId, enrollmentId, assetId?, issuedAt v1
(security audit events) All services Audit service Login, PII access, admin action actorId, action, resourceType, resourceId (separate audit service — not CAP/OL schemas)

Design note — who requests notifications

Section titled “Design note — who requests notifications”

notification.requested is emitted by the business service that decides a notification is needed. Orchestrator does not subscribe to CAP domain events to infer when to notify. Same principle as payment/identity: Orchestrator stays generic and does not need CAP’s domain event catalog. On dispatch, OL skips the requested channel if the user disabled it in GET/PUT /notifications/preferences, except auth-critical templates (auth.account_verify, auth.password_reset, ol.account_provisioned).

Account deletion is an event. POST /auth/delete-account deactivates the Orchestrator User and outbox-publishes user.deleted { userId }. CAP redacts onboarding/candidate PII, inactivates CentreStaff, suspends assessor profiles, and removes awarding-body staff membership. Applications, certificates, and wallet history stay. The last centre super_admin may still delete; UI should warn via CAP GET /me/deletion-eligibility.

Chat send is not an event. The client posts messages to Orchestrator REST. Optional email/in-app pings are in-process dispatch on OL (channel allow-list). CAP does not emit notification.requested for Send. A future system-line in a thread may use an event; that is out of v1.

Centre-staff invite secrets are not an event. CAP calls Orchestrator gRPC ProvisionAccount. New-account generated passwords (and that email) are in-process OL dispatch — they must never appear on notification.requested. Existing-member “added to centre” mail may be in-process on the same RPC or a no-secret notification.requested. user.created remains the provision signal for CAP (idempotent); there is no cap.staff.invited consumer on OL.

Payment initiation is gRPC InitiatePayment; completion is async payment.completed — see Payment architecture.

Identity: gRPC VerifyIdentity and ProvisionAccount — see Contracts — gRPC.

Review UI: Contracts hub · Events · gRPC.