- HammerJS swipe cards (right=journal, left=skip, up=story) with tilt/color feedback
- Three tap buttons as swipe alternative (J/S/X)
- Undo stack (max 10) with Back button
- Progress bar + header counter sync
- Thumbnail strip (all photos, colored dots, tap to jump)
- Desktop: J/S/X badges on all tagged photos including skip
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On viewports < 768px, show a Tinder-style card UI instead of the photo
grid. Cards show one untagged photo at a time with swipe gestures
(right=journal, left=skip, up=story), colour overlays during drag, tap
buttons as alternatives, a progress bar, and a 10-deep undo stack.
Desktop grid is unchanged, wrapped in #desktop-view.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix D: apply _sanitise_slug() to grav_trip_slug in POST /select before
storing in TripState, preventing path traversal via ../sequences.
Fix E: add _yaml_str() helper that doubles single quotes; apply to title,
location_city, and location_country in both run_export and overwrite_export
frontmatter blocks, preventing invalid YAML for values like Xi'an.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Six Playwright tests covering server-side state persistence across hard reloads,
stale-phase propagation after back-navigation, stale banner dismiss, exported group
immutability, and notes surviving phase navigation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements GET /export summary view and POST /export/run which downloads
originals from Immich, writes entry.md with YAML frontmatter, and sets
group status to exported. Includes POST /export/overwrite for single-group
re-export. All 42 tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GET /write now checks all groups are written/skipped before showing
the completion screen; incomplete sessions are redirected to the first
draft group
- POST /write/done now accepts form data (not JSON) and redirects to
/export; wired up from the completion screen via a <form> POST button
- phase5.html extra_scripts block wrapped in {% if group %} to prevent
Jinja errors when group is None on the completion screen
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add group.py route, phase4.html template, and supporting state changes.
Photos are shown as a flat stream; clicking divider zones inserts
entry-break boundaries that split photos into labelled groups. Labels
persist via group_labels dict. Done materialises groups into state.groups
and advances to write phase.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rename /curate/retag to /curate/swap; response now includes new_tag
- /curate/reorder: read body["order"] key (was ordered_ids); include date field
- /curate/remove and /curate/swap: return 404 if asset_id not found
- Update phase3.html JS fetch calls and reorder payload to match spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements GET / listing Immich albums with resume badge, POST /select
creating TripState and redirecting to /triage; graceful error display
when Immich is unreachable.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements Task 4: base.html DaisyUI/Alpine shell, notes autosave panel,
nav.py phase switching with downstream stale marking, notes.py save/get
endpoints, state debug endpoint, and stub /triage route for test support.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds services/travel-memories/ with Flask factory (create_app), stub
route blueprints, pytest/playwright smoke test infra (httpserver session
fix, pytest.ini pythonpath), phase2–6 fixture JSONs, Dockerfile, and
docker-compose service entry. Smoke test (test_health) passes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>