Commit graph

274 commits

Author SHA1 Message Date
Ullrich Schäfer
55afc4cbf3
Fix Dependabot alerts: brace-expansion and path-to-regexp
- Override brace-expansion >=4.0.0 <5.0.5 → 5.0.5 (process hang via zero-step sequences)
- Override path-to-regexp <0.1.13 → 0.1.13 (ReDoS via Express transitive dep)
- Dismissed esbuild alert #1 (already on 0.25.12+, alert for <=0.24.2)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 07:49:37 +01:00
Ullrich Schäfer
81d0feffdd
Archive observability change, sync specs to main
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 21:44:07 +01:00
Ullrich Schäfer
5915907656
Merge pull request #118 from trails-cool/fix-planner-csp
Fix CSP: allow Planner to connect to Journal for callbacks
2026-03-27 21:34:45 +01:00
Ullrich Schäfer
f344c27478
Allow Planner to connect to Journal in CSP
The Planner's save-to-journal callback makes a cross-origin request to
trails.cool from planner.trails.cool. Add the Journal's origin to the
Planner's connect-src CSP directive.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 21:34:41 +01:00
Ullrich Schäfer
39b57b73b7
Add passkey authentication E2E tests
Uses Playwright's virtual WebAuthn authenticator (CDP) to test:
- Register with passkey + sign in (full round-trip)
- Login fails with no credential (friendly error message)
- Duplicate email rejection
- Duplicate username rejection

Would have caught the credential encoding bug.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 21:33:34 +01:00
Ullrich Schäfer
24fc6cc089
Merge pull request #116 from trails-cool/fix-passkey-credential-encoding
Fix passkey credential ID encoding
2026-03-27 21:20:43 +01:00
Ullrich Schäfer
d95d142122
Fix passkey credential ID encoding and improve error handling
Bug: @simplewebauthn v13 changed credential.id from Uint8Array to
base64url string. Buffer.from(string) without encoding stored the
ASCII text instead of decoded bytes. Authentication then failed to
match because it correctly decoded with "base64url".

Fix: Buffer.from(credential.id, "base64url") in both registration
and add-passkey flows.

Also: catch WebAuthn "not allowed" errors and show a friendly message
instead of the raw browser error.

Existing passkeys must be re-registered after deploy.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 21:18:14 +01:00
Ullrich Schäfer
3180017f16
Merge pull request #115 from trails-cool/fix-planner-health
Fix Planner health check DB connection
2026-03-27 20:58:22 +01:00
Ullrich Schäfer
7fdbd4cddf
Fix Planner health check: use createDb instead of non-existent db export
@trails-cool/db doesn't export a db instance — only createDb and withDb.
The health check was importing a non-existent export, always failing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:58:17 +01:00
Ullrich Schäfer
93befca4ac
Merge pull request #114 from trails-cool/disable-sentry-replays
Disable Sentry session replays
2026-03-27 20:52:15 +01:00
Ullrich Schäfer
9187c3ce2b
Disable Sentry session replays
Removes replayIntegration and replay sample rates from both apps.
Quota was already exhausted.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:52:10 +01:00
Ullrich Schäfer
b4412d1b9c
Merge pull request #113 from trails-cool/health-version
Add deployed version to health endpoints
2026-03-27 20:48:31 +01:00
Ullrich Schäfer
0ff9052ae8
Add version (git SHA) to health endpoints
Returns SENTRY_RELEASE (set at build time) as the version field,
making it easy to verify which commit is deployed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:48:27 +01:00
Ullrich Schäfer
73b8ce26e1
Merge pull request #112 from trails-cool/doc-route-registration
Document route registration requirement
2026-03-27 20:46:54 +01:00
Ullrich Schäfer
98df1501c7
Document explicit route registration requirement in CLAUDE.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:46:16 +01:00
Ullrich Schäfer
bfef1cd3f2
Merge pull request #111 from trails-cool/fix-journal-routes
Register health and metrics routes in Journal
2026-03-27 20:42:18 +01:00
Ullrich Schäfer
3c5fb517dc
Add health and metrics routes to Journal route config
The route files existed but weren't registered in the explicit routes.ts,
so React Router never compiled them into the build.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:42:10 +01:00
Ullrich Schäfer
1246799f12
Merge pull request #110 from trails-cool/grafana-smtp
Add SMTP to Grafana for alert emails
2026-03-27 20:27:50 +01:00
Ullrich Schäfer
296f9e57dd
Add SMTP configuration to Grafana for alert emails
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:27:45 +01:00
Ullrich Schäfer
4801c40e04
Merge pull request #109 from trails-cool/fix-grafana-alerts-v2
Fix Grafana alert rule expressions
2026-03-27 20:23:51 +01:00
Ullrich Schäfer
3914da7a57
Fix Grafana alert rules: proper threshold expressions
The threshold expressions were missing the 'expression' field referencing
the query refId, causing 'no variable specified for refId C' errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:23:46 +01:00
Ullrich Schäfer
8ae452999a
Merge pull request #108 from trails-cool/business-dashboard
Add Business Metrics Grafana dashboard
2026-03-27 20:17:08 +01:00
Ullrich Schäfer
e866a1ad40
Add Business Metrics Grafana dashboard
Panels:
- Stat cards: total users, routes, activities, active planner sessions
- Time series: cumulative user growth, route growth
- Bar charts: signups/day, routes/day, planner sessions/day
- Table: top 20 routes by distance

