docs: update CLAUDE.md, bugs log, and posting pipeline for Grav 2.0 + trip entity
- CLAUDE.md: add Grav 2.0 upgrade method, Admin2 setup, trip entity architecture, updated paths - bugs-and-fixes.md: fix stale paths, add BUG-004 (Admin2 empty dashboard) and BUG-005 (PHP session path) - posting-pipeline.md: update paths to trips/dailies structure Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
# Bugs & Fixes
|
||||
|
||||
Backlog of confirmed bugs with root cause analysis and implementation spec for the fix.
|
||||
|
||||
---
|
||||
|
||||
## BUG-001 — New entry not visible after form submission
|
||||
|
||||
**Status:** fixed 2026-06-18
|
||||
**Reported:** 2026-06-18
|
||||
|
||||
### Symptom
|
||||
|
||||
After submitting a new post via `/post`, the entry page file is created correctly on disk but does not appear in the `/trips/<active_trip>/dailies` feed or in the Grav Admin panel until the cache is manually flushed.
|
||||
|
||||
### Root cause
|
||||
|
||||
Grav's page-tree cache (`cache/doctrine/`) is not invalidated when `add-page-by-form` writes a new page to disk. The tracker template uses `page.children`, which Grav serves from cache — so the new child page is invisible until the cache is cleared.
|
||||
|
||||
### Workaround (manual)
|
||||
|
||||
Run in terminal after each submission:
|
||||
|
||||
```bash
|
||||
docker exec intotheeast_grav bash -c "cd /var/www/html && php bin/grav clearcache"
|
||||
```
|
||||
|
||||
### Fix spec
|
||||
|
||||
Wire cache-clear into the form process so it happens automatically on every successful submission.
|
||||
|
||||
**Approach — custom Grav plugin event hook:**
|
||||
|
||||
1. Create a small plugin `user/plugins/cache-on-save/` with one event listener:
|
||||
- Listen on `onFormProcessed`
|
||||
- When the form name is `new-entry`, call `$this->grav['cache']->deleteAll()` (note: `clear()` does not exist on `Grav\Common\Cache` in Grav 1.7)
|
||||
2. Enable the plugin in `user/config/plugins/cache-on-save.yaml`
|
||||
|
||||
This is the cleanest approach: it fires exactly once per successful submission, requires no changes to `post-form.md`, and works for any future forms too.
|
||||
|
||||
**Alternative — disable page cache entirely:**
|
||||
|
||||
Set `cache: { enabled: false }` in `system.yaml`. Simpler but degrades frontend performance; not recommended for production.
|
||||
|
||||
### Files to create/modify
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `user/plugins/cache-on-save/cache-on-save.php` | New plugin, ~30 lines |
|
||||
| `user/plugins/cache-on-save/cache-on-save.yaml` | Plugin manifest, enabled: true |
|
||||
| `user/config/plugins/cache-on-save.yaml` | Runtime config, enabled: true |
|
||||
|
||||
### Acceptance criteria
|
||||
|
||||
1. Submit a new post via `/post`
|
||||
2. Navigate to `/trips/<active_trip>/dailies` — the new entry is visible immediately, no manual cache flush needed
|
||||
3. Grav Admin also shows the new page immediately
|
||||
|
||||
---
|
||||
|
||||
## BUG-002 — Stale Twig cache after theme file changes
|
||||
|
||||
**Status:** fixed 2026-06-18
|
||||
**Reported:** 2026-06-18
|
||||
|
||||
### Symptom
|
||||
|
||||
After theme template files are added or modified (e.g., creating `partials/base.html.twig`), Grav's Twig compiled-template cache still holds the old compiled version. Pages that extend the changed file throw 500 errors like "Template partials/base.html.twig is not defined" even though the file exists on disk.
|
||||
|
||||
### Root cause
|
||||
|
||||
Grav caches compiled Twig templates in `cache/twig/`. When a new file is added, existing templates that reference it don't know to recompile — their cache entries are still valid from their own mtime perspective.
|
||||
|
||||
### Workaround (manual)
|
||||
|
||||
Run after any theme file is added or changed:
|
||||
|
||||
```bash
|
||||
docker exec intotheeast_grav bash -c "cd /var/www/html && php bin/grav clearcache"
|
||||
```
|
||||
|
||||
### Fix spec
|
||||
|
||||
Disable Twig template caching in development via `user/config/system.yaml`:
|
||||
|
||||
```yaml
|
||||
twig:
|
||||
cache: false
|
||||
```
|
||||
|
||||
Acceptable for a single-user dev setup — eliminates both BUG-001's side-effect and this bug entirely. Performance cost is negligible at one-user scale. On production, leave Twig cache enabled (it's fine there because template files don't change at runtime).
|
||||
|
||||
**Files to change:**
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `user/config/system.yaml` | Add `twig: { cache: false }` under development section |
|
||||
|
||||
### Acceptance criteria
|
||||
|
||||
1. Add a new theme template file
|
||||
2. Reload any page — no 500 error, template works immediately without manual cache flush
|
||||
|
||||
---
|
||||
|
||||
## BUG-003 — One post per day limit; silent failure on duplicate date
|
||||
|
||||
**Status:** fixed 2026-06-18
|
||||
**Reported:** 2026-06-18
|
||||
|
||||
### Symptom
|
||||
|
||||
Submitting a second post with the same date as an existing entry shows "Entry posted successfully!" but creates no file. The user's post is silently discarded.
|
||||
|
||||
### Root cause
|
||||
|
||||
The `add-page-by-form` plugin built the page slug from date only (`Y-m-d`), producing folder names like `2026-06-18.entry`. With `overwrite_mode: false`, if that folder already exists the plugin skips page creation but does not abort — the `message` process step runs regardless, showing a false success.
|
||||
|
||||
### Fix
|
||||
|
||||
Change the slug template in `user/pages/02.post/post-form.md` to include time and title:
|
||||
|
||||
```twig
|
||||
{{ form.value.date|date('Y-m-d-Hi') }}-{{ form.value.title|lower|regex_replace('/[^a-z0-9]+/', '-')|trim('-') }}
|
||||
```
|
||||
|
||||
Example: title "Arrived in Tokyo" at 14:30 on 2026-06-18 → `2026-06-18-1430-arrived-in-tokyo`
|
||||
|
||||
The slug is locked at creation time. Renaming the title afterwards does not change the URL.
|
||||
|
||||
### Acceptance criteria
|
||||
|
||||
1. Submit two posts on the same day with different times or titles — both appear in `/trips/<active_trip>/dailies` as separate entries
|
||||
2. Renaming a post's title in the frontmatter does not break its URL
|
||||
|
||||
---
|
||||
|
||||
## BUG-004 — Admin2 shows empty dashboard after Grav 2.0 upgrade
|
||||
|
||||
**Status:** fixed 2026-06-19
|
||||
|
||||
### Symptom
|
||||
|
||||
After installing Grav 2.0 + Admin2, logging in shows an empty dashboard with no sidebar navigation (only a Settings item visible). Pages and content are not accessible.
|
||||
|
||||
### Root causes (three separate issues)
|
||||
|
||||
**A) Wrong user account type.** `system.yaml` had `accounts.type: regular` (old file-based system). Admin2's API plugin uses the Flex user collection to look up accounts. With `regular`, the API saw zero users and entered setup-wizard mode.
|
||||
|
||||
**B) Wrong pages type.** `system.yaml` had `pages.type: regular`. Admin2's pages API requires `pages.type: flex` to serve the page tree.
|
||||
|
||||
**C) Missing `api.*` permissions on user account.** Grav 2.0 Admin2 uses a new `api.*` permission namespace (`api.super`, `api.access`, etc.) instead of the old `admin.super`. A user with only `access.admin.super: true` appears as a non-admin to Admin2.
|
||||
|
||||
### Fix
|
||||
|
||||
In `user/config/system.yaml`:
|
||||
```yaml
|
||||
accounts:
|
||||
type: flex
|
||||
pages:
|
||||
type: flex
|
||||
```
|
||||
|
||||
In `user/accounts/<username>.yaml`:
|
||||
```yaml
|
||||
access:
|
||||
admin:
|
||||
login: true
|
||||
super: true # keep for backward compat
|
||||
api:
|
||||
super: true # required by Admin2
|
||||
access: true # required by Admin2
|
||||
```
|
||||
|
||||
### Notes
|
||||
|
||||
- `api.super: true` causes Admin2 to grant all sub-permissions automatically (`api.pages`, `api.config`, etc.)
|
||||
- JWT secret in `user/plugins/api/api.yaml` can stay empty — HMAC-SHA256 works with an empty key locally; production generates its own secure secret
|
||||
- The old `admin` plugin must be disabled (`enabled: false`) to avoid route conflict with `admin2`
|
||||
|
||||
---
|
||||
|
||||
## BUG-005 — PHP session fails after Grav 2.0 container upgrade
|
||||
|
||||
**Status:** fixed 2026-06-19
|
||||
|
||||
### Symptom
|
||||
|
||||
After replacing Grav core files inside the container, all pages return a CRITICAL error in `logs/grav.log`: `Failed to start session: session_start(): Failed to read session data: files (path: )`. Site is inaccessible.
|
||||
|
||||
### Root cause
|
||||
|
||||
The `getgrav/grav` Docker image's PHP configuration does not set `session.save_path`. Grav 1.7 worked because the image's default PHP config included it; the updated image layer did not.
|
||||
|
||||
### Fix
|
||||
|
||||
Add to `php/php-local.ini`:
|
||||
```ini
|
||||
session.save_path = /tmp
|
||||
```
|
||||
|
||||
Restart the container to pick up the change. This file is bind-mounted into the container so no image rebuild is needed.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,132 @@
|
||||
# Daily Entry Posting Pipeline
|
||||
|
||||
Two ways to create a daily entry: the mobile frontend form at `/post`, or directly from the Grav Admin2 panel. Both produce the same page structure under `user/pages/01.trips/<active_trip>/01.dailies/`.
|
||||
|
||||
The active trip is set in `user/config/site.yaml` → `active_trip`. The post form's `pageconfig.parent` in `post-form.md` must be kept in sync with this value.
|
||||
|
||||
---
|
||||
|
||||
## Frontmatter Reference
|
||||
|
||||
Every entry page (`template: entry`) supports these frontmatter fields:
|
||||
|
||||
| Field | Type | Required | Notes |
|
||||
|---|---|---|---|
|
||||
| `title` | string | ✅ | Entry headline |
|
||||
| `date` | datetime | ✅ | Format: `Y-m-d H:i` (e.g. `2026-06-17 10:00`) |
|
||||
| `template` | string | ✅ | Always `entry` |
|
||||
| `published` | bool | ✅ | `true` to show in tracker feed |
|
||||
| `lat` | string | — | Latitude decimal degrees (e.g. `52.3676`) |
|
||||
| `lng` | string | — | Longitude decimal degrees (e.g. `4.9041`) |
|
||||
| `location_city` | string | — | City name shown under the title (e.g. `Kyoto`) |
|
||||
| `location_country` | string | — | Country name shown under the title (e.g. `Japan`) |
|
||||
| `weather_desc` | string | — | Condition label — must be one of the values below |
|
||||
| `weather_temp_c` | number | — | Temperature in Celsius (displayed rounded, e.g. `19`) |
|
||||
| `hero_image` | string | — | Filename of the hero image (e.g. `photo.jpg`). Leave blank to auto-select the first uploaded image. |
|
||||
|
||||
**`weather_desc` allowed values** (matched to emoji icons in `entry.html.twig`):
|
||||
`Sunny` · `Partly cloudy` · `Cloudy` · `Foggy` · `Drizzle` · `Rain` · `Snow` · `Thunderstorm`
|
||||
|
||||
**Page media (photos):** images are stored as files in the page folder (`user/pages/01.tracker/<slug>/`). All images in the folder are shown in the gallery. `hero_image` pins one as the full-width header.
|
||||
|
||||
**Example complete frontmatter:**
|
||||
```yaml
|
||||
---
|
||||
title: 'First Day in Kyoto'
|
||||
date: '2026-07-20 09:30'
|
||||
template: entry
|
||||
published: true
|
||||
lat: '35.0116'
|
||||
lng: '135.7681'
|
||||
location_city: 'Kyoto'
|
||||
location_country: 'Japan'
|
||||
weather_desc: 'Sunny'
|
||||
weather_temp_c: 28
|
||||
hero_image: 'temple.jpg'
|
||||
---
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Flow 1 — Mobile Frontend Form (`/post`)
|
||||
|
||||
This is the primary posting flow, designed for one-handed phone use.
|
||||
|
||||
```
|
||||
Browser → /post (post-form.md)
|
||||
└─ Grav Form plugin validates fields
|
||||
└─ add-page-by-form plugin (onFormProcessed)
|
||||
├─ reads pageconfig.parent (/trips/japan-korea-2026/dailies) and pageconfig.slug_field (date + title)
|
||||
├─ reads pagefrontmatter (template: entry, published: true)
|
||||
├─ merges form field values into new page frontmatter
|
||||
├─ writes user/pages/01.trips/<active_trip>/01.dailies/<slug>/entry.md
|
||||
└─ moves uploaded photos into the page folder
|
||||
└─ cache-on-save plugin (onFormProcessed)
|
||||
└─ calls $grav['cache']->deleteAll() so tracker feed shows the entry immediately
|
||||
└─ form shows success message, resets fields
|
||||
```
|
||||
|
||||
**The form fields and their mapping to frontmatter:**
|
||||
|
||||
| Form field | Frontmatter key | Notes |
|
||||
|---|---|---|
|
||||
| `title` | `title` | Required |
|
||||
| `date` | `date` | Defaults to current datetime |
|
||||
| `content` | page body (markdown) | Required |
|
||||
| `photos` | page media files | Uploaded to page folder |
|
||||
| `lat` | `lat` | Filled via "Get Location" button |
|
||||
| `lng` | `lng` | Filled via "Get Location" button |
|
||||
| `location_city` | `location_city` | Manual text entry |
|
||||
| `location_country` | `location_country` | Manual text entry |
|
||||
| `weather_temp_c` | `weather_temp_c` | Hidden — set by weather JS widget |
|
||||
| `weather_desc` | `weather_desc` | Hidden — set by weather JS widget |
|
||||
|
||||
**Slug format:** `<YYYY-MM-DD>.<slugified-title>` (controlled by `slug_field: 'date,title'` in `post-form.md`).
|
||||
|
||||
**Security:** the `/post` page requires `access: site.login: true` — anonymous visitors get redirected to login.
|
||||
|
||||
---
|
||||
|
||||
## Flow 2 — Admin Panel (sit-down workflow)
|
||||
|
||||
Use this for drafts, scheduled posts, or editing existing entries.
|
||||
|
||||
1. Log in at `/admin`
|
||||
2. Go to **Pages** → **Add Page**
|
||||
3. Set:
|
||||
- **Page Title:** your entry title
|
||||
- **Parent Page:** `/trips/japan-korea-2026/dailies` (adjust to active trip)
|
||||
- **Page Template:** `entry`
|
||||
4. Fill in the **Entry** tab fields (city, country, lat/lng, weather)
|
||||
5. Write content in the **Content** tab
|
||||
6. Upload photos via the **Media** tab
|
||||
7. Set `published: true` (or leave `false` for a draft)
|
||||
8. For scheduling: set `publish_date` in **Options** → **Scheduling**
|
||||
9. Save
|
||||
|
||||
The Admin form fields are defined by `user/themes/intotheeast/blueprints/entry.yaml`.
|
||||
|
||||
**Drafts:** set `published: false` — the entry won't appear in the tracker feed until you flip it to `true`. Useful for writing ahead of time on the road.
|
||||
|
||||
**Scheduling:** Grav supports `publish_date` and `unpublish_date` in page frontmatter. Set them in the Admin Options tab. Requires `pages.publish_dates: true` in `system.yaml` (already enabled).
|
||||
|
||||
---
|
||||
|
||||
## Page folder structure
|
||||
|
||||
```
|
||||
user/pages/01.trips/
|
||||
└─ japan-korea-2026/ ← trip entity (active_trip in site.yaml)
|
||||
├─ trip.md ← trip page (title, date_start, date_end, cover_image, album_url)
|
||||
├─ *.gpx ← GPX route files (served as media, rendered on map)
|
||||
├─ 01.dailies/
|
||||
│ └─ 2026-07-20-1430-first-day-in-kyoto.entry/
|
||||
│ ├─ entry.md ← frontmatter + markdown body
|
||||
│ ├─ temple.jpg ← hero image (referenced by hero_image)
|
||||
│ └─ market.jpg ← additional gallery image
|
||||
├─ 02.map/map.md
|
||||
├─ 03.stats/stats.md
|
||||
└─ 04.stories/stories.md
|
||||
```
|
||||
|
||||
The entry folder name follows `<YYYY-MM-DD-HHmm>-<slug>.entry`. Grav uses this for ordering and routing. The `.entry` suffix enables the `entry` template.
|
||||
Reference in New Issue
Block a user