Skip to content

feat(mail): authorable transactional email templates (TIGER-267) - #359

Merged
WebTigers merged 3 commits into
mainfrom
feat/tiger-267-email-templates
Oct 23, 2026
Merged

WebTigers merged 3 commits into
mainfrom
feat/tiger-267-email-templates

Conversation

@WebTigers

Copy link
Copy Markdown
Owner

What

Adds a DB-override tier to Tiger_Mail's existing file-based template engine so owners/agents can author transactional-email subject + HTML body (with {{var}} placeholders) from an admin screen — no code change, no deploy. File = base, DB row = override, last wins: the same live-override pattern as Config/Translation, scoped by org_id ('' = global default, else per-tenant).

Engine (library/)

  • migrations/0054 — email_template store. Plain UNIQUE(org_id, template_key) (not active-only): an override's key is deliberately reused — store() revives soft-deleted rows — and a generated active-only column is rejected by MySQL/MariaDB (err 1901) anyway. Rationale is in the migration docblock.
  • Tiger_Model_EmailTemplate — resolve() (org row wins over global, the config cascade), byKey(), store() (upsert-with-revive), reset() (soft-delete → the file default renders again).
  • Tiger_Mail — a registered-template registry (registerTemplate/registeredTemplates), forOrg(), {{var}} substitution, template() now prefers an authored row over the .phtml and falls back fail-safe to the file on any error, plus renderTemplate() for preview (including unsaved drafts).

Admin module (modules/email)

  • /email/admin — a DataTables list (Default vs Customized) and an editor with a clickable variable palette + live iframe preview.
  • Every /api method _isAllowed-guarded; admin-gated ACL, deny-by-default; full en i18n; house primitives only (TigerModal — no browser dialogs); no inline <script>/<style>.
  • The 5 core emails (reset, otp, verify, register-verify, backup) are registered with their real variables so the screen isn't empty.

Tests

  • Unit substitution: 2 pass.
  • Integration (real MySQL 8.2): 5 pass, 16 assertions — migration applies clean, org-override-wins, reset, revive-without-dup-key, override-vs-file-fallback, preview.

Other locales (es/pt/hi/de/fr) are a follow-up; only en ships here.

🤖 Generated with Claude Code

https://claude.ai/code/session_01ASauLLscjqdsNqBNsx2Typ

WebTigers and others added 3 commits October 23, 2026 07:14
Add a DB-override tier to Tiger_Mail's file-based template engine so owners
and agents can author transactional-email subject + HTML body (with {{var}}
placeholders) without a code change. File = base, DB row = override, last
wins — the same live-override pattern as Config/Translation, scoped by org
('' = global default, else per-tenant).

Engine (library):
- migration 0054: email_template store, plain UNIQUE(org_id, template_key)
  (key is reused, not freed — store() revives soft-deleted rows; a generated
  active-only column is rejected by MySQL/MariaDB err 1901 anyway).
- Tiger_Model_EmailTemplate: resolve (org wins over global), byKey, store
  (upsert-with-revive), reset (soft-delete → file default renders again).
- Tiger_Mail: a registered-template registry (registerTemplate/
  registeredTemplates), forOrg(), {{var}} substitution, template() prefers an
  authored row over the .phtml and falls back fail-safe, plus renderTemplate()
  for preview (incl. unsaved drafts).

Admin module (modules/email):
- /email/admin: DataTables list (Default vs Customized) + an editor with a
  variable palette and a live iframe preview.
- every /api method _isAllowed-guarded; admin-gated ACL deny-by-default; full
  en i18n; house primitives only (TigerModal, no browser dialogs).
- the 5 core emails (reset/otp/verify/register-verify/backup) registered with
  their real variables.

Tests: unit substitution (2) + integration behavioral against real MySQL (5,
16 assertions) — migration applies, org-override-wins, reset, revive-without-
dup-key, override-vs-file-fallback, preview.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASauLLscjqdsNqBNsx2Typ
Picks up Tiger_Model_EmailTemplate (@api) and the new `email` module —
the CI `check` job's build-capabilities --check gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASauLLscjqdsNqBNsx2Typ
Bump Tiger_Version::VERSION to 1.39.0 and add the CHANGELOG entry for the
authorable transactional email templates (TIGER-267), so the release tag
v1.39.0 matches the version-check gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASauLLscjqdsNqBNsx2Typ
@WebTigers
WebTigers merged commit 006253f into main Oct 23, 2026
14 checks passed
@WebTigers
WebTigers deleted the feat/tiger-267-email-templates branch October 23, 2026 13:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant