Reviewer's follow-up: it's not enough to record when a user accepted
the Terms; we also need to record which version of the text they saw.
Changes:
- journal.users gains a nullable `terms_version` text column (nullable
so the three pre-existing users without a version are kept as-is).
- New apps/journal/app/lib/legal.ts exports TERMS_VERSION as a single
source of truth, reused by the legal pages' "Last updated" header
and by the registration flow as the value to send/store.
- Registration form posts `termsVersion` alongside `termsAccepted` on
all three relevant steps (start, finish, register-magic-link).
- API route validates that `termsVersion` is a non-empty string on
any step that requires terms, and forwards it to the auth server.
- auth.server finishRegistration and registerWithMagicLink now take
`termsVersion` and persist it on the users row.
- journal-auth spec gets a new scenario for version storage and a
rejection scenario for missing version.
PRIVACY_LAST_UPDATED is also exported from the same module and used
by the Privacy page header, keeping both pages on a single legal.ts
source of truth for "last updated" labels. Privacy is not per-user
stored — it's informational, not contract.
Existing users have NULL terms_version; if we ever prompt them to
re-accept updated Terms, we can backfill with the version they
re-accept at that point.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fixes one contradiction and closes five gaps where the code (after the
legal-review rounds in #235, #246, #247) now exceeds what the spec
required.
Contradiction fixed:
- Alpha banner was specified as dismissible via sessionStorage, with
"reappears in a new session". In reality the dismiss control and
sessionStorage were removed during privacy hardening — the banner
is now always visible. Updated the requirement to match.
New scenarios documenting what's already shipped:
- Impressum: EU ODR link + non-participation notice; English
translation noted as informational.
- Terms of Service: service availability, minimum age 16 for Journal
accounts, content usage-rights licence, acceptable-use rules
(including no mass automated data extraction), German-law-tiered
liability, bilingual structure.
- Datenschutzerklärung: explicit data-categories-and-purposes list;
Terms acceptance classified under Art. 6(1)(b) and explicitly NOT
(1)(a); dedicated server-logs section (≤14 days, Art. 6(1)(f));
storage-durations list; alpha-reset caveat; per-third-party
disclosures with transfer details (Sentry, OSM tile servers,
Overpass proxy, BRouter, SMTP); Art. 44 ff. DSGVO third-country
transfer note for Sentry with SCC basis; Berlin supervisory
authority; Privacy Manifest appendix.
- Footer: now includes a link to the source repository on both apps.
No functional changes — only spec text catching up with what is live
in production.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Move completed legal-disclaimers change to archive, apply deltas to
main specs: append "Terms acknowledgement at signup" requirement to
journal-auth and create the legal-disclaimers capability spec
covering Impressum, Terms, Datenschutzerklärung, alpha banner, and
footer links.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Main specs (7): Converted from delta format (## ADDED/MODIFIED) to
proper main spec format (## Purpose + ## Requirements)
Changes (3): Added missing spec files for e2e-test-reorganization,
journal-poi-details, and mobile-nearby-sync
Mobile testing: Added missing scenario for "No Vitest" requirement
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Synced new spec (chart ↔ map interaction, mobile touch, iOS safe area,
responsive header) to openspec/specs/elevation-map-interaction/.
All 4 artifacts complete. All 14 tasks complete.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract highway=* tags from BRouter tiledesc messages alongside surface
data and add a new "Road Type" color mode that colors the route polyline
and elevation chart by OSM highway classification (cycleway, residential,
path, etc.). Includes color palette, legend, hover labels, i18n (EN+DE),
unit tests for tag extraction, and E2E tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Full notes lifecycle:
- GPX: description field in GpxData, <metadata><desc> in generate/parse
- Export: Plan GPX and Save to Journal include notes as description
- Journal: updateRoute extracts description from GPX, stores on route
- Reimport: Edit in Planner passes notes via URL params → Yjs Y.Text
- Drop import: GPX with <desc> restores notes in session
Spec updated: session-notes gains GPX export, Journal sync, and
reimport requirements.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added scenarios for character-level notes sync and cursor awareness
between participants.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Synced delta spec (6 requirements) to openspec/specs/multi-day-routes/.
Archived change to openspec/changes/archive/2026-04-11-multi-day-routes/.
All 4 artifacts complete. All 35 tasks complete.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add ## Purpose sections and convert delta headers to ## Requirements
on all 25 specs
- Add SHALL keywords to requirements missing them (gpx-import,
planner-session, planner-journal-handoff)
- Convert prose GPX format section to proper scenarios (no-go-areas)
- Create specs/ delta files for 7 changes that were missing them
(activity-photos, local-dev-stack, multi-day-routes, route-discovery,
route-sharing, visual-redesign, waypoint-notes)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove Garage from service list (commented out, not deployed)
- Replace S3_ENDPOINT/S3_BUCKET with actual Journal env vars
(JWT_SECRET, SESSION_SECRET, WAHOO_*)
- Add monitoring exporters (postgres-exporter, node-exporter, cAdvisor)
to monitoring stack scenario
- Add metrics collection requirement documenting Prometheus scrape
targets and pg_stat_statements custom queries
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bugs fixed:
- FIT parser returns timestamps as Date objects, not strings — convert
to ISO 8601 before passing to generateGpx (caused str.replace crash)
- FIT parser already converts semicircles to degrees — remove redundant
conversion that produced near-zero coordinates
- Wahoo CDN URLs are pre-signed S3 URLs — remove Bearer auth header
from download requests (caused 400 "Unsupported Authorization Type")
- Filter out third-party workouts (fitness_app_id >= 1000) since Wahoo
does not share their data via the API
UX improvements:
- Individual imports use fetcher (no page refresh), button shows
"Importing..." inline
- "Import all" button imports all unimported workouts on the page
sequentially with progress indicator
- Add @vitejs/plugin-basic-ssl for local HTTPS dev (opt-in via HTTPS=1)
Also adds unit test for FIT-to-GPX conversion with real fixture file,
and updates wahoo-import spec to reflect all behaviors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Archive completed changes and sync their delta specs to main:
- wahoo-import: new wahoo-import spec, updated journal-auth and account-settings
- journal-route-previews: new route-preview spec, updated map-display and route-management
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Documents:
- Right-click to delete
- Save to Journal preserves no-go areas in GPX extensions
- Export Plan includes full planning state
- Export Route is clean track only
- GPX extensions format with trails:planning namespace
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
BRouter supports a `polygons` parameter with full vertex coordinates.
We were approximating polygons as circles (centroid + max radius),
which poorly represented elongated or concave shapes.
Now passes polygon vertices directly — no approximation, exact
no-go boundaries.
Also removes unused haversineMeters helper and updates the spec.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Exporters:
- postgres_exporter: DB connections, transactions, cache hit ratio, query stats
- node_exporter: host CPU, memory, disk, network
- cAdvisor: per-container CPU and memory usage
PostgreSQL:
- Enable pg_stat_statements for query-level performance tracking
- Track index scans vs sequential scans, cache hit ratio
Dashboard (service-health.json):
- DB: connections, size, transactions/s, slow queries, cache hit ratio, index usage
- Host: disk gauge, CPU, memory, network I/O, disk I/O
- BRouter: request latency p50/p95/p99, container CPU + memory
- All containers: CPU and memory comparison
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Enrich BRouter response with per-point 3D coordinates and segment boundary
tracking (EnrichedRoute interface)
- ColoredRoute component: plain, elevation gradient (green→yellow→red), and
surface color modes with invisible wide polyline for click targeting
- Click-to-split: click on route polyline inserts waypoint at nearest point,
mapped to correct segment via boundary indices
- MidpointHandles: draggable CircleMarkers at route segment midpoints for
reshaping, hidden below zoom 12, opaque on hover
- Color mode toggle (select) synced via Yjs routeData
- i18n keys for color mode labels (en + de)
- Unit tests for segment boundary tracking (13 tests)
- E2E tests for enriched route response and color mode toggle
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both changes fully implemented. Sync delta specs to main:
- map-display: add Planner home page nav and cursor rendering requirements
- planner-session: add session participant awareness requirement
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace blank home page with landing page: hero with "Start Planning"
CTA, 5 feature cards, Journal CTA, footer with attribution. All strings
in en + de. Sync planner-session spec and archive change.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All 85 tasks complete. Archive change to openspec/changes/archive/ and
sync 9 capability specs to openspec/specs/ for future reference.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>