본문으로 건너뛰기

인생 업적 도감 만들기: 달리기 자동 판정까지, 삼성헬스 연동은 진행 중

· 약 8분
Datapopcorn CEO / AI automation educator

달리기 기록이 들어오면 최초·최고·누적 업적을 자동으로 판정하는 지구 온라인을 만들고 있습니다. GPX 수집과 업적 계산은 구현했고, 삼성헬스 기록을 읽는 휴대폰 앱도 설치했습니다. 다만 삼성헬스에 있는 운동이 헬스커넥트 조회에서는 나오지 않아, 실제 운동부터 업적 생성까지 이어지는 자동 연동은 아직 완성하지 못했습니다.

2026년 10월 4일까지 확인한 개발 기록입니다. 구현한 기능, 실제 기기에서 확인한 결과, 아직 검증하지 못한 부분을 나눠 적었습니다. 완성된 서비스의 사용 가이드가 아니라, 다음 개발을 이어가기 위한 중간 기록입니다.

체크리스트를 하나 더 만들고 싶지는 않았습니다​

아이디어는 단순했습니다. 게임에서는 처음 해본 일이나 최고 기록을 달성하면 업적이 뜹니다. 현실에서도 처음 5km를 달린 날, 이전보다 멀리 뛴 날, 꾸준히 무언가를 이어온 순간을 그런 식으로 남길 수 있으면 좋겠다고 생각했습니다.

그래서 처음에는 나이대별 추천 업적 70개를 넣고, 최초 기록·개인 최고·누적 이정표를 직접 남기는 웹앱을 만들었습니다. 나만의 업적 추가, 연대기, 검색과 필터, JSON 백업·복원도 붙였습니다. 업적을 얻을 때 토스트와 효과음이 나오도록 했고, 음소거와 볼륨 조절도 넣었습니다.

그런데 계속 직접 입력해야 한다면 결국 관리할 목록만 하나 늘어납니다. 방향을 바꿨습니다. 일상에서 이미 생기는 기록을 가져오고, 도감은 그 기록에서 업적을 찾아주는 것이 목표입니다. 애매한 일은 사람에게 확인하되, 숫자로 판정할 수 있는 일까지 매번 체크하게 만들고 싶지는 않았습니다.

첫 자동화 대상으로 달리기를 골랐습니다​

달리기에는 시각, 거리, 시간처럼 비교하기 쉬운 값이 있습니다. 처음 5km를 넘었는지, 연결된 활동 중 가장 멀리 달렸는지, 한 달에 얼마나 누적했는지를 규칙으로 계산할 수 있습니다. 이 단계에서는 AI가 필요하지 않았습니다.

현재 자동 판정하는 업적은 일곱 가지입니다.

업적판정 기준주의할 점
첫 달리기 활동 기록포함된 활동 중 가장 이른 기록인생 최초가 아니라 최초 관측
처음 기록된 5km 완주5,000m 이상인 가장 이른 활동더 오래된 기록을 추가하면 바뀔 수 있음
처음 기록된 10km 완주10,000m 이상인 가장 이른 활동GPS나 원본 앱의 거리 오차는 남음
개인 최장 거리포함된 활동 중 가장 큰 거리연결한 데이터 범위 안의 최고
첫 5km 구간 최고 기록출발부터 5km 지점까지의 경과 시간연속 GPS 트랙이 있을 때만 계산, 휴식 포함
달리기 활동 10회중복·제외 활동을 뺀 10건잘못된 기록을 제외하면 다시 계산
한 달 누적 50km한국 시간 기준 월 누적 50,000m월 경계를 한국 시간으로 처리

특히 5km 기록은 운동 앱에서 말하는 '가장 빠른 임의의 5km 구간'과 다릅니다. 지금 구현한 것은 출발부터 첫 5km까지입니다. 전체 평균 페이스에 5km를 곱해 구간 기록인 것처럼 만들지도 않습니다.

가상 달리기 10건에서 자동 업적 7개가 발견된 지구 온라인 체험 화면

위 화면의 활동 10건과 누적 거리는 기능 확인용 가상 데이터입니다. 실제 삼성헬스 기록이나 수집 성공 사례가 아닙니다.

업적보다 먼저 근거와 되돌리기를 만들었습니다​

활동을 한 번 업적으로 바꾸고 끝내면, 원본이 잘못됐을 때 정정하기 어렵습니다. 그래서 활동을 먼저 저장하고, 업적은 현재 포함된 활동으로 다시 계산하게 했습니다. 같은 GPX를 다시 올리거나 다른 이름으로 내보내도 중복을 줄이고, 잘못된 활동은 제외한 뒤 결과를 다시 볼 수 있습니다.

업적 카드에는 어떤 활동 때문에 달성했는지 근거를 붙였습니다. 활동의 시각, 거리와 시간, 출처 파일 또는 출처 식별값을 확인할 수 있습니다. '첫 기록'도 인생 전체에 대한 단정이 아니라, 연결된 기록 중 가장 이른 관측이라는 설명을 달았습니다.

