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
| Column | Type | Constraint |
|---|---|---|
Id | GUID | Primary key |
TenantId | string | Max length 80, nullable — null means global default |
TemplateKey | string | Max length 160, required |
Channel | string | Max length 40, required |
Version | int | Monotonic per tenant, key and channel |
SubjectTemplate | string | Max length 1000 |
BodyTemplate | text | Explicit column type — no length cap |
Locale | string | Max length 35, nullable |
IsActive | bool | Entity default true; no database default |
Description | string | Max length 500, nullable |
CreatedOnUtc | timestamp | — |
UpdatedOnUtc | timestamp | — |
Indexes
| Index | Columns | Unique |
|---|---|---|
UX_Templates_Tenant_Key_Channel_Version | tenant, key, channel, version | Yes |
IX_Templates_Key_Channel | key, channel | No |
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.
Related Articles
See Also
Keywords
- Notification database
- Template Storage
- Draft database documentation
Source References
microservices/src/notification-service/Infrastructure/NotificationDbContext.csmicroservices/src/notification-service/Domain/NotificationEntities.csmicroservices/src/notification-service/Application/TemplateEngine.csmicroservices/src/notification-service/Seed/DefaultTemplateSeeder.csmicroservices/src/notification-service/Api/NotificationEndpoints.cs
Revision Information
- Status: Draft
- Last reviewed: 2026-07-21
- Review cycle: Quarterly