New `syncUserActivity` routine pulls daily aggregates from
POST /v2/measure?action=getactivity and writes one Measurement row per
(date, metric) for three fields:
steps → ACTIVITY_STEPS (count)
distance → WALKING_RUNNING_DISTANCE (metres)
calories → ACTIVE_ENERGY_BURNED (kcal)
`elevation`, soft/moderate/intense/active duration and
`totalcalories` are deliberately skipped — no clean MeasurementType
counterpart today; revisit when v1.5 ships the iOS workout passthrough.
Rows anchor measuredAt at the day's 23:59:59 UTC end-of-day so the
Berlin-timezone analytics aggregator buckets them into the correct
local day even across DST shifts. Idempotency rides on the W17b
composite (Migration 0055, NULLS NOT DISTINCT) — repeat syncs of the
same date update value in place rather than inserting duplicates.
Park behaviour mirrors syncUserMeasurements: connections at
error_reauth short-circuit without making the upstream call.