docs(claude-md): fix four stale facts; document testing, dev commands, patches
Audit of the root CLAUDE.md (scored 76/100) found the architecture and remote-ops coverage strong but the test workflow entirely undocumented and several facts drifted from the tree. Corrections (verified against the checkout): - active_trip was japan-korea-2026; committed value is /trips/denmark-2026 and no japan-korea trip folder exists. Also note the value is a route. - Admin2 2.0.10 -> 2.0.12 (installed version). - demo-load/demo-reset described as italy-only; the Makefile loops over every fixture trip under user/docs/demo/trips/. - user/ gitignore claim omitted the three un-ignored site-owned plugins and the secret/env exclusions. Additions: - Section 3 "Testing": make test/test-config/test-post/test-ui, the auto-created testrunner account, Playwright layout, the auth.setup.js storageState dependency, and GRAV_BASE_URL for worktree servers. - Local dev command table, plus which theme assets are build outputs (js/src -> bundles) versus hand-authored (css/style.css, css/tokens.css). - Custom plugins: story-blocks and entry-actions alongside cache-on-save. - Local plugin patches: install-plugins overwrites git-ignored third-party plugins; deploy/patches/ + apply-plugin-patches is the tracked fix path. - travel-memories service on 8082; make pixelfed-import. Every make target and file path referenced was verified to resolve. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,7 @@
|
|||||||
### Current stack
|
### Current stack
|
||||||
|
|
||||||
- **Grav:** 2.0.7 stable (baked into the custom Docker image via `Dockerfile`; server upgrades in place via `bin/gpm self-upgrade`)
|
- **Grav:** 2.0.7 stable (baked into the custom Docker image via `Dockerfile`; server upgrades in place via `bin/gpm self-upgrade`)
|
||||||
- **Admin:** Admin2 v2.0.10 (plugin slug: `admin2`, NOT `admin`)
|
- **Admin:** Admin2 v2.0.12 (plugin slug: `admin2`, NOT `admin`)
|
||||||
- **GPM channel:** `stable` — set in `user/config/system.yaml` → `gpm.releases` (authoritative). `GRAV_CHANNEL=production` in `docker-compose.yml` is cosmetic/consistency only
|
- **GPM channel:** `stable` — set in `user/config/system.yaml` → `gpm.releases` (authoritative). `GRAV_CHANNEL=production` in `docker-compose.yml` is cosmetic/consistency only
|
||||||
- **Plugin management:** `admin2`, `api`, and `flex-objects` are now **GPM-managed via `plugins.txt`** (installed by `make install-plugins`), no longer hand-extracted from the core bundle. `git-sync` stays **remote-only** — never in `plugins.txt`
|
- **Plugin management:** `admin2`, `api`, and `flex-objects` are now **GPM-managed via `plugins.txt`** (installed by `make install-plugins`), no longer hand-extracted from the core bundle. `git-sync` stays **remote-only** — never in `plugins.txt`
|
||||||
- **Docker image:** `getgrav/grav` with `GRAV_CHANNEL=production`
|
- **Docker image:** `getgrav/grav` with `GRAV_CHANNEL=production`
|
||||||
@@ -24,12 +24,43 @@
|
|||||||
|
|
||||||
### Dev server
|
### Dev server
|
||||||
|
|
||||||
The Docker dev server runs at **http://localhost:8081** (mapped from container port 80 in `docker-compose.yml`).
|
The Docker dev server runs at **http://localhost:8081** (mapped from container port 80 in `docker-compose.yml`). A second service, `travel-memories`, runs at **http://localhost:8082**. Both ports and the container name are overridable via `GRAV_PORT` / `TM_PORT` / `GRAV_CONTAINER` — a worktree's `.worktree-env` sets these so isolated servers never collide (see "Dual-repo submodule structure").
|
||||||
|
|
||||||
|
### Local dev commands
|
||||||
|
|
||||||
|
| Command | What it does |
|
||||||
|
|---|---|
|
||||||
|
| `make setup` | One-shot first run: `build` → `start` → `install-plugins` → `fix-perms` |
|
||||||
|
| `make start` / `make stop` | Bring the compose stack up / down (`start-grav` = Grav service only) |
|
||||||
|
| `make build` | Rebuild the custom Docker image (after `Dockerfile` changes) |
|
||||||
|
| `make build-assets` | Rebuild theme JS/CSS bundles in a `node:20-alpine` container |
|
||||||
|
| `make install-plugins` | GPM-install everything in `plugins.txt`, then re-apply local patches |
|
||||||
|
| `make fix-perms` | Fix ownership in the container after root-owned writes |
|
||||||
|
|
||||||
|
**`make build-assets` is mandatory after editing anything in `user/themes/intotheeast/js/src/`.** Sources live in `js/src/`; esbuild writes the committed bundles — `js/main.js`, `js/map.js`, `js/feed-actions.js`, `js/trip-publish.js`, `js/post/`, and the CSS extracted into `css-compiled/`. **Never hand-edit those.** By contrast `css/style.css` and `css/tokens.css` are hand-authored sources, not build outputs. `build-assets` runs as your host UID (`--user`) so the outputs in the bind-mounted `user/` tree are not root-owned.
|
||||||
|
|
||||||
|
### Custom plugins
|
||||||
|
|
||||||
|
Three plugins are site-owned and tracked in the `user/` repo (everything else under `user/plugins/` is GPM-managed and git-ignored):
|
||||||
|
|
||||||
|
| Plugin | Role |
|
||||||
|
|---|---|
|
||||||
|
| `cache-on-save` | Clears the page-tree cache on `new-entry` submits, and derives the write target from `site.active_trip` (`onFormValidationProcessed` → `setData('parent', …)`) |
|
||||||
|
| `story-blocks` | Storytelling shortcode blocks for long-form stories (depends on `shortcode-core`) |
|
||||||
|
| `entry-actions` | Owner-only, active-trip-scoped journal entry actions (delete) via the Grav API |
|
||||||
|
|
||||||
|
### Local plugin patches
|
||||||
|
|
||||||
|
Third-party plugins live in the **git-ignored** `user/plugins/`, so local fixes to them do not travel with the content repo and are **overwritten by `make install-plugins`** or a fresh image build. Keep the fix as a tracked patch in `deploy/patches/` instead:
|
||||||
|
|
||||||
|
- `make apply-plugin-patches` — idempotent `git apply` (skips already-applied patches). `make install-plugins` runs it automatically as its last step
|
||||||
|
- `make remote-apply-plugin-patches-test` / `-prod` — piped over SSH into `patch -p1 --forward`; also runs automatically after a remote plugin install
|
||||||
|
- Details and the current patch list: `deploy/patches/README.md`
|
||||||
|
|
||||||
### Trip entity architecture
|
### Trip entity architecture
|
||||||
|
|
||||||
The site is structured around Trip entities. Key facts:
|
The site is structured around Trip entities. Key facts:
|
||||||
- Active trip is set in `user/config/site.yaml` → `active_trip: japan-korea-2026`
|
- Active trip is set in `user/config/site.yaml` → `active_trip` (currently `/trips/denmark-2026`). The value is a **route**, not a bare slug
|
||||||
- Trip pages live at `user/pages/01.trips/<slug>/`
|
- Trip pages live at `user/pages/01.trips/<slug>/`
|
||||||
- Each trip has two content subfolders: `01.dailies/` (journal entries) and `04.stories/` (stories). The former `02.map/` and `03.stats/` standalone views were **removed** (2026-07-04, see `docs/working/plans/2026-07-04-standalone-page-cleanup.md`) — map and stats now render inline on the trip page
|
- Each trip has two content subfolders: `01.dailies/` (journal entries) and `04.stories/` (stories). The former `02.map/` and `03.stats/` standalone views were **removed** (2026-07-04, see `docs/working/plans/2026-07-04-standalone-page-cleanup.md`) — map and stats now render inline on the trip page
|
||||||
- `01.dailies/` and `04.stories/` are `routable:false` **data containers** — visiting `/trips/<slug>/dailies` or `/stories` directly 404s/redirects; their children (entries/stories) render at their own detail URLs and are aggregated by the trip page
|
- `01.dailies/` and `04.stories/` are `routable:false` **data containers** — visiting `/trips/<slug>/dailies` or `/stories` directly 404s/redirects; their children (entries/stories) render at their own detail URLs and are aggregated by the trip page
|
||||||
@@ -141,12 +172,13 @@ For a full upgrade/deploy through local → test → prod (ordered steps, smoke
|
|||||||
- `make content-push` — commit and push `user/` to Gitea (triggers production pull via webhook)
|
- `make content-push` — commit and push `user/` to Gitea (triggers production pull via webhook)
|
||||||
- `make content-pull` — pull latest from Gitea to local
|
- `make content-pull` — pull latest from Gitea to local
|
||||||
- `plugins.txt` is manually maintained — installing a plugin via Admin does NOT update it
|
- `plugins.txt` is manually maintained — installing a plugin via Admin does NOT update it
|
||||||
- `make demo-load` — load demo content into `italy-2026-demo` trip (12 journal entries + 4 stories + 7 GPX files); source in `user/docs/demo/trips/italy-2026-demo/`
|
- `make demo-load` — load **every** fixture trip under `user/docs/demo/trips/` into the pages tree (currently `italy-2026-demo` and `no-photos-demo`). Add a new fixture by dropping a trip folder there; no Makefile edit needed
|
||||||
- `make demo-reset` — remove the entire `italy-2026-demo` pages folder and clear cache (full reset; re-run demo-load to restore)
|
- `make demo-reset` — remove the demo trips' pages folders and clear cache (full reset; re-run `demo-load` to restore)
|
||||||
|
- `make pixelfed-import` — import posts from Pixelfed via `scripts/pixelfed-import.py`
|
||||||
|
|
||||||
### User repo gitignore
|
### User repo gitignore
|
||||||
|
|
||||||
Only these folders are tracked in the `user/` Git repo: `pages/`, `config/`, `accounts/`, `themes/`. The `plugins/` and `data/` folders are excluded.
|
Only these folders are tracked in the `user/` Git repo: `pages/`, `config/`, `accounts/`, `themes/`. The `plugins/` and `data/` folders are excluded — **except** the three site-owned plugins, which are un-ignored explicitly (see "Custom plugins" below). Also ignored: the test accounts, `italy-2026-demo` pages, secrets (`config/plugins/git-sync.yaml`, `config/security.yaml`, `api-private.php`), and the whole `env/` override tree.
|
||||||
|
|
||||||
### Dual-repo submodule structure
|
### Dual-repo submodule structure
|
||||||
|
|
||||||
@@ -253,3 +285,21 @@ Every plan in `docs/working/plans/` must have a `**Status:**` line immediately a
|
|||||||
**When asked what's open:** surface `Not started` and `In progress` plans. Show `Deferred` plans but label them clearly. Omit `Complete` and `Abandoned` unless explicitly asked.
|
**When asked what's open:** surface `Not started` and `In progress` plans. Show `Deferred` plans but label them clearly. Omit `Complete` and `Abandoned` unless explicitly asked.
|
||||||
|
|
||||||
**When finishing a plan:** update the `**Status:**` field in the plan file to `✅ Complete (YYYY-MM-DD)` before closing the session. This applies whether execution was done by Claude directly, via the superpowers:executing-plans skill, or via superpowers:subagent-driven-development.
|
**When finishing a plan:** update the `**Status:**` field in the plan file to `✅ Complete (YYYY-MM-DD)` before closing the session. This applies whether execution was done by Claude directly, via the superpowers:executing-plans skill, or via superpowers:subagent-driven-development.
|
||||||
|
|
||||||
|
## 3. Testing
|
||||||
|
|
||||||
|
**The dev server must be running** (`make start`) — every suite drives the live site over HTTP.
|
||||||
|
|
||||||
|
| Command | Scope |
|
||||||
|
|---|---|
|
||||||
|
| `make test` | Everything: `test-config` → `test-post` → `test-ui` |
|
||||||
|
| `make test-config` | Form/config sanity via `scripts/test-form-config.sh` |
|
||||||
|
| `make test-post` | End-to-end post submission via `scripts/test-post.sh` |
|
||||||
|
| `make test-ui` | Playwright suite (`npx playwright test`) |
|
||||||
|
|
||||||
|
- **Test account is automatic.** `test-post` and `test-ui` depend on `test-account`, which creates a `testrunner` admin (password `Testpass1234`) inside the container if absent. It is git-ignored — never commit it, and keep the password free of shell/Make/URL-special characters since several consumers interpolate it.
|
||||||
|
- **Playwright layout:** config at `playwright.config.js`, specs under `tests/ui/` (`a11y`, `auth`, `dailies`, `gpx`, `home`, `maps`, `nav`, `post`, `stories`, `trip`), shared helpers in `tests/ui/helpers.js`, global setup/teardown in `tests/`.
|
||||||
|
- **Auth is a dependency project.** `auth.setup.js` runs first and writes `tests/.auth/user.json`; the `chromium` project reuses it as `storageState`. Don't add per-test logins.
|
||||||
|
- **Base URL:** defaults to `http://localhost:8081`; override with `GRAV_BASE_URL` (required when testing a worktree's isolated server on `8090+`).
|
||||||
|
- Single spec / focused run: `npx playwright test tests/ui/maps` (add `--headed` to watch). `retries: 0` and screenshots-on-failure only, so a failure is a real failure.
|
||||||
|
- **`window.tripMap` / `window.homeMap` are asserted by the map specs** — any surface using the `entry-map` partial must keep assigning them (see "One map path" above).
|
||||||
|
|||||||
Reference in New Issue
Block a user