feat: ETags, immutable caching, and the data-version stamp #136

Merged
manlycucumber merged 1 commit from feature/17-caching-etags into develop 2026-07-03 05:57:31 +00:00
manlycucumber commented 2026-07-03 05:56:02 +00:00 (Migrated from github.com)

Makes every cacheable response revalidatable and edge-friendly (epic #17) — the caching contract the Cloudflare tier depends on for the R2 deployment.

What's here

  • Cache\CacheHeaders (#18) — a strong ETag derived from sha256(dataVersion|key) (changes exactly when content would, without hashing the possibly-large body), an immutable Cache-Control (public, max-age=3600, s-maxage=604800, immutable), and conditional-GET handling — a client holding the current ETag gets a bodiless 304.
  • ResponseCache now short-circuits 304s before touching the store and stamps ETag + Cache-Control + x-cache on hits and misses alike. /v1/meta is cacheable the same way; /v1/health is no-store.
  • Service-wide data-version stamp (#19) — the kernel sets X-Data-Version on every response (successes, errors, 304s), so any client or proxy reads which build produced it without parsing the body.
  • docs/deploy/cloudflare.md (#20) — the cache-everything rule, the query-string-in-cache-key requirement (so ?calendar=sspx never collides with universal), the origin headers table, and the purge-on-version-bump flow. Live edge rules + the purge token stay maintainer config.

Verification

  • composer check green: phpcs, PHPStan [OK], PHPUnit 68 tests / 230 assertions.
  • Real server: /v1/dayETag, Cache-Control: …immutable, X-Data-Version, X-Cache: MISS; If-None-Match304; /v1/healthno-store.

Refs #17 #18 #19 #20

Makes every cacheable response revalidatable and edge-friendly (epic #17) — the caching contract the Cloudflare tier depends on for the R2 deployment. ## What's here - **`Cache\CacheHeaders`** (#18) — a strong **ETag** derived from `sha256(dataVersion|key)` (changes exactly when content would, without hashing the possibly-large body), an **immutable** `Cache-Control` (`public, max-age=3600, s-maxage=604800, immutable`), and **conditional-GET** handling — a client holding the current ETag gets a bodiless **304**. - **`ResponseCache`** now short-circuits 304s before touching the store and stamps ETag + `Cache-Control` + `x-cache` on hits and misses alike. `/v1/meta` is cacheable the same way; `/v1/health` is `no-store`. - **Service-wide data-version stamp** (#19) — the kernel sets **`X-Data-Version`** on *every* response (successes, errors, 304s), so any client or proxy reads which build produced it without parsing the body. - **`docs/deploy/cloudflare.md`** (#20) — the cache-everything rule, the **query-string-in-cache-key** requirement (so `?calendar=sspx` never collides with universal), the origin headers table, and the purge-on-version-bump flow. Live edge rules + the purge token stay maintainer config. ## Verification - `composer check` green: phpcs, PHPStan `[OK]`, **PHPUnit 68 tests / 230 assertions**. - Real server: `/v1/day` → `ETag`, `Cache-Control: …immutable`, `X-Data-Version`, `X-Cache: MISS`; `If-None-Match` → **304**; `/v1/health` → `no-store`. Refs #17 #18 #19 #20
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Directorium/Api!136
No description provided.