docs: restructure docs/ into guides/ reference/ working/ research/
This commit is contained in:
@@ -0,0 +1,508 @@
|
||||
# Grav 2.0 Upgrade Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Upgrade the local dev Docker environment from linuxserver/grav 1.7 to getgrav/grav 2.0 RC, validate the full Milestone 1 posting workflow, and update the production install script for a fresh Grav 2.0 deploy.
|
||||
|
||||
**Architecture:** Two tracks in sequence — (1) swap the Docker image and update all dependent config/paths, boot the site with `make setup`, run the existing test suite; (2) update `server-install.sh` so `make remote-install` deploys Grav 2.0 fresh on the production PHP 8.4 server. The `user/` directory (content, config, theme, custom plugins) is already isolated as a git repo and requires only a small compatibility addition to `cache-on-save`.
|
||||
|
||||
**Tech Stack:** Grav CMS 2.0.0-rc.9, PHP 8.4 (production) / Docker `getgrav/grav` with PHP 8.3 (dev), Apache, Twig 3, Symfony 7, Playwright (UI tests).
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- All work on branch `update-to-2.0` (already created)
|
||||
- Never read `.env` — contains sensitive credentials
|
||||
- Only modify files in the project root or `user/` subfolders
|
||||
- `user/config/system.yaml` is tracked in the **user/ git repo** — commit it with `git -C user add config/system.yaml && git -C user commit ...`, NOT from the main repo
|
||||
- `user/plugins/cache-on-save/` is tracked in the **main repo** (after adding `.gitignore` exception) — commit blueprints.yaml with `git add user/plugins/cache-on-save/blueprints.yaml` from the project root
|
||||
- Container name stays `intotheeast_grav`; local port stays `8081`
|
||||
- `make` commands are the only way to interact with the remote server
|
||||
- Grav 2.0 requires PHP ≥ 8.3 (dev container uses 8.3 default; production uses 8.4 — both compliant)
|
||||
- Production download URL format: `https://getgrav.org/download/core/grav-admin/${GRAV_VERSION}${GRAV_CHANNEL_SUFFIX}`
|
||||
|
||||
---
|
||||
|
||||
## Files Changed
|
||||
|
||||
| File | Action | Reason |
|
||||
|---|---|---|
|
||||
| `docker-compose.yml` | Modify | Switch image, update volume + PHP ini path, add env var |
|
||||
| `Makefile` | Modify | Three `docker exec` targets hardcode linuxserver's `/app/www/public` path |
|
||||
| `.gitignore` | Modify | Add `!user/plugins/cache-on-save/` exception to track the custom plugin in the main repo |
|
||||
| `user/plugins/cache-on-save/blueprints.yaml` | Create | Grav 2.0 compat flag (required by GPM) — committed to main repo |
|
||||
| `user/config/system.yaml` | Modify | Switch GPM channel from `stable` to `testing` |
|
||||
| `scripts/server-install.sh` | Modify | Support `GRAV_CHANNEL_SUFFIX` for `?testing` query param on 2.0 RC download |
|
||||
|
||||
---
|
||||
|
||||
## Task 1: Swap Docker image and fix container paths
|
||||
|
||||
**Files:**
|
||||
- Modify: `docker-compose.yml`
|
||||
- Modify: `Makefile`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces: A running Grav 2.0 container reachable at `http://localhost:8081` with `user/` mounted at `/var/www/html/user` and PHP upload limits applied via `/usr/local/etc/php/conf.d/php-local.ini`
|
||||
|
||||
- [ ] **Step 1: Stop and remove the current container**
|
||||
|
||||
```bash
|
||||
cd /home/mischa/Nextcloud/Projects/travel-blog-intotheeast
|
||||
docker compose down
|
||||
```
|
||||
|
||||
Expected: container `intotheeast_grav` stops and is removed.
|
||||
|
||||
- [ ] **Step 2: Update `docker-compose.yml`**
|
||||
|
||||
Replace the entire contents of `docker-compose.yml` with:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
grav:
|
||||
image: getgrav/grav
|
||||
container_name: intotheeast_grav
|
||||
environment:
|
||||
- GRAV_CHANNEL=beta
|
||||
ports:
|
||||
- "8081:80"
|
||||
volumes:
|
||||
- ./user:/var/www/html/user
|
||||
- ./php/php-local.ini:/usr/local/etc/php/conf.d/php-local.ini
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
Key changes from old file:
|
||||
- `image`: `lscr.io/linuxserver/grav:latest` → `getgrav/grav`
|
||||
- `environment`: removed `PUID`/`PGID` (linuxserver-specific), added `GRAV_CHANNEL=beta`
|
||||
- `volumes[0]`: `/config/www/user` → `/var/www/html/user`
|
||||
- `volumes[1]`: `/config/php/php-local.ini` → `/usr/local/etc/php/conf.d/php-local.ini`
|
||||
|
||||
- [ ] **Step 3: Update Makefile — three targets use the old container path**
|
||||
|
||||
In `Makefile`, make these three targeted replacements:
|
||||
|
||||
**`install-plugins` target** — change working directory flag:
|
||||
|
||||
Old:
|
||||
```makefile
|
||||
install-plugins:
|
||||
docker exec -w /app/www/public intotheeast_grav php bin/gpm install $(shell cat plugins.txt | tr '\n' ' ') -y
|
||||
```
|
||||
|
||||
New:
|
||||
```makefile
|
||||
install-plugins:
|
||||
docker exec -w /var/www/html intotheeast_grav php bin/gpm install $(shell cat plugins.txt | tr '\n' ' ') -y
|
||||
```
|
||||
|
||||
**`demo-load` target** — change cache clear path:
|
||||
|
||||
Old:
|
||||
```makefile
|
||||
demo-load:
|
||||
cp -r user/docs/demo/tracker/. user/pages/01.tracker/
|
||||
docker exec intotheeast_grav bash -c "cd /app/www/public && php bin/grav clearcache"
|
||||
```
|
||||
|
||||
New:
|
||||
```makefile
|
||||
demo-load:
|
||||
cp -r user/docs/demo/tracker/. user/pages/01.tracker/
|
||||
docker exec intotheeast_grav bash -c "cd /var/www/html && php bin/grav clearcache"
|
||||
```
|
||||
|
||||
**`demo-reset` target** — change cache clear path:
|
||||
|
||||
Old:
|
||||
```makefile
|
||||
demo-reset:
|
||||
@for dir in user/docs/demo/tracker/*/; do \
|
||||
folder=$$(basename "$$dir"); \
|
||||
rm -rf "user/pages/01.tracker/$$folder"; \
|
||||
done
|
||||
docker exec intotheeast_grav bash -c "cd /app/www/public && php bin/grav clearcache"
|
||||
```
|
||||
|
||||
New:
|
||||
```makefile
|
||||
demo-reset:
|
||||
@for dir in user/docs/demo/tracker/*/; do \
|
||||
folder=$$(basename "$$dir"); \
|
||||
rm -rf "user/pages/01.tracker/$$folder"; \
|
||||
done
|
||||
docker exec intotheeast_grav bash -c "cd /var/www/html && php bin/grav clearcache"
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Validate docker-compose syntax**
|
||||
|
||||
```bash
|
||||
docker compose config
|
||||
```
|
||||
|
||||
Expected: prints merged compose config with no errors. If you see `Error`, re-check the YAML indentation in `docker-compose.yml`.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add docker-compose.yml Makefile
|
||||
git commit -m "feat: switch to getgrav/grav 2.0 RC docker image
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: Add Grav 2.0 compat flag and switch GPM to testing channel
|
||||
|
||||
**Files:**
|
||||
- Modify: `.gitignore` (add exception for `user/plugins/cache-on-save/`)
|
||||
- Create: `user/plugins/cache-on-save/blueprints.yaml` (committed to main repo)
|
||||
- Modify: `user/config/system.yaml` (committed to user/ git repo, not main repo)
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: Running container from Task 1
|
||||
- Produces: GPM resolves 2.0-compatible plugin versions on install; `cache-on-save` is recognized as 2.0-compatible by Grav's plugin registry
|
||||
|
||||
- [ ] **Step 1: Create `user/plugins/cache-on-save/blueprints.yaml`**
|
||||
|
||||
Create the file with this exact content:
|
||||
|
||||
```yaml
|
||||
name: Cache On Save
|
||||
version: 1.0.0
|
||||
description: Clears Grav cache on new-entry form submission
|
||||
author:
|
||||
name: Mischa
|
||||
email: mischa@gorinskat.nl
|
||||
license: MIT
|
||||
|
||||
dependencies:
|
||||
- { name: grav, version: '>=1.6.0' }
|
||||
|
||||
grav:
|
||||
version: ['1.7', '2.0']
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Update GPM channel in `user/config/system.yaml`**
|
||||
|
||||
Find the `gpm:` section (around line 200 in the file) and change `releases: stable` to `releases: testing`:
|
||||
|
||||
Old:
|
||||
```yaml
|
||||
gpm:
|
||||
releases: stable
|
||||
official_gpm_only: true
|
||||
```
|
||||
|
||||
New:
|
||||
```yaml
|
||||
gpm:
|
||||
releases: testing
|
||||
official_gpm_only: true
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Add gitignore exception and commit blueprints.yaml to main repo**
|
||||
|
||||
```bash
|
||||
cd /home/mischa/Nextcloud/Projects/travel-blog-intotheeast
|
||||
|
||||
# Add exception so cache-on-save is tracked in the main repo
|
||||
# Insert after the existing "user/plugins/" line in .gitignore:
|
||||
# !user/plugins/cache-on-save/
|
||||
|
||||
# Then commit to the main repo:
|
||||
git add .gitignore user/plugins/cache-on-save/blueprints.yaml
|
||||
git commit -m "feat: track cache-on-save plugin in main repo; add Grav 2.0 compat flag
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Commit system.yaml to the user/ git repo**
|
||||
|
||||
```bash
|
||||
cd /home/mischa/Nextcloud/Projects/travel-blog-intotheeast
|
||||
git -C user add config/system.yaml
|
||||
git -C user commit -m "feat: switch GPM to testing channel for Grav 2.0
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: Boot Grav 2.0 and install plugins
|
||||
|
||||
**Files:** None (runtime only)
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: docker-compose.yml from Task 1, GPM config from Task 2
|
||||
- Produces: Running Grav 2.0 instance at `http://localhost:8081` with all plugins installed
|
||||
|
||||
- [ ] **Step 1: Run setup**
|
||||
|
||||
```bash
|
||||
cd /home/mischa/Nextcloud/Projects/travel-blog-intotheeast
|
||||
make setup
|
||||
```
|
||||
|
||||
This starts the container and installs all plugins from `plugins.txt`. First run may take 1-2 minutes as `getgrav/grav` downloads and extracts Grav 2.0 RC.
|
||||
|
||||
Expected output ends with something like:
|
||||
```
|
||||
GPM Packages Installed: admin, email, error, form, login, problems, add-page-by-form, shortcode-gallery-plusplus
|
||||
```
|
||||
|
||||
If `make setup` fails on plugin install with a permission error, fix with:
|
||||
```bash
|
||||
docker exec intotheeast_grav chown -R www-data:www-data /var/www/html/cache /var/www/html/logs /var/www/html/tmp
|
||||
make install-plugins
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify PHP upload limits are applied**
|
||||
|
||||
```bash
|
||||
docker exec intotheeast_grav php -r "echo ini_get('upload_max_filesize') . ' / ' . ini_get('post_max_size');"
|
||||
```
|
||||
|
||||
Expected: `100M / 500M`
|
||||
|
||||
If you see `2M / 8M` (PHP defaults), the ini mount path is wrong. Verify with:
|
||||
```bash
|
||||
docker exec intotheeast_grav php -r "echo php_ini_scanned_files();"
|
||||
```
|
||||
It should include `/usr/local/etc/php/conf.d/php-local.ini`.
|
||||
|
||||
- [ ] **Step 3: Verify site loads**
|
||||
|
||||
```bash
|
||||
curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/
|
||||
```
|
||||
|
||||
Expected: `200`
|
||||
|
||||
If you get `500`, check container logs:
|
||||
```bash
|
||||
docker logs intotheeast_grav --tail 50
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Verify Admin2 loads**
|
||||
|
||||
```bash
|
||||
curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/admin
|
||||
```
|
||||
|
||||
Expected: `200` (Admin2 SPA login page, not the old Twig admin)
|
||||
|
||||
- [ ] **Step 5: Run config and HTTP tests**
|
||||
|
||||
```bash
|
||||
make test-config
|
||||
make test-post
|
||||
```
|
||||
|
||||
`test-config` validates the form YAML config. `test-post` submits the posting form via HTTP and checks an entry is created.
|
||||
|
||||
Expected: both exit 0.
|
||||
|
||||
If `test-post` fails, check the output of:
|
||||
```bash
|
||||
bash scripts/test-post.sh
|
||||
```
|
||||
This is the critical `add-page-by-form` go/no-go test. If it fails with a 500 or the entry isn't created, see the **If add-page-by-form fails** section at the bottom of this plan.
|
||||
|
||||
- [ ] **Step 6: Commit task completion note**
|
||||
|
||||
No new files to commit. Move to Task 4.
|
||||
|
||||
---
|
||||
|
||||
## Task 4: Run Playwright test suite and fix any Admin2 regressions
|
||||
|
||||
**Files:**
|
||||
- Modify: `tests/*.spec.js` (only if tests fail due to Admin2 DOM changes)
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: Running Grav 2.0 from Task 3
|
||||
- Produces: All Playwright tests passing (or updated for Admin2's new DOM)
|
||||
|
||||
- [ ] **Step 1: Run the full UI test suite**
|
||||
|
||||
```bash
|
||||
cd /home/mischa/Nextcloud/Projects/travel-blog-intotheeast
|
||||
make test-ui
|
||||
```
|
||||
|
||||
Expected: 25 tests pass.
|
||||
|
||||
- [ ] **Step 2: If any tests fail, classify the failure**
|
||||
|
||||
For each failing test, determine whether it is:
|
||||
|
||||
**A) A genuine regression** (e.g., posting form broken, tracker page missing entries, gallery not rendering) — these are blockers. Stop, investigate the root cause, and fix the underlying Grav/plugin issue before updating the test.
|
||||
|
||||
**B) An Admin2 DOM change** (e.g., selectors targeting old admin HTML structure like `.admin-menu`, `.grav-nav`, admin-specific CSS classes) — these are acceptable test updates. Update the selector in the test file to match Admin2's new HTML.
|
||||
|
||||
To inspect the current Admin2 DOM for a failing selector:
|
||||
```bash
|
||||
# Check what the admin page actually renders
|
||||
curl -s http://localhost:8081/admin | grep -o '<[^>]*class="[^"]*admin[^"]*"[^>]*>' | head -20
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Update any Admin2 selector regressions**
|
||||
|
||||
For each type-(B) failure, open the relevant test file in `tests/` and update the selector. Example pattern for updating an admin navigation selector:
|
||||
|
||||
Old (targeting classic admin):
|
||||
```js
|
||||
await page.click('.grav-nav-toggle')
|
||||
```
|
||||
|
||||
New (targeting Admin2 SPA — find actual selector from step 2's output):
|
||||
```js
|
||||
await page.click('[data-testid="nav-toggle"]') // replace with actual Admin2 selector
|
||||
```
|
||||
|
||||
After each fix, re-run just that test:
|
||||
```bash
|
||||
npx playwright test tests/<filename>.spec.js --headed
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Re-run full suite to confirm all pass**
|
||||
|
||||
```bash
|
||||
make test-ui
|
||||
```
|
||||
|
||||
Expected: all tests pass.
|
||||
|
||||
- [ ] **Step 5: Commit any test updates**
|
||||
|
||||
If any test files were modified:
|
||||
```bash
|
||||
git add tests/
|
||||
git commit -m "test: update Playwright selectors for Admin2 DOM
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
|
||||
```
|
||||
|
||||
If no test files changed, no commit needed.
|
||||
|
||||
---
|
||||
|
||||
## Task 5: Update production install script for Grav 2.0
|
||||
|
||||
**Files:**
|
||||
- Modify: `scripts/server-install.sh`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: Nothing from prior tasks (independent of Docker)
|
||||
- Produces: `make remote-install` deploys a fresh Grav 2.0 on the production PHP 8.4 server when `GRAV_VERSION=2.0.0-rc.9` and `GRAV_CHANNEL_SUFFIX=?testing` are set in `.env`
|
||||
|
||||
- [ ] **Step 1: Update the wget download line in `scripts/server-install.sh`**
|
||||
|
||||
The script currently downloads Grav with:
|
||||
```bash
|
||||
wget --no-verbose "https://getgrav.org/download/core/grav-admin/$GRAV_VERSION" -O grav-admin.zip
|
||||
```
|
||||
|
||||
Grav 2.0 RC requires `?testing` appended to the URL. Add `GRAV_CHANNEL_SUFFIX` support:
|
||||
|
||||
Old (line ~15 in the file):
|
||||
```bash
|
||||
echo "==> Downloading Grav $GRAV_VERSION"
|
||||
cd "$WEBROOT"
|
||||
wget --no-verbose "https://getgrav.org/download/core/grav-admin/$GRAV_VERSION" -O grav-admin.zip
|
||||
```
|
||||
|
||||
New:
|
||||
```bash
|
||||
echo "==> Downloading Grav $GRAV_VERSION"
|
||||
cd "$WEBROOT"
|
||||
wget --no-verbose "https://getgrav.org/download/core/grav-admin/${GRAV_VERSION}${GRAV_CHANNEL_SUFFIX:-}" -O grav-admin.zip
|
||||
```
|
||||
|
||||
The `${GRAV_CHANNEL_SUFFIX:-}` expands to empty string if unset, keeping stable releases working without any changes to `.env`.
|
||||
|
||||
- [ ] **Step 2: Add GRAV_CHANNEL_SUFFIX to the env var validation block**
|
||||
|
||||
At the top of the script the required vars are validated. `GRAV_CHANNEL_SUFFIX` is optional, so do NOT add it to the `:?` required list. Instead, add a comment above the download step:
|
||||
|
||||
After the `set -e` and required var block, add a comment before the download line:
|
||||
|
||||
```bash
|
||||
# GRAV_CHANNEL_SUFFIX: optional, set to '?testing' for RC/beta releases (e.g. 2.0.0-rc.9)
|
||||
# Leave unset or empty for stable releases.
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Verify the script logic looks correct**
|
||||
|
||||
```bash
|
||||
# Dry-run: simulate what the URL would be with 2.0 RC vars
|
||||
GRAV_VERSION=2.0.0-rc.9 GRAV_CHANNEL_SUFFIX='?testing' bash -c \
|
||||
'echo "https://getgrav.org/download/core/grav-admin/${GRAV_VERSION}${GRAV_CHANNEL_SUFFIX:-}"'
|
||||
```
|
||||
|
||||
Expected output:
|
||||
```
|
||||
https://getgrav.org/download/core/grav-admin/2.0.0-rc.9?testing
|
||||
```
|
||||
|
||||
```bash
|
||||
# Dry-run: simulate stable release (no suffix)
|
||||
GRAV_VERSION=1.7.53 bash -c \
|
||||
'echo "https://getgrav.org/download/core/grav-admin/${GRAV_VERSION}${GRAV_CHANNEL_SUFFIX:-}"'
|
||||
```
|
||||
|
||||
Expected output:
|
||||
```
|
||||
https://getgrav.org/download/core/grav-admin/1.7.53
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add scripts/server-install.sh
|
||||
git commit -m "feat: support GRAV_CHANNEL_SUFFIX for Grav 2.0 RC production install
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## If `add-page-by-form` fails (contingency)
|
||||
|
||||
If `make test-post` in Task 3 step 5 returns a non-zero exit code or the entry is not created, `add-page-by-form` is incompatible with Grav 2.0. The fallback is to write a custom replacement plugin.
|
||||
|
||||
**Do not proceed to Task 4 if the posting workflow is broken.** Instead:
|
||||
|
||||
1. Check the container logs for the specific error:
|
||||
```bash
|
||||
docker logs intotheeast_grav --tail 100 | grep -i "error\|exception\|warning"
|
||||
```
|
||||
|
||||
2. Note the error, stop work, and report back. The custom replacement plugin is a separate task requiring design input from the project owner before implementation.
|
||||
|
||||
The custom plugin would:
|
||||
- Hook `onFormProcessed` (same as `cache-on-save`)
|
||||
- Read form field values (`title`, `content`, `photo`)
|
||||
- Build the page path under `user/pages/01.tracker/`
|
||||
- Write the page file to disk using `Grav\Common\Page\Page`
|
||||
- Merge `cache-on-save` functionality (call `$this->grav['cache']->deleteAll()`)
|
||||
- Replace both `add-page-by-form` and `cache-on-save` with a single plugin
|
||||
|
||||
This is ~200 lines of PHP and ~1 day of work. It should be planned separately.
|
||||
|
||||
---
|
||||
|
||||
## Final smoke test (after all tasks complete)
|
||||
|
||||
Run the full test suite one last time:
|
||||
|
||||
```bash
|
||||
cd /home/mischa/Nextcloud/Projects/travel-blog-intotheeast
|
||||
make test
|
||||
```
|
||||
|
||||
Expected: all three suites (`test-config`, `test-post`, `test-ui`) exit 0.
|
||||
|
||||
Then verify the go/no-go criteria from the spec are all met before merging to `main` or deploying to production.
|
||||
Reference in New Issue
Block a user