Files
intotheeast-com/docs/working/2026-07-08-travel-blog-ideation.md
T
m038andClaude Fable 5 94bfc53b90 docs(working): overnight pre-trip readiness audit + product ideation report
Audit: posting pipeline / auth / API surface review with prioritized P1-P3
findings and a morning checklist; P1-1 (prod 2M upload limit) marked
resolved 2026-07-09 via the CGI->FPM switch in Webmin. Ideation: 7 ranked,
repo-grounded ideas (top pick: OG meta + RSS follow-along stack).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0195b3cDdMeize2Mm1FgC2aU
2026-07-09 17:59:05 +02:00

14 KiB
Raw Blame History

date, topic, focus, mode
date topic focus mode
2026-07-08 travel-blog-reader-experience-and-road-workflow reader experience, story mode, on-the-road posting workflow — ahead of Denmark 2026 (departing ~mid-July) repo-grounded

Ideation: Reader Experience, Story Mode & the Road Workflow

Grounding Context

Codebase context. Grav 2.0.7 blog structured around Trips → Entries/Stories (CONCEPTS.md). Posting pipeline is mature and hardened as of the 2026-07-08 journal-post-form ship: /post create+edit, FilePond photos with client HEIC→JPEG, live photo editor, draft persistence, owner-scoped entry-actions API (delete / reorder / trip publish). Trip page renders inline map + filter-bar feed + stats. main.js already has a lightbox. Verified gaps: no Open Graph / twitter:card meta anywhere in user/themes/intotheeast/templates/partials/base.html.twig, no RSS/feed plugin installed, transport_mode is serialized into the map JSON (trip.html.twig:66-69) but no JS or partial consumes it, entry.html.twig detail view is a 12-line stub already slated for retirement (docs/working/backlog.md).

Past learnings & open threads. Curated-home brainstorm PAUSED mid-layout (hero+stats / map / latest entry / latest story / CTA; marker→popup preview). Per-photo captions deferred (data-alt uses filename placeholder). Transport-mode visualization deferred. Story-blocks authoring deferred until real stories are written. travel-memories Immich→Grav pipeline complete. Backlog: Komoot GPX pull, GPX-manager polish, full-res photo re-import.

External context. Polarsteps' most-loved follow feature: family views a shared trip link without an account or app (Polarsteps vs FindPenguins, Polarsteps review); both apps monetise post-trip printed travel books. RSS-to-email digests (Buttondown, MailerLite, Mailchimp RSS campaigns) are the standard low-friction "family inbox" channel (RSS-to-email guide, service comparison 2026).

Run notes. Autonomous overnight run: no blocking questions asked; ideation frames applied inline by one agent instead of the parallel fleet (budget-lean), orchestrator-only basis verification. direct: bases were verified by grep/read against the working tree this night.


Topic Axes

  • Following along — how family & friends learn there's a new entry
  • Reading the feed — arrival/dwell experience on the trip page
  • Story mode — curated set pieces
  • On-the-road posting — the owner's daily workflow
  • After the trip — compounding, archive, keepsakes

Ranked Ideas

  1. The follow-along stack
  2. The thirty-second post
  3. Transport-mode visualization
  4. The "Today" view
  5. Per-photo captions
  6. Trip Wrapped recap page
  7. Komoot route pull

1. The follow-along stack (OG → share → RSS → digest)

Description: Make following the trip effortless for people who will never bookmark a blog. Four stages, each independently shippable, each building on the last:

flowchart TB
  A[Stage 1: Open Graph + twitter:card meta\nper entry/trip/story] --> B[Stage 2: Share button on the\npost-success panel - Web Share API]
  B --> C[Stage 3: RSS/Atom feed\nof the active trip]
  C --> D[Stage 4: RSS-to-email digest\nfor family inboxes]

Stage 1 alone changes every link pasted into WhatsApp/Signal from a bare URL into a photo + title + location card. Stage 2 turns the existing post-success panel ("View your journal / Post another") into "…/ Share this entry" — one tap after every post, while the moment is fresh. Stage 3 gives the RSS-literate a subscription and is the substrate for Stage 4, where a Buttondown/MailerLite RSS campaign mails new entries to subscribed family on a daily/weekly cadence.

