Skip to content

운동 전후 컨디션 기능 전면 제거 — 화면의 유령 표시에서 서버 조작 기입 중단·데이터 정리까지 (2026-08-24)

  • 기간: 2026-08-24 (2세션 — 전 세션 Phase 1 인계, 이 세션 Phase 2~4. 오너 보고: "세션마다 운동전 컨디션, 운동후 컨디션 표시해주는데, 사실 이거 없어진 기능이거든. 싹 정리해줄 수 있어?")
  • 랜딩: PR #686 (Phase 1~3, 01a49249) — 마이그레이션 20260821670000, 엣지 0건, 웹 Vercel 자동 배포 확인. 후속 PR #706 (3e5315d5, 20260821700000) — 모트라 인입 엔진의 '보통' 채움까지 제거(오너 지시 "모트라 재인입시도 안채우게")
  • 설계서: 없음(정리 트랙) — 계획·오너 결정·Phase 진행은 이슈 #668 쓰레드가 정본
  • 정본: session-screen-props(en·ko) 통과 필드 조항, session-hierarchy daily_conditions 폐기 명시, src/react/services/appShellSnapshotProjection.ts 스키마 버전 v3 주석
  • 도구: 없음
  • 게이트: tests/react/workoutFlowDraftSafety.test.mjs — 통과 필드 왕복 보존 + "보통" 자동 기입 재발 방지
  • 버그리포트: 없음 (결함이 아니라 폐기 기능 잔존 — 이슈 #668로 관리)
  • 계약: session-screen-props(en·ko)에서 conditionByDate/onSetCondition 제거, 스냅샷 키 래칫 v3

Phase 현황

Phase내용상태
Phase 1UI 표시·입력 표면 전면 제거 (전 세션 인계)✅ PR #686 (7ce29dda)
Phase 2재베이스·검증·왕복 보존 테스트✅ PR #686 (e1e3a9d9)
Phase 3잔여 배관 D2~D5 삭제 + 조작 기입 중단 + 마이그레이션 670000✅ PR #686 (7fa88455)
Phase 4머지 · Production 적용·검증 · 기록✅ 이 문서

1. 배경

컨디션(운동 전/후) 기능은 폐기됐지만 완전히 꺼지지 않았다. 게이트 상수(POST_COND_UI = false)로 숨긴 표면과 그대로 렌더되던 표면(모바일·데스크톱 세션 상세, 데스크톱 backfill 입력)이 공존했고, 오너가 "없어진 기능인데 세션마다 표시된다"고 보고했다.

2. 문제 제기

표시·입력이 표면마다 제각각 살아 있었다

세션 상세 두 플랫폼의 컨디션 전/후 듀오 타일, 데스크톱 backfill의 칩 2줄이 항상 렌더. 게이트 방식의 부분 적용이 원인.

"보통" 자동 기입이 이슈 기재보다 훨씬 깊었다

Phase 1이 고친 makeFlowDraft 기본값 외에 — 클라이언트 8곳(저장 payload 2 · 드래프트 빌더 2 · 읽기 매퍼 4)과 서버 save_workout_v4_enginecoalesce(...,'보통'), sessions.condition 컬럼 default '보통' 까지 조작 기입이 살아 있었다. 즉 UI를 다 꺼도 신규 세션마다 '보통'이 저장되고 있었다. 실측: Production 세션 1,996행 중 1,994행이 '보통'.

죽은 배관이 스냅샷·읽기 모델까지 닿아 있었다

daily_conditions 읽기(부팅 질의 1개)·쓰기 체인, conditionByDate 투영 전 구간, 부팅 스냅샷의 conditions 페이로드, CONDITION_SCORE/cond7 파생 — 호출 진입점 없이 전부 잔존.

3. 해결 방안

원칙 (오너 결정, 2026-08-24)

  • D2 삭제 · D3 삭제 · D4 삭제 · D5 삭제 — "전부 걍 지우면 될듯." 별도 트랙 이월 없이 이 트랙에서 전부 수행.
  • 유지(전 세션 D1): sessions.condition/post_condition 컬럼, daily_conditions 테이블·데이터 — 드롭 없음. '보통' 외 과거 값은 통과 필드로 보존.

접근

  • 게이트 상수로 숨기기 — 부분 적용이 지금 상태를 만든 원인. 마크업·배관째 제거로 통일.
  • 스냅샷에서 conditions만 무시 — exactRecord 키 래칫이 양방향이라 키를 남기면 계약이 거짓말을 한다. 스키마 버전 2→3으로 구 스냅샷을 무효화(1회 콜드 부팅)하는 기존 메커니즘 사용.
  • 모트라·wodup 인입 엔진까지 재발행 — BUG-013 수리 직후 실사용 검증된 경로와 봉인된 일회성 경로. 안정성 리스크가 이득보다 커서 기각, 잔여로 기록.

4. 적용한 내용

Phase 1 — UI 표면 제거 (7ce29dda, 전 세션)

세션 상세(모바일 SessionSheetBody·데스크톱 DesktopSessionDetailParts) 컨디션 타일, WorkoutFinish 게이트 블록, 데스크톱 backfill 칩, makeFlowDraft 기본값, designContract 마커 2건, CSS 3계열, 계약 문서 5종.

Phase 2 — 검증·왕복 잠금 (e1e3a9d9)

21커밋 전진분 재베이스(충돌 0) 후 전 검사 체인 통과. 기존 테스트가 읽기 레그(post_condition→detail)·쓰기 레그(draft→RPC payload)를 이미 잠그고 있음을 확인하고, 빠진 고리(수정 드래프트 보존 + "보통" 재발 방지)를 신규 테스트로 추가.

Phase 3 — 배관 삭제 + 조작 중단 (7fa88455, 마이그레이션 20260821670000)

  • 쓰기: setConditionForDatesaveDailyConditiondaily_conditions 체인·setUiCondition·DTO 제거.
  • 읽기: condByDate 상태, conditionByDate 투영(calendarReadModelMapper→calendarViewSelector→sessionController→mobileApp→SessionScreen), 부팅 daily_conditions 질의, 스냅샷 conditions·세션 condition 키(스키마 v3, store·projection 상수 동시).
  • 파생: CONDITION_SCORE·cond7/condWeek/cond14·lgBuildConditionByDate·주간 출석 condition/score.
  • 조작 기입 중단: 클라 8곳 통과화 + 마이그레이션으로 ① 컬럼 default ''save_workout_v4_engine 전체 본문 재발행(조작 라인 1곳만 변경, 동적 치환 금지 규칙 준수) ③ condition='보통' 전행 '' 정리 + postcheck(손댄 대상만 단언).

주요 결정과 그 근거

  • update 엔진의 coalesce(..., session.condition)은 무접촉 — 빈 payload가 기존 값을 보존하는 동작 자체가 통과 필드 원칙의 서버측 구현이다.
  • 번호 재선점 회피 670000 — 650000은 #683이, 660000은 #684 재번호가 선점(둘 다 이 트랙 진행 중 머지). 하루 3연속 번호 선점.

작업 중 드러난 것

  • 충돌 PR은 Actions 자체가 안 돈다(기존 함정 재확인) — main이 뜨거운 날엔 머지 직전 재베이스가 두 번 필요했다.
  • schema.sql은 손으로 append하지 않고 마이그레이션 concat 재생성(계약 테스트의 normalize·join 규칙 그대로)이 정확하다.
  • 스냅샷 스키마 버전 상수가 있다 — src store·src projection·e2e 체크포인트(error-cases/support/appShellSnapshotCheckpoint.mjs 하드코딩). 하나라도 빠지면 저장 거부 또는 migration-smoke 3케이스(CASE-012/013/014) 실패. 텍스트 계약(errorCaseRequiredObservationPolicy)까지 네 곳이 함께 움직인다.
  • npx tsx --test … | tail은 실패 exit를 가린다(기존 함정 재현으로 실패 커밋을 1회 푸시) — exit는 파이프 밖에서 잡을 것.
  • Management API 프로브에 한글 리터럴을 인라인으로 넣으면 인코딩이 깨져 WHERE가 0행 매치될 수 있다 — group by로 분포를 받아 검증했다.

5. 적용 결과

항목결과
검사 체인npm run check 전체(로컬 lint 제외 — 설치 결손, CI 판정) exit 0 · 테스트 1,867/1,867 · vite build 통과
CIPR #686 전 레인 통과 (scope·verify·migration-smoke)
신규 세션 condition 자동 기입클라 8곳 + 서버 coalesce + 컬럼 default '보통'전부 빈 값 (Production 엔진 본문·default 실측 확인)
과거 자동 기입 데이터Production condition='보통' 1,994행 → 0행 ('' 1,994 · '무거움' 2행 보존, postcheck 통과)
통과 필드 보존post_condition 실값 7행(적당함 5 등)·'무거움' 2행 무손실
부팅 질의daily_conditions select 1개 제거
스냅샷conditions·세션 condition 키 소멸(v3), v2 스냅샷은 1회 콜드 부팅으로 재생성
Production 적용db push 670000 EXIT 0 · remote-schema missing 0/failures 0
VercelProduction 번들 barbelicRepository-Bi2ljER9.js에 manifest 20260821670000 · '보통' 리터럴 0
오너 실기기 확인대기 — 세션 상세(모바일·데스크톱)·기록 작성·운동 종료 4표면에서 컨디션 표면 0개 확인 필요

6. 이번 개선으로 향상된 것

폐기 기능이 보이지도, 데이터를 만들지도 않는다

완료 세션 상세의 컨디션 타일 2개 → 0개. 신규 저장·수정·오프라인 대기 저장 어디서도 '보통'이 생성되지 않는다 — 클라·서버·스키마 세 층 모두에서.

과거 기록은 소실 없이 통과한다

'보통' 외 값과 post_condition 실값은 수정 저장 왕복에서 보존 — 매퍼 왕복 테스트로 잠금.

구조적으로 남는 것

  • 통과 필드 계약(session-screen-props en·ko)과 그 이유가 명문화 — 이 필드에 UI를 되살리려면 계약부터 뒤집어야 한다.
  • 스냅샷 키 래칫 v3 — 컨디션 키는 이제 계약 위반.
  • "게이트로 숨기기 ≠ 폐기" — 폐기는 표시·입력·배관·기본값·서버 조작까지 한 번에 끊어야 끝난다는 사례가 기록으로 남음.

남은 것

  • import_motra_workouts_v1'보통' 채움닫힘(같은 날 후속): 오너 지시 "모트라 재인입시도 안채우게" → PR #706(20260821700000)이 640000 전문 재발행으로 리터럴 제거 + motra 스코프 방어 정리·postcheck 2단(데이터 0행·함수 본문 '보통' 부재). Production 적용·실측 확인. wodup 인입 엔진의 동일 패턴은 지시 범위 밖이라 무접촉 유지.
  • 전환기 잔상 1행: 670000 배포 전에 로드된 오너의 구버전 번들이 당일 저장에서 '보통'을 payload로 보내 1행 생성(서버는 더 이상 조작하지 않지만 명시 값은 저장). 화면 비표시·무해. 오너 앱 새로고침 뒤 670000의 정리 UPDATE 재실행으로 해소 예정.
  • 오너 실기기 확인 후 이슈 #668 종결.