Skip to content

Session Hierarchy

작성일: 2026-06-03 · 개정: 2026-09-04 (이슈 #1215 다섯 층 모델)

데이터 모델 정본은 session-data-model.md이다. 이 문서는 위계·상태·테이블을 화면과 파일 소유권 관점에서 요약한다.

데이터 위계

운동 기록의 기준 위계는 아래와 같다(이슈 #1215, 2026-09-04부터 다섯 층).

text
하루
  세션 N개                 -- session
    종목 N개               -- session_exercise (복합 종목이면 동작들을 묶는 층)
      세부 종목 1~5개      -- session_exercise_part (동작 하나; 단일 종목은 정확히 1개)
      세트 N개             -- exercise_set (세트 한 번)
        세부 세트 N개      -- exercise_set_part (세부 종목 하나의 값: 횟수·무게 …)

하루는 기록의 조회 단위일 뿐, 저장 단위가 아니다. 저장 단위는 세션이다.

세트 수 규칙(오너 결정 D1~D3): 세션·종목의 총 세트 수는 exercise_set 행 수, 세부 종목(동작)별 세트 수는 그 세부 종목을 가리키는 exercise_set_part 행 수, 횟수·볼륨은 세부 세트 단위로 더한다. 서버 헬퍼는 session_set_totals_v1(session_id).

세션 상태

세션은 세 가지 상태로 표시한다.

  • completed: 완료한 과거 기록. 파란색으로 표시한다.
  • missed: 과거에 기록해두었지만 완료하지 못한 기록. 회색으로 표시한다.
  • planned: 미래의 기록. 회색으로 표시한다.

완료 기록·계획·그룹 운동 계획(보드)은 모두 session 테이블의 행이며 session.status로 구분한다.

  • 완료 기록: status = completed
  • 계획: status = planned — 날짜가 오늘보다 과거로 지나가면 missed
  • 그룹 운동 계획(보드): status = planned + group_id(그룹 리더 소유)

계획을 수행해 완료하면 같은 행planned → completed로 바뀐다(새 행도, 연결 테이블도 없다). 하지 않은 세트는 지워진다. 보드에서 시작한 완료 세션은 origin_kind = 'group-board', origin_ref = '<group_id>:<date>'로 출처를 남긴다.

Supabase 구조

완료 기록·계획·그룹 운동 계획이 한 구조를 쓴다.

text
session
  session_exercise
    session_exercise_part
    exercise_set
      exercise_set_part
  • session_exercise_part.session_exercise_idexercise_set_part.exercise_set_id는 NOT NULL — 소속 없는 세부 행은 존재할 수 없다.
  • planned_sessions·planned_sets·group_boards·group_board_sets·group_board_likes·group_board_comments·planned_session_adoptions 테이블과 composite_meta 컬럼은 이슈 #1215(2026-09-04)로 삭제됐다. 보드 좋아요·댓글은 session_likes·session_comments로 합쳐졌다. 계획 반영(팔로우한 사람의 계획을 내 달력에 링크로 가져오기)은 기능 자체가 폐기됐다.
  • 읽기 표면: 통계·달력·피드 함수는 completed_session_v1·planned_session_v1 뷰를 읽는다. 복합 종목의 묶음은 별도 메모 없이 층 필드로 읽는다(이슈 #1244): 읽기 함수(세션 상세·달력 하루 요약·피드 카드·계획 상세)가 세부 종목 행마다 session_exercise_id(소속 종목 id)·session_exercise_name(종목 이름, 복합이 아니면 ''session_exercise_position(종목 순서)·movement_position(종목 안 동작 순서)·details(수행 상세)를 싣고, 계획 상세는 exercise_set_position(세트 순서)도 싣는다. 같은 소속 종목에 동작이 2개 이상이면 앱이 한 종목(복합)으로 묶는다. 옛 composite_meta 합성 함수(session_part_composite_meta_v1·bounded_home_composite_meta)는 삭제됐다.
  • 쓰기 계약: save_session_v5(p_payload, p_client_mutation_id, p_request_hash)(완료·계획·그룹 계획의 생성·수정·계획→완료 전이) + delete_session_v5(p_session_id, p_expected_revision, p_client_mutation_id, p_request_hash) 한 쌍. 상세는 workout-write-path.md.

주요 테이블

session — 세션 한 행(완료 기록·계획·그룹 운동 계획)

  • id, user_id, date, status(completed | planned | missed)
  • group_id(그룹 운동 계획이면 그룹 id, 개인은 null), origin_kind·origin_ref(보드에서 시작한 완료 세션의 출처)
  • title, note, condition, pre_note, post_condition, start_time, end_time, duration_label, scheduled_time, body_weight_kg, session_intent
  • source, source_ref, brid, server_revision(모든 종류의 낙관적 동시성 — 계획이 쓰던 expected_updated_at 대체), kudos, created_at, updated_at

session_exercise — 종목 한 행(복합 종목이면 동작들을 묶는 층)

  • id, session_id, position, name, import_group_key(WodUp 인입 복합 묶음 키, 앱 저장은 null), created_at

session_exercise_part — 세부 종목(동작) 한 행; 단일 종목은 정확히 1개

  • id, session_exercise_id(NOT NULL), session_id, exercise_id, synonym_id, position
  • entry_kind, entry_title, note, entry_review, recording_fields, bodyweight_factor, load_multiplier
  • source, source_ref, provider_exercise_id, raw_payload(선택한 수행 디테일 details 포함), created_at

exercise_set — 세트 한 행

  • id, session_exercise_id, position, set_type, created_at

exercise_set_part — 세부 세트 한 행(세부 종목 하나의 값)

  • id, exercise_set_id(NOT NULL), session_exercise_part_id(세부 종목 id, #1245), position, set_type
  • reps, target_reps, set_result, load, load_unit, load_lb, effective_load, assist_kg, duration_seconds, distance_meters, calories
  • perceived_rpe(RPE 1.0~10.0 — 이슈 #1237로 5단계 번호·옛 난이도 컬럼 삭제), rest_seconds, free_rest, note
  • source, source_ref, raw_payload, created_at

화면 표현

모바일 세션 페이지 달력:

  • 완료 세션이 있는 날짜: 파란색 표시
  • 미완료/예정 세션이 있는 날짜: 회색 표시
  • 하루에 세션이 여러 개면 날짜 셀에 개수를 작게 표시

선택 날짜 상세:

text
선택한 날짜
  세션 카드
    상태 배지
    종목 수 / 세트 수 / 볼륨 또는 계획
    종목 목록
      세트 목록

파일 소유권

  • 현재 React 앱 surface: src/react/
  • 세션/홈/운동 입력 UI: src/react/ui/screens/SessionScreen.jsx, src/react/ui/screens/HomeScreen.jsx, src/react/ui/screens/WorkoutFlow.jsx, src/react/ui/styles/styles.css
  • 화면 UI: src/react/ui/screens/*의 순수 프레젠테이션 컴포넌트가 담당한다. root-level 보조 화면 파일은 로드하지 않는다.
  • Supabase 공개 facade: src/react/services/barbelicApi.js
  • Supabase 읽기/쓰기: src/react/services/barbelicRepository.js
  • 데이터 변환/요약 계산: src/react/services/barbelicMappers.js
  • 디자인/기능 접합 마커 계약: src/react/contracts/designContract.js
  • Supabase 전체 schema: supabase/schema.sql

개인 상태 저장

  • 날짜별 컨디션: daily_conditions기능 폐기(2026-08-24, #668)
    • 키: user_id + date
    • 테이블·과거 데이터는 보존하지만, 앱은 더 이상 읽지도 쓰지도 않는다(파이프라인 제거).
  • 주 운동 스타일: profiles.primary_training_style
    • 온보딩의 6종 선택값을 안정적인 식별자로 저장한다.
    • 신체 변화 이력은 body_metrics, 초기 1RM은 user_manual_pr_records가 정본이다.
  • DB migration baseline: supabase/migrations/20260821000000_baseline_v2.sql
  • Legacy patch reference: supabase/legacy/exercise_sets_patch.sql (do not apply)