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

143 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
date: 2026-07-08
topic: travel-blog-reader-experience-and-road-workflow
focus: reader experience, story mode, on-the-road posting workflow — ahead of Denmark 2026 (departing ~mid-July)
mode: 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](https://voluntouring.org/2025/07/04/polarsteps-vs-findpenguins/), [Polarsteps review](https://www.overlandsite.com/tools/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](https://www.wprssaggregator.com/rss-to-email/), [service comparison 2026](https://www.readless.app/blog/rss-to-email-services-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](#1-the-follow-along-stack-og--share--rss--digest)
2. [The thirty-second post](#2-the-thirty-second-post-quick-log--auto-location--auto-weather)
3. [Transport-mode visualization](#3-transport-mode-visualization)
4. [The "Today" view](#4-the-today-view-resume-the-curated-home)
5. [Per-photo captions](#5-per-photo-captions)
6. [Trip Wrapped recap page](#6-trip-wrapped-recap-page)
7. [Komoot route pull](#7-komoot-route-pull-in-gpx-manager)
### 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:
```mermaid
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) |