Two-milestone plan (M1 edit/delete/publish from feed cards, M2 editable
FilePond photos). Enriched from the ce-brainstorm Product Contract to
implementation-ready, then hardened through a ce-doc-review pass:
- KTD1 committed to patching add-page-by-form's edit branch (the
overwrite_mode:edit create path is unreachable as-is; verified in code)
- owner-username server guards + shared scope-guard helper for both the
edit save path and the new entry-actions delete route (traversal-safe,
page-tree resolution)
- missing edit/delete UX states (loading lock, in-flight guards, focus
management, save-failure preservation) filled in
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H1FrCYNq6RXdGYbn5PFrhM
The hero_image blueprint field was dropped (journal heroes come from the
first uploaded photo), so AE3 now asserts the More-options disclosure
toggles open/closed rather than probing the hero input's visibility.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a test for the ≥1-photo requirement (submit blocked with a photo-section
error) and the max of 6 (FilePond maxFiles). Rework AE4: a corrupt HEIC is the
only "photo", so fail-closed now means submit is blocked rather than posting a
text-only entry. Give the success-CTA test a photo so it can post under the new
rule.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Covers the theme datetime override: the date field renders as
<input type="datetime-local">, is prefilled with the current local time in
the native value format, and clearing it blocks submit client-side (no
success notice) — the guard that keeps an invalid date from wiping the
FilePond photo list on a server re-render.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Covers the reorder pipeline: two uploads produce photo-1.jpg/photo-2.jpg on the
posted entry, and the top-level photo_order POST key never appears in the entry
frontmatter. Adds a second image fixture so both slots are exercised.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Retarget AE1's completed-item assertion (the item is now hidden once the
section auto-collapses) to the "✓ N photo ready" summary, and add a spec
covering collapse-after-upload + re-expand on tap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
waitForPhotoUpload waits on FilePond processing-complete; AE1/AE4 use
input.filepond--browser + the .photo-convert-status error status; V3/V4 back
to FilePond limit + non-image rejection; reauth hint -> .photo-reauth-hint;
test-form-config asserts type:filepond. Verified against a live server via a
browser smoke run (HEIC->JPEG attach, corrupt fail-closed, draft restore).
- test-form-config.sh: assert parent is NOT hardcoded (injected server-side),
active_trip set in site.yaml, and the new fields incl. custom 'photos' type.
- helpers.js: resolve active trip from site.active_trip (parent coupling gone);
fillEditor() drives EasyMDE via window.postFormEditor; waitForPhotoUpload()
waits on the new picker.
- post.spec / validation.spec: content via the editor, filepond selectors ->
the photo picker, P8 checks editor value, V3/V4 exercise the picker cap +
fail-closed non-image.
- post-form-ux.spec.js (new): AE3 disclosure, AE1 HEIC->JPEG, AE4 corrupt-HEIC
fail-closed, R18 weather gating, R20 draft restore.
- fixtures: real + corrupt .heic.
- test-post.sh: resolve dailies dir from active_trip.
Refs AE1-AE4, R18, R20, U7.
Add docs/solutions/architecture-patterns/dual-repo-submodule-workflow.md
covering the outer-repo + user/ submodule structure, when to bump the pin
(cross-repo feature boundaries, not routine content), the reachable/push-first
rules, and the worktree + per-worktree dev-server flow. Update CLAUDE.md's
folder explanation and add a "Dual-repo submodule structure" section.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Converts the orphaned gitlink (160000 with no .gitmodules) into a proper
submodule pointing at the content remote, and absorbs user/.git into
.git/modules/user so linked worktrees can populate user/. Bumps the pin
from 75da83d to the current pushed origin/main (924cfc1) as a clean
baseline. Enables per-worktree user/ checkouts for parallel dual-repo work.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Enriched from the requirements-only brainstorm to implementation-ready:
7 units (active-trip parent injection, full field exposure, EasyMDE,
client-side HEIC conversion, Field Notes mobile styling, draft resilience,
tests). Applied headless doc-review fixes plus two owner decisions:
/post bundle built ESM + code-split (defer heic-to for cold-load), and
R20 draft persistence narrowed to text (photos re-picked after re-auth).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Capture the safe procedure + three non-obvious traps from the standalone-
page cleanup: keep the folder as a routable:false data container, repoint
Back-link fallbacks to the grandparent (silent direct-landing regression),
and sync the gitignored demo source + Makefile or the next demo-load undoes it.
Seed CONCEPTS.md (Trip, Entry, Story, Active Trip) and surface docs/solutions/
+ CONCEPTS.md in CLAUDE.md so future sessions discover them.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Replace 'Shared feed-map partial' section with 'entry-map' partial + the
single MapUtils.initEntryMap map path
- Trip architecture: two content subfolders (dailies/stories as inert
routable:false containers); map/stats inline on trip page
- Fix stale references to deleted map/stats/dailies/stories templates in
architecture.md (template list, page tree, GPX flow) and trip-switching.md
(scaffold + verify steps)
- Correct GPX rendering: toGeoJSON bundled in map.js, no leaflet CDN
- Pre-launch smoke test now checks the trip page feed, not /dailies
Left docs/working/* (milestones, learnings, QA, plans) as point-in-time history.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Split env config into local vs remote:
- .env: local/shared config, always loaded (docker compose + make test)
- .env.test / .env.prod: full remote config, loaded on demand via ENV
Remote targets now generate -test/-prod variants (e.g. remote-install-prod);
a guard-env prerequisite blocks bare remote targets with no environment set.
Refresh .env.example to document the two-tier layout and add .env.prod/.env.test
to gitignore and the never-read list in CLAUDE.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 1 cleanup companion — demo-load no longer creates the retired
map/stats sub-pages or copies their now-deleted source .md files.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Status → Complete; document the markLatest opt added during execution,
the window.tripMap/homeMap exposure, and the test outcome (38 passed;
M6/H1 pre-existing and out of scope).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BftDn9vu9SonFAY4vxu4uk
Plan for extracting duplicated MapLibre init into a shared
MapUtils.initEntryMap(opts). Incorporates ce-doc-review findings:
card-absent fallback invariant scoped (no-op→navigate), exact
isLatest predicate, and the home-map attribution restyle documented
as an intentional change. Filter-hidden-card click left as a noted
known limitation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BftDn9vu9SonFAY4vxu4uk
Adds a 'Shared trip-feed-col partial' section (callers, param table, the
home-predeparture sibling, and the initTripStats JS glue) and points the
trip-page filter-bar note at it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BftDn9vu9SonFAY4vxu4uk
Converge home-active feed-col chrome (date range, filter bar, stats/
cycling panels) with the trip page via a shared partial + shared
initTripStats() glue. Map convergence deferred to a later spec.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BftDn9vu9SonFAY4vxu4uk
Assigns Status to the 18 plans that had none, based on checkbox
completion state, memory entries, and CLAUDE.md documentation:
- 16 marked Complete (dates approximate from git/memory)
- 1 marked Not started (template-refactor, now unblocked)
- 1 marked Deferred (pixelfed-import, superseded by travel-memories)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
Defines Status field values (Not started / In progress / Deferred /
Complete / Abandoned) and scanning rules so any session knows which
plans are open vs done without reading every file.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
- Wrong active trip slug in intro (japan-korea → us-canada-mex-2024)
- Home page URL /home not /
- TC-M.3: describe teal-fade animation precisely, not "background flash"
- TC-M.6: arrows hidden by hover:none (touch devices), not by screen width
- TC-M.7: add note that home feed only renders in trip mode; explain how to verify
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
- 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>
- P6: verify "Entry posted successfully!" toast after submit
- P7: verify server resolves default:now to a recent timestamp in saved frontmatter (Grav renders the literal "now" string in the HTML input; resolution happens server-side)
- P8: verify title/content fields empty after successful submit (form reset:true)
Also fix pre-existing helpers.js issues:
- TRACKER_DIR now resolves via docker inspect or GRAV_USER_DIR env var so tests find entries even when running from a worktree without a user/ directory
- DAILIES_URL exported and derived from post-form.md pageconfig.parent so P1/P2 navigate to the correct active-trip URL
- cleanupEntry/findEntry now guard against missing TRACKER_DIR
- P2 marked test.skip (was running and failing on missing fixture)
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>
Also fix auth.setup.js AUTH_FILE path: the file lives in tests/ui/auth/
so the relative path to tests/.auth/user.json needs ../../ not ../ to
match the storageState path in playwright.config.js.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WPJztrVGbwic2xTG7G9fjM
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>
Both api and admin2 are bundled with the Grav 2.0 zip and not available
via GPM. Extract and install both during remote-install. Remove the
ad-hoc remote-install-admin2 target — the main install now covers it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
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>
- server-install.sh: use GitHub releases URL (avoids channel suffix hack)
- GRAV_VERSION bumped to 2.0.0-rc.10 in .env.example
- production-todo.md: mark Phase 2.1 env vars as done
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr