Design discussion: should email templates live in the database? #95
pascal-klesse
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Background
This discussion grew out of the question "should email templates live in the database?" during the Hub Overhaul planning (see #83-#94). It's a design question that doesn't have an obvious right answer and benefits from input before any issue gets cut.
The three goals hiding behind the question
When someone says "templates in DB", they usually want one of three different things:
A. Marketing / Support edits copy without redeploy.
B. Per-tenant individualised templates.
C. Templates fully DB-driven, no
.tsxfiles.The argument shape for each is very different.
Where we land today
Templates are React-Email
.tsxfiles undersrc/core/email/templates/(core) andsrc/modules/email/templates/(project copy-on-edit overlay). Each template exports a typedVarsinterface and ametafactory. The Email Builder in the Hub already lets devs visually compose + save.tsxfiles via codegen. Sync-from-template only touches core; module overlays survive.Arguments against moving full templates into the DB (i.e. against goal C)
password-reset.tsxexposesVars { resetUrl: string }. The auth subsystem callssendTemplate("password-reset", { resetUrl }). That contract is structurally code, not text. Putting it in DB swaps a typed interface for a string column with a convention..tsxfile today, the IDE flags{props.rsetUrl}instantly. A DB-stored template only fails at first send. NewVarsfields can't be propagated by codemods.invitationandnew-deviceuse raw JSX outside that grammar; they'd need rewriting or a "raw mode" fallback that reintroduces the sandbox problem), or arbitrary JSX in a string column with full AST validation + component allowlist.git diff, no PR, no reviewer-before-prod. Audit log helps, but reviewer sees the change after it's live.Where DB-storage does make sense
Free / ad-hoc / marketing mails without a backend hook (newsletters, one-off announcements). They have no
Varscontract, aren't security-critical wired, and operators want to author them anyway. That'd be its own system, sitting next to the transactional pipeline rather than replacing it.Proposed direction (for goals A and B)
Keep transactional templates as code. Add a DB-backed override layer for i18n keys (parallel i18n integration is in flight — this layer assumes that wiring lands first).
t("email.welcome.greeting", vars)consults the chain.tenantIdcolumn.This addresses A (Marketing/Support edits copy without redeploy) without giving up TypeScript safety or PR-review discipline. B (per-tenant) becomes a forward-compatible follow-up.
What I'd like input on
Decision is not being made here yet
This is a design discussion. If consensus forms, we'll cut a focused issue ("Hub: global i18n key overrides with editor"). If a more compelling alternative emerges, we'll cut that instead.
All reactions