A2Z Studio
앱 개발

단백질 기록 앱에서 목표를 바꿔도 지난달 달성률이 변하지 않게 한 설계

A2Z Studio·발행일 2026년 10월 10일·읽는 시간 약 2분

핵심 요약

  • 오늘의 목표와 과거 날짜에 적용할 목표는 다른 데이터다.
  • 목표 변경 이력을 저장하면 지난 기록의 달성 여부를 당시 기준으로 계산할 수 있다.
  • 기존 사용자를 위한 마이그레이션에서 현재 목표를 이력의 시작값으로 넣는다.

Protein Meter는 음식별 단백질 섭취량을 기록하는 iOS 앱입니다. 기록은 날짜별로 쌓이고, 사용자는 체중이나 운동 목표가 달라지면 일일 목표량을 다시 설정할 수 있습니다. 여기서 통계 화면에 중요한 질문이 생깁니다. 오늘 목표를 바꿨을 때 지난달 달성률도 새 목표로 다시 판정해야 할까요?

지난 기록은 그날의 목표로 평가하는 편이 사용자가 보던 이력과 일치합니다. 그래서 앱에는 섭취 기록과 별도로 목표 변경 이력을 둡니다. 이 글은 현재 저장소의 Flutter·Drift 코드를 읽고 정리한 구현 설명이며, 의료·영양 권장량에 관한 안내는 아닙니다.

기록과 목표를 분리한 이유

섭취 기록 테이블에는 날짜, 음식 이름, 단백질 양, 생성 시각이 있습니다. 목표 이력 테이블에는 effectiveDate와 targetG를 저장합니다. 가령 9월 1일의 목표가 100g이고 9월 15일부터 120g으로 바뀌었다면, 9월 10일의 110g 섭취는 달성, 9월 20일의 110g 섭취는 미달성입니다. 현재 프로필의 목표 120g만 사용하면 9월 10일의 판정도 뒤집힙니다.

섭취 기록: 날짜 → 그날의 합계
목표 이력: 적용 시작일 → 그날부터 사용할 목표
달성 여부: 그날의 합계 >= 그날에 적용되는 목표

앱은 getDayTargetMapForMonth에서 조회 월 말 이전의 이력을 날짜순으로 가져옵니다. 각 날짜마다 그날 이전에 적용된 마지막 목표를 찾고, 일자별 목표 지도를 만듭니다. 월별 통계 Provider는 그 지도와 기록 합계를 비교해 달성 일수를 셉니다.

같은 날 여러 번 바꾼 경우

현재 구현은 목표를 저장할 때 그날의 기존 이력을 지우고 새 값 한 건을 넣습니다. 따라서 통계에서 하루에 적용되는 목표는 하나입니다. 하루 중 몇 시에 목표를 바꿨는지까지 과거 기록에 반영하지 않는 제품 선택입니다. 일 단위 달성률을 보여주는 앱에는 이해하기 쉬운 기준이지만, 시간대별 분석이 필요해지면 이력의 시각까지 계산해야 합니다.

기존 설치 사용자의 데이터 이전

목표 이력은 데이터베이스 스키마 버전 3에서 추가됐습니다. 이전 버전에는 프로필의 현재 목표만 있었으므로, 업그레이드할 때 TargetHistories 테이블을 만들고 기존 목표를 시작값으로 넣습니다. 코드에서는 2000년 1월 1일을 적용 시작일로 사용합니다. 실제 가입일을 추측하는 대신, 기존 기록 전체에 적용할 기준값을 명시한 것입니다.

if (from < 3) {
  await m.createTable(targetHistories);
  final profile = await getProfile();
  if (profile != null) {
    // 기존 목표를 과거 기록의 기준값으로 저장
  }
}

이 방식에는 한계도 있습니다. 이전 버전에서 사용자가 목표를 여러 번 바꿨다면 과거의 각 목표는 복구할 수 없습니다. 저장하지 않았던 이력은 추론하지 않고, 마이그레이션 시점에 알 수 있는 값으로 일관된 기준을 마련했습니다.

구현을 점검할 때 보는 사례

  1. 목표를 100g에서 120g으로 바꾼 뒤, 변경 전 날짜의 판정이 유지되는가.
  2. 하루에 두 번 바꿨을 때 해당 날짜에 최신 목표 한 건만 남는가.
  3. 버전 2 데이터베이스를 업그레이드했을 때 기존 기록을 열 수 있는가.
  4. 기록이 없는 날짜를 달성 일수의 분모에 넣지 않는 현재 통계 정의가 화면 설명과 맞는가.

마지막 항목은 통계의 의미를 결정합니다. 현재 코드는 기록이 있는 날짜를 분모로 사용합니다. 달력의 모든 날짜를 분모로 삼는 ‘연속 달성률’과는 다르므로, 지표 이름과 설명에서도 이 차이를 분명히 해야 합니다.