From 41e61fc14861964e1c97f9d1855d5bac59b02e60 Mon Sep 17 00:00:00 2001 From: Mischa Date: Sat, 4 Jul 2026 22:54:59 +0200 Subject: [PATCH] build: per-environment Grav config override (prod Twig prod-mode) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prod needs twig.cache:true / debug:false / auto_reload:false, but those values break local dev, so they must not live in the committed system.yaml. Add a per-environment override deployed only to the server via Grav's environment://config (user/env//config/system.yaml): - deploy/env/prod/system.yaml — version-controlled source of truth. - make remote-apply-env-prod — writes it to the server + clears cache; resolves the host in-recipe (WEB_HOST || REMOTE_HOST) to avoid the recursive-make empty-export trap. - remote-diag now shows the deployed override + whether twig cache is populating, so prod-mode can be verified not assumed. - CLAUDE.md §1 rewritten: never flip committed system.yaml; use the override. Backlog updated (twig prod-mode + /post login-gate done; note stale .env.prod GRAV_VERSION and pending git-sync). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Np4cMQLF77i664CAQXySzU --- CLAUDE.md | 34 ++++++++++++++++++++++++++++------ Makefile | 21 ++++++++++++++++++++- deploy/env/prod/system.yaml | 20 ++++++++++++++++++++ docs/working/backlog.md | 7 ++++--- 4 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 deploy/env/prod/system.yaml diff --git a/CLAUDE.md b/CLAUDE.md index bd59064..46430cd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -171,15 +171,37 @@ Active settings in `user/config/system.yaml`: With these settings, Grav rebuilds templates on every request. This is intentionally slower but means you never need to flush cache after editing a `.html.twig` file. -### Production mode (not yet configured) +### Production mode (per-environment override) -Before going live, change in `user/config/system.yaml`: +Production needs different Twig settings than dev, but **never change the +committed `user/config/system.yaml`** — `twig.cache: false` (and `debug`/ +`auto_reload: true`) are the *intended dev values*, and committing prod values +there breaks local development for everyone. -| Setting | Prod value | Why | -|---|---|---| -| `twig.cache` | `true` | Templates compiled once and reused; safe because theme files don't change at runtime | +Instead, prod values are a **per-environment override** deployed to the server +only, via Grav's per-environment config (`environment://config`, keyed on the +request hostname): -**Pre-launch smoke test required:** with `twig.cache: true`, submit one post via `/post` and confirm the entry appears in the trip page feed at `/trips/italy-2026-demo` immediately. This verifies the cache-on-save plugin (BUG-001 fix) works correctly with caching enabled. +| Setting | Dev (committed) | Prod (override) | Why prod differs | +|---|---|---|---| +| `twig.cache` | `false` | `true` | Compile templates once and reuse | +| `twig.debug` | `true` | `false` | No debug functions in prod | +| `twig.auto_reload` | `true` | `false` | Don't stat templates every request | + +- **Source of truth:** `deploy/env/prod/system.yaml` (version-controlled). +- **Deploy:** `make remote-apply-env-prod` — writes it to + `/user/env//config/system.yaml` and clears cache. It + deep-merges over the committed `system.yaml`. +- **Not synced by content:** `user/env/` is outside the content repo's tracked + folders, so `content-push` / git-sync / `remote-fetch-content` do **not** + restore it. **Re-run `make remote-apply-env-prod` after any fresh install.** +- The hostname segment defaults to `REMOTE_HOST`; override with `WEB_HOST` in + `.env.` if Grav sees a different host than the SSH host. + +**Pre-launch smoke test required:** with the prod override applied, submit one +post via `/post` and confirm the entry appears in the trip page feed +immediately. This verifies the cache-on-save plugin (BUG-001 fix) works +correctly with caching enabled. ### What the cache-on-save plugin handles diff --git a/Makefile b/Makefile index 16f6df2..ba2524d 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,10 @@ REMOTE_PORT ?= 22 SSH := ssh -p $(REMOTE_PORT) $(REMOTE_USER)@$(REMOTE_HOST) WEBROOT ?= $(REMOTE_HOME)/public_html SITE_CONFIG_DIR ?= $(REMOTE_HOME)/site-config +# Hostname Grav uses to pick its per-environment config (user/env//). +# Defaults to the SSH host; override in .env. only if the web hostname +# Grav sees differs from the SSH host (e.g. an addon domain on a shared box). +WEB_HOST ?= $(REMOTE_HOST) # ── Environment guard + generated per-env remote targets ────────────────────── # Every remote-* target below gains `-test` / `-prod` variants, e.g. @@ -22,7 +26,8 @@ SITE_CONFIG_DIR ?= $(REMOTE_HOME)/site-config REMOTE_TARGETS := remote-env-setup remote-env-remove remote-wipe remote-install \ remote-fetch remote-fetch-content remote-install-plugins remote-update-plugins \ remote-upgrade-grav remote-git-sync-disable remote-git-sync-enable \ - remote-content-status remote-clean remote-diag remote-maintenance-on remote-maintenance-off + remote-content-status remote-clean remote-diag remote-apply-env \ + remote-maintenance-on remote-maintenance-off ENVS := test prod guard-env: @@ -173,6 +178,18 @@ remote-content-status: guard-env remote-clean: guard-env $(SSH) "cd $(WEBROOT) && php bin/grav clearcache" +# Deploy per-environment Grav config overrides to the server's +# user/env//config/ tree (deep-merged over the committed config). +# Source of truth: deploy/env/$(ENV)/system.yaml (version-controlled). This +# tree is outside the content repo, so it is NOT restored by content sync — +# re-run after any fresh install. +remote-apply-env: guard-env + @test -f deploy/env/$(ENV)/system.yaml || { echo "ERROR: missing deploy/env/$(ENV)/system.yaml"; exit 1; } + @host="$${WEB_HOST:-$(REMOTE_HOST)}"; \ + test -n "$$host" || { echo "ERROR: WEB_HOST/REMOTE_HOST unresolved"; exit 1; }; \ + $(SSH) "mkdir -p $(WEBROOT)/user/env/$$host/config && cat > $(WEBROOT)/user/env/$$host/config/system.yaml && cd $(WEBROOT) && php bin/grav clearcache" < deploy/env/$(ENV)/system.yaml; \ + echo "Applied deploy/env/$(ENV)/system.yaml -> $(WEBROOT)/user/env/$$host/config/system.yaml" + # Read-only health check: plugin install state, versions, key config, log tail. remote-diag: guard-env $(SSH) "cd $(WEBROOT) && \ @@ -180,6 +197,8 @@ remote-diag: guard-env echo '=== installed plugin versions ==='; for p in login admin2 flex-objects form api; do printf '%s: ' \"\$$p\"; grep -m1 '^version:' user/plugins/\$$p/blueprints.yaml 2>/dev/null || echo '(NOT installed)'; done; \ echo '=== what does GPM say about api? ==='; php bin/gpm info api 2>&1 | head -12; \ echo '=== api override (enabled/route/session) ==='; grep -nE '^enabled:|^route:|session_enabled:' user/config/plugins/api.yaml 2>&1; \ + echo '=== per-env override present? ==='; for f in user/env/*/config/system.yaml; do echo \"\$$f:\"; cat \"\$$f\" 2>/dev/null | grep -E 'cache:|debug:|auto_reload:'; done; \ + echo '=== twig cache populating? (non-empty => cache on) ==='; ls cache/twig/ 2>/dev/null | head -1 || echo '(empty)'; \ echo '=== grav.log tail ==='; tail -8 logs/grav.log 2>/dev/null" remote-maintenance-on: guard-env diff --git a/deploy/env/prod/system.yaml b/deploy/env/prod/system.yaml new file mode 100644 index 0000000..4244eb6 --- /dev/null +++ b/deploy/env/prod/system.yaml @@ -0,0 +1,20 @@ +# Production-only Grav config overrides. +# +# Deep-merged OVER the committed user/config/system.yaml via Grav's +# per-environment config mechanism: on the server this file is deployed to +# /user/env//config/system.yaml +# and Grav's `environment://config` stream (keyed on the request hostname) +# layers it on top of `user://config`. +# +# These values are deliberately NOT in the committed system.yaml because they +# would break local development (see CLAUDE.md §1 — dev keeps twig.cache:false +# so theme edits take effect immediately). Prod is the only place they apply. +# +# Deploy with: make remote-apply-env-prod +# The user/env/ tree is outside the content repo's tracked folders, so it is +# NOT restored by content-push / git-sync / remote-fetch-content — re-run the +# target above after any fresh install. +twig: + cache: true + debug: false + auto_reload: false diff --git a/docs/working/backlog.md b/docs/working/backlog.md index dbd82b1..788c0c4 100644 --- a/docs/working/backlog.md +++ b/docs/working/backlog.md @@ -6,11 +6,12 @@ Ideas and improvements not yet planned or scheduled. ## Production — remaining items -- [ ] Set `twig.cache: true` in `user/config/system.yaml` on the server (do not commit — breaks local dev) +- [x] Prod Twig prod-mode (`cache: true`, `debug/auto_reload: false`) — applied as a per-environment override via `make remote-apply-env-prod` (source: `deploy/env/prod/system.yaml`); committed `system.yaml` stays dev - [ ] Smoke test: submit one post via `/post`, confirm entry appears in dailies immediately (verifies cache-on-save with twig cache on) -- [ ] Confirm `/post` requires login — unauthenticated visitors must not be able to post +- [x] Confirm `/post` requires login — verified on prod (returns the login gate to unauthenticated visitors) - [ ] Register at carto.com and review terms for production traffic -- [ ] Japan & Korea 2026 trip page: set `date_start`, add `cover_image`, upload GPX route file(s) +- [ ] Update `GRAV_VERSION` in `.env.prod` to `2.0.4` (was stale `2.0.0-rc.10`; fixed on the running server via self-upgrade, but a future fresh install would repeat the RC) +- [ ] git-sync on prod: install, add encrypted token, apply `folders:` fix, enable after first content round-trip ---