Files
intotheeast-com/docs/working/specs/2026-07-04-grav-2.0.4-upgrade-design.md
m038andClaude Opus 4.8 3085cede28 docs: correct upgrade spec channel + CLI commands after container verification
- GPM channel is system.yaml gpm.releases (testing->stable), not GRAV_CHANNEL
- core upgrade is 'bin/gpm self-upgrade -y'; existing remote-upgrade-grav
  target ('bin/grav upgrade') is broken and must be fixed
- add server content-pull + cache-clear + preflight steps to Phase 2

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 14:58:27 +02:00

10 KiB
Raw Permalink Blame History

Grav 2.0.4 Upgrade + GPM-Manage admin2/api/flex-objects — Design

Date: 2026-07-04 Status: Design approved — pending implementation plan

Goal

Perform one coordinated upgrade of the intotheeast stack:

  1. Bump Grav core from 2.0.0-rc.102.0.4 (stable).
  2. Promote admin2, api, and flex-objects from bundle-extracted plugins to GPM-managed plugins (this is "option B").

These two changes are not separable. The stable plugins hard-require the stable core, so GPM enforces an atomic upgrade of the whole chain.

Background / findings

Version gaps

The project has been frozen on the final release candidate since the original Grav 2.0 upgrade. Grav went stable on 2026-06-21; latest patch is 2.0.4 (2026-06-29). No breaking changes exist within the 2.0.x line — the 2.0.12.0.4 releases are security hardening (XSS re-checks on editor Twig, ZIP-bomb limits, .htaccess case-insensitive bypass fix) plus bugfixes.

Installed vs. bundled-in-2.0.4 versions:

Plugin Installed 2.0.4 stable
core (grav) 2.0.0-rc.10 2.0.4
admin2 2.0.0-rc.15 2.0.9
api 1.0.0-rc.15 1.0.6
flex-objects 1.4.0-rc.7 1.4.3
login 3.8.9 3.8.11
form 9.1.6 9.1.8
shortcode-core 6.0.0 6.2.1

