04 — Event Catalog
Status: ✅ Draft
Prerequisite: TD2, 01 — Service Decomposition
Next: 05 — Event Schemas
Complete inventory of all event types on the platform — every event Core publishes and every event modules publish. For each event: who produces it, who consumes it, what triggers it, and what its retention and replay requirements are.
Payload schemas (field-level definitions) are in 05 — Event Schemas. This document is the catalog — what exists and why. Doc 05 is the schema — exactly what each event contains.
1. Event Naming Convention
All event types follow domain.action dot notation. Lowercase. No abbreviations.
registration.confirmed
allocation.waitlisted
miqaat.phase.changed
capacity.imbalance.detected
Rules:
domain— the owning module or Core engine (e.g.registration,allocation,rbac,miqaat)action— past tense verb describing the state change that occurred (e.g.confirmed,changed,detected)- No future tense (
registration.willConfirmis wrong — events describe what happened, not what will happen) - No underscores in the event type name — use dots only
Module teams register their event types with the Domain Event Schema Registry before publishing. The registered name becomes the contract identifier.
2. Standard Envelope (Reference)
Every event on the platform uses the same envelope, confirmed in TD2. The payload field is what varies per event type. Full schema is in 05 — Event Schemas.
{
"eventId": "uuid-v4",
"eventType": "registration.confirmed",
"schemaVersion": "1.0",
"timestamp": "2026-07-15T10:30:00Z",
"idempotencyKey": "uuid-v4",
"sourceModule": "ams",
"miqaatId": "MQ-1447-KHI",
"itsId": "ITS-1234567",
"correlationId": "uuid-v4",
"payload": { }
}
3. Core-Published Events
Core engines publish decision events when they complete an action that the rest of the platform needs to react to. These are Core-to-platform broadcasts — not module-to-module events.
Contract IDs C-020 to C-026 are assigned to these events (from TD3 Section 6).
miqaat.created · C-020a
| Item | Detail |
|---|---|
| Producer | Miqaat Lifecycle Engine |
| Contract | C-020a |
| Fire condition | A new Miqaat is created in Platform Admin and assigned a miqaatId for the first time |
| Who subscribes | Config Cascade Engine (seeds default config for new Miqaat) · All modules (to learn a new Miqaat is available) · Audit Log Backbone |
| Why modules care | Modules need to know a new Miqaat exists so they can begin their own setup workflows and display it in Miqaat pickers |
| Retention | Long — platform lifecycle record |
| Replay requirement | Yes — Config Cascade must be able to replay this to rebuild its state |
miqaat.phase.changed · C-020
| Item | Detail |
|---|---|
| Producer | Miqaat Lifecycle Engine |
| Contract | C-020 |
| Fire condition | A Miqaat transitions from one phase to the next (e.g. setup → registration_open, registration_open → registration_closed, operational → closed) |
| Who subscribes | All modules (phase change affects what operations are permitted) · Config Cascade Engine · Rule Engine · Allocation Engine · Audit Log Backbone |
| Why modules care | Modules gate their own features on Miqaat phase — registration UI opens on registration_open, passes are printed on operational, etc. Modules listen to this event and react rather than polling Core for phase |
| Retention | Long — all phase changes are lifecycle records |
| Replay requirement | Yes — modules that go down during a phase transition must replay to get current state |
miqaat.archived · C-020b
| Item | Detail |
|---|---|
| Producer | Miqaat Lifecycle Engine |
| Contract | C-020b |
| Fire condition | A Miqaat is archived — all operations are closed, records are sealed |
| Who subscribes | All modules · Audit Log Backbone |
| Why modules care | Modules must close all open workflows, disable write operations, and switch to read-only mode for archived Miqaat data |
| Retention | Permanent — archive event is part of the Miqaat's immutable record |
| Replay requirement | Yes |
allocation.confirmed · C-021
| Item | Detail |
|---|---|
| Producer | Allocation Engine |
| Contract | C-021 |
| Fire condition | An allocation request is accepted and a seat/slot is confirmed for the Mumin |
| Who subscribes | The requesting module (e.g. AMS, Istefadah Registration) · Notification Dispatch Engine (to trigger confirmation message) · Audit Log Backbone · HR Bank (if the allocation is tied to a khidmat role) |
| Why modules care | The module that submitted the allocation request needs to update its own records to reflect the confirmed state and trigger downstream workflows (e.g. pass generation, welcome communication) |
| Retention | Long — allocation records are platform history |
| Replay requirement | Yes — critical for state reconstruction after an outage |
allocation.waitlisted · C-022
| Item | Detail |
|---|---|
| Producer | Allocation Engine |
| Contract | C-022 |
| Fire condition | An allocation request is received but no seat/slot is available — the Mumin is placed on the waitlist |
| Who subscribes | The requesting module · Notification Dispatch Engine (to trigger waitlist notification) · Audit Log Backbone |
| Why modules care | Module needs to update its own records to reflect waitlist status and communicate it to the Mumin |
| Retention | Long |
| Replay requirement | Yes |
allocation.released · C-022a
| Item | Detail |
|---|---|
| Producer | Allocation Engine |
| Contract | C-022a |
| Fire condition | A confirmed allocation is released (cancelled by the Mumin, revoked by an operator, or freed up due to Miqaat capacity change) — next person on the waitlist is promoted |
| Who subscribes | The holding module · Notification Dispatch Engine · Audit Log Backbone |
| Why modules care | Module must update its records, revoke pass if already issued, and acknowledge the waitlist promotion flow |
| Retention | Long |
| Replay requirement | Yes |
capacity.imbalance.detected · C-023
| Item | Detail |
|---|---|
| Producer | Capacity Balance Engine |
| Contract | C-023 |
| Fire condition | Capacity figures received from modules (via capacity.configured events) are out of acceptable ratio — e.g. Vaaz venue significantly exceeds Mawaid or Kitchen capacity |
| Who subscribes | Platform Admin dashboard · Audit Log Backbone |
| Why modules care | Platform Admin surfaces this as a pre-go-live alert. Modules with misconfigured capacity may receive follow-up from the ops team. Not a direct module consumer — this is an operational alert for the Core ops team. |
| Retention | Medium — relevant until the Miqaat is operational and balanced |
| Replay requirement | No |
eligibility.status.changed · C-024
| Item | Detail |
|---|---|
| Producer | Eligibility Engine |
| Contract | C-024 |
| Fire condition | A Mumin's eligibility status for a given Miqaat and rule set changes — either from eligible to ineligible or from ineligible to eligible (e.g. after a rule change or new data from ITS sync) |
| Who subscribes | The module that triggered the eligibility check · Allocation Engine (if eligibility gates allocation) · Notification Dispatch Engine · Audit Log Backbone |
| Why modules care | A Mumin whose eligibility status changes after registration has been submitted requires the module to act (revoke, notify, escalate) |
| Retention | Long — eligibility changes are audit-sensitive |
| Replay requirement | Yes |
role.assigned · C-025
| Item | Detail |
|---|---|
| Producer | RBAC Engine |
| Contract | C-025 |
| Fire condition | A role is assigned to an itsId for a given Miqaat scope in Platform Admin |
| Who subscribes | The affected module (if it needs to unlock features for this role) · Notification Dispatch Engine (to notify the person) · Audit Log Backbone |
| Why modules care | Some modules conditionally unlock UI features or workflows when a user holds a specific role. Listening to role.assigned lets them react without polling RBAC. |
| Retention | Long — role changes are audit records |
| Replay requirement | Yes |
role.revoked · C-026
| Item | Detail |
|---|---|
| Producer | RBAC Engine |
| Contract | C-026 |
| Fire condition | A role is revoked from an itsId in Platform Admin |
| Who subscribes | All modules holding cached role state for this itsId · Notification Dispatch Engine · Audit Log Backbone |
| Why modules care | Modules must not serve UI features or approve actions for a role that has been revoked. This event is the signal to invalidate any local role cache. |
| Retention | Long |
| Replay requirement | Yes |
4. Module-Published Events
Business modules are the primary event publishers. Every significant state change in a module is published as an event. The module owns the event type and its schema.
Events are listed by domain group — registration, volunteer management, accommodation, scanning, payment, and operational. Within each group: event type, publishing module, Core subscribers, and fire condition.
4.1 Registration Events
| Event Type | Publisher | Core Subscribers | Fire Condition |
|---|---|---|---|
registration.submitted | AMS, Istefadah Registration | Audit Log | A Mumin submits a registration form — not yet confirmed |
registration.confirmed | AMS, Istefadah Registration | Eligibility Engine · HR Bank · Audit Log | Registration is accepted and confirmed (after eligibility and allocation checks pass) |
registration.cancelled | AMS, Istefadah Registration | Allocation Engine · Audit Log | A registration is cancelled by the Mumin or an operator |
registration.rejected | AMS, Istefadah Registration | Audit Log | A registration is rejected (e.g. eligibility failure after submission) |
AMS is the primary publisher for community/safar-level registrations. Istefadah Registration module publishes for Istefadah-specific registrations. Both modules publish to the same event types — the sourceModule field distinguishes the publisher.
4.2 Attendance Events
| Event Type | Publisher | Core Subscribers | Fire Condition |
|---|---|---|---|
attendance.recorded | AMS, Istefadah Registration, Scanning | Eligibility Engine (for prior attendance rules) · HR Bank · Audit Log | Attendance for a session or day is recorded for a Mumin |
attendance.checked_in | Jamaat Scan, Kiosk, Scanning | Audit Log | A Mumin checks in at a venue or session via scanning or kiosk |
attendance.checked_out | Jamaat Scan, Kiosk, Scanning | Audit Log | A Mumin checks out (where applicable) |
4.3 Volunteer & Khidmat Events
| Event Type | Publisher | Core Subscribers | Fire Condition |
|---|---|---|---|
volunteer.applied | VMS | Audit Log | A Mumin applies to volunteer for a khidmat role |
volunteer.assigned | VMS | HR Bank · Audit Log | A Mumin is assigned to a volunteer role |
volunteer.approved | VMS | Audit Log | A volunteer assignment is approved by an authorised coordinator |
volunteer.released | VMS | HR Bank · Audit Log | A volunteer is released from their assigned role |
khidmat.assigned | VMS | HR Bank · Audit Log | A khidmat (service role) is formally assigned — HR Bank uses this to build the cross-Miqaat history record |
khidmat.completed | VMS | HR Bank · Audit Log | Khidmat is confirmed as completed — HR Bank writes the history record |
Why khidmat.assigned and volunteer.assigned are separate: volunteer.assigned is an operational state within VMS (the person is rostered). khidmat.assigned is the formal platform-level record that HR Bank cares about — it may fire later, after confirmation, and carries additional context about the role type and Miqaat scope.
4.4 Accommodation Events
| Event Type | Publisher | Core Subscribers | Fire Condition |
|---|---|---|---|
accommodation.allocated | Accommodation module | Audit Log | A Mumin is allocated to accommodation (Bethak, room, hotel) |
accommodation.released | Accommodation module | Audit Log | Accommodation allocation is released |
capacity.configured | Accommodation, Venue, Mawaid, Kitchen modules | Capacity Balance Engine · Audit Log | A module finalises its capacity figure for the Miqaat — triggers Capacity Balance Engine to check ratios |
capacity.configured is special — it is published by multiple modules (venue, food, accommodation, kitchen) and is the primary trigger for the Capacity Balance Engine. Each module publishes once when its capacity is finalised, and again if the figure changes. The Capacity Balance Engine aggregates across all of them.
4.5 Pass & Scanning Events
| Event Type | Publisher | Core Subscribers | Fire Condition |
|---|---|---|---|
pass.generated | Pass module, Scanning module | Audit Log | A Miqaat pass is generated for a Mumin |
pass.printed | Scanning, Kiosk | Audit Log | A physical pass is printed — triggers the point of no return in pass issuance |
pass.revoked | Pass module, Platform Admin | Audit Log | A pass is revoked (allocation cancelled, rule violation, operator action) |
checkpoint.scanned | Jamaat Scan, Scanning, Kiosk | Audit Log | A pass or ID is scanned at a checkpoint — records movement/entry |
sharaf.photo.captured | Sharaf Photos module | Audit Log | A Sharaf photo is captured for a Mumin (Ashara Mubaraka context) |
4.6 Payment Events
| Event Type | Publisher | Core Subscribers | Fire Condition |
|---|---|---|---|
payment.received | Payment module | Eligibility Engine · Audit Log | Payment is confirmed received and cleared |
payment.failed | Payment module | Audit Log | A payment attempt fails |
payment.refunded | Payment module | Audit Log | A payment is refunded |
Eligibility Engine subscribes to payment.received because payment clearance can gate registration eligibility in some Miqaat types (e.g. Vajebaat payment must be confirmed before Istefadah eligibility resolves).
4.7 Communications Events
| Event Type | Publisher | Core Subscribers | Fire Condition |
|---|---|---|---|
broadcast.sent | Broadcast module | Audit Log | A broadcast message is dispatched to a group audience |
notification.delivered | Notification Dispatch Engine | Audit Log | A Notification Dispatch delivery is confirmed by the channel |
notification.failed | Notification Dispatch Engine | Audit Log | A delivery attempt fails after all retries are exhausted |
Broadcast vs Notification: Confirmed in Day 4 sessions — Broadcast (bulk, Jamaat-wide, role-targeted) is a separate engine from Notification Dispatch (individual, transactional, triggered by module events). They have separate event types.
4.8 Safar & Miqaat Management Events
| Event Type | Publisher | Core Subscribers | Fire Condition |
|---|---|---|---|
safar.created | Safar Management module | Audit Log | A new Safar record is created in ITS (community record — distinct from a Core miqaat.created event) |
safar.updated | Safar Management module | Audit Log | Safar record is updated |
grouping.assigned | Grouping module (Istefadah) | Audit Log | A Mumin is assigned to a group/bethak for the Miqaat |
timetable.published | Timetable module | Audit Log | A Miqaat timetable is published — visible to all modules and attendees |
helpline.ticket.raised | Helpline module | Audit Log | A helpline ticket is raised during the Miqaat |
helpline.ticket.resolved | Helpline module | Audit Log | A helpline ticket is resolved |
4.9 Vendor & Procurement Events
| Event Type | Publisher | Core Subscribers | Fire Condition |
|---|---|---|---|
indent.raised | Any module with procurement workflow | Vendor Registry · Audit Log | A procurement indent is raised by a module |
indent.approved | Any module with procurement workflow | Audit Log | An indent is approved in the module's workflow |
indent.rejected | Any module with procurement workflow | Audit Log | An indent is rejected |
Vendor Registry subscribes to indent.raised to track procurement activity against the budget envelope and to flag cross-event vendor conflicts.
4.10 Nikah & Rasm Events
| Event Type | Publisher | Core Subscribers | Fire Condition |
|---|---|---|---|
nikah.application.submitted | Nikah module | Audit Log | A Nikah application is submitted |
nikah.approved | Nikah module | Audit Log | Nikah application approved |
rasm.saifee.recorded | Rasm-e-Saifee module | Audit Log | A Rasm-e-Saifee ceremony is recorded |
misaaq.recorded | Misaaq module | Audit Log | A Misaaq commitment is recorded — triggers eligibility updates in some rule sets |
misaaq.recorded may feed the Eligibility Engine in some Miqaat rule configurations — a Mumin who has not yet taken Misaaq may be ineligible for certain Istefadah slots.
5. Producer → Consumer Map
Full cross-reference of every event type and its subscribers.
Core engine as consumer
| Event Type | Core Engine Subscriber | Reason |
|---|---|---|
capacity.configured | Capacity Balance Engine | Triggers ratio check across all modules |
khidmat.assigned | HR Bank | Build cross-Miqaat khidmat record |
khidmat.completed | HR Bank | Mark khidmat as completed in history |
volunteer.assigned | HR Bank | Cross-reference with khidmat record |
volunteer.released | HR Bank | Update history if khidmat was in progress |
registration.confirmed | Eligibility Engine | Updates eligibility state for attendance-based rules in future Miqaats |
attendance.recorded | Eligibility Engine | Prior attendance rule family — records attendance count |
payment.received | Eligibility Engine | Payment-gate rule family — clears payment block on eligibility |
misaaq.recorded | Eligibility Engine | Misaaq rule family — clears eligibility block |
indent.raised | Vendor Registry | Budget envelope tracking; conflict detection |
miqaat.created | Config Cascade Engine | Seeds default config for new Miqaat |
| All events | Audit Log Backbone | Immutable platform-wide audit record |
Core engine as publisher — module consumer
| Event Type | Core Publisher | Who Typically Subscribes |
|---|---|---|
miqaat.created | Miqaat Lifecycle | All modules (Miqaat picker, setup workflows) |
miqaat.phase.changed | Miqaat Lifecycle | All modules (feature gating on phase) |
miqaat.archived | Miqaat Lifecycle | All modules (switch to read-only) |
allocation.confirmed | Allocation Engine | Requesting module · Pass module · Notification Dispatch |
allocation.waitlisted | Allocation Engine | Requesting module · Notification Dispatch |
allocation.released | Allocation Engine | Requesting module · Pass module |
eligibility.status.changed | Eligibility Engine | Requesting module · Allocation Engine |
capacity.imbalance.detected | Capacity Balance | Platform Admin only |
role.assigned | RBAC Engine | Affected module · Notification Dispatch |
role.revoked | RBAC Engine | All modules (cache invalidation) |
6. Event Retention and Replay
Retention tiers
| Tier | Retention | Event types |
|---|---|---|
| Permanent | Never deleted | miqaat.created · miqaat.archived · role.assigned · role.revoked · allocation.confirmed · khidmat.completed · registration.confirmed · all audit-sensitive events |
| Long | Until 1 year post Miqaat archive (TBC — security session) | Most operational events — miqaat.phase.changed · allocation.waitlisted · attendance.recorded · pass.generated · pass.printed · payment.received |
| Medium | Until Miqaat closes (TBC) | capacity.configured · capacity.imbalance.detected · checkpoint.scanned · helpline.ticket.* |
Retention periods marked TBC are subject to the Dedicated Security session outcome (data residency, compliance, and audit retention policy).
Replay requirements
Must support replay (consumer goes down and needs to catch up):
- All Core-engine subscribers — Eligibility Engine, HR Bank, Capacity Balance Engine must be able to replay from a given offset
- All modules subscribing to
miqaat.phase.changedandrole.revoked— state changes that affect feature gating
Replay is at-least-once delivery. Consumers must use idempotencyKey in the event envelope to detect and safely ignore duplicate delivery. Exactly-once is not a platform guarantee — this shifts the idempotency responsibility to consumers.
7. Event Bus Operational Requirements
Confirmed in TD2. Included here for completeness.
| Requirement | Detail |
|---|---|
| Durability | Events must not be dropped on publish. Durable storage required — no in-memory-only bus |
| Replay from offset | Consumers must be able to replay from any point in the event stream — required for recovery after module downtime during peak windows |
| At-least-once delivery | Platform assumes at-least-once. Consumers handle idempotency. |
| Consumer groups | Multiple modules may subscribe to the same event type independently. Each gets its own copy and manages its own offset. |
| Dead Letter Queue (DLQ) | Events that exceed retry limits land in a DLQ. Visible in Platform Admin Event Bus Health. Core team inspects, retries, or discards. |
| Topic-level ACLs | Module credentials only grant access to their registered event type topics. A module cannot read another module's topics unless explicitly subscribed. |
| Schema version mismatch alerts | Platform Admin surfaces alerts when a consumer is receiving events in a schema version it has not declared support for |
Bus technology: Under analysis — decision confirmed before Phase 1 infrastructure provisioning. Pattern B and the event envelope are confirmed regardless of technology.
8. Subscription Management
A module declares its event subscriptions in its System Definition Document before build begins. Core provisions bus-level topic access based on those declarations at onboarding.
A module's bus credentials grant access only to the topics it declared. If requirements change:
- Module team updates their System Definition Document
- Core team reviews and provisions the additional subscription in Platform Admin
- Module team is notified when access is provisioned
Modules cannot self-provision new subscriptions. This prevents data leakage — a module cannot read another module's operational events by guessing topic names.
9. Open Questions
| Question | Blocked On |
|---|---|
| Exact retention periods per tier | Dedicated Security session (data residency + compliance) |
| Event bus technology selection | Infrastructure session + TD2 analysis |
Whether capacity.configured fires once (finalization) or can be updated | Business / module design session |
misaaq.recorded → Eligibility Engine subscription — which rule sets does this apply to? | Business session (module-specific rule configuration) |
| Historical event migration — what happens to events from pre-Core Miqaats? | Migration planning session |
| Module-specific event types for AMS + 11 remaining modules | Remaining discovery sessions |