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
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.
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:
The consumer pipeline transforms these files into runtime-ready artifacts and publishes them to Azure Blob Storage.
Required technology
@usewaypoint/email-builder/ EmailBuilder.js renderer for source JSON -> HTML@singleton-sd/post-kit-types@singleton-sd/post-kit-compilerfor deterministic validation/compilation@singleton-sd/post-kit-publisheras reusable library/CLI for CISource files
template.jsonEmailBuilder.js document. This is the editable source of truth and must remain round-trippable through the shared PostKit editor.
metadata.jsonMust 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.jsonRepresentative non-secret sample values used by the editor, previews, tests, and CI validation.
Runtime artifact
Publishing should create a stable bundle containing at minimum:
Potential manifest fields:
Do not make compiled HTML the editable source of truth.
Storage layout
Use an explicit tenant/environment boundary, e.g.:
The exact blob naming strategy may evolve, but the abstraction must preserve tenant and environment isolation.
Compilation pipeline
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
Work
@singleton-sd/post-kit-typestemplate contracts/schemas.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