From dcf9c1345549c22c8916924490ee78d13b870290 Mon Sep 17 00:00:00 2001 From: Mischa Date: Sat, 4 Jul 2026 23:40:11 +0200 Subject: [PATCH] docs: document Grav env-tree config save behavior + git-sync env path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Once user/env// exists, Grav Admin saves ALL config (system + plugin) into that env tree, not user/config/ — so prod's git-sync.yaml lives at the env path, and Admin-on-server config edits are server-only (not committed, not synced). Documented the footgun in CLAUDE.md §1 (session-loaded) and rewrote git-sync-notes.md: env-path location, v3.4.4 folders format, gitignore table (incl. versions.yaml + security-private.php TODO), and fresh-server enable procedure. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Np4cMQLF77i664CAQXySzU --- CLAUDE.md | 18 +++++++++ docs/working/git-sync-notes.md | 69 +++++++++++++++++++++++++++++----- 2 files changed, 77 insertions(+), 10 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 46430cd..53a1c9e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -198,6 +198,24 @@ request hostname): - The hostname segment defaults to `REMOTE_HOST`; override with `WEB_HOST` in `.env.` if Grav sees a different host than the SSH host. +> **⚠️ Once `user/env//` exists, Grav's Admin saves ALL config there.** +> Creating the env override dir has a site-wide side effect: Grav's Admin panel +> writes **every** config change (system *and* plugin) into the active +> environment's config tree — e.g. editing a plugin on prod saves to +> `user/env/intotheeast.com/config/plugins/.yaml`, **not** +> `user/config/plugins/.yaml`. Consequences you must remember: +> - Config edited via **Admin on the server is server-only**: `user/env/` is +> outside the content repo's tracked folders, so it is **not committed** and +> **not synced by git-sync** (which syncs only `pages`/`config`/`themes`). +> Good for secrets — `git-sync.yaml` (token) safely lives at the env path — +> but it means prod Admin config edits silently do **not** reach Gitea/local. +> - When reading/writing server config, check **both** `user/config/...` and +> `user/env//config/...` (env wins). Server tooling must search the env +> path first — see `scripts/git-sync-toggle.sh` and `make remote-diag`. +> - Repo-authored config (`user/config/...` via `make content-push`) still +> applies everywhere; the env tree only holds per-host overrides + Admin-on- +> server edits. Full details: `docs/working/git-sync-notes.md`. + **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 diff --git a/docs/working/git-sync-notes.md b/docs/working/git-sync-notes.md index 9819723..b1c5045 100644 --- a/docs/working/git-sync-notes.md +++ b/docs/working/git-sync-notes.md @@ -1,17 +1,41 @@ # Git Sync Plugin — Setup Notes -## Folders YAML bug +## ⚠️ Config lives in the ENVIRONMENT tree, not `user/config/` (IMPORTANT) -The plugin UI always saves the folders field as a single comma-string: +Prod has a per-environment override directory `user/env//config/` +(created for Twig prod-mode — see CLAUDE.md §1). **A crucial Grav side effect: +once that env dir exists, the Admin panel saves ALL config changes — system and +plugin — into the active environment's config tree**, not `user/config/`. -```yaml -folders: - - 'pages,config,themes' +So on prod, `git-sync.yaml` (configured via Admin) lives at: + +``` +user/env/intotheeast.com/config/plugins/git-sync.yaml ← here (env tree) +user/config/plugins/git-sync.yaml ← NOT here ``` -But the plugin code iterates the array expecting separate items. This causes `git status pages,config,themes` to be passed as a single path, so git sees nothing to commit and sync silently does nothing. +Why this matters: -**Fix:** Edit `user/config/plugins/git-sync.yaml` directly: +- **Server-only, not synced, not committed.** `user/env/` is outside the + content repo's tracked folders (`pages`/`config`/`accounts`/`themes`) and is + not one of git-sync's synced folders (`pages`/`config`/`themes`). So config + saved via Admin *on the server* never reaches Gitea or local. This is ideal + for the git-sync token (it stays server-only) but means **prod Admin config + edits silently diverge** — author durable config in the repo, not prod Admin. +- **Look in both places.** When inspecting/toggling server config, check + `user/config/plugins/.yaml` **and** + `user/env//config/plugins/.yaml` (env wins). +- **Tooling is env-path-aware.** `scripts/git-sync-toggle.sh` takes a `WEBROOT` + and searches `user/env/*/config/plugins/git-sync.yaml` first, then + `user/config/plugins/git-sync.yaml`. `make remote-git-sync-disable/enable-` + and `make remote-diag-` use it. + +## Folders format + +Older plugin versions' UI saved the `folders` field as a single comma-string +(`- 'pages,config,themes'`), which the plugin iterated as one path, so sync +silently did nothing. **git-sync v3.4.4 (installed on prod 2026-07-04) saves it +correctly** as separate list items: ```yaml folders: @@ -20,8 +44,33 @@ folders: - themes ``` -Never use the Admin UI to change folders — it will rewrite the broken format. +If you see the comma-string form on an older version, fix it by editing +`git-sync.yaml` directly (at whichever path it lives — see above); do not +re-save folders via the Admin UI on the buggy version. -## Files to gitignore +## Per-install / secret files — must be gitignored (never synced) -`user/config/plugins/git-sync.yaml` contains an encrypted token and is server-specific. `user/config/security.yaml` contains Grav nonces/salts, also server-specific. Both are in `.gitignore` and must never be committed. +git-sync syncs the `config/` folder, so any per-install or secret file tracked +there would get pushed to Gitea and pollute every environment. Keep these out +of the content repo (all in `user/.gitignore`): + +| File | Why | +|---|---| +| `config/plugins/git-sync.yaml` | encrypted token; server-specific (also lives at env path on prod) | +| `config/plugins/api-private.php` | API JWT secret | +| `config/security.yaml` | Grav nonces/salts (legacy location) | +| `config/versions.yaml` | per-install Grav schema-migration state — differs per env (dev 2.0.4, prod 2.0.7); Grav regenerates it. Untracked 2026-07-04. | +| `config/security-private.php` | **TODO:** committed salt secret; should be gitignored like `api-private.php` (deferred — untracking resets server sessions) | + +## git-sync config summary (prod, 2026-07-04) + +- `repository: https://git.gorinskat.nl/m038/intotheeast-com-content.git`, + `branch: main`, HTTPS + token auth (SSH is Tailscale-only). +- `sync.direction: both`, `on_save/on_delete/on_media: true` → prod Admin edits + and `/post` push to Gitea; content-repo pushes pull to prod **via webhook** + (`/_git-sync`). The webhook is configured in Gitea repo settings (same secret + as the test instance). +- **Before enabling on a fresh server**, reset the synced folders clean + (`make remote-fetch-content-`) so no install-time drift (e.g. a stale + `versions.yaml`) gets pushed on the first sync. Toggle with + `make remote-git-sync-disable/enable-`.