GPX에서는 좌표와 시간으로 거리를 계산합니다. 끊긴 트랙 구간 사이를 임의로 이어 붙이지 않고, 시간 정보가 없는 코스 안내용 파일이나 달리기로 보기 어려운 위치 튐은 거릅니다. 계산에 사용한 좌표와 원문을 서버 DB에 보관하지는 않지만, 사용자가 자동 수집 폴더에 넣은 원본 GPX 파일은 그대로 남습니다.

저장 위치도 나뉩니다. 수동으로 작성한 인생 업적은 브라우저의 localStorage에, 자동 수집한 활동은 이 컴퓨터의 SQLite에 저장합니다. 따라서 백업도 따로 해야 하며, 다른 기기와 자동으로 동기화되는 서비스는 아닙니다.

GPX 자동 수집은 됐지만, 운동 앱에서 파일이 오는 일은 별개였습니다​

로컬 서버에는 GPX를 직접 가져오는 기능과 전용 폴더를 5초마다 확인하는 기능을 붙였습니다. 자동 수집을 켜고 서버를 실행해두면, 화면을 닫아도 폴더에 들어오는 새 GPX를 처리할 수 있습니다. 서버가 꺼져 있으면 수집도 멈춥니다.

여기서 구분해야 할 것이 있습니다. 폴더에 들어온 파일을 처리하는 것과, 운동 앱이 그 폴더에 파일을 보내주는 것은 다른 일입니다. 앞부분만 만들고 '달리기 완전 자동 연동'이라고 부르면 안 됩니다.

GPX 방식은 파일을 받았을 때의 처리 경로로 남겨두고, 실제 사용 기기에 맞는 연결을 따로 확인했습니다. 사용 중인 밴드는 Galaxy Fit3였고, 운동 원본은 삼성헬스에서 확인할 수 있었습니다.

삼성헬스 연결 앱은 운동과 거리만 읽도록 만들었습니다​

다음 경로를 시도했습니다.

헬스커넥트는 안드로이드 앱 사이에서 건강 데이터를 공유하는 경로입니다. 기존 브라우저 앱만으로 휴대폰의 건강 저장소를 읽을 수는 없어, 작은 안드로이드 연결 앱인 Earth Health Bridge를 만들었습니다. 이번 앱은 백그라운드 자동 동기화가 아니라 화면을 열어 조회하고 내보내는 수동 연결입니다.

요청한 권한은 두 개뿐입니다.

android.permission.health.READ_EXERCISE
android.permission.health.READ_DISTANCE

인터넷, 위치, 심박, 수면, 걸음, 쓰기 권한은 선언하지 않았습니다. 삼성헬스 출처의 최근 30일 운동을 읽고, 달리기와 러닝머신 세션만 내보내도록 했습니다. 운동 구간에 포함되는 거리 기록을 안전하게 대응시킬 수 없으면 추정하지 않고 제외합니다.

삼성헬스 요약 기록에는 첫 5km 구간 시간을 임의로 채우지 않습니다. 해당 값은 null로 두고, 거리·횟수처럼 확인 가능한 업적만 판정하도록 했습니다. 이 앱이 모든 건강 데이터를 수집하는 제품으로 커지는 것도 이번 범위에서는 막아뒀습니다.

권한 승인과 조회 성공은 확인했지만, 실제 운동은 들어오지 않았습니다​

테스트 앱을 휴대폰에 설치하고, 시스템 권한 화면에서 운동과 거리 읽기만 승인했습니다. 실제 조회는 오류 없이 끝났고, 빈 결과를 JSON으로 내보낸 뒤 지구 온라인에서 가져오는 경로도 확인했습니다.

그런데 조회 결과가 0건이었습니다. 이를 바로 '최근 운동 기록이 없다'고 해석하지 않고 삼성헬스 원본과 비교했습니다. 원본에는 조회 기간 안에 해당하는 Galaxy Fit3 달리기 기록이 있었지만, 연결 앱의 헬스커넥트 조회에는 나타나지 않았습니다.

당시 확인한 상태는 다음과 같습니다.

확인한 항목결과
연결 앱 설치성공
연결 앱의 운동·거리 읽기 권한승인됨
삼성헬스의 운동·거리 쓰기 권한이미 허용되어 있었음
삼성헬스의 건강·웰니스 데이터 처리 동의이미 켜져 있었음
연결 앱의 최근 30일 삼성헬스 운동 조회0건
삼성헬스 원본 화면조회 기간 안의 달리기 기록 존재
빈 결과 JSON 내보내기와 로컬 가져오기성공
실제 달리기 데이터로 업적 생성미검증

여기까지로 원인을 확정할 수는 없습니다. 삼성헬스에서 공유 저장소로 전달되지 않은 것인지, 조회 조건이나 출처 필터가 실제 저장 형태와 맞지 않는 것인지는 추가로 구분해야 합니다. 이 글에서는 특정 삼성헬스 버그로 단정하지 않습니다.

