Files
natascha-rieter-nl/docs/handover/GRAV2-MIGRATION-HANDOVER.md
m038 8c93dfd7c9 Sync local state with remote after untracked local evolution
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.
2026-08-30 14:48:54 +02:00

172 lines
8.9 KiB
Markdown

# 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
```bash
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)
```bash
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 (image `2.0.21-ls271`,
port 8081, mounts `./migration-test/user`, `restart: "no"`).
- `migration-test/user/``rsync -a --exclude='.git'` copy of the live `user/`
folder (~50M, `.git` excluded on purpose since `user/` is itself a separate
git content-sync repo — copying `.git` would have created a confusing nested
repo). **This copy is stale** as of whenever it was taken; re-sync before
further testing if `user/` content has changed since:
```bash
rsync -a --exclude='.git' ./user/ ./migration-test/user/
```
- `~/.docker/cli-plugins/docker-compose` (outside repo, machine-level) —
symlink to the Homebrew `docker-compose` binary, registering it as the
`docker compose` CLI plugin. This was a durable fix for `make start` (which
calls `docker compose up -d` and previously failed with
`unknown 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 if `make start` ever
breaks again on a different machine.
## Findings so far
1. **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 `./user` volume mount — so an in-place `gpm selfupgrade` wouldn't
persist across container recreation anyway. The real upgrade path is an
**image tag swap** (`1.7.49.5-ls244` → `2.0.21-ls271` or whatever is current)
combined with a content/plugin compatibility pass.
2. **Front-end renders correctly** on Grav 2.0.21 core against the unmodified
1.7-era `user/` content and theme — verified via curl against
`http://localhost:8081/`, including the `langswitcher` redirect (`/` → `/nl`).
3. **Classic `admin` plugin (v1.10.55) login page renders correctly** on Grav
2.0.21 — confirmed via `curl 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 through
`admin2` (the alpha SvelteKit rewrite) instead.
4. **No errors, exceptions, fatals, deprecation notices, or warnings** appeared
in `docker logs natascha_grav2_test` for either the `/` or `/admin` requests.
5. `bin/grav`/`bin/gpm` CLI layout is the same path as 1.7
(`/app/www/public/bin/`, must `cd` there 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 plugins` doesn't exist in 2.0
(confirm via `php bin/grav list`).
6. Grav's built-in `page-system-validator` tool (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 the `admin` plugin's `onPageInitialized()` 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 create` in 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-sync`
- `flex-objects`
- `admin-media-move`, `admin-media-replace`, `admin-media-actions`
- `automagic-images`
- `social-meta-tags`
- `langswitcher` (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's `blueprints.yaml` under `migration-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-cloning `grav-plugin-api` and `grav-plugin-admin2`
into `user/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)
1. Bring the sandbox back up (command above), re-sync `migration-test/user`
from `./user` if content has changed since.
2. 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 isolated `migration-test/user` copy.
3. 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.
4. 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-grav` GPM 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.
5. Revisit whether `admin2` is still wanted given classic admin's
better-than-expected 2.0 compatibility.