Brings in phase (b); README and CHANGELOG combine both, DESIGN 7.3 keeps
the ClassifiedValueTokens wording with the env1 key id.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Webhook inbox rows apply matched events independently; unmatched
events retry, then are skipped with a note instead of failing the row.
- Notification and marketing messages are never deleted by retention,
so unsubscribe links keep working; their bodies are still cleared.
- Events only suppress recipients of the matched message; an SES
bounce without recipients no longer suppresses every destination.
- SNS notifications outside a 1 h / +5 min window are refused, and
failed certificate fetches are cached for 5 minutes.
- EmailTemplateDefinition and EmailTemplates.ensure let other qbits
register their templates once without overwriting edits.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keeps the polished home layout with phase (c)'s event-backed metrics.
Also fixes unsubscribe privacy: a message with an unsubscribe link goes
to exactly one recipient, its token binds that address, and the handler
suppresses only that address (DESIGN 8.2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phase (c) of docs/DESIGN.md: the email_webhook_inbox and email_event
tables; a /qqq/hooks/email route provider with SES (SNS signature and
certificate host rules, subscription confirmation), Postmark (basic
auth), SendGrid (ECDSA) and Mailgun (HMAC with replay protection)
verification into a durable inbox; a claim-safe inbox processor that
maps provider events to email_event rows, message status and
suppressions; RFC 8058 one-click unsubscribe with a confirmation page;
the Reprocess action; and event-backed home metrics.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Key id from QQQ_AUDIT_HMAC_KEY_ID (default env1), canonical values
through ValueUtils, String.valueOf for record keys, and core's verify
argument order. A test pins the stand-in to core's published context
vector (QRun-IO/qqq#1182).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Number-first tiles with plain labels, bar charts for sends per hour and
suppressions added, a compact recent-messages table that stacks on
phones, compact UTC dates, plain provider status words, record labels
for versions, messages and providers, and dark-mode button colours in
the preview that pass 4.5:1.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Template sends keep the template's category.
- Render budget (10,000 iterations, 1 MiB), nesting 8, linear parsing.
- URL attributes in HTML and MJML accept only http, https or mailto;
unquoted attribute expressions are refused.
- MJML includes refused and disabled; the compiler runs with PATH only.
- Record variables load only referenced fields; records without a
classification source are tokenized in snapshots.
- Approved templates keep their brand; brand URLs are https and image
hosts are restricted for PHI mail.
- Viewers never trigger an MJML compile from the preview.
- Button links match a single link.
- PHI ciphertexts are bound to table, column and message (AES-GCM AAD).
- EmailDemoServer (test scope) seeds 24 hours of real traffic for
screenshots.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phase (a) part 2 of docs/DESIGN.md: the variable engine with escaping,
if/each and fallbacks; variable schemas; Markdown in the branded
responsive layout with dark-mode colours and contrast checks; HTML and
MJML kinds (MJML through a pluggable compiler at activation); versions
with New Version, Activate Version and Approve For PHI; templated sends
with record variables read as the sender; the classification stand-in
(core #1142); PII/PHI refusal; redacted variable snapshots with
ClassifiedValueTokens-shaped tokens and encrypted PHI bodies (stand-ins
for core #1161); the secure-message built-in; the preview widget; the
home dashboard; contingent possible values; and the canary-PHI egress
test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>