Skip to content

Barbelic 제품 요구사항 문서 (PRD)

기준일: 2026-08-20 · 상태: 역추출 스냅샷 v1

1. 문서 개요

이 문서는 사전 기획서가 아니다. 2026-08-20 시점의 실제 구현·계약 문서에서 역추출(reverse-engineered)한 제품 요구사항 스냅샷이며, 제품이 "무엇을 하기로 되어 있고, 지금 어디까지 되어 있는지"를 한 장에서 조망하기 위해 작성됐다.

  • 이 문서와 개별 정본이 충돌하면 항상 개별 정본이 이긴다. 화면별 정본은 ../contracts/의 props 계약, 계산 의미의 정본은 ../policies/, 데이터·쓰기 계약의 정본은 ../data/의 각 문서다. 전체 문서 지도는 ../README.md.
  • 각 절에는 요구사항 요점과 함께 현재 상태(구현 / 부분 / 미배선 / 미구현) 를 명시한다.
  • 문서에서 확인하지 못한 서술은 "(추정)"으로 표시했다.

2. 제품 비전·포지셔닝

Barbelic은 바벨 중심 근력 운동(파워리프팅·역도·맨몸 스트렝스)의 기록·분석 앱이다. 태그라인은 "바벨아래 모든순간".

  • 저장의 최소 단위는 "세트"지만, 제품의 관점 단위는 세션이다: 하루 > 세션 > 종목 > 세트의 위계로 기록하고 조회한다 (../architecture/session-hierarchy.md).
  • 단순 로거가 아니라 통계 의미론이 버전 관리되는 기록계를 지향한다. 실측 PR과 추정치(e1RM)를 엄격히 분리하고, 계산 규칙 변경은 정책 버전·소급 replay와 함께만 허용한다 (../policies/README.md).
  • 기록에서 파생되는 레벨(누적 볼륨)·직업(주종목)·9단계 티어(수행 능력) 게이미피케이션으로 지속 동기를 제공한다 (./gamification-policy.md).
  • 제품명은 첫 글자 B를 대문자로 쓴 Barbelic이며 정규 주소는 https://www.barbelic.com (../process/brand-identity.md).

3. 타깃 사용자·핵심 사용 시나리오

문서에서 확인되는 상정 사용자는 바벨/맨몸 스트렝스 훈련을 수년간 지속하며 기록을 쌓는 리프터다(4년치 620세션 규모를 성능 기준 fixture로 사용, 외부 앱 이력 보유 사용자 상정).

핵심 시나리오:

  1. 운동 중 실시간 기록 — 시작(날짜·컨디션·계획 불러오기) → 기록(종목·세트·휴식 타이머·RPE) → 종료(리뷰·저장). 진행 중 이탈·새로고침·토큰 만료에도 드래프트가 살아남는다.
  2. 계획과 회고 — 미래 날짜에 계획 세션을 만들고, 지난 날짜에 완료 기록을 백필하며, 달력·하루 종합·세션 상세로 되짚는다.
  3. 기록 추적 — 종목별 실측 1RM~20RM, 추정 1RM 추이, 스트렝스 스탠다드 대비 티어를 확인한다.
  4. 기간 분석 — 주/월/분기/연 리포트로 볼륨·강도 분포·출석 리듬을 본다.
  5. 외부 이력 반입 — 타 서비스(WodUp) 운동 이력을 JSONL로 인입해 과거 기록을 확보한다.
  6. (계약만 존재) 소셜 — 팔로잉 피드로 친구의 세션 포스트를 본다.

4. 플랫폼·배포 형태

