Commit graph

461 commits

Author SHA1 Message Date
Ullrich Schäfer
3f0fe859a5
Fix lint: remove unused variable in ElevationChart
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:57:27 +02:00
Ullrich Schäfer
b496cd9b02
Add Journal day breakdown and elevation chart dividers
- routes.server.ts: Extract dayBreaks from parsed GPX waypoints on save
- routes.$id.tsx: Compute per-day stats in loader, render day breakdown
  section with distance/ascent/descent per day
- ElevationChart: Dashed vertical lines at day boundaries
- i18n: Add Journal day breakdown keys (en + de)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:56:57 +02:00
Ullrich Schäfer
78ee4ef3dc
Add elevation chart day dividers and wire days through SessionView
- ElevationChart: Dashed vertical lines at day boundaries with distance labels
- SessionView: Lift useDays() to top level, pass to both ElevationChart and
  SidebarTabs to avoid duplicate hook calls

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:54:56 +02:00
Ullrich Schäfer
94016fd4c4
Add sidebar day breakdown and overnight toggle UI
- DayBreakdown: Collapsible day sections with per-day stats
- WaypointSidebar: Overnight toggle button (moon icon), day-grouped view
  when any waypoint is marked overnight, route summary in header
- SessionView: Wire useDays() hook into sidebar via SidebarTabs
- i18n: Add multiDay keys for en + de (day labels, overnight, stats)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:53:43 +02:00
Ullrich Schäfer
efdb3c1973
Add multi-day data model, computeDays, and GPX roundtrip
- overnight.ts: Yjs helpers to set/clear/check overnight flag on waypoints
- compute-days.ts: Pure function splitting routes into DayStage[] at day breaks
- use-days.ts: Reactive hook mapping Yjs state into computeDays() input
- GPX generate: emit <type>overnight</type> for isDayBreak waypoints
- GPX parse: recognize <type>overnight</type> and set isDayBreak on waypoints

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:51:31 +02:00
Ullrich Schäfer
c9d6f65616
Merge pull request #197 from trails-cool/chore/dependency-updates-v2
Update dependencies and move Sentry to pnpm catalog
2026-04-10 23:42:15 +02:00
Ullrich Schäfer
04efe791cd
Update dependencies and move Sentry to pnpm catalog
Dependency bumps:
- react, react-dom: 19.2.4 → 19.2.5 (catalog)
- @sentry/node, @sentry/react: 10.47.0 → 10.48.0
- @sentry/vite-plugin: 5.1.1 → 5.2.0
- @geoman-io/leaflet-geoman-free: 2.19.2 → 2.19.3
- jsdom: 29.0.1 → 29.0.2
- prettier: 3.8.1 → 3.8.2
- turbo: 2.9.3 → 2.9.6
- typescript-eslint: 8.58.0 → 8.58.1
- vitest: 4.1.2 → 4.1.4

