Skip to main content

Notification Template Storage

Summary

NotificationTemplates stores versioned subject and body templates. A row with a null tenant is a global default; a tenant-scoped row overrides it for that tenant.

Audience

Engineers, architects, QA, support and security reviewers.

Reference Content

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

Ownership

Owned by NotificationDbContext. Written by the template create and update endpoints and by the startup seeder; read by TemplateEngine during dispatch and by the template list endpoint.

Columns

ColumnTypeConstraint
IdGUIDPrimary key
TenantIdstringMax length 80, nullable — null means global default
TemplateKeystringMax length 160, required
ChannelstringMax length 40, required
VersionintMonotonic per tenant, key and channel
SubjectTemplatestringMax length 1000
BodyTemplatetextExplicit column type — no length cap
LocalestringMax length 35, nullable
IsActiveboolEntity default true; no database default
DescriptionstringMax length 500, nullable
CreatedOnUtctimestamp
UpdatedOnUtctimestamp

Indexes

IndexColumnsUnique
UX_Templates_Tenant_Key_Channel_Versiontenant, key, channel, versionYes
IX_Templates_Key_Channelkey, channelNo

The unique index is the only structural guarantee that two rows cannot claim the same version for the same tenant, key and channel. Nothing prevents two active rows at different versions for the same triple — resolution simply prefers the highest.

Versioning semantics

Creating a template reads the current maximum version for the tenant, key and channel triple, defaults it to zero when none exists, and inserts at that value plus one. Existing rows are never modified by the create path. The update path modifies a row in place without producing a new version, so an update silently rewrites published content at the same version number.

Global-default convention

A blank tenant supplied on create is stored as null. Resolution queries the tenant-specific row first, ordered by version descending and filtered to active rows, then falls back to the null-tenant row using the same ordering. A tenant therefore inherits the global default until it creates its own row.

Lifecycle

Rows are inserted by create or by the seeder, updated in place, and deactivated only by setting the active flag. No reviewed code path deletes a template row.

Classification

Implemented.

Requires confirmation

Whether in-place update of a published version is intended alongside versioned create requires confirmation.

See Also

Keywords

  • Notification database
  • Template Storage
  • Draft database documentation

Source References

  • microservices/src/notification-service/Infrastructure/NotificationDbContext.cs
  • microservices/src/notification-service/Domain/NotificationEntities.cs
  • microservices/src/notification-service/Application/TemplateEngine.cs
  • microservices/src/notification-service/Seed/DefaultTemplateSeeder.cs
  • microservices/src/notification-service/Api/NotificationEndpoints.cs

Revision Information

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