표면형태비고
모바일 웹React 18 + Vite SPA하단 탭: 홈 · 일지 · 피드 · 리포트 · 내 정보 + 메뉴 드로어(세션 검색 등)
데스크톱 웹동일 SPA의 데스크톱 화면군홈(프로필+피드) · 운동일지 · 나의 기록 · 훈련 통계 · 기록표 · 세션 검색 · 내 정보 · 관리자
iOSCapacitor/WKWebView 셸 (com.dekerd.barbelic)원격 정규 origin을 여는 얇은 셸 + 네이티브 인증 브리지 v1 (../platform/ios-setup.md, ../contracts/native-bridge.md)
  • 호스팅: Vercel (정적 dist-vite + 테스트 관리자 로그인용 Serverless Function 1개). 백엔드: Supabase (Postgres + RLS + RPC + Edge Functions + Storage + Auth).
  • 웹·iOS 모두 단일 origin https://www.barbelic.com을 사용한다. 릴리스는 DB migration → Edge Function → Vercel 배포가 한 release 단위로 묶인다.
  • UI 문안은 한국어이며 종목명은 한·영 병기다. 별도 다국어(i18n) 체계는 문서에서 확인되지 않는다(추정: 미도입).

5. 기능 요구사항

각 영역: 요구사항 요점 → 현재 상태 → 정본 문서.

5.1 온보딩·인증

  • 소셜 로그인 3종(Kakao·Google·Apple)을 독립 provider 모듈로 제공하고, 웹·iOS 모두 Supabase Auth PKCE 흐름을 쓴다. 데이터 소유자는 provider가 아니라 auth.users.id다.
  • 온보딩(모바일 5스텝): 약관 → 프로필+아이디 → 신체 정보 → 메인 종목(직업 6종 중 택1) → 초기 1RM 입력 → 웰컴. 진행 상태는 profiles에 저장되지만 이를 쓰는 공개 RPC는 없다(save_onboarding_progress는 2026-08-20 회수 — 중단하면 처음부터 다시 한다). 완료는 complete_onboarding만 가능하다.
  • 닉네임: 전역 유일 핸들이 아닌 표시명(중복 허용), 정규화 후 1~24자, placeholder 거부. 정책은 서버가 정본이고 UI는 같은 정책을 받아 즉시 피드백만 한다.
  • 약관 동의: terms_of_service v2·privacy_policy v2 필수, marketing v1 선택. 동의 이력은 append 보존형이며, 필수 동의 철회 시 온보딩이 consents 스텝으로 되돌아간다. 게시된 법률 문서 버전은 불변이다.
  • 계정 확장: 로그인된 사용자가 내 정보에서 미연결 provider를 같은 계정에 연결(identity linking) 할 수 있다. 연결 해제와 계정 병합은 범위 밖.
  • iOS는 barbelicNative 브리지 + barbelic://auth/callback custom scheme으로 외부 인증 세션을 열며, custom scheme에 토큰을 싣지 않는다.

현재 상태: 구현. 단 production 노출 gate(socialAuthProviders)는 기본 ["kakao"] — Google/Apple은 개인정보처리방침 v3 게시 등 출시 체크리스트 완료 후 활성화한다.

정본: ../contracts/onboarding-props.md · ../data/onboarding-data-model.md · ../platform/social-auth.md · ../contracts/native-bridge.md

5.2 운동 기록 (플로우 · 드래프트 보호 · 멱등 저장)

  • 3단계 플로우: 시작(날짜·시작 시간·컨디션·시작 전 메모·그날 계획 불러오기/빈 세션) → 기록(종목 추가·세트 입력·완료 체크·휴식 타이머·RPE(1.0~10.0 숫자, 단축 버튼 6~10)·세트/종목 리뷰) → 종료(운동 후 컨디션·세션 리뷰·요약 → 저장/폐기).
  • 세트 입력: 세트 타입(웜업/메인/다운), 중량은 kg canonical + lb·%(1RM 대비) 입력 모드 원본 왕복 보존, 반복수, 휴식(초 또는 자유 휴식), 메모. 맨몸 종목은 검토된 체중 계수(0/0.25/0.5/0.75/1.0)로 "유효 무게 = 추가 중량 + 체중×계수"를 계산하고 저장 시 당시 체중을 스냅샷으로 고정한다.
  • 종목 확장 입력: 수행 디테일 태그(최대 3, 통계 귀속 불변), 연속 동작(복합) 세트 빌더, 세트 없는 자유 기록(kind:"note" — 통계 미귀속).
  • 드래프트 보호: 진행 중 드래프트는 UI-local이되 스냅샷(step·활성 세트·휴식 타이머 포함)을 debounce 저장. owner-scoped IndexedDB에 7일 보존, 계정 전환 시 경계 침범 금지, 서버 저장 확정·명시적 폐기·만료에만 삭제.
  • 멱등 저장: 완료 운동의 생성·수정·삭제는 v4 RPC 3종만 사용. client mutation UUID + request hash + 서버 workout_mutation_receipts 고유 제약으로 중복 반영을 차단하고, 수정·삭제는 revision CAS(충돌 시 자동 병합 없이 재조회 안내). 신규 생성의 복구 가능한 실패만 로컬 pendingSaves로 보존해 재전송한다(수정·삭제는 live-only).

