Local site-ai/ had diverged significantly from the last commit pushed to Gitea (new remote-env-setup/remove targets, SITE_CONFIG_DIR/MAIN_REPO split, credential cleanup in server-install.sh, migration docs) without ever being committed. This catches the repo up to what's actually on disk. Also untracks the legacy user/ subtree left over from before content was split into its own standalone repo (natascha-rieter.nl-user) — user/ is gitignored here and stays a separate git repo, unaffected by this commit.
8.9 KiB
Grav 1.7 → 2.0 Migration Simulation — Handover
Status as of 2026-08-25: Investigation in progress, not concluded. Nothing has touched production. This document is for a future session to pick up where this one left off.
What this is
The user asked (advisory, then "let's look into it — zero impact on production") what the best strategy is to upgrade local Grav from 1.7.49.5 to the latest 2.x, and to try installing a 2.x admin UI. Per explicit instruction, instead of upgrading in place, a second, fully isolated Docker container running Grav 2.0.21 was stood up next to the existing 1.7 dev container, using a copy of the real site content, to see what breaks before committing to a real migration.
Nothing about the live dev container, the user/ git content repo, or
production has been changed. All make remote-* targets remain untouched.
Current environment state
| Container | Image | Port | Data | State | |
|---|---|---|---|---|---|
| existing dev | natascha_grav |
lscr.io/linuxserver/grav:1.7.49.5-ls244 |
8080 | ./user (live mount) |
Up, compose project site-ai (docker-compose.yml) |
| migration sandbox | natascha_grav2_test |
lscr.io/linuxserver/grav:2.0.21-ls271 |
8081 | ./migration-test/user (copy, no .git) |
Stopped (exited cleanly, restart: "no" so it doesn't auto-start) |
Docker runs via Colima (no Docker Desktop). Colima must be running before any
of this works: check with colima status, start with colima start.
To resume the sandbox container
cd /Users/mischa/Nextcloud/Projects/Natascha/natascha-rieter.nl/site-ai
docker compose -f docker-compose.grav2.yml -p natascha-grav2-test up -d
Then it's reachable at http://localhost:8081 (front-end) and http://localhost:8081/admin (admin login).
To tear it down completely (once done investigating)
cd /Users/mischa/Nextcloud/Projects/Natascha/natascha-rieter.nl/site-ai
docker compose -f docker-compose.grav2.yml -p natascha-grav2-test down
rm -rf migration-test
docker-compose.grav2.yml itself can also be deleted once the simulation is
finished and a real decision is made — it was created purely as a scratch
sandbox definition and is separate from the production-mirroring
docker-compose.yml.
Files created this investigation (all under site-ai/)
docker-compose.grav2.yml— the sandbox compose file (image2.0.21-ls271, port 8081, mounts./migration-test/user,restart: "no").migration-test/user/—rsync -a --exclude='.git'copy of the liveuser/folder (~50M,.gitexcluded on purpose sinceuser/is itself a separate git content-sync repo — copying.gitwould have created a confusing nested repo). This copy is stale as of whenever it was taken; re-sync before further testing ifuser/content has changed since:rsync -a --exclude='.git' ./user/ ./migration-test/user/~/.docker/cli-plugins/docker-compose(outside repo, machine-level) — symlink to the Homebrewdocker-composebinary, registering it as thedocker composeCLI plugin. This was a durable fix formake start(which callsdocker compose up -dand previously failed withunknown shorthand flag: 'd'because no compose plugin was registered). Chosen explicitly by the user over editing the Makefile. Not something a future session needs to redo, but worth knowing about ifmake startever breaks again on a different machine.
Findings so far
-
Grav 2.0 is not an in-place upgrade. Official docs say so explicitly. Also, in this project's setup, Grav core lives inside the Docker image, not in the
./uservolume mount — so an in-placegpm selfupgradewouldn't persist across container recreation anyway. The real upgrade path is an image tag swap (1.7.49.5-ls244→2.0.21-ls271or whatever is current) combined with a content/plugin compatibility pass. -
Front-end renders correctly on Grav 2.0.21 core against the unmodified 1.7-era
user/content and theme — verified via curl againsthttp://localhost:8081/, including thelangswitcherredirect (/→/nl). -
Classic
adminplugin (v1.10.55) login page renders correctly on Grav 2.0.21 — confirmed viacurl http://localhost:8081/admin: full CSS/JS asset loading, Dutch-localized labels, working nonce, no visible PHP errors. This is a better result than official Grav 2.0 docs suggest — the docs imply classic admin is incompatible with 2.0 and that migration should go throughadmin2(the alpha SvelteKit rewrite) instead. -
No errors, exceptions, fatals, deprecation notices, or warnings appeared in
docker logs natascha_grav2_testfor either the/or/adminrequests. -
bin/grav/bin/gpmCLI layout is the same path as 1.7 (/app/www/public/bin/, mustcdthere first —FATAL: Must be run from ROOT directory of Grav!otherwise), but the CLI command set differs between 1.7 and 2.0 — e.g.php bin/grav pluginsdoesn't exist in 2.0 (confirm viaphp bin/grav list). -
Grav's built-in
page-system-validatortool (meant for before/after render-diffing across an upgrade) cannot be used from the CLI on this setup — it throws a PHP fatal (Call to a member function param() on null in .../admin/admin.php:354) because theadminplugin'sonPageInitialized()handler expects an HTTP request object that doesn't exist under CLI invocation. This happened on the old 1.7 container, so it's an artifact of the admin plugin's CLI handling generally, not a 2.0-specific regression. Don't waste time trying to make this tool work as a validation method — it needs a different approach (see "Next steps").
What has NOT been tested yet
-
The actual admin dashboard post-login — page editing, media management, anything behind auth. This requires real admin credentials, which were deliberately not obtained/guessed. If the user provides a throwaway password (or creates one via
bin/grav user createin the sandbox container, which is safe since it's isolated test data), this is the obvious next concrete step. -
Individual plugin compatibility, specifically the ones most likely to break because they hook deep into core APIs that changed in 2.0:
git-syncflex-objectsadmin-media-move,admin-media-replace,admin-media-actionsautomagic-imagessocial-meta-tagslangswitcher(front-end redirect already confirmed working, but not deeper admin-side behavior)draft-preview
Grav 2.0's plugin blueprints can declare a
compatibility:key; check each plugin'sblueprints.yamlundermigration-test/user/plugins/<name>/for this key, and/or check each plugin's upstream repo/changelog for 2.0 support statements.bin/gpm info <plugin>may also surface something once run from inside the sandbox container (untested). -
admin2(the alpha SvelteKit/Vite/Tailwind admin rewrite) has not been installed or tested in the sandbox at all. It's not GPM-installable — it requires manually git-cloninggrav-plugin-apiandgrav-plugin-admin2intouser/plugins/. Given it's explicitly alpha/non-production-ready upstream, and classic admin already renders fine on 2.0 in this test, it's worth explicitly asking the user whether they still want this installed before spending time on it, rather than assuming yes from the original advisory question.
Suggested next steps (pick up here)
- Bring the sandbox back up (command above), re-sync
migration-test/userfrom./userif content has changed since. - Either:
- Ask the user for a throwaway admin password to log in and click through the real dashboard/page-editing/media flows, or
- Create a fresh test admin user inside the sandbox container only
(
docker exec -it natascha_grav2_test sh -c "cd /app/www/public && php bin/grav user create") — safe since it only affects the isolatedmigration-test/usercopy.
- Go through the plugin list above one by one: check blueprint
compatibility:declarations, and exercise each plugin's actual feature (git-sync a commit, upload/replace media, edit a flex-objects-backed page) inside the sandbox to see what actually breaks vs. what merely lacks a compatibility flag. - Once a real compatibility picture exists, come back to the original
question — decide whether the production upgrade path should be:
(a) image-tag swap + fix whatever plugins broke, or
(b) use Grav's official
migrate-gravGPM plugin (side-by-side staged migration with Reset/Restart/Promote controls) instead of doing it by hand. This official tool was identified during research but deliberately not used yet, since the user asked specifically for a separate-container simulation first. - Revisit whether
admin2is still wanted given classic admin's better-than-expected 2.0 compatibility.