Catalog cleanup:
- Move @sentry/node and @sentry/react to pnpm catalog (used by both apps)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:39:55 +02:00
Ullrich Schäfer
3ad8c301ea
Merge pull request #193 from trails-cool/chore/catalog-cleanup
Deduplicate dependency versions via pnpm catalog
2026-04-10 23:07:13 +02:00
Ullrich Schäfer
760818c843
Deduplicate dependency versions via pnpm catalog
Root package.json had hardcoded versions for react, react-dom, @types/react,
@types/react-dom, tailwindcss, @tailwindcss/vite, drizzle-orm, drizzle-kit,
and drizzle-postgis that drifted from catalog entries. Switched them all to
catalog: and bumped catalog versions to match.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:04:34 +02:00
Ullrich Schäfer
a408d69965
Merge pull request #190 from trails-cool/spec/multi-day-routes-journal
Expand multi-day-routes spec to include Journal integration
2026-04-10 22:57:41 +02:00
Ullrich Schäfer
b38122f770
Merge branch 'main' into spec/multi-day-routes-journal 2026-04-10 22:55:26 +02:00
Ullrich Schäfer
f8948fe974
Merge pull request #191 from trails-cool/chore/vite-8-upgrade
Upgrade Vite from 6.4.2 to 8.0.8
2026-04-10 22:55:06 +02:00
Ullrich Schäfer
26cd8a8a0f
Merge branch 'main' into spec/multi-day-routes-journal 2026-04-10 22:55:05 +02:00
Ullrich Schäfer
06949fc7b5
Upgrade Vite from 6.4.2 to 8.0.8
Vite 8 ships Rolldown as its Rust-based bundler, replacing esbuild+Rollup.
Removed the esbuild override from pnpm-workspace.yaml since Vite 8 no longer
uses esbuild for bundling. All plugins (@react-router/dev, @tailwindcss/vite,
@sentry/vite-plugin, @vitejs/plugin-basic-ssl) support Vite 8.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:52:43 +02:00
Ullrich Schäfer
f7f9bef2ba
Expand multi-day-routes spec to include Journal integration
The spec was Planner-only — day structure would be lost when saving to the
Journal. Added GPX roundtrip (D9), Journal storage (D10), route detail day
breakdown (D11), and shared computeDays in @trails-cool/gpx (D12).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 22:44:03 +02:00
Ullrich Schäfer
d7db09f13e
Merge pull request #189 from trails-cool/dependabot/npm_and_yarn/nodemailer-8.0.5
Bump nodemailer from 8.0.4 to 8.0.5
2026-04-10 21:04:28 +02:00
dependabot[bot]
3b49aa7a5b
Bump nodemailer from 8.0.4 to 8.0.5
Bumps [nodemailer](https://github.com/nodemailer/nodemailer) from 8.0.4 to 8.0.5.
- [Release notes](https://github.com/nodemailer/nodemailer/releases)
- [Changelog](https://github.com/nodemailer/nodemailer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodemailer/nodemailer/compare/v8.0.4...v8.0.5)

---
updated-dependencies:
- dependency-name: nodemailer
  dependency-version: 8.0.5
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-10 19:01:58 +00:00
Ullrich Schäfer
8a076f8c4b
Merge pull request #187 from trails-cool/fix/security-vite-lodash
Fix security alerts: vite 6.4.2, lodash 4.18.1
2026-04-06 22:38:29 +01:00
Ullrich Schäfer
1c99768928 Fix security alerts: bump vite to 6.4.2, override lodash to 4.18.1
- Vite 6.4.1 → 6.4.2: fixes path traversal in optimized deps .map
  handling (medium) and arbitrary file read via dev server WebSocket
  (high)
- lodash 4.17.23 → 4.18.1 via pnpm override: fixes code injection
  via _.template (CVE-2026-4800, high) and prototype pollution via
  _.unset/_.omit (CVE-2026-2950, medium). Transitive dep from
  @react-router/dev — override needed until they bump it upstream.
  Skipped 4.18.0 which was marked as a bad release.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 23:35:53 +02:00
Ullrich Schäfer
43625915d7
Merge pull request #184 from trails-cool/deps/i18n
Bump i18next and react-i18next
2026-04-06 22:32:16 +01:00
Ullrich Schäfer
70319e702f Bump i18next from 26.0.1 to 26.0.3 and react-i18next from 17.0.1 to 17.0.2
Previous attempt left duplicate i18next versions in the lockfile
(26.0.1 for @trails-cool/i18n peer dep, 26.0.3 for root). This caused
two different i18next instances at runtime, breaking i18n initialization
and leaving pages blank in E2E tests.

Fix: update specifiers and run pnpm dedupe to ensure a single version.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 23:29:26 +02:00
Ullrich Schäfer
d56bbc9708
Merge pull request #183 from trails-cool/deps/playwright
Bump playwright from 1.58.2 to 1.59.1
2026-04-06 22:26:30 +01:00
Ullrich Schäfer
18f5388614 Bump playwright from 1.58.2 to 1.59.1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 23:23:56 +02:00
Ullrich Schäfer
279b043faf
Merge pull request #186 from trails-cool/deps/react-router
Bump react-router packages from 7.13.2 to 7.14.0
2026-04-06 22:21:41 +01:00
Ullrich Schäfer
99cfbc6c1b
Merge pull request #185 from trails-cool/deps/sentry
Bump @sentry/node and @sentry/react from 10.46.0 to 10.47.0
2026-04-06 22:16:56 +01:00
Ullrich Schäfer
75e1d87795
Merge pull request #182 from trails-cool/deps/misc
Bump postgres and isbot
2026-04-06 22:16:18 +01:00
Ullrich Schäfer
03e945eb7b
Merge branch 'main' into deps/misc 2026-04-06 22:13:54 +01:00
Ullrich Schäfer
3b0436fe33 Bump react-router packages from 7.13.2 to 7.14.0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 23:13:04 +02:00
Ullrich Schäfer
a96ffebde6
Merge pull request #181 from trails-cool/deps/tooling
Bump eslint, typescript-eslint, and turbo
2026-04-06 22:12:53 +01:00
Ullrich Schäfer
7c3ab0a95c Bump @sentry/node and @sentry/react from 10.46.0 to 10.47.0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 23:11:40 +02:00
Ullrich Schäfer
2a59fc0538 Bump postgres from 3.4.8 to 3.4.9 and isbot from 5.1.36 to 5.1.37
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 23:10:16 +02:00
Ullrich Schäfer
0af67bef0e Bump eslint, typescript-eslint, and turbo
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 23:09:49 +02:00
Ullrich Schäfer
12fde4aa20
Merge pull request #178 from trails-cool/fix/leaflet-ssr
Fix Leaflet SSR error: use .client.tsx convention
2026-04-06 21:56:00 +01:00
Ullrich Schäfer
9b2adebc4d Add ClientMap wrapper to avoid lazy() SSR resolution
.client.tsx modules return undefined on the server, but lazy() still
tries to resolve them during SSR causing "Element type is invalid".
Replace lazy()+Suspense with a ClientMap component that dynamically
imports the map only in useEffect (client-side only).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 22:52:57 +02:00
Ullrich Schäfer
81eb38a24d Fix Leaflet SSR error: rename to .client.tsx
Leaflet accesses `window` on import, crashing during SSR. Renamed
RouteMapThumbnail to .client.tsx so React Router excludes it from
the server bundle entirely. Updated all lazy() imports to match.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 22:52:57 +02:00
Ullrich Schäfer
64231252bc
Merge pull request #180 from trails-cool/fix/planner-health-connection-leak
Fix DB connection leak in health check handlers
2026-04-06 21:42:43 +01:00
Ullrich Schäfer
f80ed10a8b Remove unused journal health route file
api.health.ts was never registered in routes.ts — the server.ts
handler intercepts /api/health before React Router sees it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 22:40:24 +02:00
Ullrich Schäfer
be13145072 Fix DB connection leak in health check handlers
Both server.ts files called createDb() on every /health request,
creating a new postgres.js connection pool (~10 connections) that was
never closed. Docker healthchecks hit this every 15s, exhausting
max_connections within minutes and causing "too many clients" errors.

Fix: use a fresh postgres.js client (max: 1) per health check that is
properly closed in a finally block. This truly tests whether the DB is
accepting new connections without leaking.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 22:39:42 +02:00
Ullrich Schäfer
2d7844c02b
Merge pull request #179 from trails-cool/fix/openspec-validation
Fix all OpenSpec validation failures
2026-04-06 21:22:22 +01:00
Ullrich Schäfer
0b9b99984e Fix all OpenSpec validation failures (36/36 passing)
- 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>
2026-04-06 22:17:52 +02:00
Ullrich Schäfer
c6949e9490
Merge pull request #177 from trails-cool/fix/wahoo-import-pass-stats
Pass workout stats through on import
2026-04-05 19:06:37 +01:00
Ullrich Schäfer
e358c432e7
Fix lint: duration is never reassigned, use const
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 20:04:10 +02:00
Ullrich Schäfer
80291ccf6e
Pass workout stats (distance, duration, startedAt) through on import
ActivityInput now accepts optional distance, duration, and startedAt.
GPX-derived stats take precedence when available, but provider stats
are used as fallback for workouts without GPS data.

The import form and Import All now pass these fields from the Wahoo
workout data so activities show correct metadata even without a FIT file.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:59:54 +02:00
Ullrich Schäfer
b331c2295f
Merge pull request #176 from trails-cool/docs/fix-infra-spec-drift
Fix infrastructure spec drift
2026-04-05 18:57:42 +01:00
Ullrich Schäfer
c6244666fd
Fix infrastructure spec drift
- 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>
2026-04-05 19:57:31 +02:00
Ullrich Schäfer
6203df7543
Merge pull request #174 from trails-cool/fix/wahoo-import-bugs-and-ux
Fix Wahoo import bugs, add Import All UX
2026-04-05 16:50:30 +01:00
Ullrich Schäfer
20b91ef511
Fix Wahoo import bugs, add Import All, update spec
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>
2026-04-05 17:47:48 +02:00
Ullrich Schäfer
01d7620617
Merge pull request #173 from trails-cool/feat/activity-import-ux
Add activity import source, delete, and No GPS indicator
2026-04-05 15:52:15 +01:00
Ullrich Schäfer
fdd193cbf0
Add activity import source badge, delete action, and No GPS indicator
- Activity detail: show "Imported from wahoo" badge when activity was
  imported from an external provider
- Activity detail: add delete button with confirmation, cleans up
  sync_imports so the workout can be reimported
- Import page: show "No GPS" badge with tooltip on workouts that have
  no file URL from the provider

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:49:42 +02:00
Ullrich Schäfer
ab870dbfa5
Merge pull request #172 from trails-cool/fix/journal-dockerfile-copy-lib
Fix journal Dockerfile: copy app/lib for custom server
2026-04-05 15:30:27 +01:00