
Digital Healthcare · Wearable
온심 onsim
심박수 기반 맞춤 운동 처방 · 실시간 존 코칭 디지털 헬스케어 앱
- 클라이언트
- HB Connect (에이치비커넥트)
- 기간
- 2024.03 — 현재 (백엔드 2023.07 —) · 앱 2년 6개월+ · 운영 중
- 역할
- 앱 · 웨어러블 · 관리자 콘솔 리드, 2026.08 — 백엔드 전담
- 팀 구성
- 개발자 1인(본인) + 기획 · 스포츠의학 자문
- 플랫폼
- iOS · watchOS · Android · Wear OS · Web(Admin)
- 상태
- App Store · Google Play 출시, v2.0.0 운영 중
3,000+
누적 가입자
845 files
Dart
21만+ 줄
수작성 코드
3.1만 줄
Swift · Kotlin
7,211
누적 커밋
13
지원 언어
Overview
프로젝트 개요
온심은 국가대표 · 프로 선수를 담당해 온 스포츠의학 전문가의 아이디어에서 출발한 앱입니다. 건강 설문과 개인 프로필을 바탕으로 사용자에게 맞는 목표 심박 구간(온심존)을 제안하고, 운동 중 실시간으로 그 구간 안에 머물도록 코칭합니다.
암 · 심장 · 고혈압 · 당뇨 · 콩팥 · 간 · 근감소증 · 비만 등 12개 질환 축별 FITT 운동 처방을 ACSM 가이드라인 12판에 근거해 규칙화했고, 폰 · Apple Watch · Wear OS · BLE 센서 4개 심박 소스를 하나의 파이프라인으로 중재합니다. 소셜 '같이하기', 보상 허브, 트레이너 상담 · AI 챗까지 포함한 종합 헬스케어 플랫폼으로 성장했습니다.
My Role
담당 업무
- 01Flutter 앱 전체 설계 · 구현 (845개 Dart 파일, 순수 수작성 약 21만 줄)
- 02watchOS 독립 앱(SwiftUI), 운동 Live Activity 위젯, 워치페이스 컴플리케이션 — Swift 약 1.8만 줄
- 03Wear OS 독립 배포 모듈(Compose) + Samsung Health Sensor SDK 파트너 연동 — Kotlin 약 1.3만 줄
- 04HealthKit · Health Connect · BLE · 햅틱 · TTS · 네이버 로그인 등 Flutter ↔ 네이티브 채널 7종 설계
- 05Firebase Functions(TypeScript 2만 줄) — Callable · FCM · 소셜 집계 · AI 프롬프트
- 06NestJS 백엔드(11만 줄) 운영 · AWS CDK 배포, Grafana 134패널을 자체 관리자 대시보드로 이관
- 07관리자 콘솔을 바닐라 JS에서 Next.js + Tailwind로 재구축 (Firebase App Hosting)
- 0813개 언어 i18n, App Store 심사 대응, 릴리스 브랜치 전략 · 빌드 번호 자동화
Features
핵심 기능
맞춤 운동 처방 엔진
12개 질환 축 FITT 처방, 다질환 보수 병합, 복약 판정, 갱신 주기, 시니어 처방군. 발급 · 갱신 판정은 서버 전담, 앱은 버전 스탬프 계약으로 결과만 수신.
온심존 실시간 코칭
존 컬러 링 + 심박 파동 시각화, 존 이탈 햅틱 코치, iOS Live Activity · Android 상시 알림, GPS 궤적 · 구간 스플릿 · 페이스.
4개 심박 소스 중재
폰 · Apple Watch · Wear OS · BLE 심박/RSC 센서를 동일 파이프라인으로 처리. Samsung Health 연동은 파트너 승인 서명까지 완료.
채팅형 가입 · 컨디션 챗봇
약관 → PARQ → 개인화 설문 → 암 하위 질문 → 처방 미리보기를 한 흐름으로. 컨디션 체크로 '오늘의 추천 심박수' 산출, RPE · talk test 강도 보정.
건강 기록 · PHR
HealthKit · Health Connect 일일/주간 집계 그래프, 수면 · 월경(명시 동의 뒤), 건강검진 XML · FHIR 파일 업로드.
소셜 · 보상 · 상담
실시간 등반 트랙, 친구 · 피드 · 콕, 미션 · 포인트 상점 · 온심펫, 트레이너 실시간 상담과 AI 챗 '온스텝' 주간 리포트.
Architecture
설계 원칙
2축 백엔드 격리
자체 NestJS REST(be.onsim.im)와 Firebase 서버리스를 앱 모듈 단위로 완전 분리. BE 호출은 포그라운드 게이트에서만, 백그라운드 변경분은 resume 시 drain.
네이티브 채널 계약
onsim/health · onsim.watch · onsim.ble · live_activity · haptics 등 채널 계약을 문서화하고 iOS · Android 양쪽에 동일한 의미론으로 구현.
암호화 로컬 캐시
모든 로컬 파일 캐시를 ChaCha20-Poly1305로 암호화하고 키를 로그인 계정에 봉인. 로그아웃 시 키 파기로 암호학적 삭제.
워치 신뢰 모델
'워치 운동의 진위는 워치가 정한다' 원칙. 생존 하트비트, 유령 세션 구제 저장, 묵은 명령 차단, Data Layer 신뢰 배달을 iOS · Wear OS 양쪽에 동일 설계로 이식.

