AWS SDK for Java v2 2.41.10 -> 2.41.34 (GHSA-443w-3rq3-5m5h, #13) on top of 0.1.1 (TagRuleEngine PVS fix, #10). Published from the GA tag v0.1.2 on this commit; [skip ci] so the release-branch push does not also publish a 0.1.0 RC. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
qbit-cdn
QQQ qbit that puts any CDN in front of a QQQ application: portable cache
headers, change-driven invalidation, edge statistics and an Admin -> CDN app.
Design: QRun-IO/qqq docs/specs/2026-10-12-qbit-cdn-design.md.
What it does
- Tables (standard QQQ tables,
cdn_prefix):cdn_provider,cdn_hostname,cdn_cache_policy,cdn_table_tag_rule,cdn_purge_request,cdn_revalidation_hook,cdn_edge_stat_daily,cdn_origin_check,cdn_drift_finding. Secrets never live in tables (secretRefnames an environment variable prefix). - Purge pipeline: a record-change listener on the configured purgeable tables
turns changes into canonical tags and paths (
cdn_table_tag_rule), recordscdn_purge_requestrows, and the scheduled dispatcher sends them: flush window, merge, revalidation hooks first (HMAC-signed, fan-out to every pod), tag purge or budgeted path invalidation (CloudFront), async polling, retries with backoff, then DEAD. - Header policy:
CdnResponseHeaderPolicychoosesCache-Control,CDN-Cache-Controland tag headers fromcdn_cache_policy(alwaysprivate, no-storefor authenticated or cookie-setting responses). - Actions (standard streamed ETL: Review is the dry run, Result has linked lines; never in the nav): Purge From CDN (per purgeable table), Retry Purge, Purge Everything, Test Connection, Import Edge Stats, Check Config Drift; scheduled: dispatcher, daily stats import, daily drift check.
- Admin -> CDN app: sections Connection / Settings / Activity / Performance, a home widget with honest empty states, and a Health status card.
- Providers: CloudFront (invalidations, connection test, CloudWatch stats,
drift against the OpenTofu
expected_config), Souin (self-hosted, tags), NONE. Seedocs/cloudfront-expected-config.md. - Permissions:
cdn.view,cdn.purge,cdn.purgeAll,cdn.admin.
Purge-path placeholders
cdn_table_tag_rule templates (tagTemplates, invalidationPaths) can use {field} for the changed record's own fields and {prefix.field} for a joined record, e.g. /blog/{blog.slug}/{slug}*.
A joined placeholder is resolved like this:
- The foreign-key field is
<prefix>Idon the rule's table (blogIdfor{blog.slug}). - The joined table is the one behind that field's possible-value source: the source's table name for a table-type source, or the source name when it names a table. So
{blog.slug}readscms_blogwhenblogIdhas a possible-value source oncms_blog. - With no such field or possible-value source, the bare prefix is the table name (
blog).
If the joined table does not exist, the placeholder is skipped (the rest of the template is dropped, as for any missing value) and a warning is logged once per table per rule evaluation.
Install
new CdnQBitProducer().withQBitConfig(new CdnQBitConfig()
.withBackendName("rdbms")
.withSchedulerName("quartz")
.withPurgeableTables(List.of("blog_post", "page", "project")))
.produce(qInstance);
The cdn_ tables must exist in the backend (see the app's migrations).
CloudFront credentials: <secretRef>_ACCESS_KEY_ID / <secretRef>_SECRET_ACCESS_KEY.
Drift: the OpenTofu expected_config JSON in CDN_EXPECTED_CONFIG (or the
variable named by the provider setting expectedConfigEnv).
Build
./mvnw verify # tests, coverage gate, checkstyle