최근 30일이라는 읽기 범위도 데이터가 없어진다는 뜻은 아닙니다. 기본 읽기 권한의 범위와 과거 기록 접근 권한을 구분해야 합니다. 이번에 대조한 원본 기록은 그 30일 안에 있었기 때문에, 기간 제한만으로 0건을 설명할 수는 없었습니다.

유료 앱은 결제하지 않았습니다​

대안으로 이미 설치된 Health Sync도 확인했습니다. 무료 체험이 끝난 상태였고, 앱 안내와 Google Play 구매 화면에는 US$3.99 일회성 라이선스가 표시됐습니다. 그러나 이 앱을 구매하면 이번 누락이 해결된다는 검증은 없었습니다.

구매 화면까지는 확인했지만 결제는 진행하지 않았습니다. 삼성헬스와 헬스커넥트의 기본 연결에 유료 중간 앱이 필수인 것은 아닙니다. 먼저 무료 경로에서 데이터가 어디까지 존재하는지 확인하는 편이 맞다고 판단했습니다.

원인을 모르는 상태에서 앱을 하나 더 붙이면 비용뿐 아니라 출처도 복잡해집니다. 예를 들어 다른 동기화 앱이 헬스커넥트에 다시 쓴 데이터라면, 읽는 쪽에서도 원래 삼성헬스 기록과 중간 앱의 출처를 구분해야 합니다. 단순히 모든 출처를 허용해 0건을 없애는 식으로 처리하지 않으려 합니다.

지금 완료한 것과 남은 것은 이렇습니다​

업적 계산 쪽은 최초 기록, 거리 기준, 최고 기록, 월 경계, 중복, 제외 후 재계산, 잘못된 GPX, 헬스커넥트 요약 가져오기 등을 포함해 단위 테스트 30개를 통과했습니다. 별도 테스트 DB에서는 API 가져오기, 폴더 수집, 백업·복원, 재시작 후 유지와 CSRF 거부도 확인했습니다. 이 테스트 결과는 실제 삼성헬스 운동을 끝까지 가져오는 데 성공했다는 의미는 아닙니다.

범위현재 상태
수동 인생 업적 도감과 연대기구현
GPX 기반 자동 업적 7종구현·테스트
근거 보기, 중복 제거, 제외·재계산구현·테스트
전용 폴더 GPX 수집로컬 서버 실행 중 작동
삼성헬스 연결 앱 설치·읽기 권한실제 기기에서 확인
휴대폰 JSON → 로컬 도감 가져오기빈 결과로 경로 검증
실제 삼성헬스 운동 반영원본과 조회 결과 불일치로 막힘
휴대폰부터 도감까지 백그라운드 자동 동기화미구현
공개 배포와 다중 기기 동기화미구현

효과음도 현재 개인용 프로토타입에 적용된 것만 유지했습니다. 소리까지 포함한 공개 배포를 하려면 음원의 사용 권한은 별도로 확인해야 합니다.

다음에는 판정 엔진이 아니라 데이터 경계를 확인합니다​

다음 작업을 시작할 때 앱을 다시 만드는 것부터 반복하지 않으려고 확인 순서를 남깁니다. 이미 설치된 연결 앱과 구현한 판정 엔진은 그대로 두고, 같은 운동 하나가 각 단계에서 보이는지부터 대조할 계획입니다.

  1. 같은 날짜의 기록을 삼성헬스와 헬스커넥트 화면에서 비교합니다. 공유 저장소에 없는 것인지, 읽는 코드가 못 찾는 것인지 먼저 나눕니다.
  2. 출처와 시간 필터를 점검합니다. 출처 제한을 무작정 없애거나 걷기를 달리기로 바꾸지 않고, 실제 저장된 기록의 조건과 맞는지 확인합니다.
  3. 새로 기록한 운동과 기존 운동을 구분합니다. 신규 전달 문제인지 과거 기록 전달 문제인지 확인합니다. 필요한 경우 실제 운동이 생긴 뒤 시험하며, 테스트용 가짜 운동을 건강 앱에 쓰지는 않습니다.
  4. 실제 운동 한 건으로 전체 경로를 검증합니다. 시각·거리·시간을 원본과 비교하고, 재가져오기 시 중복이 생기지 않는지 확인합니다.
  5. 그다음에 자동 동기화를 붙입니다. 백그라운드 읽기 권한, 전송 경로, 인증, 서버 실행 조건과 철회 방법은 별도 단계로 다룹니다.

이 실험에서 가장 분명해진 것은 업적 계산과 데이터 연결이 별개의 문제라는 점입니다. 규칙 테스트가 모두 통과하고, 권한이 승인되고, 조회까지 성공해도 사용자에게 필요한 기록이 들어오지 않을 수 있습니다. 지금 지구 온라인은 '기록을 받으면 판정하는 단계'까지 왔고, 다음 목표는 실제 운동 하나가 빠짐없이 도착하는 것을 확인하는 것입니다.

참고한 공식 문서​

문서가 설명하는 지원 범위와 이번 기기에서 확인한 결과는 구분했습니다. 다른 기기에서도 같은 문제가 발생한다고 일반화하지 않습니다.