Files
m038andClaude Opus 5 839a4d0e69 docs: cut CLAUDE.md to rules-only (179 → 74 lines)
CLAUDE.md now carries only what must be known *before* opening a file:
hard rules, gotchas, and an entry-point table. Everything descriptive
moved to the doc that lives next to the code.

Moved out:
- stack versions, plugin roles, asset pipeline, nav shape, user/ repo
  tracking rules → docs/reference/architecture.md
- Playwright layout, config facts, auth-setup project, test account
  → docs/reference/testing.md (new)
- folder map, full make command list (build/test/demo/worktree targets
  that only existed in CLAUDE.md) → README.md
- dev/prod Twig settings table → already in docs/guides/deploy-cycle.md

Fixed while verifying, all of them descriptions that had drifted:
- demo fixtures were listed as italy-2026-demo + no-photos-demo; the
  actual folders are italy-2025 + italy-2026-demo
- the map engine was cited at js/src/maplibre-utils.js; it is
  js/maplibre-utils.js, a hand-authored file beside the bundles
- the build-output list omitted fonts/ and the generated
  templates/partials/weather-icons.html.twig, and did not flag that
  js/maplibre-utils.js and js/nav.js are sources living in js/
- README called user/ a "standalone git repo" (it is a submodule)
- docs/README.md linked to a non-existent working/production-todo.md
- git-sync-notes.md pointed at "CLAUDE.md §1", a section number that
  no longer exists

Net: ~17.1k → ~8.5k chars of always-loaded context.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-24 21:14:34 +02:00

4.9 KiB

Git Sync Plugin — Setup Notes

⚠️ Config lives in the ENVIRONMENT tree, not user/config/ (IMPORTANT)

Prod has a per-environment override directory user/env/<hostname>/config/ (created for Twig prod-mode — see ../guides/deploy-cycle.md → "The env override tree"). 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/.

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

Why this matters:

  • ⚠️ user/env/ is NOT safe unless gitignored — it is NOT scoped out by the folders setting. An earlier version of this note claimed user/env/ "never reaches Gitea" because it is outside git-sync's synced folders. That is wrong and caused a live secret leak (2026-07-05). git-sync's auto-commit stages files outside the configured folders; on prod it pushed the whole user/env/intotheeast.com/config/ tree — JWT secret, CSRF salt, and the git-sync token + webhook secret — to Gitea. The fix was to gitignore /env/ (commit 6e8eadb). So: prod Admin config edits stay server-only only because /env/ is now gitignored, not because of folder scope. Author durable config in the repo, not prod Admin. Full analysis: docs/solutions/architecture-patterns/git-sync-secret-exposure-and-tracked-file-boomerang.md.
  • Look in both places. When inspecting/toggling server config, check user/config/plugins/<name>.yaml and user/env/<host>/config/plugins/<name>.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-<env> and make remote-diag-<env> 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:

folders:
  - pages
  - config
  - themes

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.

Per-install / secret files — must be gitignored (gitignore is the boundary)

git-sync's auto-commit stages everything under user/ that is not gitignored — the folders setting does not scope the commit add-set (a 2026-07-05 leak proved this by pushing user/env/**, outside the configured folders). So .gitignore — not folder scope — is the only thing keeping a per-install or secret file off Gitea. Keep all of these gitignored in user/.gitignore:

Path Why
env/ whole per-host env tree — holds the live git-sync token, JWT secret, CSRF salt + all server-side Admin config. Gitignored + untracked 2026-07-05 (commit 6e8eadb) after it leaked to Gitea. NOT safe on folder scope alone.
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 CSRF/nonce + admin rate-limit signing salt; gitignored + untracked 2026-07-05 (commit 2840018). Each env keeps its own; untracking regenerates prod's salt (one-time admin re-login).

Why a key inside a tracked config file (e.g. popularity.salt in api.yaml) can't just be stripped — it regenerates at runtime and boomerangs back via git-sync's git add -A. See docs/solutions/architecture-patterns/git-sync-secret-exposure-and-tracked-file-boomerang.md for the full round-trippable-set model.

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-<env>) 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-<env>.