Ang mga hakbang, distansya, kaloriya, tibok ng puso, at tulog ay kailangang kunin mula sa platform ng user (Android Health Connect sa Android, Apple HealthKit sa iOS) ng isang app para sa kalusugan at nutrisyon — at ipresenta ito bilang isang malinis, na-deduplicate na pang-araw-araw na profile. Napakakonti ng pagkakapareho sa pagitan ng dalawang API: magkahiwalay na read mechanics, iba't ibang authorization schemes, at iba't ibang data structures. Binuo namin ang mobile sync layer na nagpapamukha sa kanila na iisa.
Ang Hamon
- Dalawang native na API na walang pinagkakasunduan. Ang Apple HealthKit ay nagbabalik ng pang-araw-araw na aggregates sa pamamagitan ng callbacks; ang Health Connect ay nagbabalik ng raw, paginated samples na may mayamang source metadata. Parehong konsepto, ganap na magkakaibang hugis — at kailangang i-normalize ng app ang pareho sa isang schema.
- Ang double-counting ay ang default. Ang isang telepono, isang smartwatch, at isang third-party app ay maaaring mag-ulat ng parehong 8,000 hakbang. Ang walang habas na pagsasama-sama ng mga ito ay nagpapalobo sa bawat metric. Kailangan ng app na kilalanin ang magkakapatong na sources at bilangin ang bawat aktibidad sa totoong mundo nang isang beses.
- Ang baterya at network ay hindi kayang bayaran ang pagiging bago. Nagbabago ang data ng kalusugan buong maghapon, ngunit ang pagbabasa ng buong kasaysayan sa bawat sync ay makakaubos ng baterya at magpapabara sa mga cellular connection. Kailangang manatiling magaan ang dalas ng sync habang pakiramdam ay live pa rin.
Maaaring nakakalito ang mga pahintulot. Dosenang uri ng data, dalawang permission models, background-read restrictions, at mga user na nagbibigay ng ilang scopes ngunit hindi ang iba — lahat ng ito ay kailangang hawakan ng app nang hindi nagiging sanhi ng pag-crash ng daloy.
Ang Aming Solusyon
Binuo namin ang isang three-layer sync: isang manipis na native layer ang nagbabasa ng API ng bawat platform, isang on-device normalization layer ang nagde-deduplicate at nag-aayos ng data sa pang-araw-araw na buod, at iniimbak ito ng backend at binabalanse sa isang pinagkakatiwalaang ledger. Hindi kailanman nagpapadala ang client ng raw samples — nagpapadala ito ng malinis, timezone-correct na pang-araw-araw na rollups.

Arkitektura
- Binabasa ng iOS ang Apple HealthKit sa pamamagitan ng react-native-health; binabasa ng Android ang Health Connect sa pamamagitan ng react-native-health-connect.
- Ang On-device normalization ay nagpapalit ng output ng parehong platform sa isang schema at nagde-deduplicate bago umalis ang anumang data sa telepono.
- Sync triggers — 30 araw na kasaysayan sa unang paglunsad, pagkatapos ay magaan na 1-araw na incremental reads sa bawat 10-minutong interval at sa bawat pag-resume ng app.
- Transport — ang normalized daily rollups ay na-POST sa /user-health/system-activity ng pangunahing server, na nagpapasa sa mga ito (kasama ang user ID + timezone) sa health microservice.
- Persistence — ang bawat source/araw ay iniimbak idempotently bilang isang HealthSystemAggregate; isang MongoDB change stream ang pagkatapos ay nagbabalanse nito sa isang per-day HealthLedger.
Expo / React Native managed workflow na may native na HealthKit at Health Connect modules.
Mga Pangunahing Tampok
- Isang normalization contract para sa dalawang API. Ang mga platform-specific na reader ay nagpapakain ng isang formatHealthData step na naglalabas ng parehong hugis anuman ang source — kaya ang backend at UI ay hindi kailanman nagba-branch sa iOS vs Android.
2. Max-based deduplication sa device. Sa loob ng bawat source, ang mga pagbasa ng isang araw ay pinagsasama; pagkatapos ang pang-araw-araw na halaga ay ang Math.max() sa lahat ng sources (ang kaloriya ay naka-key sa pamamagitan ng source|deviceType), kaya maraming pagbasa mula sa isang device ang naiipon habang ang isang relo at isang telepono na nag-uulat sa parehong araw ay hindi nagdodoble:
// Sum readings within each source, then take the max ACROSS sources dateSourceMap[date][source] += entry.count; const totalSteps = Math.ceil(Math.max(...Object.values(dateSourceMap[date]))); |
3.Ang tamang read strategy sa bawat platform. Ang mga read ng Health Connect ay paginated na may pageToken loop (1,000 records/page); ang daily aggregates ng HealthKit ay ino-loop araw-araw. Ang bawat kakaibang ugali ay nakapaloob sa sarili nitong reader, hindi nakikita ng iba pang bahagi ng app.
4. Isang sync cadence na iginagalang ang baterya. Ang isang buong 30-araw na backfill ay tumatakbo nang isang beses lamang (binabantayan ng first-call flag); pagkatapos noon, bawat sync ay kumukuha lamang ng isang araw — mabilis sa cellular, mura sa power.
5. Timezone-correct na pang-araw-araw na pagpapangkat. Ang mga sample ay nakabukod sa mga YYYY-MM-DD keys sa sariling timezone ng user, kaya ang isang workout sa 11 PM ay napupunta sa tamang araw anuman ang lokasyon ng server.
6. Idempotent backend writes. Ang bawat rollup ay nag-uupsert sa (userId, deviceId, source, date) — ang muling pagpapadala sa parehong araw ay isang no-op, na nagpapanatili sa retries at overlapping syncs na ligtas.
7. Tapat na degradation. Ang nawawalang mga pahintulot, walang laman na reads, at mga error sa rate-limit ng Health Connect ay nahuhuli at lumilitaw nang malinis — ang walang laman na araw ay hindi kailanman nagpapabagsak sa sync, at ang user ay nakakakuha ng malinaw na prompt sa halip na isang tahimik na pagkabigo.
Mga Resulta
- Isang nag-iisa, pare-parehong health profile sa iOS at Android — ang pagkakaiba ng platform ay hindi nakikita ng iba pang bahagi ng app.
- Ang magkakapatong na device/app sources ay na-deduplicate, kaya ang mga hakbang at kaloriya ay sumasalamin sa katotohanan sa halip na mga pinabobong kabuuan.
- Ang magaan na incremental syncs ay nagpapanatiling sariwa ng data nang hindi nauubos ang baterya o nauubos ang mobile data.
Ang timezone-correct, idempotent writes ay nangangahulugang bawat metric ay napupunta sa tamang araw, at ang retries ay hindi kailanman sumisira sa record.
Technology Stack
React Native (Expo) · react-native-health (HealthKit) · react-native-health-connect · NestJS · MongoDB · MongoDB Change Streams · moment-timezone

