diff --git a/docs/working/2026-06-21-travel-memories-handover.md b/docs/working/2026-06-21-travel-memories-handover.md new file mode 100644 index 0000000..5be150b --- /dev/null +++ b/docs/working/2026-06-21-travel-memories-handover.md @@ -0,0 +1,86 @@ +# travel-memories — Session Handover (2026-06-21) + +## What this is + +`services/travel-memories/` is a local Flask app that turns Immich photo albums into Grav CMS journal entries and story pages. It runs at **http://localhost:8082** via Docker. + +## Current state + +All 11 SDD tasks are complete. The app is fully functional end-to-end across all 6 phases. This session was spent fixing bugs discovered during real use and adding triage UX improvements. + +**Last commit:** `a265b08` — fix: use amber/sky colors for journal/story borders and badges + +## What was built this session + +### New triage UX (Phase 2) + +**Desktop:** +- **Selection ring**: white ring on currently focused card; first card auto-selected on load +- **Arrow key navigation**: `←` / `→` move the selection ring through photos +- **Enter**: open lightbox for current card; **click**: also opens lightbox +- **Lightbox**: full-screen overlay — `←`/`→` navigate, `J`/`S`/`X` tag without closing, `Esc` close; badge + date shown at bottom +- **Badge**: amber J / sky S / ghost X on every tagged photo; updates dynamically when tag changes +- **Colored borders**: amber (`border-amber-500`) for journal, sky blue (`border-sky-400`) for story, dimmed for skip +- **Skip all untagged** button: bulk-skips everything still untagged + +**Mobile (<768px):** +- Tinder-style HammerJS swipe cards: right=journal, left=skip, up=story +- Card tilts + color overlay during drag (amber/sky/grey) +- Three tap buttons (X / J / S) below the card as alternative +- Back button with undo stack (max 10 actions) +- Progress bar synced with header counter +- Horizontal thumbnail strip at bottom: all photos, colored dot per tag, tap to jump to any photo + +## Bugs fixed this session + +| Bug | Root cause | Fix | +|---|---|---| +| Triage badge not updating on tag change | Badge is server-rendered; JS wasn't updating it | Added `updateBadge(el, tag)` helper called after each tag | +| Arrow keys not working | Alpine modifier is `left`/`right` not `arrowleft`/`arrowright` | Fixed modifier names | +| Dimmed photo stays dimmed after retag | Jinja classes have newlines → `.split(' ')` produces `'opacity-40\n'` not `'opacity-40'` | Changed to `.split(/\s+/).filter(c => c && ...)` | +| Colored border disappears after retag | Filter `!c.startsWith('border-')` strips `border-4` (width) too | Re-add `border-4` alongside color class | +| Borders appear white | DaisyUI `border-success`/`border-info` near-invisible in `forest` theme | Use explicit Tailwind: `border-amber-500`, `border-sky-400` | +| Badge text unreadable | DaisyUI badge semantic classes give poor contrast in `forest` theme | Use `bg-amber-500 text-black border-0 font-bold` etc. | + +## Gotchas for next session + +- **Docker rebuild required after any template/code change**: `docker compose build travel-memories && docker compose up -d --force-recreate travel-memories` +- **`--force-recreate` required** to pick up `.env` changes (plain `restart` doesn't re-read it) +- **Immich API key needs scopes**: `album.read`, `asset.read`, `asset.download` (Immich calls it `asset.view` in some versions — check the Immich UI) +- **State directory permissions**: if state/ was created as root, run `docker compose exec -u root travel-memories chown 1000:1000 /app/state` +- **Never read `.env`** — contains real Immich credentials; pass to docker commands only + +## What's not done yet + +Nothing was explicitly left incomplete — the pipeline works end-to-end. Potential next steps: + +1. **Full-resolution lightbox**: currently shows Immich preview thumbnail; could load `/proxy/original/` for the full-res image (endpoint may need adding to `routes/proxy.py`) +2. **End-to-end test for triage UX**: the new JS-heavy triage UI has no Playwright coverage +3. **Phase 2 → real trip**: use the app on the actual japan-korea-2026 Immich album +4. **Mobile swipe color consistency**: swipe-right currently shows green overlay (intuitive for "go") — could switch to amber to match journal color, but debatable + +## File map + +``` +services/travel-memories/ +├── app/ +│ ├── __init__.py Flask factory +│ ├── immich.py Immich API client (x-api-key auth) +│ ├── state.py TripState / Photo models, atomic JSON R/W +│ └── routes/ +│ ├── albums.py Phase 1 — album selection + slug sanitisation +│ ├── triage.py Phase 2 — tag/skip-untagged/done endpoints +│ ├── curate.py Phase 3 — reorder/swap +│ ├── group.py Phase 4 — grouping + dividers +│ ├── write.py Phase 5 — titles/captions +│ ├── export.py Phase 6 — write Grav markdown files +│ ├── proxy.py Immich thumbnail proxy +│ └── nav.py Shared nav context + stale propagation +│ └── templates/ +│ ├── base.html DaisyUI forest + Alpine + HammerJS CDN +│ ├── phase1.html Album selection +│ ├── phase2.html Triage (desktop grid + mobile swipe + lightbox) +│ └── phase[3-6].html Curate, group, write, export +├── Dockerfile +└── docker-compose.yml Port 8082, UID/GID env vars, state volume +```