Objective
Implement the PostKit runtime API as a Node.js/TypeScript Azure Functions application that accepts trusted email requests, resolves the authenticated tenant, loads the correct published template, renders variables, and sends through a provider abstraction.
Context
PostKit is a shared transactional email platform for multiple PoCs and trusted server-side consumers. Consumers include backend APIs, marketing-site server endpoints, server actions, scheduled jobs, and other trusted services.
The API must never trust a raw caller-provided tenant identifier as the sole tenant boundary.
Required technology
- Azure Functions
- Node.js >= 20
- TypeScript + ESM
- pnpm workspace package under
apps/api
- Shared request/response contracts from
@singleton-sd/post-kit-types
- Azure SDKs for managed services where applicable
- Structured logging and correlation IDs
- Provider abstraction for email delivery
Core API contract
Initial endpoint concept:
Example trusted request:
{
"template": "marketing.contact-us",
"to": "hello@example.com",
"variables": {
"name": "Jane Doe",
"email": "jane@example.com",
"message": "I'd like to know more"
}
}
Tenant identity must be derived from authentication/credentials and mapped server-side.
Runtime flow
Authenticated consumer
-> Azure Function
-> resolve tenant + environment
-> validate request
-> load compiled template + metadata
-> validate required variables
-> merge tenant branding/default variables
-> render subject + HTML
-> send using configured provider
-> structured result + correlation ID
Multi-tenancy requirements
- Tenant identity is derived from trusted auth, API key mapping, managed identity, or equivalent server-side trust mechanism.
- Never allow a consumer to gain access to another tenant by changing a
tenant field in the payload.
- Tenant-specific branding and templates are isolated by storage paths/keys.
- Environment boundaries must also be explicit (
development, staging, production or equivalent).
- Design the tenant resolver behind an interface so authentication can evolve without rewriting core email logic.
Internal abstractions
Create clear interfaces/modules for:
TenantResolver
TemplateStore
TemplateRenderer
EmailProvider
- request validation
- variable validation
- observability/logging
Do not couple Azure Blob Storage or one email provider directly to business logic.
Error handling
Return stable typed errors for at least:
- unauthenticated/unauthorised consumer
- unknown template
- invalid template metadata
- missing/invalid variables
- invalid recipient
- provider failure
- storage failure
Do not leak provider credentials, storage paths, or sensitive payloads in responses/logs.
Reliability expectations
- Log correlation/request IDs.
- Make provider failures observable.
- Keep runtime rendering deterministic.
- Avoid outbound GitHub calls when sending.
- Do not require a database for template resolution.
- Keep API stateless.
Security expectations
- No public/browser use of long-lived PostKit credentials.
- Validate and normalise recipient inputs.
- Sanitize/escape template variables according to the selected template engine rules.
- Keep tenant secrets and provider credentials in Azure-supported secret/configuration mechanisms.
- Prefer Managed Identity where practical.
Work
Agent implementation notes
Before implementation, inspect the latest API/Azure Functions/deployment conventions in singleton-sd/poc-plattform-kit. Reuse its Node/TypeScript, configuration, testing, logging, and deployment patterns where appropriate.
Do not add a template database. Runtime templates come from the published template storage abstraction covered by the template publishing epic.
Acceptance criteria
- A trusted consumer can send a template email through a typed HTTP endpoint.
- Tenant identity is resolved from authentication and cannot be spoofed by request payload.
- The API can load a tenant/environment-specific compiled template.
- Variables are validated before provider invocation.
- Provider failures and validation failures return stable typed errors.
- Logs include correlation information without exposing secrets or full sensitive payloads.
- The API is deployable as Azure Functions and is independently testable/buildable from the monorepo.
Objective
Implement the PostKit runtime API as a Node.js/TypeScript Azure Functions application that accepts trusted email requests, resolves the authenticated tenant, loads the correct published template, renders variables, and sends through a provider abstraction.
Context
PostKit is a shared transactional email platform for multiple PoCs and trusted server-side consumers. Consumers include backend APIs, marketing-site server endpoints, server actions, scheduled jobs, and other trusted services.
The API must never trust a raw caller-provided tenant identifier as the sole tenant boundary.
Required technology
apps/api@singleton-sd/post-kit-typesCore API contract
Initial endpoint concept:
Example trusted request:
{ "template": "marketing.contact-us", "to": "hello@example.com", "variables": { "name": "Jane Doe", "email": "jane@example.com", "message": "I'd like to know more" } }Tenant identity must be derived from authentication/credentials and mapped server-side.
Runtime flow
Multi-tenancy requirements
tenantfield in the payload.development,staging,productionor equivalent).Internal abstractions
Create clear interfaces/modules for:
TenantResolverTemplateStoreTemplateRendererEmailProviderDo not couple Azure Blob Storage or one email provider directly to business logic.
Error handling
Return stable typed errors for at least:
Do not leak provider credentials, storage paths, or sensitive payloads in responses/logs.
Reliability expectations
Security expectations
Work
apps/apiAzure Functions app.Agent implementation notes
Before implementation, inspect the latest API/Azure Functions/deployment conventions in
singleton-sd/poc-plattform-kit. Reuse its Node/TypeScript, configuration, testing, logging, and deployment patterns where appropriate.Do not add a template database. Runtime templates come from the published template storage abstraction covered by the template publishing epic.
Acceptance criteria