From 99f290fbca806c27f9c62171a22afdc80d4ac287 Mon Sep 17 00:00:00 2001 From: Mischa Date: Sat, 4 Jul 2026 14:54:28 +0200 Subject: [PATCH] docs: add Grav 2.0.4 upgrade + GPM-manage plugins design spec Coordinated upgrade of core rc.10 -> 2.0.4 and promotion of admin2/api/flex-objects to GPM management (option B). Documents the dependency-forced atomicity, the three plugin-management categories, git-sync handling (disable-during-upgrade, remote-only), and the local -> test -> prod(documented-only) rollout. Co-Authored-By: Claude Opus 4.8 --- .../2026-07-04-grav-2.0.4-upgrade-design.md | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 docs/working/specs/2026-07-04-grav-2.0.4-upgrade-design.md diff --git a/docs/working/specs/2026-07-04-grav-2.0.4-upgrade-design.md b/docs/working/specs/2026-07-04-grav-2.0.4-upgrade-design.md new file mode 100644 index 0000000..31710a1 --- /dev/null +++ b/docs/working/specs/2026-07-04-grav-2.0.4-upgrade-design.md @@ -0,0 +1,190 @@ +# 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.10` → `2.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.1–2.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 `. `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.zip` → `2.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) | +| `docker-compose.yml` | `GRAV_CHANNEL=beta` → `production` so GPM serves stable releases, not RCs | +| `scripts/server-install.sh` | remove the admin2/api stash+restore special-casing (lines 25–26 and 43–45); they now install via `gpm install` from `PLUGINS` | +| `Makefile` | add 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:22–24) so the env-suffix macro +(Makefile:31–34) auto-generates `-test` / `-prod` variants: + +- `remote-update-plugins` → `cd $(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` (`bin/grav upgrade`) already exists. + +> 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. + +### Phase 2 — test +1. `make remote-git-sync-disable-test` +2. `make remote-upgrade-grav-test` (core → 2.0.4) +3. `make remote-update-plugins-test` (`gpm update -y` — all plugins incl. + admin2/api/flex/git-sync/login/form) +4. Review `git status` in the server's `user/` for unexpected config diffs; + handle any deliberately (do not blind-commit). +5. Smoke test on the test URL (same checklist as Phase 1). +6. **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 channel** — the server must resolve stable releases; verify the channel + (`gpm.releases` / `GRAV_CHANNEL`) yields 2.0.x stable, not RCs.