Axis: Following along Basis: direct: grep confirms zero og: / twitter: meta tags in partials/base.html.twig and no feed plugin in plugins.txt or user/plugins/; the success panel exists in post-form.js (initSuccessState). external: Polarsteps' account-free share link is its most-cited family feature; RSS-to-email is a commodity integration. Rationale: The site's readers are family and friends on phones in messaging apps — not blog visitors. Every entry already produces a perfect preview image (cover = first photo, by design). This is the highest leverage-to-effort ratio in the whole candidate set, and Stage 1 could ship before departure. Downsides: Stage 4 introduces an external service and subscriber management; OG images should respect draft/unpublished state (don't leak draft covers to crawlers); feed must exclude unpublished entries. Confidence: 90% (Stage 12), 75% (Stage 34) Complexity: Low (Stage 12), Medium (Stage 34)

2. The thirty-second post (quick log + auto-location + auto-weather)

Description: A "quick log" posting mode for hard days: one photo + one sentence, no title required (derive it from date/location), plus removal of the two manual taps that remain in the flow — read GPS from the first photo's EXIF server-side to fill lat/lng when the fields are empty, and fetch weather server-side at submit time from coords + entry date (Open-Meteo archive API for backdated entries). The full form stays for real writing days; quick log keeps the streak alive on the days that produce none.

Axis: On-the-road posting Basis: direct: post-form.md requires photos + title + content + date; location and weather are manual button taps in post-form.js (initGeo). reasoned: on a solo trip the binding constraint on journal completeness is end-of-day energy, not tooling; every removed field measurably raises the posting rate — the same logic that already removed the hero-image field and auto-collapsed the photo section. Rationale: The blog's value compounds with consistency. Denmark is a cycling trip — many days will end tired. A 30-second floor means zero-entry days become one-photo entries instead of gaps. Downsides: EXIF GPS may not survive the client-side HEIC→JPEG conversion (canvas-based converters typically strip metadata) — verify with a real iPhone photo first; if stripped, read EXIF client-side before conversion and post coords explicitly. Title-less entries need a rendering decision in the feed partials. Confidence: 70% Complexity: Medium

3. Transport-mode visualization

Description: Consume the already-serialized transport_mode field: style the map connector line per mode (e.g. dashed for train/bus/plane, solid for walking/cycling) and show the mode emoji/icon on entry cards and map popups. The data is being shipped to the client on every trip page load and rendered nowhere.

Axis: Reading the feed Basis: direct: trip.html.twig:68 serializes transport_mode into the map entries JSON; grep finds zero consumers in maplibre-utils.js, main.js, or any partial. The form select (walking/bicycle/bus/train/car/plane) shipped in the current post form. Rationale: For a cycling-centric trip, how you moved is half the story the map tells. This closes a loop that was deliberately half-built: the capture side shipped, the display side was deferred. All data will exist from day one of Denmark — the earlier this ships, the more of the trip benefits. Downsides: Connector styling interacts with the GPX-vs-connector suppression logic (force_connect, same-file proximity checks) — needs care in MapUtils.initEntryMap; js/map.js rebuild via make build-assets. Confidence: 85% Complexity: LowMedium

4. The "Today" view (resume the curated home)

Description: Resume the paused curated-home brainstorm with a sharper frame: the active-trip home is the page family checks daily, so lead with now — a pulsing last-position marker, "Day 12 · Aarhus · 340 km so far", the latest entry, the latest story, then the full feed/map below. Marker→popup preview (already sketched in the paused brainstorm) makes the map the navigation surface.

Axis: Following along / Reading the feed Basis: direct: the curated-home brainstorm exists and is paused at the layout question (hero+stats / map / latest entry / latest story / CTA). external: Polarsteps' follow screen is exactly this — current position + day counter first, log second. Rationale: The home page is the URL family will have. Today it renders the same feed chrome as the trip page; a "where is he now" lead answers the question every visitor actually arrives with, in one glance, and gives repeat visits a reason. Downsides: It's a design decision as much as a build — the brainstorm needs finishing first; risks scope creep against the shared trip-feed-col partial (keep the partial single-purpose, add a curated lead above it rather than forking it). Confidence: 65% Complexity: Medium

5. Per-photo captions

Description: Give photos one-line captions: store per-image captions in Grav media metadata (<file>.meta.yaml), add a caption field to the edit-mode photo editor grid (tap a thumbnail → caption input, persisted via the media API), render as museum-style wall text in the feed and lightbox, and use it as real alt text (replacing the filename placeholder in data-alt).

Axis: Reading the feed Basis: direct: data-alt currently carries the filename as a placeholder; per-image captions were explicitly deferred "pending Mischa's decision". reasoned: photos carry most of the feed's content weight; a single line of context ("the ferry that almost left without me") is the cheapest possible narrative upgrade and doubles as accessibility. Rationale: Between a bare photo grid and a written story there is nothing today; captions are the missing middle register — and they make the eventual printed book/recap dramatically better. Downsides: Captioning is one more thing to do on the road (keep it optional and editable later); .meta.yaml sidecars must survive the photo-NN renumber pipeline (PhotoRenumberer currently renames files — sidecars need to move with them, and deleteUnlistedImages already deletes them). Confidence: 70% Complexity: Medium

6. Trip Wrapped recap page

Description: An auto-generated end-of-trip recap: days on the road, total km (GPX-exact where available), entries written, photos taken, countries/towns visited, transport-mode split, biggest climbing day — rendered as a shareable, designed page per trip (/trips/<slug>/recap or an inline trip-page section that unlocks when the trip ends). Extension later: print-CSS → the Polarsteps-style trip book.

Axis: After the trip Basis: external: Spotify Wrapped / Strava Year in Sport demonstrate the format's shareability; Polarsteps' printed travel book is its flagship post-trip product. direct: the stats machinery (per-file GPX aggregation, cycling stats, haversine fallback) already exists in initTripStats. Rationale: The site already computes most of these numbers live; a recap reuses them as a keepsake and gives every finished trip a satisfying capstone that the trip page (an infinite feed) doesn't provide. Slovenia/Italy/US archives get retroactive value. Downsides: Needs the full-res photo re-import (backlog) before a printed extension is worthwhile; design effort is the real cost — a half-designed recap undercuts the point. Confidence: 65% Complexity: Medium

7. Komoot route pull in gpx-manager

Description: Paste a Komoot tour URL into /gpx-manager and the server fetches the GPX (api.komoot.de returns GPX per tour ID) and saves it to the trip page — replacing the export→download→upload dance after each riding day.

Axis: On-the-road posting Basis: direct: docs/working/backlog.md names this with the API endpoint; the gpx-manager UI, slugification, and media API plumbing all exist. Rationale: On a cycling trip the GPX step is daily friction; this collapses it to a paste. Server-side fetch also sidesteps mobile-browser download/upload juggling. Downsides: Auth requirements for non-public tours are unresearched (backlog says the same); Komoot's API is unofficial — could break mid-trip, so the manual upload path must remain first-class. Confidence: 60% Complexity: Medium


Rejection Summary

# Idea Reason Rejected
1 Offline-first /post (service-worker queue) Cost ≫ value: queued multipart uploads vs sessions/nonces is genuinely hard, Denmark coverage is good, and localStorage drafts already protect the text — too risky days before departure
2 Retire entry permalink + add #anchor deep links Already a tracked backlog item; cleanup, not a product direction
3 Auto-story scaffold from a date range Premature — story authoring tooling is deliberately deferred until real stories have been written; revisit with material in hand
4 No-account emoji reactions on entries Adds the site's first anonymous public write endpoint (abuse/rate-limit/storage surface) right before departure; worth revisiting post-trip as the only "return channel" idea
5 Printed trip book (standalone) Folded into idea 6 as its extension — the recap is the shippable first step and the book depends on the full-res re-import
6 Full-res pixelfed re-import + srcset Enabler already tracked in the backlog, not an idea in itself; sequence it before any print/keepsake work
7 Distribution foundation (RSS+OG+sitemap bundle) Duplicate of idea 1, which stages the same work
8 travel-memories on-trip cadence Workflow practice with the existing app; nothing to build
axis: story mode No survivors — deliberate gap: story tooling stays deferred until the first real stories exist (only candidate was rejection #3)