Skip to main content

Notification Event Compatibility

Summary

Three compatibility characteristics define the event surface: two different contract-coupling models on one resolver, two seeded template keys no event can reach, and a legacy notification path that produces notifications without any event at all.

Audience

Engineers, architects, QA, support and implementation partners.

Two coupling models

CouplingEventsDrift detection
Shared compiled contract10Compile time — a publisher change breaks the build
Service-local payload record32None — drift appears only as blank content at runtime

Ten events deserialize into types shared with their publishers. The Asset, Performance, Training and Helpdesk families — 32 events — deserialize into private records declared inside the resolver that structurally mirror what the publisher is expected to emit.

For those 32, nothing links the two definitions. A publisher can rename a field and both sides compile; the mismatch surfaces as an empty template variable in a delivered notification.

Template key coverage

Every template key the resolver uses has a seeded default template — verified by comparing the resolver's key set against the seeder's. There are no missing templates.

The reverse is not true. Two seeded keys are not reachable from any resolver case: a performance self-submission key and a performance manager-reviewed key. The resolver deliberately re-targets those two events to action-oriented keys instead — a self-submission notifies the manager that a review is required, and a manager review notifies HR that calibration is required.

The two employee-facing templates therefore exist as seeded rows that nothing renders. They are orphans, not gaps.

Unmapped modules

No Workflow, Recruitment, Attendance, Organization, Onboarding or Identity event appears in the supported list. Those modules raise no notification through this service. An event of such a type reaching the queue would resolve to no intents and be recorded with a no-recipient outcome — absorbed silently.

The legacy bypass

The monolith writes notification rows directly to its own tables through an authenticated controller path, with no event, no broker and no envelope. The portal reads that path for its user-facing inbox.

This means notifications exist in the platform that never passed through the event surface documented here, and the two stores are not synchronised. The event-driven service and the legacy path are parallel producers of the same user-visible concept.

Channel override compatibility

The per-event channel configuration map lets an operator change the channel set for any event type without a code change or a contract change. Lookup is case-insensitive on the event type and values are normalised to canonical channel casing, so it tolerates loose configuration input. This is the one forward-compatibility affordance built into the event surface.

Forward compatibility by convention

Channels, statuses, stages and outcomes are all plain strings backed by constants rather than enums, with the source comment on the channel set naming forward compatibility as the reason. An unrecognised value would be stored rather than rejected.

Classification

Transitional.

Requires confirmation

Whether the 32 locally duplicated payloads should move to shared contracts, whether the two orphan templates should be retired or wired, and the migration plan for the legacy bypass all require confirmation.

See Also

Keywords

  • Notification database
  • Compatibility
  • Draft database documentation

Source References

  • microservices/src/notification-service/Application/EventNotificationResolver.cs
  • microservices/src/notification-service/Seed/DefaultTemplateSeeder.cs
  • Controllers/NotificationsController.cs
  • microservices/src/notification-service/Application/NotificationOptions.cs
  • microservices/src/notification-service/Domain/NotificationEntities.cs

Revision Information

  • Status: Draft
  • Last reviewed: 2026-07-21
  • Review cycle: Quarterly