mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 06:32:03 +00:00
feat(strava): add per-user BYO-OAuth workout source + Garmin indirect-path docs
Add Strava as a per-user BYO-OAuth workout source, mirroring the shipped WHOOP/Oura/Polar pattern. Strava caps every new app at single-player mode, so each self-hoster registers their own app and pastes the client id/secret into Settings (falling back to a shared env app). Strava is a workout source only — it exposes no daily metrics and no training-depth analytics are derived. - Schema (migration 0233): per-user encrypted client id/secret + access/refresh tokens, plaintext athlete id, incremental cursor, and backfill marker on `User`; `STRAVA` added to `MeasurementSource`. - Token model follows Oura's reactive-refresh-on-401 with a compare-and-set on the stored refresh ciphertext, because Strava rotates its refresh token on every refresh. - Client over safeFetch: authorization-code + refresh, activity list + budget- aware per-activity detail (for calories/HR), honouring the 200/15min cap; each activity maps to one `Workout` row. Activity name/description stay in metadata as data, never surfaced or interpolated. - Dedup reuses the existing source-agnostic two-layer picker: `STRAVA` slots into the workout ladder below the device-native wearables and above MANUAL/IMPORT, so an Apple-Watch + Strava twin collapses to one canonical row. - Poll-cohort hourly sync (:17) + self-converging boot backfill, wired into the integration-sync registrar. Webhook deferred. - OAuth routes (connect/callback/credentials/disconnect/status/test) with signed state, cross-account re-auth rejection, and a surgical `www.strava.com` connect-src gated to the Strava surfaces. - Settings card + consolidated status envelope entry; env + compose whitelist; i18n across all six locales. - Garmin: no direct connector is possible (business-partner-only). Add docs/integrations/garmin.md documenting the Apple Health / Google Health Connect path and Garmin's withheld proprietary scores, cross-linked from both platform docs, plus a non-connector info note in the Connections panel. Regenerate docs/api/openapi.yaml for the new `STRAVA` MeasurementSource value.
This commit is contained in:
1 parent
89634e20ee
commit
75eb0637e6
49 files changed
+2683
-15
No files matched your search
@@ -2243,6 +2243,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
- in: query
|
||||
name: valueMin
|
||||
schema:
|
||||
@@ -4016,6 +4017,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
activeEnergy:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4035,6 +4037,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
walkingRunningDistance:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4054,6 +4057,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
flightsClimbed:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4073,6 +4077,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
sleep:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4092,6 +4097,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
weight:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4111,6 +4117,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bloodPressure:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4130,6 +4137,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
pulse:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4149,6 +4157,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bodyFat:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4168,6 +4177,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bodyTemperature:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4187,6 +4197,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
spo2:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4206,6 +4217,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
hrv:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4225,6 +4237,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
restingHeartRate:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4244,6 +4257,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
vo2Max:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4263,6 +4277,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
skinTemperature:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4282,6 +4297,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
respiratoryRate:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4301,6 +4317,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
recovery:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4320,6 +4337,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
stress:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4339,6 +4357,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
sleepDebt:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4358,6 +4377,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
metricPriority:
|
||||
type: object
|
||||
properties:
|
||||
@@ -4380,6 +4400,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
activeEnergy:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4399,6 +4420,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
walkingRunningDistance:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4418,6 +4440,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
flightsClimbed:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4437,6 +4460,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
sleep:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4456,6 +4480,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
weight:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4475,6 +4500,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bloodPressure:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4494,6 +4520,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
pulse:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4513,6 +4540,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bodyFat:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4532,6 +4560,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bodyTemperature:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4551,6 +4580,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
spo2:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4570,6 +4600,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
hrv:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4589,6 +4620,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
restingHeartRate:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4608,6 +4640,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
vo2Max:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4627,6 +4660,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
skinTemperature:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4646,6 +4680,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
respiratoryRate:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4665,6 +4700,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
recovery:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4684,6 +4720,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
stress:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4703,6 +4740,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
sleepDebt:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -4722,6 +4760,7 @@ paths:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
deviceTypePriority:
|
||||
type: object
|
||||
properties:
|
||||
@@ -14677,6 +14716,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
notes:
|
||||
anyOf:
|
||||
- type: string
|
||||
@@ -15434,6 +15474,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
notes:
|
||||
anyOf:
|
||||
- type: string
|
||||
@@ -15679,6 +15720,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
- type: "null"
|
||||
start:
|
||||
type: string
|
||||
@@ -15808,6 +15850,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
- type: "null"
|
||||
start:
|
||||
type: string
|
||||
@@ -15988,6 +16031,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
description: v1.25.0 — the active source the debt is resolved FROM, picked off the user's `sleepDebt` source ladder.
|
||||
`COMPUTED` is HealthLog's own rolling-balance estimate (the only producer today); a provider value would
|
||||
be a device-native debt. Clients explain the figure when it is `COMPUTED`.
|
||||
@@ -16203,6 +16247,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
externalId:
|
||||
anyOf:
|
||||
- type: string
|
||||
@@ -16314,6 +16359,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
externalId:
|
||||
anyOf:
|
||||
- type: string
|
||||
@@ -18931,6 +18977,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
activeEnergy:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -18950,6 +18997,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
walkingRunningDistance:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -18969,6 +19017,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
flightsClimbed:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -18988,6 +19037,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
sleep:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19007,6 +19057,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
weight:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19026,6 +19077,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bloodPressure:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19045,6 +19097,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
pulse:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19064,6 +19117,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bodyFat:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19083,6 +19137,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bodyTemperature:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19102,6 +19157,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
spo2:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19121,6 +19177,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
hrv:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19140,6 +19197,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
restingHeartRate:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19159,6 +19217,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
vo2Max:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19178,6 +19237,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
skinTemperature:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19197,6 +19257,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
respiratoryRate:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19216,6 +19277,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
recovery:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19235,6 +19297,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
stress:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19254,6 +19317,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
sleepDebt:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19273,6 +19337,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
metricPriority:
|
||||
type: object
|
||||
properties:
|
||||
@@ -19295,6 +19360,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
activeEnergy:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19314,6 +19380,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
walkingRunningDistance:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19333,6 +19400,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
flightsClimbed:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19352,6 +19420,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
sleep:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19371,6 +19440,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
weight:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19390,6 +19460,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bloodPressure:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19409,6 +19480,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
pulse:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19428,6 +19500,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bodyFat:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19447,6 +19520,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bodyTemperature:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19466,6 +19540,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
spo2:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19485,6 +19560,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
hrv:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19504,6 +19580,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
restingHeartRate:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19523,6 +19600,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
vo2Max:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19542,6 +19620,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
skinTemperature:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19561,6 +19640,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
respiratoryRate:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19580,6 +19660,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
recovery:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19599,6 +19680,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
stress:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19618,6 +19700,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
sleepDebt:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19637,6 +19720,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
additionalProperties: false
|
||||
deviceTypePriority:
|
||||
type: object
|
||||
@@ -19705,6 +19789,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
activeEnergy:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19724,6 +19809,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
walkingRunningDistance:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19743,6 +19829,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
flightsClimbed:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19762,6 +19849,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
sleep:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19781,6 +19869,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
weight:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19800,6 +19889,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bloodPressure:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19819,6 +19909,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
pulse:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19838,6 +19929,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bodyFat:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19857,6 +19949,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bodyTemperature:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19876,6 +19969,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
spo2:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19895,6 +19989,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
hrv:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19914,6 +20009,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
restingHeartRate:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19933,6 +20029,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
vo2Max:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19952,6 +20049,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
skinTemperature:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19971,6 +20069,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
respiratoryRate:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -19990,6 +20089,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
recovery:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20009,6 +20109,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
stress:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20028,6 +20129,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
sleepDebt:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20047,6 +20149,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
metricPriority:
|
||||
type: object
|
||||
properties:
|
||||
@@ -20069,6 +20172,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
activeEnergy:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20088,6 +20192,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
walkingRunningDistance:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20107,6 +20212,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
flightsClimbed:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20126,6 +20232,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
sleep:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20145,6 +20252,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
weight:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20164,6 +20272,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bloodPressure:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20183,6 +20292,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
pulse:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20202,6 +20312,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bodyFat:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20221,6 +20332,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
bodyTemperature:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20240,6 +20352,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
spo2:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20259,6 +20372,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
hrv:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20278,6 +20392,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
restingHeartRate:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20297,6 +20412,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
vo2Max:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20316,6 +20432,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
skinTemperature:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20335,6 +20452,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
respiratoryRate:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20354,6 +20472,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
recovery:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20373,6 +20492,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
stress:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20392,6 +20512,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
sleepDebt:
|
||||
maxItems: 8
|
||||
type: array
|
||||
@@ -20411,6 +20532,7 @@ components:
|
||||
- TELEGRAM
|
||||
- MCP
|
||||
- GOOGLE_HEALTH
|
||||
- STRAVA
|
||||
additionalProperties: false
|
||||
deviceTypePriority:
|
||||
type: object
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Garmin (via Apple Health or Google Health Connect)
|
||||
|
||||
**There is no direct Garmin connector for a self-hosted HealthLog instance, and
|
||||
there cannot be one.** Garmin's data-sharing program is business-partner-only:
|
||||
it is approval-gated, requires a public callback endpoint, and is not the
|
||||
"register your own app, paste a key" model the wearable integrations here rely
|
||||
on. So instead of a broken half-integration, HealthLog reads Garmin data the
|
||||
honest way — through the phone health platform your Garmin already feeds.
|
||||
|
||||
## The path that works
|
||||
|
||||
```
|
||||
Garmin device → Garmin Connect → Apple Health (iOS) ─┐
|
||||
→ Google Health Connect ├─→ HealthLog
|
||||
(Android) ─┘
|
||||
```
|
||||
|
||||
- **iOS:** Garmin Connect writes to Apple Health automatically. Import it with
|
||||
the existing [Apple Health](./apple-health.md) path (the `export.zip` upload or
|
||||
the native client's background sync).
|
||||
- **Android:** since Garmin Connect 5.14.1 (July 2025) the app writes to **Google
|
||||
Health Connect**. Connect HealthLog through the existing
|
||||
[Google Health](./google-health.md) integration.
|
||||
|
||||
No extra code, no Garmin developer account, no approval queue — if your Garmin
|
||||
already syncs to your phone's health platform, HealthLog already reads it.
|
||||
|
||||
## What comes through
|
||||
|
||||
Everything Garmin shares with Apple Health / Health Connect flows in: steps,
|
||||
heart rate (including beat-to-beat variability), sleep stages (REM / deep /
|
||||
light), calories (active and total), distance, weight and body composition,
|
||||
cadence, and — partially — blood-oxygen saturation.
|
||||
|
||||
## What Garmin withholds
|
||||
|
||||
These are Garmin's **proprietary** scores. Garmin does **not** share them with
|
||||
Apple Health or Health Connect, so no self-hosted integration — and no amount of
|
||||
configuration — can obtain them. They are only available inside Garmin Connect
|
||||
itself:
|
||||
|
||||
- Body Battery
|
||||
- HRV Status
|
||||
- VO₂ max
|
||||
- Training Load and Training Effect
|
||||
- Recovery Time
|
||||
- Intensity Minutes
|
||||
- Stress score
|
||||
- Running dynamics
|
||||
|
||||
If you rely on those specific numbers, keep the Garmin Connect app for them;
|
||||
everything else lands in HealthLog through the platform path above.
|
||||
@@ -0,0 +1,74 @@
|
||||
# Strava integration
|
||||
|
||||
HealthLog reads your Strava activities and folds them into the same workout
|
||||
history as every other source. Strava is a **workout source only** — its API is
|
||||
activity-centric and exposes no sleep, recovery, body-composition or glucose
|
||||
data, so connecting it adds runs, rides, swims and the rest to your workout
|
||||
surface and nothing else.
|
||||
|
||||
The OAuth app is brought **per user**: each self-hoster registers their own
|
||||
Strava API application and pastes the client id/secret into Settings. Strava
|
||||
caps every newly-created app at "single-player mode" (an athlete capacity of 1)
|
||||
until you request a capacity increase — perfectly fine for a personal
|
||||
self-host, and the reason a single shared app cannot serve many operators.
|
||||
|
||||
## What you get — and what you don't
|
||||
|
||||
**Covered** (one `Workout` row per activity): sport type, start and end time,
|
||||
moving duration, distance, elevation gain, average and maximum heart rate (when
|
||||
the activity recorded it), and calories. Power, cadence, the "trainer"/"commute"
|
||||
flags and the activity name are kept on the row's metadata for provenance but
|
||||
are **not** surfaced as training analytics — HealthLog treats Strava as another
|
||||
workout source, not a training-load platform.
|
||||
|
||||
**Not covered**: Strava exposes no daily metrics (steps, sleep, resting heart
|
||||
rate, weight, …). Those come from your wearable's own integration or from Apple
|
||||
Health / Google Health Connect.
|
||||
|
||||
## Duplicate activities are collapsed automatically
|
||||
|
||||
If you record a run on an Apple Watch **and** it also lands in Strava, the same
|
||||
run arrives twice — once via Apple Health, once via Strava. HealthLog keeps one
|
||||
canonical row per logical workout using your **source-priority ladder**: by
|
||||
default the device-native capture (Apple Watch, WHOOP, Withings) wins over the
|
||||
Strava copy, because a Strava activity is often a re-upload with lower-fidelity
|
||||
or missing heart-rate data. A run you record **only** on Strava (phone GPS)
|
||||
survives untouched. You can promote Strava above the wearables in
|
||||
**Settings → Sources** if you prefer the Strava copy.
|
||||
|
||||
## 1. Register a Strava API application
|
||||
|
||||
1. Sign in at <https://www.strava.com/settings/api>.
|
||||
2. Create an application. For **Authorization Callback Domain** enter the host
|
||||
of your HealthLog instance (the domain only, no scheme or path).
|
||||
3. Copy the **Client ID** and **Client Secret**.
|
||||
|
||||
## 2. Paste the credentials into HealthLog
|
||||
|
||||
1. Open **Settings → Integrations** and find the **Strava** card.
|
||||
2. Paste the Client ID and Client Secret into the **API Credentials** fields and
|
||||
save. (An operator can instead configure a shared app via the
|
||||
`STRAVA_CLIENT_ID` / `STRAVA_CLIENT_SECRET` environment variables; per-user
|
||||
credentials always take precedence.)
|
||||
3. Click **Connect Strava** and approve the access request. HealthLog requests
|
||||
the `activity:read_all` scope so it can read every activity, including those
|
||||
you marked "only me".
|
||||
|
||||
## 3. First sync
|
||||
|
||||
The first history import runs in the background shortly after you connect;
|
||||
afterwards an hourly poll pulls new activities. Strava rotates its refresh token
|
||||
on every refresh, and HealthLog persists the rotated token each time, so the
|
||||
connection stays healthy without you re-authorising.
|
||||
|
||||
## Disconnecting
|
||||
|
||||
Disconnecting revokes the grant at Strava and clears the stored tokens.
|
||||
Activities already imported stay in your history; reconnecting resumes the sync.
|
||||
|
||||
## Related
|
||||
|
||||
- Wearable that syncs to Strava but not directly to HealthLog? See the device's
|
||||
own page, or ingest via [Apple Health](./apple-health.md) /
|
||||
[Google Health Connect](./google-health.md).
|
||||
- **Garmin owners:** Garmin has no direct connector — see [garmin.md](./garmin.md).
|
||||
Reference in new issue
Block a user