Dependency chain (why it's atomic)

From the stable plugin blueprints:

  • api 1.0.6 requires grav >= 2.0.4 and login >= 3.8.11
  • admin2 2.0.9 requires api >= 1.0.6
  • flex-objects 1.4.3 requires form >= 6.0.0, api >= 1.0.0

So stable admin2/api cannot run on the rc.10 core — GPM would refuse. This is the core reason option B is the right approach: gpm resolves and enforces the entire chain automatically, which the previous manual-extract approach never did.

Three plugin management categories

The upgrade must account for the fact that plugins reached the servers three different ways:

Category Plugins In plugins.txt? How installed Upgrade mechanism
GPM-managed email, error, form, login, problems, add-page-by-form, shortcode-gallery-plusplus yes gpm install gpm update
Manually-placed → GPM (option B) admin2, api, flex-objects will add hand-extracted from grav-admin zip plugins.txt for fresh installs; gpm update on existing test env
Remote-only git-sync no (config gitignored, holds encrypted token) installed directly on the server documented separately; carried by gpm update; disabled during upgrade

git-sync compatibility

git-sync is version 3.4.4 with an explicit compatibility: 2.0 flag and is one of Grav's own reference plugins for the Admin Next / API. It is safe to carry through the upgrade. Note the documented folders-YAML quirk (docs/working/git-sync-notes.md): its config must list folders as an array, never the UI-written comma-string.

Local vs. server upgrade mechanisms differ

  • Local bakes the core into the Docker image (Dockerfile) → upgrade by rebuilding the image.
  • Server is a native webroot install → core upgrades via bin/grav upgrade, plugins via bin/gpm update.

The plan therefore has distinct local and remote steps.

Decisions

  • Option B (GPM management) for admin2/api/flex-objects. Add them to plugins.txt so future fresh installs pull them via GPM.
  • Rollout order: local → test → prod.
  • Prod is currently empty → the prod phase is written as a documented fresh-install runbook only and is not executed in this effort. Fresh prod install uses the option-B-modified server-install.sh with GRAV_VERSION=2.0.4.
  • Rollback = git. All relevant data (pages/, config/, accounts/, themes/) is committed. No separate backup step. Rollback is git revert of this branch plus a rebuild/redeploy.
  • Upgrade verb on existing installs is gpm update (update-all), not gpm install <plugins.txt>. install skips already-installed plugins and never touches git-sync (which is not in the list); update upgrades every installed plugin regardless of how it was placed, catching the manual and remote-only categories in one shot.
  • git-sync stays out of plugins.txt (that list is shared with local; git-sync is remote-only with a manual encrypted token). Documented as separately managed.
  • git-sync is disabled before the test upgrade and left disabled, so the upgrade cannot auto-commit reformatted/server-specific config back into the shared Gitea user repo. The user validates first, then re-enables it as a separate deliberate step.

File changes (Phase 0)

File Change
Dockerfile grav-admin zip URL 2.0.0-rc.10/grav-admin-v2.0.0-rc.10.zip2.0.4/grav-admin-v2.0.4.zip. Verified: the 2.0.4 zip still extracts to a grav-admin/ folder, so the existing cp block is unchanged.
plugins.txt add api, admin2, flex-objects (form, login already present as their deps)
user/config/system.yaml gpm.releases: testing → stable — this is the authoritative GPM channel. testing is what has been serving RC/pre-release versions. Tracked in the user repo, so it applies to both local and server once pushed.
docker-compose.yml GRAV_CHANNEL=betaproduction for consistency only. This env drives the base image's docker-entrypoint.sh, not bin/gpm's channel — gpm.releases above is what governs updates.
scripts/server-install.sh remove the admin2/api stash+restore special-casing (lines 2526 and 4345); they now install via gpm install from PLUGINS
Makefile fix broken remote-upgrade-grav: php bin/grav upgrade is not a real command — change to php bin/gpm self-upgrade -y. Add the new remote targets (below) to REMOTE_TARGETS so each gets -test/-prod variants.
CLAUDE.md, docs/reference/architecture.md, memory update stack versions; document the three-category plugin model and the channel change

New Makefile targets

Added to the REMOTE_TARGETS list (Makefile:2224) so the env-suffix macro (Makefile:3134) auto-generates -test / -prod variants:

  • remote-update-pluginscd $(WEBROOT) && php bin/gpm update -y
  • remote-git-sync-disable → set enabled: false in $(WEBROOT)/user/config/plugins/git-sync.yaml (touch only the enabled key; never rewrite folders)
  • remote-git-sync-enable → set enabled: true in the same file

remote-upgrade-grav exists but its command is broken (php bin/grav upgrade is not a Grav CLI command) — it is fixed to php bin/gpm self-upgrade -y as part of Phase 0. Core self-upgrade respects the gpm.releases channel.

Verified CLI command names (against the running rc.10 container): php bin/gpm self-upgrade -y (core), php bin/gpm update -y (all plugins), php bin/grav cache (clear cache; aliases clearcache/cache-clear).

The exact idempotent shell used to toggle the enabled key is finalized in the implementation plan; it must not disturb the folders array or the encrypted token in git-sync.yaml.

Phases

Phase 0 — branch + edits

New branch off main. Apply all file changes above.

Phase 1 — local

  1. Remove the stale manually-extracted admin2, api, flex-objects folders from user/plugins/ so GPM does a clean install.
  2. make build (core → 2.0.4)
  3. make start
  4. Install the newly-listed plugins and update the already-installed ones to their 2.0.4-compatible versions via GPM. Note: gpm install skips plugins that are already present, so login (3.8.9 → ≥3.8.11, required by api) and form need gpm update, not install. The exact gpm update + gpm install sequencing (run inside the container via docker exec) is pinned in the plan.
  5. Assert versions: admin2 2.0.9, api 1.0.6, flex-objects 1.4.3, login ≥ 3.8.11.
  6. Smoke test: admin2 login; submit /post → entry appears in the active trip's dailies; /gpx-manager list + upload + delete; a trip page and a story render; maps load.

Prerequisite: the Phase 0 config changes (esp. system.yaml gpm.releases: stable) are committed and pushed to Gitea, or GPM on the server will still resolve the testing channel and pull RCs.

  1. make remote-git-sync-disable-test
  2. make remote-fetch-content-test — pull latest user/ content to the test server so system.yaml gpm.releases: stable is in place before any GPM operation.
  3. make remote-upgrade-grav-test (core self-upgrade → 2.0.4)
  4. make remote-update-plugins-test (gpm update -y — all plugins incl. admin2/api/flex/git-sync/login/form)
  5. Clear cache on the server (php bin/grav cache).
  6. Review git status in the server's user/ for unexpected config diffs; handle any deliberately (do not blind-commit).
  7. Smoke test on the test URL (same checklist as Phase 1).
  8. Leave git-sync disabled and notify the user. After the user validates, re-enable as a separate deliberate step: make remote-git-sync-enable-test, then a content-push round-trip to confirm sync still works.

Phase 3 — prod (DOCUMENTED, NOT EXECUTED)

Prod is empty, so this is a fresh install, not an upgrade. Documented as a runbook:

  • Run the option-B-modified server-install.sh with GRAV_VERSION=2.0.4 (make remote-install-prod).
  • admin2/api/flex-objects now install via GPM from plugins.txt — no manual extraction.
  • Set up git-sync manually afterward: install, add the encrypted token, apply the folders-YAML array fix (docs/working/git-sync-notes.md).

Rollback

git revert the branch (Dockerfile + plugins.txt + docker-compose + server-install.sh + Makefile) and rebuild/redeploy. Content, config, and accounts are already in git, so no data restore is needed.

Risks

  • git-sync auto-commit during upgrade — mitigated by disabling git-sync before the test upgrade and reviewing git status before re-enabling.
  • admin2/api behavioral changes across RC→stable — these back the /post form and /gpx-manager; covered by the smoke tests, which are the highest-weight validation in this effort.
  • GPM channelgpm.releases must be stable on the server before any gpm update/self-upgrade, or GPM pulls RCs. Enforced by pushing the system.yaml change and running remote-fetch-content first (Phase 2 step 2).
  • bin/gpm self-upgrade on shared hosting — Grav 2.0.3 fixed self-upgrade failures on shared-folder setups. On the native server this can still be fragile; run php bin/gpm preflight first and use -o/--overwrite if a retry is needed.