Skip to main content

Notification Integration Event Contracts

Summary

Notification deserializes consumed payloads into 14 contract types: 10 shared contracts from the platform contracts assembly and 4 service-local payload records declared privately inside the resolver.

Audience

Engineers, architects, QA, support and implementation partners.

Reference Content

The verified reference material for this topic is set out in the sections below.

Shared contract base

The platform declares an abstract IntegrationEvent record carrying event identifier, event type, occurrence timestamp, correlation and causation identifiers, tenant and user identifiers, source service and schema version. Publishing services derive concrete contracts from it.

Notification does not deserialize into the base type. It deserializes the message body into the specific payload type for the event, using web-style JSON options, and reads the envelope metadata separately from AMQP properties and headers.

Shared contracts consumed

Ten types are referenced from the shared contracts assembly:

ContractEvent
EmployeeCreatedEventEmployeeCreated
LeaveApprovedEventLeaveApproved
LeaveRejectedEventLeaveRejected
PayrollFrozenEventPayrollFrozen
PayslipGeneratedEventPayslipGenerated
DocumentGeneratedEventDocumentGenerated
TenantProvisionedEventTenantProvisioned
ExpenseApprovedEventExpenseApproved
ExpenseRejectedEventExpenseRejected
ExpensePaidEventExpensePaid

These are genuinely shared types: the publishing service and Notification compile against the same definition, so a change to one is a compile-time change for both.

Service-local payload records

Four private records are declared inside the resolver and cover the remaining 32 event types:

RecordCoversTypes
AssetEventPayloadAsset lifecycle6
PerformanceEventPayloadPerformance lifecycle7
TrainingEventPayloadTraining and certification9
HelpdeskEventPayloadHelpdesk ticket lifecycle10

Each is a structural copy of what the publisher is expected to emit, not a shared type. The four families whose publishers reshaped their contracts to a uniform payload are consumed through these local records.

Contract-coupling consequence

This split produces two different coupling models on one surface.

For the ten shared contracts, a publisher-side change breaks the build, so drift is caught at compile time.

For the 32 events covered by local records, nothing connects the publisher's contract to Notification's copy. A publisher renaming or removing a field compiles cleanly on both sides; the mismatch appears only at runtime as a null or default value after deserialization. Because deserialization is tolerant and the resolver guards on a small number of key fields, a drifted field typically produces an empty template variable rather than an error — a silent degradation.

Deserialization behavior

Parsing is tolerant by design: a payload that fails to deserialize, or whose key identifier is empty, yields a null intent and therefore no notification, recorded with a no-recipient outcome rather than raising. Missing string fields are coalesced to empty values when building template variables.

Classification

Transitional — shared contracts are Implemented; the local-record duplication is a Transitional coupling.

Requires confirmation

Whether the four locally duplicated payload families are intended to move to shared contracts requires confirmation.

See Also

Keywords

  • Notification database
  • Integration Events
  • Draft database documentation

Source References

  • microservices/src/notification-service/Application/EventNotificationResolver.cs
  • microservices/src/contracts/Events/IntegrationEvent.cs
  • microservices/src/notification-service/Messaging/NotificationEventEnvelope.cs

Revision Information

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