운동 전후 컨디션 기능 전면 제거 — 화면의 유령 표시에서 서버 조작 기입 중단·데이터 정리까지 (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 1 | UI 표시·입력 표면 전면 제거 (전 세션 인계) | ✅ 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_engine의 coalesce(...,'보통'), 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)
- 쓰기:
setConditionForDate→saveDailyCondition→daily_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 통과 |
| CI | PR #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 |
| Vercel | Production 번들 barbelicRepository-Bi2ljER9.js에 manifest 20260821670000 · '보통' 리터럴 0 |
| 오너 실기기 확인 | 대기 — 세션 상세(모바일·데스크톱)·기록 작성·운동 종료 4표면에서 컨디션 표면 0개 확인 필요 |
6. 이번 개선으로 향상된 것
폐기 기능이 보이지도, 데이터를 만들지도 않는다
완료 세션 상세의 컨디션 타일 2개 → 0개. 신규 저장·수정·오프라인 대기 저장 어디서도 '보통'이 생성되지 않는다 — 클라·서버·스키마 세 층 모두에서.
과거 기록은 소실 없이 통과한다
'보통' 외 값과 post_condition 실값은 수정 저장 왕복에서 보존 — 매퍼 왕복 테스트로 잠금.
구조적으로 남는 것
- 통과 필드 계약(session-screen-props en·ko)과 그 이유가 명문화 — 이 필드에 UI를 되살리려면 계약부터 뒤집어야 한다.
- 스냅샷 키 래칫 v3 — 컨디션 키는 이제 계약 위반.
- "게이트로 숨기기 ≠ 폐기" — 폐기는 표시·입력·배관·기본값·서버 조작까지 한 번에 끊어야 끝난다는 사례가 기록으로 남음.
남은 것
— 닫힘(같은 날 후속): 오너 지시 "모트라 재인입시도 안채우게" → PR #706(import_motra_workouts_v1의'보통'채움20260821700000)이 640000 전문 재발행으로 리터럴 제거 + motra 스코프 방어 정리·postcheck 2단(데이터 0행·함수 본문'보통'부재). Production 적용·실측 확인. wodup 인입 엔진의 동일 패턴은 지시 범위 밖이라 무접촉 유지.- 전환기 잔상 1행: 670000 배포 전에 로드된 오너의 구버전 번들이 당일 저장에서
'보통'을 payload로 보내 1행 생성(서버는 더 이상 조작하지 않지만 명시 값은 저장). 화면 비표시·무해. 오너 앱 새로고침 뒤 670000의 정리 UPDATE 재실행으로 해소 예정. - 오너 실기기 확인 후 이슈 #668 종결.