Skip to content

Epic: Define Git-backed email templates, compilation, and publishing #3

Description

@patoperpetua

Objective

Build the template toolchain that lets every consumer repository own editable email templates in Git, validate/compile them in CI, and publish tenant/environment-specific runtime artifacts to PostKit storage without redeploying the PostKit API.

Core model

Editable source lives with the consumer application:

content/email-templates/
  marketing.contact-us/
    template.json      # EmailBuilder.js source of truth
    metadata.json
    preview.json
  marketing.waitlist/
    template.json
    metadata.json
    preview.json

The consumer pipeline transforms these files into runtime-ready artifacts and publishes them to Azure Blob Storage.

Required technology

  • TypeScript
  • @usewaypoint/email-builder / EmailBuilder.js renderer for source JSON -> HTML
  • Shared schemas/types in @singleton-sd/post-kit-types
  • @singleton-sd/post-kit-compiler for deterministic validation/compilation
  • @singleton-sd/post-kit-publisher as reusable library/CLI for CI
  • Azure Blob Storage as initial runtime storage implementation
  • GitHub Actions reusable workflow or documented workflow integration

Source files

template.json

EmailBuilder.js document. This is the editable source of truth and must remain round-trippable through the shared PostKit editor.

metadata.json

Must include at least:

{
  "key": "marketing.contact-us",
  "name": "Contact Us",
  "subject": "New message from {{name}}",
  "description": "Sent to the support inbox from the public contact form",
  "variables": ["name", "email", "message"]
}

preview.json

Representative non-secret sample values used by the editor, previews, tests, and CI validation.

Runtime artifact

Publishing should create a stable bundle containing at minimum:

template.html
metadata.json

Potential manifest fields:

  • template key
  • schema version
  • compiled timestamp/build identifier
  • source commit SHA
  • variable catalogue
  • content hash

Do not make compiled HTML the editable source of truth.

Storage layout

Use an explicit tenant/environment boundary, e.g.:

tenants/{tenant}/{environment}/
  branding.json
  templates/{templateKey}/
    template.html
    metadata.json

The exact blob naming strategy may evolve, but the abstraction must preserve tenant and environment isolation.

Compilation pipeline

consumer Git repo
  -> validate directory/files
  -> validate schemas
  -> validate variable references
  -> render EmailBuilder JSON to HTML
  -> render preview using sample data
  -> run tests
  -> create manifest/bundle
  -> publish to Azure Blob Storage

Variable rendering

EmailBuilder.js is responsible for visual structure, not runtime business data.

PostKit owns variable syntax and rendering. Select and standardise one established JS template engine (Handlebars or LiquidJS are acceptable candidates; document the decision). Avoid custom regex interpolation.

Runtime subject and generated HTML must use the same variable semantics.

Branding

Support tenant-level reusable branding/default variables, for example:

{
  "companyName": "InkAds",
  "logoUrl": "https://...",
  "websiteUrl": "https://...",
  "supportEmail": "hello@..."
}

Templates should not need to duplicate common branding values.

Safety / validation

  • Fail compilation when required source files are malformed.
  • Detect missing preview variables.
  • Detect unknown/unapproved variables where practical.
  • Prevent path traversal or publishing outside the resolved tenant/environment prefix.
  • Do not publish secrets in preview data or template bundles.
  • Publishing credentials belong in CI secret/OIDC configuration, not consumer source files.

Work

  • Define template source schema and schema versioning.
  • Implement @singleton-sd/post-kit-types template contracts/schemas.
  • Implement compiler library.
  • Compile EmailBuilder.js JSON to HTML.
  • Add variable-reference validation.
  • Add preview rendering/testing.
  • Define runtime artifact/manifest format.
  • Implement Azure Blob publisher abstraction + implementation.
  • Implement reusable CLI suitable for CI.
  • Add reusable GitHub Actions integration/example.
  • Add tenant branding publishing.
  • Add tests for malformed templates, tenant isolation, deterministic compilation, and publishing paths.

Agent implementation notes

This epic must remain independent of a specific consumer. Test fixtures can include marketing.contact-us, marketing.waitlist, and a transactional example.

The PostKit API must consume the compiled runtime artifact, not EmailBuilder.js source. That prevents EmailBuilder from becoming a runtime dependency of email delivery.

Use the Platform Kit for TypeScript/tooling/CI conventions, but keep PostKit-specific template contracts in this repo.

Acceptance criteria

  • A consumer can keep EmailBuilder source + metadata + preview data entirely in Git.
  • CI can validate and compile those templates without a database.
  • CI can publish only to the authenticated tenant/environment namespace.
  • Published templates can be consumed by PostKit without API redeployment.
  • Invalid variables/templates fail before publishing.
  • Source commit/build information is traceable from the published artifact.
  • Compilation and publishing are exposed through reusable npm packages/CLI rather than consumer-specific scripts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions