Skip to content

docs: add multi-provider SDK architecture plan#487

Open
bartmichalak wants to merge 2 commits intomainfrom
Docs/add-mobile-sdk-architecture-plan
Open

docs: add multi-provider SDK architecture plan#487
bartmichalak wants to merge 2 commits intomainfrom
Docs/add-mobile-sdk-architecture-plan

Conversation

@bartmichalak
Copy link
Contributor

Architecture plan for expanding the SDK from Apple Health-only to multi-provider (Apple Health, Google Health Connect, Samsung Health) across Flutter and React Native.

Feel free to leave comments and join the discussion!

backend/app/
schemas/
sdk/
sync_request.py # UNIFIED schema for all providers
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure about that. Since we have specific types for each provider, shouldn't we have separate schemas (for records, sleep, workouts) - to be able to define custom enums for each provider?

Alternatives:

  • not validate types completely (don't think that's a good idea)
  • enums aggregating types from all providers (also doesn't seem to be a good idea)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or we can just create mapping (provider type -> our unified type), which will do validation anyway (we can raise exception if mapping won't recognize type).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that might be a good approach too 👍

I wanted to use an enum in the API spec mostly for documentation purposes, to explicitly show what we accept on the BE side:

image

But maybe just mentioning that we accept native types and linking to the Apple / Samsung / Google documentation would be enough?


The difference stems from how each platform's health API models sleep:

- **Apple HealthKit** has no concept of a "sleep session". It stores sleep as individual `HKCategorySample` records, each representing a single phase transition (e.g., "deep sleep from 22:00 to 22:45"). All records share the same type (`HKCategoryTypeIdentifierSleepAnalysis`) and differ only by `value` (0=IN_BED, 1=ASLEEP_UNSPECIFIED, 2=AWAKE, 3=LIGHT, 4=DEEP, 5=REM). There is no parent record linking them -- HealthKit simply returns a flat list of time-stamped phase samples. Our backend already reconstructs sessions from these flat phases using a Redis-based state machine (`sleep_service.py`) that groups consecutive phases and detects session boundaries via gap analysis (>1 hour gap = session end).
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add that it's not only in the case of sleep sessions that it differs.

Samsung and Google have the concept of a 'master record' also for health metrics, example:

      // ----- BLOOD_PRESSURE -----
      {
        "uid": "bp-uuid-001",
        "dataType": "BLOOD_PRESSURE",
        "startTime": 1706774400000,
        "endTime": null,
        "dataSource": { "appId": "com.sec.android.app.shealth", "deviceId": "phone-001" },
        "device": { /* ... */ },
        "values": [
          {"type": "SYSTOLIC", "value": 120.0},    // mmHg - systolic pressure (Float)
          {"type": "DIASTOLIC", "value": 80.0},    // mmHg - diastolic pressure (Float)
          {"type": "PULSE", "value": 72.0}         // BPM - pulse during measurement (Float, optional)
        ]
      },

Copy link
Contributor Author

@bartmichalak bartmichalak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very preliminary review and just two thoughts off the top of my head, will come back to it tomorrow

Copy link
Collaborator

@KaliszS KaliszS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be useful to have here comparison of what we can get from all 3 providers (in form of table).

backend/app/
schemas/
sdk/
sync_request.py # UNIFIED schema for all providers
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or we can just create mapping (provider type -> our unified type), which will do validation anyway (we can raise exception if mapping won't recognize type).

Copy link
Contributor

@kmlpiekarz kmlpiekarz Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I attached a document with full explanation, examples, and comparisons.

Main idea:

  • We normalize data from Health Connect and Samsung to match the Apple Health structure.
  • Sleep data: In Health Connect and Samsung, one record contains stages[]. We split them into separate records to match Apple’s flat structure.
  • Workouts: If a workout contains sessions[], we also split them into separate records (like in Apple).
  • Other records - If a record contains nested samples or seriesData, we split them into separate records too.

In short, we flatten all nested arrays into individual records to keep one consistent internal structure across all providers.

@bartmichalak
Copy link
Contributor Author

@kmlpiekarz could you please review the document or just run the agant against current implementation, update the spec and merge? 🙏

@kmlpiekarz
Copy link
Contributor

@kmlpiekarz could you please review the document or just run the agant against current implementation, update the spec and merge? 🙏

Yes, starting working on docs now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants