JunSoft
RecoverFit
헬스 · 웰니스

RecoverFit

HRV · 수면 · 회복도 추적

개요

RecoverFit은 Apple HealthKit 데이터를 활용해 매일 0~100점의 회복 점수를 계산하는 100% 온디바이스 헬스 앱이다. 심박변이도(HRV), 안정시심박수, 수면, 훈련 부하를 가중 합산해 오늘 몸이 얼마나 회복됐는지 한눈에 보여준다. 서버 없이 모든 계산이 기기 안에서 이루어지며, AI 인사이트도 Apple Foundation Models로 온디바이스 생성된다.

풀고자 한 문제

Apple Watch는 HRV·수면·운동 데이터를 풍부하게 수집하지만, 흩어진 수치만으로는 '오늘 훈련해도 되는가'를 판단하기 어렵다. RecoverFit은 이 데이터를 스포츠 과학 문헌(Hulin et al. 2014 EWMA-ACWR 등)에 기반한 알고리즘으로 하나의 회복 점수로 통합해 과훈련과 부상 위험을 줄이고, 프라이버시 우려 없이 모든 처리를 기기 내에서 끝낸다.

스크린샷

앱 미리보기

  • RecoverFit 스크린샷 1
  • RecoverFit 스크린샷 2
  • RecoverFit 스크린샷 3
  • RecoverFit 스크린샷 4
핵심 기능

무엇을 할 수 있나요

01

일일 회복 점수

HRV(35%) · 안정시심박수(20%) · 수면(30%) · 훈련 부하(15%)를 가중 합산해 매일 0~100점을 자동 산출한다. HRV·RHR이 모두 있을 때 전체 가중치를, 누락 시에는 가중치를 재분배하고 missing-data 페널티(최대 0.15)를 적용해 무리한 추정을 막는다.

02

기준선 대비 HRV·RHR 분석

최근 7일 평균을 개인 기준선으로 삼아 오늘의 HRV는 기준선 대비 비율(1.10↑=100점), 안정시심박수는 기준선 대비 절대 편차(-5bpm↓=100점)로 구간 보간해 점수화한다. 개인별 정상 범위에 맞춘 상대 평가다.

03

훈련 부하 & ACWR

EWMA 기반 급성:만성 부하 비율(ACWR)을 Hulin et al. (2014) 모델로 계산한다. 급성 λ=2/(7+1)=0.25, 만성 λ=2/(28+1)≈0.069를 사용하고, ACWR 구간(Sweet Spot 0.8~1.3, Caution 1.3~1.5, Danger ≥1.5)을 색상으로 표시해 과훈련 위험을 경고한다.

04

심박 존 기반 스트레인

운동 중 심박수를 최대심박수 대비 5개 존으로 나눠 존별 가중치(Zone1=1× … Zone5=8×)와 체류 시간을 곱해 일일 스트레인을 산출한다. 심박 샘플이 없으면 활동 칼로리(cal/100) 폴백으로 스트레인을 추정한다.

05

수면 분석

수면 시간(40%) · 효율(25%) · 규칙성(20%) · 수면 단계(15%)를 가중 합산해 별도 수면 점수를 산출한다. 단계는 이상 비율(깊은 수면 20%·REM 25%) 대비 편차로 채점하고, 단계 데이터가 없으면 시간(55%)·규칙성(30%)·효율(15%)로 재가중한다.

06

온디바이스 AI 코치

iOS 26 Apple Foundation Models의 LanguageModelSession으로 회복 점수·HRV·수면·ACWR을 컨텍스트로 묶어 일일 인사이트와 주간 요약을 기기 내에서 생성한다. 모델 미지원 기기에서는 점수·추천 구간 기반 템플릿 인사이트로 자동 폴백한다.

07

트렌드 & 홈 위젯

Swift Charts로 추세를 시각화하고, 홈 화면 위젯 3종(회복 점수·수면 점수·훈련 준비도)을 App Group 공유 저장소로 구동한다. 위젯 타임라인은 1시간마다 갱신되며 회복 점수 위젯은 small·medium 패밀리를 지원한다.

08

프라이버시 우선 데이터

HealthKit을 읽기 전용으로만 연동해 건강 데이터를 절대 기록하지 않으며, CSV 내보내기로 사용자가 자신의 회복·수면·훈련 기록을 직접 추출할 수 있다. 모든 저장은 SwiftData 로컬 컨테이너에서 이루어진다.

기술 스택

어떻게 만들었나요

Language

Swift 6.0Strict Concurrency

UI

SwiftUISwift Charts@Observable

Widgets

WidgetKitTimelineProviderApp Groups

Health

HealthKitHRV (SDNN)Resting HRSleep AnalysisVO2MaxWrist Temperature

Persistence

SwiftData@ModelActor@Model

On-Device AI

Apple Foundation ModelsLanguageModelSession

Commerce

StoreKit 2Auto-Renewable Subscriptions

Architecture

Clean ArchitectureMVVMProtocol-first DI
아키텍처

Protocol-first Clean Architecture로 View → ViewModel → Protocol → Implementation 계층을 분리하고, 모든 계산을 서버 없이 온디바이스에서 처리한다. 회복·수면·훈련 부하 엔진은 순수 함수 struct로 분리해 단위 테스트가 쉽고, Swift 6 strict concurrency를 준수해 SwiftData 저장소를 @ModelActor로 격리한다.

  1. 1

    회복 점수 가중 합산: HRV 35% · RHR 20% · 수면 30% · 훈련 부하 15%로 통합하고, HRV·RHR 누락 시 가중치를 재분배한 뒤 missing-data 페널티(0.15)를 적용하며 데이터가 거의 없을 때는 점수를 70점으로 캡한다.

  2. 2

    EWMA-ACWR 훈련 부하 모델: Hulin et al. (2014) 기반으로 급성 λ=0.25(7일), 만성 λ≈0.069(28일)를 사용해 급성:만성 부하 비율을 계산하고, 직전 부하를 이월해 추세를 누적한다.

  3. 3

    100% 온디바이스: HealthKit 입력, 회복/수면/훈련 부하 계산, AI 인사이트까지 모두 기기 내에서 처리해 건강 데이터가 외부로 나가지 않는다. HealthKit은 읽기 전용이며 저장은 로컬 SwiftData 컨테이너에만 한다.

  4. 4

    Protocol-first DI: 9개 Repository/Service 프로토콜로 외부 의존성을 추상화하고 DailyCalculationService와 ViewModel에 init 주입해, 9개 의존성을 Mock으로 교체한 단위 테스트를 가능하게 한다.

  5. 5

    Swift 6 동시성 안전: SwiftData 저장소 4종을 @ModelActor actor로 구현하고 @Model 타입에 @unchecked Sendable을 적용해 actor 경계를 안전하게 넘긴다. 회복 계산은 @MainActor @Observable 서비스에서 HealthKit 페치를 async let으로 병렬화한다.

  6. 6

    App Group 공유 저장소: 앱과 WidgetKit 익스텐션이 group.com.junsoft.recoverfit 컨테이너를 통해 동일 데이터를 읽어, 계산 직후 위젯 데이터를 갱신하고 1시간 주기 타임라인으로 최신 회복 점수를 반영한다.

  7. 7

    AI 우아한 폴백: Foundation Models 가용성을 런타임에 확인해 미지원 기기에서는 점수·HRV 편차·수면 시간·추천 구간 기반 규칙 템플릿 인사이트로 자동 전환해 모든 기기에서 일관된 경험을 제공한다.

지표

41

엔진 단위 테스트

9

DI 프로토콜

3

홈 화면 위젯

4

SwiftData @ModelActor 저장소

100% on-device

데이터 처리