Back to Roadmap

HealthKit Workout Sync

Core HealthKit workout sync for running, cycling, swimming, strength, and other standard workout types. Reliable foreground and background sync, error recovery, anchor-based incremental updates.

Updated for SYNTHESIS schema

HealthKit data now lands in the activities table (not workouts). Key changes from the original schema:

Type mapping

  • Map HKWorkoutActivityType integer → canonical string slug using activity-types.json
  • Store both canonical type (activity_type = 'running') and original (source_activity_type = 'HKWorkoutActivityType:37')
  • ~30 Tier 1 types cover all common HealthKit workout types

Activity record

  • source = 'apple_health', external_id = healthkit_uuid
  • source_data JSONB stores raw HealthKit response for lossless preservation
  • Promoted fields: title, avg_heart_rate, max_heart_rate, moving_time, timezone_offset, calories, distance
  • Calories: document whether we strip BMR (Apple includes BMR in totalEnergyBurned)

Time-series → Parquet streams

  • HR samples → Parquet file on S3/R2, metadata row in activity_streams (replaces row-per-sample heart_rate_samples table)
  • GPS route data → latitude/longitude Parquet streams (replaces workout_routes/route_locations)
  • Speed, altitude, cadence as additional stream types when available

Sub-activities

  • HKWorkoutActivity (iOS 16+) → child activities with parent_id pointing to parent
  • Triathlon/multisport: parent type = triathlon, children = swimming, transition, cycling, etc.

Sync state

  • sync_states table: per-athlete per-source (not single-row per-user)
  • Anchor-based incremental sync preserved

Depends on

  • #31 Implement SYNTHESIS Schema
  • #32 Object Storage Setup (S3/R2/MinIO)

Reference

See docs/api-research/SYNTHESIS.md §3 (Activity Types), §4 (Sessions), §5 (Promoted Fields), §6 (Time-Series Samples).

Status
Done
Priority
Top
Platform
iOS
Date
1 month ago