feat(templates): T4 sendTemplated() + outbound provenance

- IiosOutboundCommand gains templateKey/version/locale/renderedHash (migration).
- OutboundService.send accepts an optional opaque `provenance` and writes it into
  the command on BOTH the PENDING and RATE_LIMITED create paths — the only way to
  stamp provenance by construction, since send() creates the row itself (review
  finding). OutboundService still neither renders nor resolves templates.
- TemplatedSender.sendTemplated: render -> OutboundService.send -> provenance, one
  entry point. EMAIL payload = {subject,html,text}; SMS = {text}. Idempotent per key.

Tests: 4 sender + 16 adapters regression green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-18 12:28:28 +05:30
parent 8ce647552a
commit 10f3545a25
6 changed files with 162 additions and 3 deletions
@@ -868,6 +868,11 @@ model IiosOutboundCommand {
idempotencyKey String @unique
providerRef String?
consentReceiptRef String? // CMP consent receipt this send went out under (P9)
// Template provenance (which source produced this send) — null for non-templated sends.
templateKey String?
templateVersion Int?
templateLocale String?
renderedHash String? // sha256 of the rendered content, for replay/audit
createdAt DateTime @default(now())
attempts IiosDeliveryAttempt[]