Commit Graph

17 Commits

Author SHA1 Message Date
m038 1159b9cba6 feat: add mobile swipe triage UI with HammerJS and undo stack
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>
2026-06-21 21:07:50 +02:00
m038 7dc7caee26 fix: sanitise trip slug on input, escape single quotes in YAML frontmatter
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>
2026-06-21 17:24:22 +02:00
m038 69cc29b5e5 test: add cross-cutting tests (reload safety, stale, back-nav, export immutability)
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>
2026-06-21 17:18:24 +02:00
m038 db7c102da1 Merge branch 'worktree-playwright-tests'
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 17:12:37 +02:00
m038 5160368407 feat: Phase 6 export — writes Grav entry folders from Immich originals
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>
2026-06-21 17:06:39 +02:00
m038 fade38e7a0 fix: enforce write phase completion gate and wire done endpoint
- 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>
2026-06-21 16:58:03 +02:00
m038 02c772f321 feat: Phase 5 write with autosave, journal/story modes, skip
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 16:54:15 +02:00
m038 b5c90a1e81 feat: Phase 4 grouping with entry-break dividers
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>
2026-06-21 16:44:54 +02:00
m038 23b68d845b fix: curate swap endpoint name, reorder date field, 404 on missing asset
- 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>
2026-06-21 16:37:25 +02:00
m038 851df070e4 feat: Phase 3 curate with remove, retag, drag reorder
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 16:33:58 +02:00
m038 a6a2b31c43 feat: Phase 2 triage with keyboard shortcuts J/S/X
Implement /triage GET/POST routes in triage.py blueprint; render
phase2.html with day-grouped photo grid, Alpine.js keyboard tagging
(J=journal, S=story, X/Space=skip), and done-button gated on all-tagged.
Remove stub from albums.py; register triage.bp in __init__.py.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 16:26:53 +02:00
m038 39d19cf2f8 feat: Phase 1 album selection with resume/start-over
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>
2026-06-21 16:18:38 +02:00
m038 c9c1a50103 fix: correct Alpine scope for notes panel, tojson escaping, remove dead code
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 16:11:41 +02:00
m038 bcfee45bd7 feat: add base shell, notes panel, back-navigation with stale propagation
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>
2026-06-21 16:08:21 +02:00
m038 203737cc3f feat: add Immich API client and photo proxy routes
Implements ImmichClient with list_albums, get_album, get_thumbnail,
get_original methods; wraps connection errors as ConnectionError.
Adds /proxy/thumb/<asset_id> and /proxy/original/<asset_id> Flask routes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 15:55:26 +02:00
m038 102ad7b77b feat: add atomic state management (TripState, Photo, Group)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 15:51:26 +02:00
m038 7ce02d642a feat: scaffold travel-memories Flask app and test infrastructure
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>
2026-06-21 15:46:32 +02:00