현재 상태: 구현. 단 모바일의 구조화된 연속 동작 입력·수정 경로는 미구현(데스크톱 대비 격차 — §8).

정본: ../contracts/workout-screen-props.md · ../contracts/completed-workout-write-pipeline.md · ../data/workout-draft-protection.md

5.3 달력·일지·계획

  • 세션은 3상태 — completed(완료·파랑) / missed(과거 미완료·회색) / planned(미래 계획·회색). 완료 기록·계획·그룹 운동 계획은 모두 session > session_exercise > session_exercise_part > exercise_set > exercise_set_part 다섯 층의 session 행이며 status로 구분한다(계획 = planned, 그룹 운동 계획 = planned + group_id; 이슈 #1215, 2026-09-04). 계획을 완료하면 같은 행이 completed가 된다.
  • 모바일 일지 탭 = 풀스크린 월 달력. 날짜 탭 → 하루 상세 드로어(하루 합계 + 세션 카드) → 세션 상세. 하루 종합의 합계는 완료 세션의 done 세트 기준이며 종목 행은 메인 세트 토큰(80kg×5, 82.5kg×3)으로 요약한다.
  • 데스크톱 운동일지 = 단일 월 스텝퍼 달력 + 하루 패널 2컬럼, 계획 작성·기록 백필·기록 수정은 중앙 컴포저 모달로 처리한다.
  • 데이터는 월 summary RPC(get_calendar_month_summary)와 일 summary RPC(get_calendar_day_summary)만 사용하고, 세션을 실제로 열 때만 get_session_detail을 호출한다. 계획 저장·삭제는 updated_at CAS revision으로 보호한다.
  • 하루 컨디션은 daily_conditions가 정본이며 홈·달력 배지에 공급된다.
  • 계획 반영(공유) v1(2026-08-23, 20260821490000) — 폐기(2026-09-04, #1215; 테이블·RPC·앱 데이터층 제거, 아래는 과거 기록): 팔로우한 사람의 달력(get_following_calendar_month_v1)에서 계획을 골라 내 달력에 링크로 반영한다(adopt_planned_session_v1/unadopt_planned_session_v1, 저장소 planned_session_adoptions). 반영한 계획은 내 달력 월/일 요약·홈 이번 달 계획에 plan_owner와 함께 섞이고 읽기 전용(만든 사람만 수정, 수정은 그대로 전파)이다. 그 계획으로 운동을 시작하면 드래프트가 복사본이 되어 수행자가 자유롭게 고치고, 완료 저장(save_workout_v4)하면 본인 세션이 되며 반영 행만 완료 처리된다(원작자 계획 불변). 클라이언트 데이터층(planAdoptionStore·카드/상세 어댑터의 planOwner/readOnly·편집기 진입 차단·삭제=반영 취소)까지 배선, UI 미배선(친구 달력 열람·반영 버튼·반영 카드 표식은 다음 단계).

현재 상태: 구현(계획 반영은 서버·데이터층만, UI 대기).

정본: ../contracts/session-screen-props.md · ../contracts/day-summary-props.md · ../contracts/desktop-screens-props.md · ../architecture/session-hierarchy.md · ../architecture/calendar-read-model-architecture.md

5.4 PR·기록 (실측/추정 1RM · 스트렝스 스탠다드)

  • 실측(NRM)과 추정(e1RM)의 엄격 분리: 실제 수행한 정확한 1..20RM만 measured PR state/event를 만들고, e1RM은 별도 추정 projection으로만 존재한다(PR 알림·state 생성 금지).
  • 종목 상세 화면: 히어로(실측 1RM·PR일·티어) → 3/5/8/10RM 기록표 + 티어 진행 래더 → 추정 1RM 추이(연도 스테퍼) → 훈련 빈도 잔디 → 최근 12주 요약(볼륨/강도/세션) → PR 추세·탑세트 → 훈련 목록·리뷰. 빈 상태는 hasRecords로 판정한다.
  • 티어 컷은 Strength Level 5앵커 → 분위수 곡선 모델로 파생한 성별·전체급 9단계 컷을 사용한다(§5.6).
  • PR 도구: 주요(즐겨찾기) 종목 목록 관리(추가·제거·드래그 정렬 즉시 적용), 1RM 직접 입력(kg/lb, 날짜 선택·모름 허용) — 온보딩 초기 1RM은 user_manual_pr_records에 저장.
  • 데이터는 raw 세트 재계산이 아니라 materialized stats·PR state/event·버전 고정 strength projection을 RPC로 받는다. 종목 상세는 fragment 순차 로딩(첫 12주 → 연도·PR·history 페이지 drain)으로 채운다.

현재 상태: 구현 (모바일 기록 탭은 2026-08-12 폐지 — 히어로·보드는 홈으로 흡수, 종목 상세 + 도구 2종만 유지).

정본: ../contracts/records-props.md · ../data/measured-pr-state-events.md · ../policies/e1rm/README.md · ../architecture/data-loading-strategy.md

5.5 리포트·통계

  • 모바일 리포트 탭: 기간(주/월/분기/연) 단위 A~F 섹션 — 헤드라인(총볼륨·운동일) / TOP 세트 5 / 볼륨 잔디 / 세션당 평균·종목·부위 랭킹 / 강도 분포(세트 무게 히스토그램·세트 목적 존·RPE) / 꾸준함(출석·세션 시간 분포·시간대 리듬). 종목 필터 지원. 데이터 없는 블록은 비노출(fail-safe).
  • 데스크톱 훈련 통계: 기간 세그 + 종목 드롭다운, 막대 추이 클릭 → 일/주/월 drilldown 모달. 세션 시간 분포·시간대 리듬은 서버 exact vector만 렌더한다.
  • 데스크톱 기록표(메인세트 모아보기): 즐겨찾기 그룹 × 월 그리드. 월 이동은 집계 셀만(get_log_table_month, 31×30행·900KB cap(#938 D7)), 셀 상세는 열람 시 1회(get_log_table_cell_detail, LRU 64).
  • 데스크톱 홈: 프로필·벤치마크 기록(최대 8종)·연간 잔디·누적 볼륨 카드·주간 계획 + 세션 피드 컬럼.

현재 상태: 구현.

정본: ../contracts/report-props.md · ../contracts/logtable-props.md · ../contracts/desktop-screens-props.md

5.6 게이미피케이션 (레벨·직업·티어)

  • 레벨 = 누적 볼륨(kg). 별도 XP 저장 없음(XP = 누적 볼륨), 기록 수정·삭제 시 재계산. Lv.1~30은 고정표(누적 6,000kg → 1,792,500kg), Lv.31부터 100,000kg + 500kg×(N-31) 공식(Lv.100 누적 10,000,000kg).
  • 직업 4종: 파워리프터(3대), 역도인(스내치·클린 앤 저크), 맨몸운동인(풀업·딥스·푸시업), 짐네스터(머슬업·HSPU). 직업 티어는 구성 종목 앵커 합산 후 공통 곡선 적용, 구성 종목 기록이 전부 있어야 계산.
  • 9단계 티어: 아이언~레전드, Strength Level 성별 앵커(Beginner~Elite 5점) → strengthlevel-normal-quantile-quadratic-v1 모델로 p25~p99.7 컷 파생. 남/여 분리, v1은 전체급만, 기준 데이터 없으면 미배치(타 성별 대체 금지). 레전드 컷은 모델 외삽값임을 명시.
  • 레벨은 운동량 누적, 티어는 수행 능력 — 상호 독립.

현재 상태: 구현 (정책 상수·볼륨 레벨 계산기·홈 노출·직업 카드·성별 일치 기준행). 후속: 레벨 진행률 전용 UI, 체급별 기준, 바 머슬업·엄격 HSPU 전용 기준(현재 대리값).

정본: ./gamification-policy.md

5.7 피드·소셜

  • 피드 탭 = 세션 포스트 타임라인(내 포스트 + 팔로잉 포스트 계약). 포스트 = 완료 세션(리뷰 본문 + 기록 첨부 카드 + KPI), 7일 이내 상대 날짜 표기, 무한 스크롤. 저장 직후 새 세션이 새로고침 없이 피드에 나타나야 한다(E2E CASE-004 검증).
  • 소셜 UI 계약: 팔로잉 스트립, 친구 검색 시트, 친구 프로필 시트(이번 달 운동/볼륨/올해 PR + 4대 1RM), 팔로우/언팔로우 토글, 친구 홈 페이지 열람.
  • 현재 상태: 구현 — 친구 검색·팔로우 v1(2026-08-22, 20260821460000) + 아이디(@handle)·친구 사진(2026-08-23, 20260821470000) + 팔로잉 포스트(2026-08-23, 20260821480000); 친구 프로필 시트·친구 홈 페이지는 미배선. 친구 추가 시트에서 아이디(profiles.handle) 또는 닉네임 부분일치 검색 → 팔로우/팔로잉 토글이 동작하고 팔로잉 목록이 서버(user_follows)에 저장된다. @handle은 온보딩 완료 시 complete_onboarding(payload.handle)로 저장되며(유일·정규화, 충돌 시 인라인 오류) 내 정보 탭(모바일·데스크톱)에서 설정/변경한다. 친구 행 사진은 소셜 제공 사진 또는 profile-images 서명 URL로 보인다. 피드 탭 = 내 포스트 + 팔로우한 사용자의 포스트(get_profile_feed가 한 정렬로 싣고 친구 카드에 author; 팔로우/언팔로우 직후 재조회). 팔로우는 승인 없는 단방향이라 팔로우하면 상대의 완료 세션(리뷰·자유 기록·main 카드·KPI)이 내 피드에 보인다. 친구 리포트(2026-08-23, 20260821520000): 친구 포스트의 아이디/아바타를 탭하면 그 친구의 리포트 페이지(get_following_volume_overview_v1 — 팔로우 게이트 뒤에서 내 리포트와 같은 볼륨 개요)가 피드 탭 위에 열리고 "피드로 돌아가기"로 복귀한다(조회 전용: 종목 점프·날짜 드로어 없음). 친구 프로필 시트·친구 홈 페이지는 계약만 있다. 좋아요·댓글 v1(2026-08-23, 20260821530000): 피드·홈 포스트 푸터의 하트/말풍선으로 본인 또는 팔로우한 사람의 완료 세션에 좋아요·댓글(1~500자, 작성자·세션 소유자가 삭제)을 남기고, 카드가 social{like_count, comment_count, liked_by_me}를 싣는다. 같은 변경으로 친구 카드 "자세히 →"가 세션 상세(읽기 전용 드로어)를 연다 — get_session_detail이 완료 세션의 팔로워 읽기를 허용. 계획 반영(공유) v1(2026-08-23, 20260821490000): 팔로우한 사람의 계획을 내 달력에 링크로 반영하는 서버 RPC·클라이언트 데이터층이 있다(§5.3) — 친구 달력 열람·반영 버튼 UI는 다음 단계.

정본: ../contracts/feed-props.md · ../updates/2026-08-23-plan-adoption.md

5.8 검색

  • 모바일 세션 검색 탭(메뉴 드로어): 종목을 고르면 그 종목의 세트 기록만 세션당 1항목·최신순으로 조회(요약 = n회 훈련·n세트·총 볼륨, 무한 스크롤).
  • 데스크톱 세션 검색: get_session_search가 반환한 최근 완료 세션 최대 120건에 대해 제목/종목명 부분일치 + "PR 세션만" 필터.
  • 종목 카탈로그 검색: 컨트롤러 소유 검색 모델(IME 조합·debounce·정규화 포함)을 화면이 어댑터로만 소비. placeholder 종목도 검색 가능해야 한다.

현재 상태: 구현 (데스크톱 검색의 view 마커 dashboard.search 레지스트리 등록은 후속).

정본: ../contracts/setsearch-props.md · ../contracts/desktop-screens-props.md

5.9 외부 데이터 인입 (WodUp)

  • JSONL 업로드 → 브라우저가 Storage 업로드 + batch 행 생성 → Edge Function이 enqueue 후 HTTP 202 즉시 반환 → 백그라운드 워커가 검증·정규화·스테이징·정본화 → UI는 batch 상태를 폴링(queued → normalizing → importing → completed / completed_with_placeholders / failed). 재시도 안전(중복 워커는 소유권 클레임으로 배제), 통계 재계산은 refresh job 큐로 위임.
  • 종목 정체성: 외부 provider 키는 스코프드 키 → 감사된 매핑 → canonical UUID로만 연결하고, 미해석 행은 placeholder/unresolved로 원본 보존한다. 식별자 발급 문법은 BRID로 통일 (../data/brid.md).
  • 재인입 의미론: 현재 시행 중인 정책(lift-guild.wodup-replay@1.0.0)은 "재인입 시 업로드 원본이 정본 — 앱 내 편집은 원복, 앱 고유 문맥(메모·컨디션·kudos 등)만 보존"이다.
  • 방향 전환(2026-08-19 오너 결정): 외부 인입을 동기화형에서 일회성 read-only 인입으로 강등하는 재설계가 확정됐다 — 인입 세션은 앱에서 편집 불가로 두고 replay(재인입 원복) 정책은 폐기 수순, 인입 전량 제거 프리미티브(remove_import_data_v1)가 먼저 랜딩됐다. 이 방향은 아직 wodup-replay 정책 문서에는 반영되지 않았다(전환 진행 중 — 별도 설계서 존재).

현재 상태: 파이프라인 구현 / 재설계 전환 중. 관리자 인입 UI(드롭존·사전검사 5종·진행·결과·placeholder 목록)는 구현.

정본: ../data/wodup-import-async-jobs.md · ../policies/wodup-replay/README.md · ../policies/exercise-model/README.md

5.10 내 정보·데이터 도구

  • 모바일: 프로필 카드(사진/이니셜·메타) + 소셜 로그인 연결 상태·연결 버튼 + 데이터 내보내기 + 로그아웃. 가져오기는 컨테이너 미배선(prop 미전달 시 행 자체 비노출).
  • 데스크톱: 위 항목 + 프로필 사진 업로드, 체성분 입력(체중·골격근량·체지방량 kg, body_metrics upsert), WodUp/InBody 파일 인입 진입점, 내보내기/가져오기.

현재 상태: 구현(모바일 가져오기 제외).

정본: ../contracts/profile-screen-props.md · ../contracts/desktop-screens-props.md

5.11 관리자 도구 (barbelic-docs /admin, 전역 데이터 전용)

  • 관리자 페이지는 앱이 아니라 문서 사이트 프로젝트(barbelic-docs)의 /admin/에서 독립 셸로 동작한다(2026-08-22 데스크톱 앱의 관리자 탭·/admin 라우트 제거 — 이관은 2026-08-21 #551). 관리자 계정(is_lift_guild_admin)으로 소셜 로그인 후 사용한다. 정본: ../process/deployment-pipeline.md "관리자 셸" 절.
  • 단일 관리자 페이지에서 뷰 전환: 운동 분류(아키타입→하위 종목→디테일 3-pane, 별칭·태그·검수 큐), 수행 디테일 카탈로그, 외부 매핑(WodUp → Barbelic 단방향, 2026-08-22 확정 — 역방향 토글 없음), WodUp 인입, 운영 콘솔. 개인 데이터(1RM·PR·즐겨찾기)는 다루지 않는다.
  • 운영 점검: get_admin_operations_checklist()가 DB/인입/통계 헬스 체크 + Edge Function 배포 버전 프로브 + migration history 검사를 묶어 제공한다.
  • 관리자 대리 인입(2026-08-21): WodUp 인입 탭에서 대상 계정을 골라 다른 유저 명의로 인입할 수 있다. 권한은 서버 is_lift_guild_admin()(배치 RLS·storage 정책·Edge Function)이 판정하고, 배치에 initiated_by_user_id(관리자)가 남는다. 조회 전용 임퍼서네이션(유저 열람)과는 별개 경로.

현재 상태: 구현 (action/view 마커 레지스트리 등록은 후속, 검수 큐 상세 모달 미구현).

정본: ../contracts/desktop-screens-props.md · ../data/admin-health-report.md

6. 비기능 요구사항

6.1 로딩 성능

  • "summary 우선 + detail on demand" — 로그인 직후 raw 전체 이력을 로드하지 않는다. 첫 화면은 materialized summary/stat 테이블로 열고, raw 세트는 세션 상세를 열 때만 가져온다. 초기 로딩 비용이 사용 기간에 비례해 커지지 않아야 한다 (../architecture/data-loading-strategy.md).
  • 화면 RPC는 JSONB 응답 계약·byte/shape cap·auth.uid() 소유권을 강제한다 (../data/app-screen-rpc-contract.md).
  • 인접 월 prefetch·fragment 순차 로딩·keyset 페이지네이션·화면별 캐시 키·generation 검사로 stale 응답을 폐기한다.
  • 로딩 UX: 화면을 게이트/스피너로 막지 않고, 크롬 실물 + 데이터 자리 스켈레톤(셔머)을 즉시 렌더한다(예: 리포트 pending, 데스크톱 로딩 오버레이 계약). 스피너 칩 전면 폐기·스켈레톤 단일 계열은 2026-08-19 오너 확정 원칙이다(계약문에 반영 진행 중).

6.2 데이터 정합성

  • 모든 완료 운동 쓰기는 멱등(mutation receipt + client mutation UUID + request hash), 수정·삭제는 revision CAS. 실패 시 자동 병합·부분 반영 금지.
  • 통계는 원자 쓰기와 분리된 stats refresh job 큐로 비동기 재계산한다. 어떤 쓰기가 통계를 dirty로 만드는지는 이벤트 계약으로 고정(과거 수정은 최소 안전 범위 무효화) (../data/stats-refresh-jobs.md, ../data/stats-refresh-dirty-events.md).
  • 계산 의미 변경은 정책 major 버전 + 전량 replay 없이는 금지 (§7).

6.3 장애 내성

  • 인증 실패와 데이터 로딩 실패를 분리한다: 세션이 있는데 데이터가 실패하면 로그인 화면이 아니라 복구 가능한 데이터 오류 화면을 보여야 한다.
  • 신규 생성의 복구 가능한 실패는 로컬 pending 큐로 보존 후 연결 회복 시 순서대로 재전송(서버 멱등성이 중복 방지). degraded 열람용 read snapshot은 쓰기 경로와 격리된 별도 저장소를 쓴다.
  • 드래프트는 토큰 만료·리로드·일시 네트워크 장애에서 생존해야 하며 계정 경계를 넘지 않는다.

6.4 관측성

  • 브라우저·React·RPC·네트워크·드래프트 영속 실패를 record_client_error_event로 전용 client_error_events 테이블에 적재한다. 전송은 사용자별 파티션·중복 억제·rate cap(브라우저 20/분, DB 60/분·1,000/24h).
  • 로그에는 원시 운동 payload·업로드 파일 내용·토큰·이메일·파일명·쿼리스트링을 절대 넣지 않는다. 상관관계 필드(operationId·durationMs·responseBytes 등)와 프론트 debug ring으로 느린 RPC를 진단한다 (../architecture/observability-logging.md).

6.5 단위·표기

  • 저장·통계의 canonical 단위는 kg. 입력은 kg/lb/%(1RM 대비) 모드를 지원하며 비-kg 원본(loadLb/loadPct)을 왕복 보존한다. 회수 단위 종목(풀업 등)은 반복수 기준으로 기록·티어 산정한다.

7. 정책으로 고정된 제품 의미론

버전 관리되는 계산 정책 5종 — 사람용 README + 기계용 manifest + 불변 스냅샷 + changelog가 한 세트이며 CI(npm run check)가 위반을 차단한다. 계산 의미 변경 = major 버전 + 전량 replay.

정책 (ID@버전)고정하는 의미시행 상태
e1RMlift-guild.e1rm@2.0.0추정 1RM: Nuzzo 2024 역보간 곡선 + 제품 앵커(100%1RM=1회), RIR 5단계 체감 표, confidence(high/medium/low), 실패 세트 2갈래 처리, 세션 투표·일별 대표점·90일 stale, 실측 NRM과의 분리enforced (생성 스크립트+SQL 계약 테스트)
max-repsbarbelic.max-reps@1.0.0맨몸/횟수 종목의 추정 최대 반복수 = 실제 반복 + 체감 밴드 RIR (kg 곡선 미적용). 추정치는 measured PR을 만들지 않음enforced
set-purposebarbelic.set-purpose@2.0.0세트 목적(지구력/비대/스트렝스) 분류 — 실제 반복수+체감 밴드 기준, 체감 없는 고반복 세트는 미분류enforced (UI까지 최광역 소비)
exercise-modellift-guild.exercise-model@1.0.1종목 정체성 = 불투명 UUID 단일 식별자, canonical 종목 / 연속 동작 세트(컴플렉스) / 표시 묶음의 3분리, 외부 해석 상태 기계, 통계 귀속 표accepted / partial — 목표 모델이며 구현 격차 감사표 동봉
wodup-replaylift-guild.wodup-replay@1.0.0재인입 시 업로드 원본이 정본, 앱 고유 문맥만 보존, 멱등 재실행enforced — 단 §5.9의 일회성 인입 강등 방향으로 대체 예정

8. 미구현·알려진 격차 (2026-08-20)

영역격차근거
피드/소셜친구 검색·팔로우(user_follows, 2026-08-22)·아이디(@handle)·친구 사진·팔로잉 포스트·친구 리포트(포스트 아이디/아바타 탭, 2026-08-23)는 배선됨. 친구 프로필 시트·친구 홈 페이지는 UI 계약만../contracts/feed-props.md
계획 공유(반영)폐기(2026-09-04, #1215) — 2026-08-23 배선됐던 서버 RPC(adopt/unadopt_planned_session_v1, 달력/홈/상세 합류, save_workout_v4 반영 완료 처리)와 클라이언트 데이터층(planAdoptionStore·어댑터·읽기 전용 가드)은 제거됐다(adopt/unadopt는 LG426 스텁). get_following_calendar_month_v1(친구 달력 읽기)만 남아 있다../updates/2026-08-23-plan-adoption.md
길드(랭킹)·회복 화면초기 요구사항에만 존재, 현행 화면 인벤토리에 없음 — 미구현../archive/claude-functional-requirements.md (아카이브) vs designContract.ts view 목록
모바일 데이터 가져오기onImport 컨테이너 미배선 (행 비노출)../contracts/profile-screen-props.md
종목 모델exercise_kind·관계형 컴플렉스 모델 DB 미구현, 모바일 연속 동작 구조화 입력 미구현, WodUp 컴플렉스 인식·매핑 target·원본 불변 보존 미준수, placeholder의 PR/e1RM 참여 차단 미완 — 감사표의 미준수/위험 항목 다수../policies/exercise-model/README.md §현재 구현 감사
외부 인입동기화형→일회성 read-only 인입 강등 재설계 진행 중 (replay 정책 대체 예정)§5.9
소셜 로그인Google/Apple production 미노출 (privacy v3 게시 등 출시 게이트 잔여)../platform/social-auth.md
게이미피케이션레벨 진행률 전용 시각 UI·체급별 티어·바 머슬업/엄격 HSPU 전용 기준 미도입(대리값 사용)./gamification-policy.md §6
온보딩데스크톱 스텝 순서·아이디 스텝의 모바일 동조, 아이디 중복 검사 RPC 등 후속 항목 잔여../contracts/onboarding-props.md Codex 후속
마커 레지스트리관리자 action/view 마커, 데스크톱 검색 dashboard.search 등 등록 후속../contracts/desktop-screens-props.md §신규 마커 요청
알림/푸시, 오프라인 완전 지원문서에서 확인되지 않음 (추정: 범위 밖 또는 미착수)

이 문서는 스냅샷이다. 화면·데이터·정책의 최신 정본은 항상 ../README.md 인덱스에서 찾는다.