Skip to content

feat(frontend): build notification email template editor — CodeMirror HTML editor, variable autocomplete palette, live sandboxed preview, Handlebars validation, and per-tenant overrides #1539

Description

@Chibey-max

Overview

Platform admins and tenants communicate with their users via automated emails (milestone approved, dispute filed, escrow funded). Today these templates are hardcoded strings. A template editor gives non-engineers control over wording, branding, and personalisation without a deployment.

What to build

  • notification_templates table: { id, tenant_id (nullable for global), event_type: string, subject: string, body_html: string, body_text: string, variables: JSONB, updated_at, updated_by }
  • Template engine: use Handlebars for variable interpolation ({{escrow.amount}}, {{user.name}}); reject templates containing {{{{raw}}}} blocks (security: no raw HTML injection)
  • GET /api/v1/admin/notification-templates — list all templates; optionally filtered by event_type
  • PUT /api/v1/admin/notification-templates/:event_type — upsert a template for a given event; validate Handlebars syntax before saving
  • POST /api/v1/admin/notification-templates/:event_type/preview — body: { variables: {} }; renders the template with provided variables and returns { subject, body_html, body_text }; never sends an email
  • Frontend NotificationTemplateEditor component:
    • Left panel: CodeMirror editor for HTML body with syntax highlighting and variable autocomplete from the schema
    • Right panel: live preview rendered in a sandboxed iframe (CSP: sandbox="allow-same-origin")
    • Variable palette: all available variables for the selected event type displayed as clickable chips that insert {{variable}} at cursor
    • Undo/redo for editor history
    • Save and Reset to default buttons; reset confirmation modal
  • Variable schema: stored in notification_templates.variables JSONB; defines name, type, example value for each variable — used for autocomplete and preview

Acceptance Criteria

  • Handlebars syntax error on save returns 422 with the error message and line number
  • {{triple_stache}}} (raw HTML) is blocked at save time with a clear error
  • Preview renders in under 500ms; POST preview endpoint applies a 10s timeout
  • CodeMirror variable autocomplete shows a dropdown after typing {{
  • Sandboxed iframe prevents the preview HTML from accessing parent window
  • Reset to default restores the system default template (not an empty string); system defaults are code-defined
  • Tenant templates override global templates for the same event type; global used as fallback
  • Tests: template save/render cycle, syntax error rejection, preview with missing variables (should render empty string for missing vars, not throw)

Technical notes

  • CodeMirror 6 with @codemirror/lang-html and a custom completion source for {{ variables
  • System defaults live in src/notifications/templates/*.hbs files; loaded at startup and registered as immutable defaults

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardThird CampaignCampaign: Third Campaignadvanced-featureNew feature implementationcomplexity:extremeExtreme complexity — spans multiple languages and subsystemsfrontendpriority: highHigh priority

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions