[Design Discussion] Notification templates management support #5388
Replies: 2 comments
|
Updated Design Approach DecisionWe have decide to proceed with the following decisions:
Furthermore, we decided to introduce the following user experience as well (But yet to decide which phase to deliver):
When the notification is resolved at send time, the content and layout will be rendered with the applicable theme from the app.
Alternatives Considered1. Managing layouts through the app We considered managing notification layouts through the app, similar to themes and page layouts, as well as directly through notification templates. We decided to manage layouts independently and associate them with notification templates. A common use case is for different notification types to have different layouts—for example, welcome and password reset emails may require different layouts even within the same app. Binding layouts to the app would limit this customization to the app level. 2. Restricting deletion of initial/default templates We considered preventing deletion of default templates. However, the current architecture does not distinguish resources created during bootstrap from those created by users. Treating them differently would therefore will not align with the agreed architecture. Instead, all unused templates can be deleted, with default templates available as samples for easy recreation. Out of Scope
Updated UIs will be shared soon. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Related Feature Issue
#5337
Problem Summary
ThunderID ships a fixed set of email and SMS notification templates that can only be changed by editing server-side files and restarting the service. There is currently no runtime API or Console support for managing, customizing, or previewing them. This design makes templates manageable at runtime, localizable, brandable by composing the existing Design output at render time, and previewable through the Console.
High-Level Approach
Template management
Localization
Branding resolution
Preview
resolveoutput the runtime uses (resolved content + composed branding + selected locale, with{{ctx(...)}}shown as-is), so an author sees the final message while editing only the pure content. It is surfaced on the top-level Notification Templates page (beside Design & Branding).Proposed UIs
Using templates in node execution
A template is engaged at runtime when a flow executes a node that sends a notification (an email/SMS node). The node references a template scenario type (Data model (1)); when execution reaches it, the runtime:
recipient-locale variant → default-locale variant.application → default(skipped for SMS, which is plain text with no branding).{{ctx(...)}}placeholders with the runtime data.Flows need no structural change: the execution context already carries the
appId(for branding) and the recipient locale; the email/SMS executor passes both into the resolution.Proposed UIs
Architecture Overview
flowchart TB subgraph clients [Clients] Console["ThunderID Console<br/>template editor + preview"] ApiClient["API consumers<br/>SDKs / GitOps"] end subgraph nt [Notification Templates module] API["Notification Templates API"] MgmtSvc["Template Mgmt Service"] LocaleResolver["Locale Resolver<br/>recipient locale + default fallback"] BrandingResolver["Branding resolver"] Renderer["Renderer<br/>substitutes ctx placeholders"] Store[("Template store<br/>DB, mutable")] end subgraph install [Install-time] Bootstrap[("Bootstrap bundle<br/>cmd/server/bootstrap/*.yaml")] Importer["Import service<br/>Upsert true"] end subgraph reused [Reused services] Design["Design service<br/>branding configuration"] end subgraph consumers [Runtime consumers unchanged] Flow["Flow / authn / OTP"] Sender["Notification senders"] end Recipient["Recipient"] Console --> API ApiClient --> API API -->|manage / resolve| MgmtSvc Flow -->|resolve + render| MgmtSvc MgmtSvc --> Store Bootstrap -->|seed defaults at install| Importer --> Store MgmtSvc -->|pick locale| LocaleResolver MgmtSvc -->|apply branding| BrandingResolver --> Design MgmtSvc -->|substitute placeholders| Renderer MgmtSvc -.rendered notification.-> Flow Flow -->|deliver| Sender --> RecipientComponents
internal/system/template{{ctx(...)}}render pipelineUpsert: true)resource_type: Templateentries + import/export supportinternal/design(/design/resolve)Render(...); otherwise unchangedEntity governance. All templates are uniform: there is no system/custom distinction. ThunderID preloads a default set of templates; administrators can create additional templates, and every template is managed the same way. Templates and their content are governed globally in this phase, and content carries per-locale variants. The default templates are shipped through the bootstrap bundle and seeded into the DB at install time, so after install they are ordinary mutable rows with nothing special
about them at runtime beyond being pre-created.
Template actions
Every template is managed the same way, whether it was preloaded or created by an administrator.
displayName; edit subject / body per localeData model and storage
There are two related models, both mutable DB rows seeded at install time by the bootstrap bundle (through the import service,
Upsert: true) and edited afterward through the same API as any other template.email:otp,sms:otp,email:password-recovery). This is the entity a flow node references to choose which notification to send; it carries thedisplayNameand holds no content of its own.contentType,content. A scenario type has zero or more content rows, one per locale.So templates get stored as raw with no branding markup.
Security Considerations
systemscope; unauthorized →AUTH-4010, forbidden business rules →AUTH-4030. Domain errors use theNTM-XXXXprefix and the sharedError/I18nMessageshape.{{ctx(...)}}values are substituted only at send time; the preview never evaluates them. Rendered email is composed in a sandbox to contain XSS from authored HTML.Impacted Areas
internal/system/template: replace the read-only declarative file store with a DB-backed mutable store keyed(channel, typeId[, locale]); add create/update/delete/list and a locale dimension.resource_type: Templateimport/export support and ship the default templates in the bootstrap bundle (cmd/server/bootstrap/), so defaults are DB-seeded at install like flows, groups, roles, and translations.internal/design(/design/resolve): reused to resolve branding at render; branding resolution is owned by Design, not this feature.Render(...); no structural flow change.api/notification-templates.yaml; Console (top-level Notification Templates page + editor).Alternatives Considered
The alternative below was considered but not selected.
Alternative 1: Use a translation catalog
Maintain one language-neutral template that references localized message keys from ThunderID’s existing translation resources.
Decision: Not selected. Each locale retains a complete template, allowing language-specific structure and layout. This can be revisited if cross-language duplication becomes a significant concern.
Alternative 2: Support application-level content customization
Allow each application to override the content of notification templates.
Decision: Not selected for this phase. Template content remains global. The intended future customization tier is the organization unit, while the application tier remains limited to branding.
Questions for Community Input
All reactions