All queries use the grafana_reader PostgreSQL datasource.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:16:54 +01:00
Ullrich Schäfer
2a5615dfdf
Merge pull request #107 from trails-cool/grafana-postgres-datasource
Add PostgreSQL datasource to Grafana with read-only user
2026-03-27 20:08:28 +01:00
Ullrich Schäfer
424eecd274
Add PostgreSQL datasource to Grafana with read-only user
- Create grafana_reader role with SELECT-only access on all schemas
- Init script runs on postgres first boot (docker-entrypoint-initdb.d)
- Grafana PostgreSQL datasource provisioned with read-only credentials
- Enables SQL queries in dashboards (user count, routes, etc.)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:07:27 +01:00
Ullrich Schäfer
5e564e7562
Merge pull request #106 from trails-cool/simplify-restart-all
Simplify restart-all to workflow_dispatch only
2026-03-27 19:18:42 +01:00
Ullrich Schäfer
9a7ecd8911
Simplify restart-all: workflow_dispatch only
Remove commit message [restart-all] detection — doesn't work with
GitHub merge commits. Keep only the explicit workflow_dispatch input.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 19:15:22 +01:00
Ullrich Schäfer
daebb63d1e
Merge pull request #105 from trails-cool/service-health-dashboard
Add service health monitoring: DB, host, container exporters + dashboard
2026-03-27 18:53:26 +01:00
Ullrich Schäfer
424e692ee0
Add service health monitoring: postgres, node, cAdvisor exporters + dashboard
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>
2026-03-27 18:50:42 +01:00
Ullrich Schäfer
f87aca6188
Merge pull request #104 from trails-cool/fix-docker-ca-certs
Install ca-certificates in Docker images for Sentry uploads
2026-03-27 18:35:51 +01:00
Ullrich Schäfer
48fa94e51b
Install ca-certificates in Docker base image for Sentry uploads
node:25-slim doesn't include CA certificates, causing sentry-cli
SSL errors: "unable to get local issuer certificate". Also removes
debug logging from previous troubleshooting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 18:35:46 +01:00
Ullrich Schäfer
f8957902d9
Merge pull request #103 from trails-cool/fix-sentry-token-newline
Fix Sentry auth token trailing newline
2026-03-27 18:23:29 +01:00
Ullrich Schäfer
318f0c93c1
Strip trailing newline from Sentry auth token
The token file may have a trailing newline that causes sentry-cli
API requests to fail with "API request failed".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 18:23:20 +01:00
Ullrich Schäfer
d121dba2c1
Merge pull request #102 from trails-cool/fix-sentry-build
Fix Sentry build: telemetry, release version, secret passing
2026-03-27 18:18:16 +01:00
Ullrich Schäfer
5d7b8c82e8
Fix Sentry build: disable telemetry, fix release version passing
- Disable Sentry Vite plugin telemetry (telemetry: false)
- Pass SENTRY_RELEASE as build-arg (not secret) since it's just the git sha
- Keep only SENTRY_AUTH_TOKEN as Docker secret

The release version was showing as *** because Docker secrets get masked
by GitHub Actions. Git sha is not sensitive — safe as a build arg.

