Five weeks of undocumented evolution left the docs describing a site that
partly no longer exists, with nothing marking which documents were historical.
The code is treated as the source of truth throughout; every claim below was
verified against code, config or the Makefile rather than inferred.
Two mechanisms, following patterns the repo already used:
- docs/reference/superseded-decisions.md (new) — one authoritative table of all
14 reversals: what was planned, where, what is true now, when, and why. Plus
a short list of decisions that were NOT reversed, since their planning docs
are old enough to look suspect.
- Inline "> **Superseded ...**" notes at each stale claim, so a claim can never
be read un-corrected. This mirrors the existing "> History:" notes in
architecture.md and "> **Changed 2026-07:**" in trip-switching.md.
Scope split by tense: present-tense docs (CLAUDE.md, reference/, guides/,
README.md, CONCEPTS.md) are corrected; past-tense records (plans/, specs/,
milestones/, summary.md, pm-analysis.md) are annotated only, never rewritten —
their staleness is what makes them records.
Present-tense corrections:
- CLAUDE.md asserted css-compiled/ is generated from css/style.css and
css/tokens.css. That source relationship does not exist: css/ is hand-authored
and served directly via assets.addCss in partials/base.html.twig, while
css-compiled/ is esbuild output from the CSS imports inside js/src/*.js.
Highest-severity finding — an always-loaded file inviting a hand-edit of a
generated bundle.
- README.md documented every remote-* target without the -test/-prod suffix
guard-env requires, so its entire server runbook was unrunnable, and listed
7 of ~20 targets while CLAUDE.md designates it authoritative for the full
list. Rewritten with all targets, grouped, and the suffix rule stated.
- README.md told readers to "git clone" into user/, which is a submodule.
- architecture.md: nav is Home + Trips + (authenticated) New Post, not
"Home + Past Trips only"; template tree omitted trips.html.twig,
post-form.html.twig and forms/, and placed base.html.twig at templates/ root
rather than in partials/; entry-actions has three API routes, not just delete;
added the undocumented css-compiled/maplibre-gl.css output and a section on
the /post pin editor as the one sanctioned non-entry-map map.
- design-system.md: documented 13 colour tokens against 19 in tokens.css
(missing --color-error, --color-draft-accent and four glass overlays); claimed
"all 3 map templates"; and described --color-canvas as "white".
- design-system-light.md documented a light palette in present tense. No light
mode exists — tokens.css has a single :root block, no prefers-color-scheme or
data-theme switch, and no light hex appears in css/. Banner added.
- posting.md said photos were optional; they are required, 1-6. It documented
hero_image, which was removed for entries (stories keep it). It had no mention
of the frontend edit flow or photo editor, both shipped 2026-07-08. Photo
files are photo-01..NN, zero-padded.
- working/README.md advertised summary.md as the project's "current state" while
summary.md describes Leaflet, /tracker, /map and /stats. Most misleading line
in the tree.
- CLAUDE.md: recorded js/src/location-map.js as the one sanctioned exception to
the single-map-path rule, and documented that make start/setup fail on a clean
checkout because docker-compose.yml still builds a travel-memories service
whose source moved out in a80b0a9.
Also: 2026-07-23-post-form-location-override.md read "Not started" while merged
in user/ as dd19995; status corrected.
Findings that are not documentation problems — the compose breakage, a
repeatable drift check, the unused shortcode-gallery-plusplus, and demo fixtures
for retired views — are collected in
docs/working/2026-07-25-doc-drift-recommendations.md and deliberately not acted
on. Design and verification method: docs/working/specs/2026-07-25-docs-reconciliation-design.md
The submodule gitlink is deliberately not bumped.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
9.0 KiB
Milestone 1 Spec — Entry Enrichment
Goal: Every entry is richer out of the box — location name shown, weather auto-captured, photos in a proper gallery, hero image visible on the feed.
Historical — written 2026-06-21. Mostly shipped as specified; three details reversed.
Still true: the location badge, Open-Meteo weather auto-fetch with its eight
weather_descvalues, and the entry photo gallery. Reversed since:
- §1.5 gallery is PhotoSwipe, not
shortcode-gallery-plusplus(R10).- §1.6
hero_imageno longer exists on entries — the hero is the first uploaded photo, and the owner controls photo order by drag-reorder (R7). Stories still usehero_image.- Photos are now required (1–6 per entry), not optional (R8).
- "Tracker feed" is the trip page and the home active-trip view; there is no
/tracker(R3).Details:
../../reference/superseded-decisions.md.
User Stories
- As a traveler (Mischa), when I submit the post form, I want my current weather conditions auto-filled so I don't have to look them up manually.
- As a traveler, I want to type my city and country once and have it appear on the entry and in the feed card, so readers know where I am without reading the whole post.
- As a reader, when I scan the feed, I want to see a thumbnail photo and location for each entry so I can quickly get a sense of where Mischa is and whether to read the full entry.
- As a reader, when I open an entry, I want to see all uploaded photos in a gallery I can browse, not a wall of raw images.
- As a traveler, when I submit a form without photos, the entry should still display cleanly with no broken image placeholders.
Feature Details
1.1 — Location Name Field on Post Form
What: Add two text fields to the post form: location_city and location_country.
Behavior:
- Both are optional (GPS coordinates are also optional)
- Placeholder text: "e.g. Kyoto" and "e.g. Japan"
- Displayed below the lat/lng fields
- On submit, stored in entry frontmatter as
location_cityandlocation_country - On the form, shown as a single labeled group "Location Name" with two side-by-side inputs on desktop, stacked on mobile
Edge cases:
- If left blank: entry shows no location badge. No error, no broken UI.
- Long city names (e.g. "Ulaanbaatar") must not overflow card layout.
- Special characters (accents, non-Latin) must render correctly.
Mobile behavior: Both fields full-width, stacked, 44px min touch targets.
1.2 — Weather Auto-Fetch on Post Form
What: A "Get Weather" button on the post form that calls the Open-Meteo free API (no API key) using the lat/lng already entered, and fills hidden weather fields.
Fields to fetch and store:
weather_temp_c— temperature in Celsius (integer)weather_desc— short description: one of: Sunny, Partly cloudy, Cloudy, Foggy, Drizzle, Rain, Snow, Thunderstorm (derived from WMO weather code)
WMO code mapping (Open-Meteo uses WMO codes):
- 0 → Sunny
- 1,2 → Partly cloudy
- 3 → Cloudy
- 45,48 → Foggy
- 51,53,55,56,57 → Drizzle
- 61,63,65,66,67,80,81,82 → Rain
- 71,73,75,77,85,86 → Snow
- 95,96,99 → Thunderstorm
API call:
https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lng}¤t=temperature_2m,weather_code&temperature_unit=celsius
UX flow:
- User fills in lat/lng (manually or via "Get Location" button)
- User taps "Get Weather" button
- Button shows "Fetching…" while loading
- On success: fills temp and desc fields (visible, editable text inputs)
- On failure (no network, no lat/lng): shows inline error "Could not fetch weather — enter manually"
Edge cases:
- If lat/lng not filled when button tapped: show inline error "Enter coordinates first"
- Weather fields are always editable manually (auto-fill is a convenience, not mandatory)
- If weather fields left blank: entry shows no weather badge. No broken UI.
- Open-Meteo returns current conditions, not historical — this is fine for posting in real time
Mobile behavior: "Get Weather" button is full-width, 44px height, placed immediately below the lat/lng + location name fields.
1.3 — Weather Display on Entry Page
What: If weather_temp_c or weather_desc is present in frontmatter, display a weather badge on the entry page.
Display format: ☀️ Sunny · 28°C (icon + description + temperature)
- Icon chosen from a small set based on
weather_desc:- Sunny → ☀️
- Partly cloudy → ⛅
- Cloudy → ☁️
- Foggy → 🌫️
- Drizzle → 🌦️
- Rain → 🌧️
- Snow → ❄️
- Thunderstorm → ⛈️
Placement: In the entry header, between the date and the body text. Same line as GPS coordinates if those are shown.
Edge cases:
- Only temp, no desc → show temp only
- Only desc, no temp → show desc only
- Neither → hide weather section entirely
- Temperature should always be integer (round if float)
1.4 — Location Badge on Feed Cards and Entry Page
What: Display location_city, location_country as a small badge on tracker feed cards and at the top of entry pages.
Feed card: Below the date, above the excerpt. Format: 📍 Kyoto, Japan
Entry page: In the header below the date, above the content. Format: 📍 Kyoto, Japan
Edge cases:
- Only city, no country →
📍 Kyoto - Only country, no city →
📍 Japan - Neither → location badge hidden entirely
- Long location names: truncate with ellipsis at 30 chars on cards (full text on entry page)
1.5 — Photo Gallery on Entry Page
What: Photos uploaded to an entry should display in a responsive grid gallery with lightbox (click to enlarge).
Implementation approach: Use Grav's native media collection for the entry page. Each .entry folder contains its photos. Render them in a grid in entry.html.twig. Use a minimal vanilla JS lightbox — no external framework.
Gallery behavior:
- Photos displayed in a 2-column grid on mobile, 3-column on desktop
- Each thumbnail is square-cropped, 150px on mobile
- Clicking/tapping a thumbnail opens a lightbox overlay
- Lightbox: dark overlay, full-size image centered, tap/click outside or press Escape to close
- Left/right navigation arrows in lightbox (swipe on mobile)
- No captions needed for v1
Edge cases:
- 0 photos: gallery section hidden entirely
- 1 photo: still uses grid (single item), lightbox works
- Many photos (>10): gallery still renders (no hard limit on display)
- Non-image files in the media folder: skip them (only render jpg, jpeg, png, webp, gif)
1.6 — Hero Image on Tracker Feed Cards
What: If an entry has photos, the first photo (or the one named in hero_image frontmatter) appears as a thumbnail on the tracker feed card.
Implementation: In tracker.html.twig, for each entry:
- If
entry.header.hero_imageis set, useentry.media[entry.header.hero_image] - Else, use the first image in
entry.mediasorted by name - Render as a 16:9 aspect-ratio thumbnail, full width of card, above the title
Edge cases:
- No photos: card shows no image, just text. No broken
<img>tag. hero_imageset but file missing: fall back to first media file, or no image- Very tall/wide images: CSS
object-fit: covermaintains card aspect ratio
Out of Scope (Milestone 1)
- Map features (Milestone 2)
- Statistics page (Milestone 3)
- Video support
- Comments or reactions
- Automated reverse geocoding (city name comes from form input, not auto-detected)
- Altitude display (data may not be present)
- Historical weather (Open-Meteo current endpoint only)
Acceptance Criteria
- Post form has
location_cityandlocation_countryfields that save to entry frontmatter - Post form has "Get Weather" button that fills
weather_temp_candweather_descvia Open-Meteo when lat/lng are provided - Entry page shows weather badge when weather fields are present; hidden when absent
- Entry page shows location badge
📍 City, Countrywhen location fields are present; hidden when absent - Tracker feed card shows location badge when present
- Tracker feed card shows a hero image when photos exist for an entry
- Entry page shows a 2-col (mobile) / 3-col (desktop) photo grid
- Clicking any photo opens a full-screen lightbox with prev/next navigation
- Pressing Escape or clicking outside lightbox closes it
- All fields are optional — empty values produce no broken UI elements
- All interactive elements meet 44px minimum touch target on mobile
- Form submits correctly with all new fields populated or all blank
Design Notes
- Weather and location badges should be subtle — small text, muted color, not the visual focus
- Use emoji icons for weather — universal, no icon font dependency
- Gallery grid:
gap: 4pxbetween thumbs, no borders, square crops - Lightbox:
background: rgba(0,0,0,0.92), image centered withmax-height: 90vh - Feed card image:
aspect-ratio: 16/9,object-fit: cover, rounded top corners matching card