The "Waypoints (3)" assertion timed out at 5s in CI. The waypoints
load from URL params but the sidebar needs BRouter mock response +
Yjs sync before updating. Increase to 15s to match other assertions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Android 9+ blocks cleartext HTTP by default. Enable usesCleartextTraffic
so the emulator can reach the Journal dev server at http://10.0.2.2:3000.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Android emulator has its own network stack — localhost refers to the
emulator, not the host. Use 10.0.2.2 (host loopback alias) on Android.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- prebuild: generate native ios/ and android/ projects
- prebuild:clean: regenerate from scratch
- run:ios / run:android: build and run locally with Xcode/Gradle
- Add ios/ and android/ to .gitignore (CNG-generated)
Allows building locally without EAS credits:
pnpm --filter @trails-cool/mobile prebuild
pnpm --filter @trails-cool/mobile run:ios
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace custom View-based bottom sheet with @gorhom/bottom-sheet:
- Native gesture-driven drag, snap points, pan-down-to-close
- Proper safe area handling built in
- Wrap app with GestureHandlerRootView
- Add react-native-reanimated plugin to Expo config
Adds react-native-reanimated and react-native-gesture-handler as
native dependencies (requires new EAS build).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Close button was overlapping the home indicator. Now uses
useSafeAreaInsets() for dynamic bottom padding.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The route polyline wasn't visible because segments were initialized
empty. Now extractSegmentsFromGpx() parses trkpt coordinates from
the GPX string via regex on init, so the route shows immediately
in both view and edit modes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The check now also verifies that source paths referenced by
COPY --from=build lines actually exist in the repo. This would have
caught the premature app/jobs COPY that broke the journal build.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The journal doesn't have an app/jobs directory yet — that will arrive
with the Komoot import PR. The COPY line was added prematurely and
breaks the Docker build.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a script that verifies every packages/*/package.json is listed in
all app Dockerfiles. Catches the recurring issue where adding a new
workspace package breaks production because the Dockerfile deps stage
doesn't know about it.
Also fixes two pre-existing missing packages in the planner Dockerfile
(api, map-core) caught by the new check.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both Dockerfiles were missing packages/jobs/package.json in the deps stage,
causing pnpm install to skip pg-boss. Also copy app/jobs directories into
the runtime stage so job handlers are available at runtime.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
pg-boss v10 requires explicit queue creation via `createQueue()` before
`schedule()` or `work()` can reference a queue. Without this, the planner
crashes on startup in fresh databases (like CI) with "Queue not found".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Proposal, design, specs, and tasks for persistent staging instance and
ephemeral PR preview environments on the existing Hetzner server.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add @trails-cool/jobs package wrapping pg-boss for durable background job
execution using the existing PostgreSQL database. Wire up planner session
expiry as the first scheduled job (hourly, 7-day TTL) — this was previously
dead code that never ran. Add placeholder worker to journal for future
Komoot import and federation jobs.
Infrastructure: grant grafana_reader access to pgboss schema, add job queue
health panels to Service Health dashboard, add failed job alert.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The smoke test failed in CI with version mismatch between react
(19.2.5 from catalog) and react-test-renderer (19.2.0 transitive).
Adding it explicitly ensures they stay in sync.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The journal now depends on @trails-cool/api which depends on zod.
The Dockerfile was missing these package.json files, causing pnpm
install to skip them and the build to fail.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The journal now depends on @trails-cool/api (added in PR #217) which
depends on zod. The Dockerfile was missing the package.json for api
and map-core, causing pnpm install to skip them and the build to fail
with "Failed to resolve import zod".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove SENTRY_DISABLE_AUTO_UPLOAD from all build profiles
- Add @sentry/cli as explicit dependency to fix pnpm module
resolution in EAS cloud builds
- SENTRY_AUTH_TOKEN configured as EAS environment secret
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Initialize @sentry/react-native with dedicated mobile project DSN
- Wrap root layout with Sentry.wrap() for unhandled error capture
- Configure Sentry plugin with org (trails-qq) and project (mobile)
for source map uploads during EAS builds
- Disabled in dev, full tracing in production
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add eas.json with development, preview, and production profiles
- Link project to EAS (projectId: 93c75cae-fecf-4ce5-8cd8-c823760b12e2)
- Add expo-dev-client, expo-constants, expo-linking dependencies
- Remove eas-cli from project deps (use globally)
- Add ITSAppUsesNonExemptEncryption to iOS infoPlist
- Use catalog react with expo.install.exclude to skip version check
- Fix slug to match EAS project registration
- Run pnpm dedupe to resolve duplicate react across workspaces
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Route detail at /routes/:id shows:
- Header with back navigation and route name
- Map placeholder (MapLibre requires EAS dev build)
- Stats row: distance, elevation gain/loss, day count
- Description text
- Version count
- "Edit in Planner" opens Journal web UI
- "Download Offline" button (handler pending Phase 5)
Safe area insets applied to header and scroll content.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Routes tab (Phase 3.1):
- Paginated FlatList fetching from Journal REST API
- Route cards with name, distance (km), elevation gain, day count
- Pull-to-refresh, loading spinner, error state with retry, empty state
- Safe area insets for notch and tab bar
API client:
- Import types from @trails-cool/api instead of hand-written interfaces
- Parse list/detail responses through Zod schemas at runtime
- Add zod as mobile app dependency
i18n:
- Add mobile namespace (en + de) for routes, activities, profile, login
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests the full handler flow with mocked DB: auth guard (401), Zod
validation (400), successful responses, and 404s for missing resources.
Also adds ~ alias resolution to Journal vitest config.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests Zod schema validation for all API endpoints (routes, activities,
compute, uploads), error codes, and cursor pagination logic. 21 new
tests covering the validation layer without requiring a running DB.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add all REST API endpoints for mobile app consumption:
Routes:
- GET /api/v1/routes — paginated list with cursor, Zod validation
- GET /api/v1/routes/:id — full detail with GPX, versions
- POST /api/v1/routes — create with Zod-validated body
- PUT /api/v1/routes/:id — update, creates new version
- DELETE /api/v1/routes/:id — returns 204
Activities:
- GET /api/v1/activities — paginated list with cursor
- GET /api/v1/activities/:id — full detail
- POST /api/v1/activities — create with GPX stat extraction
- DELETE /api/v1/activities/:id — returns 204
Supporting:
- POST /api/v1/routes/compute — BRouter proxy
- POST /api/v1/uploads — presigned upload URL generation
Device management:
- GET /api/v1/auth/devices — list connected devices with isCurrent
- DELETE /api/v1/auth/devices/:id — revoke device token
- Store device_name on token exchange
Infrastructure:
- requireApiUser() guard — returns 401 with structured error
- apiError() helper for consistent error responses
- All endpoints use Zod schemas from @trails-cool/api for validation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Journal server (Phase 1.4 + 1.5):
- Add oauth_clients, oauth_codes, oauth_tokens tables to journal schema
- Implement GET /oauth/authorize with PKCE flow and login redirect
- Implement POST /oauth/token (authorization_code + refresh_token grants)
- Add validateBearerToken() + getAuthenticatedUser() middleware
- Seed trails-cool-mobile as trusted OAuth client on server startup
- Add GET /.well-known/trails-cool discovery endpoint
- Add returnTo support to login page and magic link verify
- Add @trails-cool/api workspace dependency to journal
Mobile app (Phase 1.5 + 1.6):
- Login screen with server URL input and discovery validation
- OAuth2 PKCE login via expo-web-browser with expo-crypto for Hermes
- Token storage in expo-secure-store with auto-refresh on 401
- API client with bearer token injection and typed errors
- Server URL persistence with localhost default in dev mode
- API version compatibility check on app foreground
- Log out + switch server on Profile tab
- iOS ATS exception for local networking
Tests:
- PKCE crypto verification, OAuthError, token generation
- Discovery endpoint response shape
- API version semver compatibility
- API client error types
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TS 5.9 enables noUncheckedSideEffectImports under strict mode, which
errors on CSS side-effect imports (e.g. leaflet/dist/leaflet.css).
These imports are resolved by bundlers (Vite/Metro), not tsc. Set
noUncheckedSideEffectImports: false in the shared tsconfig base.
Reverts the unnecessary leaflet devDependencies on the map package
since this base config fix handles it properly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
leaflet, react-leaflet, and @types/leaflet are peer dependencies of
the map package. In CI, pnpm's strict isolation means they aren't
accessible from the package directory during standalone tsc. Adding
them as devDependencies ensures they're installed for typechecking
while consumers still provide them at runtime via peer deps.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The leaflet CSS side-effect import fails standalone tsc (works under
Vite). Enable allowArbitraryExtensions so tsc accepts .css imports.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>