docs(19.3-04): complete framework site-cache purge plan
- cooler.SiteCachePurger, pact.ReorderAfterSave, FAQ/menu/Journal adoption, shared Nuxt purge route - Task 4 reply push-all: plugins, layers and summercms master pushed; layer tags v0.2.0, v0.2.0, v0.4.0
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
---
|
||||
phase: 19.3-framework-transport-and-infrastructure-for-wavepath
|
||||
plan: 04
|
||||
subsystem: caching
|
||||
tags: [cooler, site-cache, purge, cabana, reorder, pact, faq, menu, journal, nuxt-layers, nitro]
|
||||
status: complete
|
||||
|
||||
requires:
|
||||
- phase: 19.3-01
|
||||
provides: "modules/cooler (cache module) that now also holds the site-cache purge service"
|
||||
provides:
|
||||
- "cooler.SiteCachePurger with framework keys site_cache.purge_url and site_cache.purge_token, published by cooler.Install; cooler.SiteCacheFromApp; cooler.PurgeSiteCacheAfterCommit"
|
||||
- "pact.ReorderAfterSave(ctx, partition *uint64) error, called by cabana's reorder inside its transaction"
|
||||
- "FAQ, menu and menu-entry admin saves, deletes and reorders purge the host site's page cache after commit"
|
||||
- "Journal purges through cooler; golem15.journal.site_cache.* and classes.SiteCachePurger/NewSiteCachePurger/PurgeSiteCacheAfterCommit kept as aliases for one release"
|
||||
- "Shared Nitro route POST /api/__site__/cache/purge (runtimeConfig siteCache.purgeToken) in vue-faq-layer v0.2.0, vue-menu-layer v0.2.0 and vue-journal-layer v0.4.0"
|
||||
affects: [19.3-05, sm-grzybyfunkcjonalne-app deployment, sm-summercmsio-app journal pointer]
|
||||
|
||||
actuals:
|
||||
tokens: 56800
|
||||
tasks: 5
|
||||
commits: 2
|
||||
plan_head_before: 1d8e50a1ee707b1f844c6fbe47bfe1597d8dc2e2
|
||||
plan_head_after: af9dad634cd4ff90bef1cd1a042b18d7dca97e18
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Framework-owned after-commit side effect: hooks take the save transaction from cabana.TxFromContext and register through lagoon.AfterCommit; failures are logged and swallowed"
|
||||
- "Lazy service lookup (SiteCacheFromApp) so commands and tests that do not run serve still get the same purger"
|
||||
- "Plugin-key alias path: framework keys win; legacy plugin keys publish the framework service with a deprecation warning"
|
||||
- "Byte-identical shared files across layers, pinned by sha256 in each layer's spec"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- modules/cooler/sitecache.go
|
||||
- modules/cooler/sitecache_test.go
|
||||
- ../sm-faq-plugin/controllers/site_cache.go
|
||||
- ../sm-faq-plugin/site_cache_admin_test.go
|
||||
- ../sm-menu-plugin/controllers/site_cache.go
|
||||
- ../sm-menu-plugin/site_cache_admin_test.go
|
||||
- ../vue-faq-layer/server/lib/siteCachePurge.ts
|
||||
- ../vue-faq-layer/server/api/__site__/cache/purge.post.ts
|
||||
- ../vue-faq-layer/tests/sitePurge.test.ts
|
||||
- ../vue-menu-layer/server/lib/siteCachePurge.ts
|
||||
- ../vue-menu-layer/server/api/__site__/cache/purge.post.ts
|
||||
- ../vue-menu-layer/tests/sitePurge.test.ts
|
||||
- ../vue-journal-layer/server/lib/siteCachePurge.ts
|
||||
- ../vue-journal-layer/server/api/__site__/cache/purge.post.ts
|
||||
- ../vue-journal-layer/tests/sitePurge.test.ts
|
||||
modified:
|
||||
- modules/cooler/cooler.go
|
||||
- modules/cooler/example_test.go
|
||||
- modules/cooler/README.md
|
||||
- modules/pact/capabilities.go
|
||||
- modules/pact/README.md
|
||||
- modules/cabana/reorder.go
|
||||
- modules/cabana/README.md
|
||||
- README.md
|
||||
- docs/services/caching.md
|
||||
- docs/backend/admin-controllers.md
|
||||
- docs/backend/lists-and-filters.md
|
||||
- docs/setup/configuration.md
|
||||
- ../sm-faq-plugin/controllers/faqs.go
|
||||
- ../sm-menu-plugin/controllers/admin_registry.go
|
||||
- ../sm-menu-plugin/controllers/menus.go
|
||||
- ../sm-menu-plugin/controllers/menuentries.go
|
||||
- ../sm-journal-plugin/plugin.go
|
||||
- ../sm-journal-plugin/classes/site_cache.go
|
||||
- ../sm-journal-plugin/controllers/site_cache.go
|
||||
- ../sm-grzybyfunkcjonalne-app/go.mod
|
||||
- ../sm-grzybyfunkcjonalne-app/go.sum
|
||||
- ../sm-grzybyfunkcjonalne-app/DEPLOY.md
|
||||
- ../sm-grzybyfunkcjonalne-app/vue-grzybyfunkcjonalne-app/package.json
|
||||
- ../sm-grzybyfunkcjonalne-app/vue-grzybyfunkcjonalne-app/pnpm-lock.yaml
|
||||
|
||||
key-decisions:
|
||||
- "Site-cache purge is a cooler service with framework keys site_cache.purge_url and site_cache.purge_token (http only to loopback, token at least 32 characters, 2 s timeout, after commit only, failures never fail a save)"
|
||||
- "pact.ReorderAfterSave(ctx, partition *uint64) runs inside cabana's reorder transaction; cabana's reorderPost now uses lagoon.Transaction so AfterCommit callbacks registered by the hook fire"
|
||||
- "Purge kinds: faq (slug), menu (code), menu_entry (id, or partition:<id> on reorder); Journal keeps post and category"
|
||||
- "Journal alias keys golem15.journal.site_cache.* publish the cooler purger with a deprecation warning when the framework keys are unset; framework keys win"
|
||||
- "Layer releases are additive minors: vue-faq-layer v0.2.0, vue-menu-layer v0.2.0, vue-journal-layer v0.4.0; plugins get no tag"
|
||||
- "Task 4 reply push-all: summercms master, three plugin mains and three layer mains pushed, layer tags created; no framework tag (plan 05 owns it)"
|
||||
|
||||
requirements-completed: [SC-4, D-10, D-11, D-19]
|
||||
|
||||
duration: 60min
|
||||
completed: 2026-10-15
|
||||
---
|
||||
|
||||
# Phase 19.3 Plan 04: Framework site-cache purge Summary
|
||||
|
||||
**The site-cache purge moved from the Journal plugin into cooler (keys `site_cache.purge_url` and `site_cache.purge_token`). Cabana gained a `pact.ReorderAfterSave` hook. FAQ, menu and Journal admin saves, deletes and reorders now purge the page cache after commit, through a shared `POST /api/__site__/cache/purge` route that ships in all three Nuxt layers. The plugins and layers are pushed and tagged, and the app's pointers are bumped locally.**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** about 60 min (2026-10-15T16:16:40Z to 17:16Z, across two executor runs split at the Task 4 checkpoint)
|
||||
- **Tasks:** 5 of 5
|
||||
- **Files modified:** 14 framework, 4 FAQ, 6 menu, 6 Journal, 6 per layer, 7 app (incl. submodule pointers), 2 vue app
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- `cooler.SiteCachePurger` is now a framework service. It is validated and published at boot, so a bad `site_cache` config fails boot. `SiteCacheFromApp` gives commands and tests the same purger lazily. `PurgeSiteCacheAfterCommit` sends one bearer POST of `{kind, slug}` per committed save.
|
||||
- `pact.ReorderAfterSave` is called inside cabana's reorder transaction after the new order is written. A hook error rolls the reorder back. Controllers without the hook behave as before.
|
||||
- FAQ create, update and delete purge, and so do menu create, update and delete and menu-entry create, update, delete and reorder. The existing locale and placement checks still run first.
|
||||
- Journal moved onto cooler. Its old keys and exported names still work as aliases, with a deprecation warning.
|
||||
- The shared Nitro route and helper are byte-identical in all three layers, pinned by sha256 in each layer's spec. Each layer has its own `'/api/__site__/**': { cache: false }` rule. vue-journal-layer keeps `/api/__journal__/cache/purge` and `journal.cachePurgeToken` as aliases.
|
||||
- The plugins, layers and summercms master are pushed, and the layer tags are on origin. sm-grzybyfunkcjonalne-app now runs the adopted plugins and layer versions. Its deployment config is unchanged because the Journal alias path keeps it working.
|
||||
|
||||
## Task Commits
|
||||
|
||||
| Task | Name | Repository: commit |
|
||||
|------|------|--------------------|
|
||||
| 1 (tracer) | FAQ save purges the site cache through cooler and the shared Nuxt route | summercms.go 0bc390f, sm-faq-plugin c60ae6e, vue-faq-layer e26f22e |
|
||||
| 2 | pact.ReorderAfterSave hook; menu plugin purges; vue-menu-layer route | summercms.go af9dad6, sm-menu-plugin 559d96b, vue-menu-layer 3bc7729 |
|
||||
| 3 | Journal moves onto cooler with alias keys; vue-journal-layer route | sm-journal-plugin d7943fb, vue-journal-layer 3e0b377 |
|
||||
| 4 | Push decision (checkpoint:decision, blocking-human) | pushes and tags below, no commits |
|
||||
| 5 | App picks up the purge | sm-grzybyfunkcjonalne-app f9cafe2 (go mod tidy), d604509 (journal/menu/faq pointers), 85939c3 (vue app pointer), 129c0df (DEPLOY.md, deviation); vue-grzybyfunkcjonalne-app 0ee97d0 (layer tags) |
|
||||
|
||||
Framework commits measured from the ledger: `git rev-list --count 1d8e50a..HEAD` = 2.
|
||||
|
||||
## Task 4: push decision
|
||||
|
||||
**Reply (verbatim):** push-all
|
||||
|
||||
Before pushing, I re-ran `git fetch origin --tags` in all seven repositories. None was behind origin. `git ls-remote --tags origin` showed no v0.2.0 on vue-faq-layer or vue-menu-layer and no v0.4.0 on vue-journal-layer, and none of these tags existed locally. The previous run had already printed push-gate-ok (all plugin and layer suites green, Docker tests run).
|
||||
|
||||
Pushed (no force, no framework tag):
|
||||
|
||||
| Repository | Branch | Range pushed |
|
||||
|------------|--------|--------------|
|
||||
| summercms.go | master | a9dd565..af9dad6 (also carries plans 19.3-01, -02 and -03 and the phase planning commits) |
|
||||
| sm-faq-plugin | main | 919cf06..c60ae6e |
|
||||
| sm-menu-plugin | main | 9c0f833..559d96b |
|
||||
| sm-journal-plugin | main | 31d901c..d7943fb |
|
||||
| vue-faq-layer | main | 321bc90..e26f22e |
|
||||
| vue-menu-layer | main | 2deac88..3bc7729 |
|
||||
| vue-journal-layer | main | 25e9bfe..3e0b377 |
|
||||
|
||||
Annotated tags created and pushed:
|
||||
|
||||
| Repository | Tag | Tag object | Commit |
|
||||
|------------|-----|------------|--------|
|
||||
| vue-faq-layer | v0.2.0 | 8acbde2 | e26f22e |
|
||||
| vue-menu-layer | v0.2.0 | a6942aa | 3bc7729 |
|
||||
| vue-journal-layer | v0.4.0 | 9213af5 | 3e0b377 |
|
||||
|
||||
Checked after the push: each plugin's `main` equals `origin/main`, summercms `master` equals `origin/master`, and `ls-remote` prints each tag. The latest framework tag on origin is still v0.1.9 in the tag listing; no new framework tag was made.
|
||||
|
||||
**Not pushed:** sm-grzybyfunkcjonalne-app (4 commits) and vue-grzybyfunkcjonalne-app (1 commit) stay local. Plan 05's release decision covers those pushes. Nothing was deployed.
|
||||
|
||||
## Identifiers and keys added
|
||||
|
||||
- **cooler:** `SiteCachePurger`, `NewSiteCachePurger`, `NewSiteCachePurgerFor`, `SiteCachePurger.Purge`, `SiteCachePurger.Endpoint`, `PurgeSiteCacheAfterCommit`, `SiteCacheFromApp`, `SiteCachePurgeURLKey`, `SiteCachePurgeTokenKey`, `SiteCachePurgeTimeout`, `SiteCachePurgeMinTokenLength`
|
||||
- **pact:** `ReorderAfterSave`
|
||||
- **Config keys:** `site_cache.purge_url` (SUMMER_SITE_CACHE__PURGE_URL), `site_cache.purge_token` (SUMMER_SITE_CACHE__PURGE_TOKEN)
|
||||
- **Layers:** runtimeConfig `siteCache.purgeToken` (NUXT_SITE_CACHE_PURGE_TOKEN); route `POST /api/__site__/cache/purge`; `server/lib/siteCachePurge.ts` exports `MIN_SITE_PURGE_TOKEN_LENGTH`, `SITE_ROUTE_CACHE_BASE`, `authorizeSitePurge`, `purgeSiteRouteCache`, `parseSitePurgeEvent`
|
||||
- **Purge kinds:** `faq`, `menu`, `menu_entry` (slug `partition:<id>` on reorder), Journal `post` and `category`
|
||||
|
||||
**Shared-file sha256 pins (identical in all three layers):**
|
||||
- `server/lib/siteCachePurge.ts`: `7c34121ae06cf011b30a1dc5d787a94657b71b8768bed3a200be0f41566001b8`
|
||||
- `server/api/__site__/cache/purge.post.ts`: `c459012280cdf59551e57f0440fcaeb24566a5ba6e3dccf31133e67a683f1c06`
|
||||
|
||||
## Tests
|
||||
|
||||
- Docker-backed tests **ran** (not skipped): `TestFaqAdminPurgesSiteCache`, `TestMenuAdminPurgesSiteCache` and the Journal admin purge test on Postgres. All suites were green.
|
||||
- Extra tests: `TestSiteCacheFrameworkKeysWin` (Journal) and `TestSiteCachePurgeConfig` subtests in cooler.
|
||||
- Task 5: the app passed `go build ./...` and `go test -short ./...`. In the vue app, `pnpm run build` succeeded, `pnpm test` passed 27/27 and `smoke:ssr` passed 38 checks. The built Nitro config carries `"/api/__site__/**": { "cache": false }` and the `/api/__site__/cache/purge` handler. The Task 5 automated verify printed TASK5-VERIFY-OK, and `grep -c '#v0.2.0'` returned 2.
|
||||
|
||||
## Decisions Made
|
||||
|
||||
See key-decisions in the frontmatter. Task 4 reply: push-all.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 3 - Blocking] cabana reorder runs in lagoon.Transaction**
|
||||
- **Found during:** Task 2
|
||||
- **Issue:** `reorderPost` in `modules/cabana/reorder.go` used a plain GORM Transaction, so `lagoon.AfterCommit` skipped and a purge registered from `ReorderAfterSave` would never be sent.
|
||||
- **Fix:** It now runs in `lagoon.Transaction`. The existing reorder tests pass.
|
||||
- **Commit:** summercms.go af9dad6
|
||||
|
||||
**2. [Docs checker] cooler example and configuration row**
|
||||
- **Found during:** Task 1
|
||||
- **Issue:** The docs checker needed real snippets for caching.md.
|
||||
- **Fix:** `modules/cooler/example_test.go` gained `ExampleSiteCacheFromApp` and a neutral `articlesController`, and caching.md pulls them via `src=`. A `docs/setup/configuration.md` row was added for the new keys, which was not in files_modified.
|
||||
- **Commit:** summercms.go 0bc390f
|
||||
|
||||
**3. [Commit order] af9dad6 amended after the menu plugin commit**
|
||||
- **Found during:** Task 2
|
||||
- **Issue:** The acceptance grep wants exactly one `pact.ReorderAfterSave` line in reorder.go, but one comment repeated the name.
|
||||
- **Fix:** The comment was reworded and af9dad6 amended. This happened before any push.
|
||||
|
||||
**4. [Rule 2 - Docs correctness] sm-grzybyfunkcjonalne-app DEPLOY.md**
|
||||
- **Found during:** Task 5
|
||||
- **Issue:** After the pointer bump, DEPLOY.md still said menu and FAQ edits do not purge the cache. It also named the old `journal: site cache purged` log line, which is now `cooler: site cache purged`.
|
||||
- **Fix:** Three sentences were updated: which saves purge, the cooler log lines, and the boot-time deprecation warning for the journal keys, which keep working. `scripts/check-deploy.sh` passes.
|
||||
- **Files modified:** ../sm-grzybyfunkcjonalne-app/DEPLOY.md
|
||||
- **Commit:** sm-grzybyfunkcjonalne-app 129c0df (separate docs commit after the pointer bumps)
|
||||
|
||||
**5. [Rule 3 - Blocking] pnpm install without a TTY**
|
||||
- **Found during:** Task 5
|
||||
- **Issue:** `pnpm install` aborted with ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY.
|
||||
- **Fix:** It was re-run with `--config.confirmModulesPurge=false`, which rebuilds the local node_modules only. The lockfile diff touches only the three layer entries.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
None beyond the deviations. Pre-existing untracked files were left alone: sm-grzybyfunkcjonalne-app `.gsd/` and its nested `sm-grzybyfunkcjonalne-app` entry, and sm-journal-plugin `go.work.sum`.
|
||||
|
||||
## Deferred Items
|
||||
|
||||
Logged in `deferred-items.md`:
|
||||
- Pre-existing gofmt findings (missing trailing newlines) in `modules/cabana/account_tokens.go`, `account_tokens_test.go`, `token_postgres_smoke_test.go`, `token_routes_test.go`, `token_scopes_test.go` and sm-journal-plugin `classes/blog_editor_test.go`.
|
||||
|
||||
## Follow-ups
|
||||
|
||||
- Move the grzybyfunkcjonalne deployment to `site_cache.purge_url`/`site_cache.purge_token` and `NUXT_SITE_CACHE_PURGE_TOKEN` (route `/api/__site__/cache/purge`) before the Journal alias keys are removed. Until then the binary logs a deprecation warning at boot.
|
||||
- Bump the Journal pointer in sm-summercmsio-app, which is 45 commits behind main.
|
||||
- Push sm-grzybyfunkcjonalne-app (f9cafe2, d604509, 85939c3, 129c0df) and vue-grzybyfunkcjonalne-app (0ee97d0) under plan 05's release decision.
|
||||
- Manual check from 19.3-VALIDATION.md: save a menu entry in a running admin and see the page update without waiting for the SWR window.
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
Plan 05 (unit tests and the framework release decision) can start. summercms master on origin already carries the cooler purge service that the pushed plugins import.
|
||||
|
||||
## Self-Check: PASSED
|
||||
@@ -6,3 +6,9 @@ Out-of-scope findings logged by executors. Not fixed in the plan that found them
|
||||
|
||||
- `internal/build/registry.go` is not gofmt-clean (const block alignment, `registryFileName` / `generatedMark`). Pre-existing, untouched by 19.3-03; `go vet` is unaffected.
|
||||
- The 19.3-03 Task 3 acceptance grep `grep -rniE 'wavepath|fonoteka|grzyby' modules/lagoon ...` matches pre-existing test files outside the plan's scope: `modules/lagoon/hidden_marshal_test.go` (comments naming the consumer app), `modules/lagoon/migrations_test.go` (`golem15.fonoteka` as a sample plugin ID) and `modules/lagoon/attach/lifecycle_test.go` (`Golem15\Fonoteka\Models\Album` morph type). CLAUDE.md says framework code never names a consuming application; a follow-up quick task could switch these to neutral names (`acme`). 19.3-03 added no such names.
|
||||
|
||||
## From 19.3-04
|
||||
|
||||
- Pre-existing gofmt findings (missing trailing newlines), untouched by 19.3-04: `modules/cabana/account_tokens.go`, `modules/cabana/account_tokens_test.go`, `modules/cabana/token_postgres_smoke_test.go`, `modules/cabana/token_routes_test.go`, `modules/cabana/token_scopes_test.go`, and in the Journal plugin `classes/blog_editor_test.go`. `go vet` and the suites are unaffected.
|
||||
- Deployment follow-up: move the grzybyfunkcjonalne deployment from `golem15.journal.site_cache.*` and `NUXT_JOURNAL_CACHE_PURGE_TOKEN` to `site_cache.purge_url`/`site_cache.purge_token` and `NUXT_SITE_CACHE_PURGE_TOKEN` (route `/api/__site__/cache/purge`) before the Journal alias keys are removed.
|
||||
- `sm-summercmsio-app` mounts the Journal plugin 45 commits behind main; bump its pointer in a separate follow-up.
|
||||
|
||||
Reference in New Issue
Block a user