Samsung Health Data SDK 파트너 제출용 데이터 흐름도 — 동의 게이트 → 온디바이스 처리 → 암호화 저장 → 철회 · 삭제까지.
Challenges
기술 과제와 해결
Health Connect 페이지네이션 유실
Problem
readRecords가 호출당 1,000건만 반환하는데 첫 페이지만 읽고 있었습니다. 삼성헬스처럼 심박을 잘게 쪼개는 소스에서는 주간 창의 가장 최근 구간이 통째로 잘렸습니다(실제 센서 공백 4분이 앱에는 17분 미측정으로 표시).
Solution
pageToken을 끝까지 순회하는 readAllRecords로 교체하고, 이미 오염된 캐시를 1회 purge하는 마이그레이션을 배포했습니다.
결과 · 주간 운동 기록 정확도 복원, 관련 CS 종결
'실패'와 '0건'을 구분하기
Problem
iOS 네이티브 read 실패를 빈 배열로 삼키고 있어, 잠긴 기기에서 백그라운드로 되살아난 앱이 전 타입 0건을 받아 어제 운동 기록이 프로세스 내내 사라졌습니다.
Solution
에러를 Dart까지 전파하고, 비포그라운드 상태의 0건 응답은 권위 데이터로 채택하지 않는 2차 방어선을 추가했습니다.
워치 ↔ 폰 동기화 신뢰성
Problem
폰과 워치가 서로를 무한히 깨우는 자동 기동 루프, HK 백그라운드 딜리버리 잔재로 인한 25초 씬 워치독 SIGKILL, 32비트 Int 트랩 시작 크래시, NSNull 페이로드 크래시 등이 누적됐습니다.
Solution
생존 하트비트 · 묵은 명령 차단 · AOD 경과시간 처리 · 유령 세션 구제 저장을 도입하고 840줄 분량의 설계 문서로 고정했습니다. 같은 설계를 Wear OS에 이식해 심박 3소스 중재까지 통일했습니다.
6차에 걸친 성능 개선
Problem
Android 운동 기록 로딩, 콜드 스타트, 랜딩 재도색, 유휴 상태 발열이 사용자 불만으로 이어졌습니다.
Solution
Dart → 파이프라인 → 네이티브 → 글래스 스냅샷 공유 → 장식 애니메이션 정책 → 유휴 시 프레임 생성 중단까지 단계별로 진단 · 수정하고, 'RepaintBoundary로 왜 못 잡는지'까지 기록했습니다.
Firestore 비용 절감 4차
Problem
소셜 · 랭킹 기능 확장으로 Firestore 읽기 비용이 급증했습니다.
Solution
Functions 캐시, 랭킹 디바운스, 클라이언트 리스너 단일화, 영속 캐시를 순차 적용하고 읽기 감사 문서로 근거를 남겼습니다.
개인정보 · 규제 대응
Problem
수면 · 월경 같은 민감정보가 사일런트 백필되고, 소셜 화면에 uid가 노출될 수 있는 구조였습니다. dev 빌드 오분류로 실계정이 삭제되는 사고도 있었습니다.
Solution
전원 명시 동의로 전환하고 SensitiveConsentManager가 미동의 타입 수집을 원천 차단, publicId 전면 도입, 로컬 캐시 전면 암호화, 계정 삭제 1시간 가드를 도입했습니다.
App Store 심사 · 릴리스 전략
Problem
Apple 로그인 이름 재입력 이슈(가이드라인 2.5.4, ITMS-90683)와 심사 창이 비어 있지 않은 상황에서 prod 병합 루틴이 충돌했습니다.
Solution
displayName 보존 → name cache → 확인 단계 → SIWA revoke로 근본 해결. v{버전} 브랜치를 종점으로 하는 릴리스 전략으로 전환하고 빌드 번호 SOT를 TestFlight 최신값으로 옮겼습니다.
Tech Stack
기술 스택
App
- Flutter 3.44 · Dart 3.12
- Provider
- Firebase 10종 (Auth · Firestore · Functions · FCM · Crashlytics · Remote Config …)
- 카카오 · 네이버 · 구글 · 애플 · 이메일 로그인
- flutter_secure_storage · pointycastle
- 13개 언어 l10n
Native
- Swift · SwiftUI (watchOS, Live Activity, 컴플리케이션)
- iOS 26 Liquid Glass 자체 플랫폼뷰
- Kotlin · Jetpack Compose (Wear OS)
- Samsung Health Sensor SDK
- HealthKit · Health Connect · BLE
- SPM (CocoaPods 이탈)
Backend
- NestJS · TypeScript
- AWS CDK · ALB · ECS
- Firebase Functions (asia-northeast3)
- Sentry · k6 부하 테스트
- GitHub Actions
Admin · Ops
- Next.js · React · Tailwind (Firebase App Hosting)
- Grafana → 자체 대시보드 이관
- handoff 96 · worklog 649 문서
Outcomes
성과
- ✓누적 가입자 3,000명+ 달성, App Store · Google Play에서 2년 6개월 연속 운영하며 v1.5 → v2.0.0(빌드 783)까지 무중단 업데이트
- ✓iOS · watchOS · Android · Wear OS 4개 플랫폼 + 관리자 웹을 단독으로 유지
- ✓Samsung Health Data SDK 파트너 승인 획득 (심박 read-only 데이터 흐름 문서 제출)
- ✓외부 패키지(adaptive_platform_ui) · Grafana · Prometheus · CocoaPods 의존 제거로 운영 부담 축소
Next Project
마미플랜 momiplan