The sourcemap warning from react-router is a known upstream issue (ships
without sourcemaps) and is harmless.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 18:18:00 +01:00
Ullrich Schäfer
cdfd23abc2
Merge pull request #101 from trails-cool/fix-pnpm-build-scripts
Fix pnpm build scripts: use onlyBuiltDependencies
2026-03-27 18:09:51 +01:00
Ullrich Schäfer
6b147d04ec
Use pnpm.onlyBuiltDependencies for @sentry/cli and esbuild
pnpm approve-builds in Dockerfile ran after install, so the approval
wasn't picked up. Use onlyBuiltDependencies in package.json instead —
this is read during install and allows build scripts to run.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 18:07:25 +01:00
Ullrich Schäfer
b2bf7cba28
Merge pull request #100 from trails-cool/fix-docker-sentry
Fix Sentry source map upload in Docker builds
2026-03-27 18:02:34 +01:00
Ullrich Schäfer
5e200c8b62
Fix Sentry source map upload in Docker builds
- Approve @sentry/cli and esbuild build scripts so postinstall runs
- Use --mount=type=secret instead of ARG for SENTRY_AUTH_TOKEN
  (fixes Docker warning about secrets in build args)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 18:01:54 +01:00
Ullrich Schäfer
87d01b4b0d
Merge pull request #99 from trails-cool/fix-cd-apps-source
Fix cd-apps: don't source env file with angle brackets
2026-03-27 17:53:22 +01:00
Ullrich Schäfer
06916868fe
Fix cd-apps: extract SENTRY_AUTH_TOKEN instead of sourcing env file
The decrypted secrets.app.env contains values with angle brackets
(SMTP_FROM) that bash interprets as redirects. The build job only
needs SENTRY_AUTH_TOKEN, so extract it with grep instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 17:52:41 +01:00
Ullrich Schäfer
fe87545744
Merge pull request #98 from trails-cool/fix-scp-paths
Fix SCP paths for decrypted secrets in CD workflows
2026-03-27 17:46:40 +01:00
Ullrich Schäfer
e880e3e9d9
Fix SCP path for decrypted secrets in CD workflows
Write decrypted env files to infrastructure/ instead of /tmp/ so
strip_components: 1 correctly places them on the server.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 17:43:30 +01:00
Ullrich Schäfer
6e39d23dd4
Merge pull request #97 from trails-cool/fix-cd-environments
Add GitHub environments to CD workflows
2026-03-27 17:36:51 +01:00
Ullrich Schäfer
9673496211
Add GitHub environments to CD workflows
- cd-apps: uses `production` environment for AGE_SECRET_KEY
- cd-infra: uses `infra` environment for AGE_SECRET_KEY

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 17:34:28 +01:00
Ullrich Schäfer
c3e80c2dad
Merge pull request #96 from trails-cool/sops-age-split-cd
SOPS+age secrets, split CD, GitHub OAuth for Grafana
2026-03-27 17:30:26 +01:00
Ullrich Schäfer
57094323d2
SOPS+age secrets, split CD workflows, GitHub OAuth for Grafana
Secrets:
- Add .sops.yaml with age encryption config
- Add encrypted secrets.app.env (app secrets) and secrets.infra.env (Grafana OAuth)
- CD decrypts at deploy time with AGE_SECRET_KEY — all other secrets
  move out of GitHub Actions into version-controlled encrypted files

Split CD:
- cd-apps.yml: triggered by apps/packages changes, builds Docker images, deploys apps
- cd-infra.yml: triggered by infrastructure/ changes, copies configs, restarts services
- Remove monolithic cd.yml

Grafana auth:
- GitHub OAuth (trails-cool org), disable login form
- Remove Caddy basic_auth block and all GRAFANA_* env vars/secrets

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 17:28:04 +01:00
Ullrich Schäfer
206f6ac941
Merge pull request #95 from trails-cool/fix-grafana-cd-password
Sync Grafana admin password on deploy
2026-03-27 15:13:37 +01:00
Ullrich Schäfer
b01624b31a
Sync Grafana admin password on each deploy
GF_SECURITY_ADMIN_PASSWORD only works on first boot. Reset the admin
password via grafana-cli after each deploy to stay in sync with secrets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 14:53:54 +01:00
Ullrich Schäfer
65f30b952a
Merge pull request #94 from trails-cool/fix-caddy-basicauth
Fix deprecated basicauth directive in Caddyfile
2026-03-27 14:35:03 +01:00