Tracker ordering fix + March–April fixture entries #1
@@ -1,2 +1,3 @@
|
|||||||
/plugins/
|
/plugins/
|
||||||
|
!/plugins/cache-on-save/
|
||||||
/data/
|
/data/
|
||||||
|
|||||||
+1
-1
@@ -125,7 +125,7 @@ cache:
|
|||||||
server: null
|
server: null
|
||||||
port: null
|
port: null
|
||||||
twig:
|
twig:
|
||||||
cache: true
|
cache: false
|
||||||
debug: true
|
debug: true
|
||||||
auto_reload: true
|
auto_reload: true
|
||||||
autoescape: true
|
autoescape: true
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
# 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 `/tracker` 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 /app/www/public && 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']->clear()`
|
||||||
|
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 `/tracker` — 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 /app/www/public && 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
|
||||||
|
|
||||||
|
---
|
||||||
@@ -319,6 +319,179 @@ Test URLs:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Post Submission Flow
|
||||||
|
|
||||||
|
These scenarios cover the full round-trip: filling the form → saving → verifying values in the UI and on disk. Use the exact test values specified so that each assertion can be precise.
|
||||||
|
|
||||||
|
**Test data (use verbatim):**
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|---|---|
|
||||||
|
| Title | `QA Test Entry` |
|
||||||
|
| Date & Time | `2026-06-18 10:00` |
|
||||||
|
| Content | `This is the QA test body. Second sentence for length.` |
|
||||||
|
| City | `Tokyo` |
|
||||||
|
| Country | `Japan` |
|
||||||
|
| Latitude | `35.689487` |
|
||||||
|
| Longitude | `139.691711` |
|
||||||
|
| Photos | none (keep simple for first run) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### TC-P.1: Post form requires authentication
|
||||||
|
|
||||||
|
| Step | Action | Expected Result |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | Open private/incognito tab (no session) | — |
|
||||||
|
| 2 | GET http://100.96.115.96:8081/post | Page loads at /post URL (no redirect) but renders the login form inline |
|
||||||
|
| 3 | Inspect page content | Login form fields (username, password) visible; post form fields absent |
|
||||||
|
|
||||||
|
**Automation:** curl /post without auth; assert `login-form-nonce` present AND `data[title]` absent
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### TC-P.2: Post form renders all fields
|
||||||
|
|
||||||
|
| Step | Action | Expected Result |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | Log in at /login | Redirected to /tracker |
|
||||||
|
| 2 | Navigate to /post | Post form page loads (200) |
|
||||||
|
| 3 | Check form fields present | Title, Date & Time, description textarea, Photos upload |
|
||||||
|
| 4 | Check location fields | Latitude, Longitude, City, Country inputs visible |
|
||||||
|
| 5 | Check action buttons | `📍 Get Current Location` and `🌤 Get Weather` buttons visible |
|
||||||
|
| 6 | Check submit button | `Post Entry` button visible |
|
||||||
|
| 7 | Check date field default | Pre-filled with today's date and time (not blank) |
|
||||||
|
|
||||||
|
**Automation:** curl /post with auth; grep for `data[title]`, `data[lat]`, `data[location_city]`, `get-location`, `get-weather`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### TC-P.3: Required field validation
|
||||||
|
|
||||||
|
| Step | Action | Expected Result |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | Log in and open /post | Form loads |
|
||||||
|
| 2 | Leave Title blank, fill in only the description | — |
|
||||||
|
| 3 | Submit form | Page reloads with validation error on Title |
|
||||||
|
| 4 | Error message | Indicates title is required |
|
||||||
|
| 5 | Fill in Title, clear Description/Content, submit | Validation error on Content field |
|
||||||
|
| 6 | Confirm | No new entry file created in pages/01.tracker/ during failed submissions |
|
||||||
|
|
||||||
|
**Manual verification required:** Validation feedback requires browser
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### TC-P.4: Successful post submission — all fields
|
||||||
|
|
||||||
|
| Step | Action | Expected Result |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | Log in and open /post | Form loads |
|
||||||
|
| 2 | Enter Title: `QA Test Entry` | — |
|
||||||
|
| 3 | Set Date to `2026-06-18 10:00` | — |
|
||||||
|
| 4 | Enter Content: `This is the QA test body. Second sentence for length.` | — |
|
||||||
|
| 5 | Enter City: `Tokyo`, Country: `Japan` | — |
|
||||||
|
| 6 | Enter Latitude: `35.689487`, Longitude: `139.691711` | — |
|
||||||
|
| 7 | Leave Photos empty | — |
|
||||||
|
| 8 | Click `Post Entry` | Form submits (POST to /post) |
|
||||||
|
| 9 | Observe result | Success message `Entry posted successfully!` shown on page |
|
||||||
|
| 10 | Form state | Form is reset / fields cleared |
|
||||||
|
|
||||||
|
**Manual verification required:** Form submission and success message require browser
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### TC-P.5: Entry file created on disk with correct values
|
||||||
|
|
||||||
|
| Step | Action | Expected Result |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | After TC-P.4 completes | — |
|
||||||
|
| 2 | Check directory `user/pages/01.tracker/` | Folder `2026-06-18.entry/` exists (add-page-by-form appends template name per `physical_template_name: true`) |
|
||||||
|
| 3 | Read `user/pages/01.tracker/2026-06-18.entry/entry.md` | File exists |
|
||||||
|
| 4 | Verify frontmatter `title` | Equals `QA Test Entry` |
|
||||||
|
| 5 | Verify frontmatter `date` | Equals `2026-06-18 10:00` |
|
||||||
|
| 6 | Verify frontmatter `location_city` | Equals `Tokyo` |
|
||||||
|
| 7 | Verify frontmatter `location_country` | Equals `Japan` |
|
||||||
|
| 8 | Verify frontmatter `lat` | Equals `35.689487` |
|
||||||
|
| 9 | Verify frontmatter `lng` | Equals `139.691711` |
|
||||||
|
| 10 | Verify frontmatter `template` | Equals `entry` |
|
||||||
|
| 11 | Verify frontmatter `published` | Equals `true` |
|
||||||
|
| 12 | Verify page body | Contains `This is the QA test body. Second sentence for length.` |
|
||||||
|
|
||||||
|
**Automation:** Read file from filesystem; parse YAML frontmatter; assert each field value exactly
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### TC-P.6: Entry appears in tracker feed
|
||||||
|
|
||||||
|
| Step | Action | Expected Result |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | BUG-001 fixed — no manual cache clear needed | — |
|
||||||
|
| 2 | GET http://100.96.115.96:8081/tracker | Page loads (200) |
|
||||||
|
| 3 | Entry card present | Card with title `QA Test Entry` visible |
|
||||||
|
| 4 | Date shown on card | `18 Jun 2026` |
|
||||||
|
| 5 | Location badge on card | `📍 Tokyo, Japan` visible |
|
||||||
|
| 6 | Entry card link | `href` points to `/tracker/2026-06-18.entry` |
|
||||||
|
| 7 | Excerpt shown | Partial text of the body content visible |
|
||||||
|
|
||||||
|
**Automation:** curl /tracker; grep for "QA Test Entry", "18 Jun 2026", "Tokyo", "Japan", "/tracker/2026-06-18.entry"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### TC-P.7: Entry detail page shows correct values
|
||||||
|
|
||||||
|
| Step | Action | Expected Result |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | GET http://100.96.115.96:8081/tracker/2026-06-18.entry | Page loads (200) |
|
||||||
|
| 2 | Page title | `QA Test Entry` in `<h1>` |
|
||||||
|
| 3 | Date header | `Thursday, 18 June 2026` (or locale equivalent) |
|
||||||
|
| 4 | Location badge | `📍 Tokyo, Japan` |
|
||||||
|
| 5 | Body content | Full text `This is the QA test body. Second sentence for length.` rendered |
|
||||||
|
| 6 | No gallery | Photo gallery section absent (no photos were uploaded) |
|
||||||
|
| 7 | Back link | `← Back to journal` link present, points to /tracker |
|
||||||
|
|
||||||
|
**Automation:** curl /tracker/2026-06-18.entry; grep for "QA Test Entry", "Tokyo", "Japan", "This is the QA test body", "Back to journal"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### TC-P.8: Entry appears on map and mini-map
|
||||||
|
|
||||||
|
| Step | Action | Expected Result |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | GET http://100.96.115.96:8081/tracker | Mini-map section visible |
|
||||||
|
| 2 | Inspect FEED_ENTRIES JSON | Contains entry with `lat: "35.689487"`, `lng: "139.691711"`, `title: "QA Test Entry"` |
|
||||||
|
| 3 | GET http://100.96.115.96:8081/map | Map page loads |
|
||||||
|
| 4 | Inspect ENTRIES JSON | Contains same entry |
|
||||||
|
|
||||||
|
**Automation:** curl /tracker and /map; grep FEED_ENTRIES and ENTRIES JSON for lat/lng values
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### TC-P.9: Entry appears in stats
|
||||||
|
|
||||||
|
| Step | Action | Expected Result |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | GET http://100.96.115.96:8081/stats | Page loads (200) |
|
||||||
|
| 2 | Entries count | Shows `2` entries (existing test entry + new QA entry) |
|
||||||
|
| 3 | Countries list | `Japan` and `Netherlands` both listed |
|
||||||
|
|
||||||
|
**Automation:** curl /stats; grep entry count and country names
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### TC-P.10: Duplicate date handling
|
||||||
|
|
||||||
|
| Step | Action | Expected Result |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | Submit a second post with the same date `2026-06-18 10:00` | — |
|
||||||
|
| 2 | Observe result | Either: error shown, OR new entry created at a different slug |
|
||||||
|
| 3 | Check filesystem | No silent data loss — original entry intact |
|
||||||
|
|
||||||
|
**Note:** `overwrite_mode: false` on add-page-by-form plugin should prevent overwrite. Behavior on conflict is to be documented here after first run.
|
||||||
|
|
||||||
|
**Manual verification required:** Requires two submissions with same date
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Cross-cutting Tests
|
## Cross-cutting Tests
|
||||||
|
|
||||||
### TC-X.1: Nav links present on all pages
|
### TC-X.1: Nav links present on all pages
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: 'QA Test Entry'
|
||||||
|
date: '2026-06-18 10:00'
|
||||||
|
template: entry
|
||||||
|
published: true
|
||||||
|
hero_image: ''
|
||||||
|
lat: '35.689487'
|
||||||
|
lng: '139.691711'
|
||||||
|
location_city: 'Tokyo'
|
||||||
|
location_country: 'Japan'
|
||||||
|
weather_temp_c: ''
|
||||||
|
weather_desc: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
This is the QA test body. Second sentence for length.
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
namespace Grav\Plugin;
|
||||||
|
|
||||||
|
use Grav\Common\Plugin;
|
||||||
|
use RocketTheme\Toolbox\Event\Event;
|
||||||
|
|
||||||
|
class CacheOnSavePlugin extends Plugin
|
||||||
|
{
|
||||||
|
public static function getSubscribedEvents(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'onFormProcessed' => ['onFormProcessed', 0],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onFormProcessed(Event $event): void
|
||||||
|
{
|
||||||
|
$form = $event['form'];
|
||||||
|
if (!$form) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($form->getName() === 'new-entry') {
|
||||||
|
$this->grav['cache']->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
enabled: true
|
||||||
Reference in New Issue
Block a user