> ## Documentation Index
> Fetch the complete documentation index at: https://secdocs.asikoexpress.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Domain Events Catalog

> Every internal event the platform defines, and exactly what happens when each fires

The backend uses an internal event bus (RabbitMQ) to fan actions out to notifications without
every service having to know how to send an email or push a WebSocket message itself. This isn't
part of the public API surface, but it directly determines what shows up as an in-app notification
or a [real-time push](/realtime-notifications) — so it's documented here in full rather than left
implicit.

There are **57 defined events**. This table accounts for every one of them, so nothing is left
ambiguous about what's actually wired up versus reserved for a feature that doesn't exist yet.

<Info>
  "Customer notification" and "Admin alert" below mean: persisted in-app notification + email +
  live WebSocket push to the customer, or a live `admin-alert` WebSocket push (plus an ops email)
  respectively. See [Real-time Notifications](/realtime-notifications) for the delivery mechanics.
</Info>

## Live — actively published and wired

These 17 events are published by a backend service today, and each one triggers a real,
content-complete customer notification and/or admin alert (not placeholder copy).

| Event                                                                     | Published by                                                                | Customer notification | Admin alert |
| ------------------------------------------------------------------------- | --------------------------------------------------------------------------- | :-------------------: | :---------: |
| `user.registered` (`USER_REGISTERED`)                                     | user-service — retail registration, and completing wholesale `set-password` |           ✅           |      ✅      |
| `user.email_verification.requested` (`USER_EMAIL_VERIFICATION_REQUESTED`) | user-service                                                                |           ✅           |      —      |
| `user.trade.approved` (`USER_TRADE_APPROVED`)                             | user-service                                                                |           ✅           |      —      |
| `user.password_reset.requested` (`USER_PASSWORD_RESET_REQUESTED`)         | user-service                                                                |           ✅           |      —      |
| `user.password.changed` (`PASSWORD_CHANGED`)                              | user-service                                                                |           ✅           |      —      |
| `user.profile.updated` (`PROFILE_UPDATED`)                                | user-service                                                                |           ✅           |      —      |
| `user.account.deactivated` (`ACCOUNT_DEACTIVATED`)                        | user-service                                                                |           ✅           |      —      |
| `user.account.reactivated` (`ACCOUNT_REACTIVATED`)                        | user-service                                                                |           ✅           |      —      |
| `wholesale.application.submitted` (`WHOLESALE_APPLICATION_SUBMITTED`)     | user-service                                                                |           ✅           |      ✅      |
| `wholesale.application.approved` (`WHOLESALE_APPLICATION_APPROVED`)       | user-service                                                                |           ✅           |      —      |
| `wholesale.application.rejected` (`WHOLESALE_APPLICATION_REJECTED`)       | user-service                                                                |           ✅           |      —      |
| `order.placed` (`ORDER_PLACED`)                                           | order-service                                                               |           ✅           |      ✅      |
| `order.paid` (`ORDER_PAID`)                                               | order-service                                                               |           ✅           |      —      |
| `order.cancelled` (`ORDER_CANCELLED`)                                     | order-service                                                               |           ✅           |      —      |
| `order.dispatched` (`ORDER_DISPATCHED`)                                   | order-service — fired when a tracking update sets status `PARCEL_COLLECTED` |           ✅           |      —      |
| `order.delivered` (`ORDER_DELIVERED`)                                     | order-service — fired when a tracking update sets status `DELIVERED`        |           ✅           |      —      |
| `product.stock.low` (`PRODUCT_STOCK_LOW`)                                 | product-service                                                             |           —           |      ✅      |

<Note>
  Loyalty point awards (leaving a review, referring a friend, sharing a product) notify the
  customer too, but **not** through this event bus — `LoyaltyService` calls
  `NotificationsService.createInApp(...)` directly, in-process, since both live in
  engagement-service. See `loyalty.service.ts`. The `loyalty.points.earned` and
  `referral.reward.earned` enum entries below exist for a bus-based version of this that was never
  needed once the direct call was in place.
</Note>

## Dormant — content ready, nothing publishes them yet

These 35 events have complete, real (non-placeholder) rendered content in
`engagement-service/src/notifications/templates.ts`, and `DomainEventsListener` is already
subscribed and ready to act on them — but no service in the codebase ever calls
`messaging.publish(...)` for them, because the feature that would trigger them doesn't exist yet
(returns, carrier/logistics integration, wholesale billing, cron-based reporting, staff CRUD,
support ticketing, etc.). Wiring one of these up is "call `publish()` from the right place," not
"write the notification."

<AccordionGroup>
  <Accordion title="Orders, delivery & returns (12)">
    `return.request.received`, `return.approved`, `return.rejected`, `refund.processed`,
    `delivery.carrier.assigned`, `delivery.ready_for_collection`, `delivery.delayed`,
    `delivery.failed`, `delivery.rescheduled`, `order.recurring.reminder`,
    `order.reorder.suggestion`, `cart.abandoned`
  </Accordion>

  <Accordion title="Wholesale / B2B (7)">
    `wholesale.delivery_instructions.needed`, `wholesale.credit_terms.updated`,
    `wholesale.account.suspended`, `wholesale.account.reinstated`, `wholesale.statement.ready`,
    `wholesale.catalogue.updated`, `wholesale.price.change`
  </Accordion>

  <Accordion title="Account, security & support (8)">
    `wishlist.reminder`, `support.ticket.received`, `support.ticket.resolved`,
    `user.totp.setup_reminder`, `user.data_export.ready`, `user.login.new_device`,
    `policy.updated`, `referral.reward.earned`
  </Accordion>

  <Accordion title="Staff & catalogue admin (5)">
    `staff.account.created`, `staff.role.updated`, `staff.account.deactivated`,
    `product.published`, `product.removed`
  </Accordion>

  <Accordion title="Reporting (3)">
    `category.updated`, `reports.sales.daily`, `reports.sales.weekly`
  </Accordion>
</AccordionGroup>

## Defined but effectively unhandled

Five events fall into neither bucket above — they exist in the `DomainEvent` enum but have no
rendered template of any kind, so `DomainEventsListener` isn't even subscribed to them:

| Event                                             | Status                                                                                                                                                     |
| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `review.created` (`REVIEW_CREATED`)               | **Published** by product-service on every new review, but has no template — currently a no-op. Likely intended for a future "thanks for your review" flow. |
| `checkout.initiated` (`CHECKOUT_INITIATED`)       | Never published, no template.                                                                                                                              |
| `product.back.in.stock` (`PRODUCT_BACK_IN_STOCK`) | Never published, no template.                                                                                                                              |
| `product.updated` (`PRODUCT_UPDATED`)             | Never published, no template.                                                                                                                              |
| `loyalty.points.earned` (`LOYALTY_POINTS_EARNED`) | Never published, no template — superseded by the direct in-process call described above.                                                                   |

<Warning>
  If you're adding a new notification-worthy action, check this table first — there's a good
  chance the event and its copy already exist in `templates.ts` and just need a `publish()` call
  added at the right point in the relevant service.
</Warning>
