docs: add travel-memories session handover (2026-06-21)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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/<id>` 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
|
||||
```
|
||||
Reference in New Issue
Block a user