Skip to content

렌더 입자성 캠페인 Phase 2 — 오너 스토어 세트 + Provider (구 W5 오너당 인스턴싱 편입)

통합 기록(형식 표준, Phase 현황·결과·남은 것): 2026-08-24-render-granularity.md

  • 날짜: 2026-08-23 (Phase 1 #609 직후, 오너 결정 D2 (나): Phase 2~4 진행)
  • 목표: 어댑터 훅마다 useRef로 따로 태어나던 스토어·조율자 12개를 계정(오너) 하나가 소유하는 세트로 묶고, 계정 전환을 "세트 교체 한 번"으로 만든다. 하위 바인딩(Phase 3~4)이 현재 계정의 스토어를 얻는 표준 경로(컨텍스트)를 연다.

바뀐 것

항목파일내용
Phase 2-1 세트 생성controllers/ownerStores.ts (신설)createOwnerStores({ closeLayerStateOnlyRef }) — 스토어 10(드래프트·달력·커스텀 종목·친구 리포트·로그테이블·내비게이션·대기 저장·계획 반영·세션 상세·토스트) + 조율자 2(통계 복구·운동 쓰기 커맨드)
Phase 2-2 Providercontrollers/ownerStoresContext.ts (신설) · app.tsxOwnerStoresContext + useOwnerStores(). 세 상태 분기(loadingData·degradedReady·ready) 모두 Provider > 키 있는 Fragment 동일 모양(재마운트 방지 계약 유지)
Phase 2-2 어댑터12개 어댑터 훅store/coordinator/commands를 입력으로 받는다(자체 생성 제거). 내비게이션 히스토리 설치 이펙트는 [store]로 — 세트 교체 시 이전 설치를 걷고 새 스토어에 재설치(mount-only 억제 1건 소멸)
Phase 2-3 adoptOwnerownerStores.ts · appController.tsxadoptOwnerStores(previous, …) = leaveOwnerStores(드래프트 보존이 먼저 → 비행 중 작업 무효화: 통계·로그테이블·세션 상세·쓰기·대기 저장·커스텀·친구·반영·토스트·내비) → createOwnerStores. 지휘자는 첫 마운트를 제외한 전환에서 세트를 교체하고 자기 소유 React 상태만 직접 리셋한다. 교체 뒤 revision 재발화로 새 세트에서 드래프트 복원

검증

  • 행동 계약 ownerStores.test.mjs 4: 세트 인스턴스 독립 / adopt = 보존 후 새 세트(이전 세트는 초기 리터럴·다음 오너 기록, 새 세트는 오너 미기록) / 떠나기 순서(보존 → 무효화) / 구독 분리.
  • 재조준: controllerBoundaries(지휘자 = adoptOwnerStores·setPlans 선행, 군집 리셋 순서는 leaveOwnerStores 본문) · backgroundTokens(app 루트 모양·startTransition 주입 위치·로그테이블 리셋 위치, ownerStores 결합 표면) · homeBootLoadingOrder(Provider > 키 Fragment ×3) · appShellSnapshotIntegrationContract(adopt 마커) · logTableMonthCache. 매니페스트 등재 3건은 pending-changes 기존 항목에 사유 병합.
  • 전 체인 npm run check 1783/1783 · check:unused · check:dual-key · eslint 억제 11 → 10.
  • 로컬 스택 test:e2e-local 8/8 · 브라우저 회귀 CASE-001·004·011·013·015·016 6/6(프로덕션 빌드).
  • 페이지 안 계정 전환 스모크(dev 서버, 임시 스크립트): 드래프트 작성 중 로그아웃 → 로그인 화면, 콘솔·페이지 오류 0 → 같은 계정 재진입 시 이어하기 배너(이전 세트가 보존한 드래프트를 새 세트가 복원).

전 → 후

지표
스토어·조율자 생성 지점12 (어댑터 useRef)1 (createOwnerStores)
지휘자 리셋 문장(appController)2013 — 스토어 몫은 adoptOwnerStores 1호출
새 스토어 추가 시 리셋 누락 가능성지휘자 목록에 손수 추가세트에 넣으면 교체로 구조적 리셋(떠나기 부수효과만 leaveOwnerStores에 추가)
exhaustive-deps 리뷰 억제1110
렌더 효과없음(설계상 Phase 3~4의 기반 공사)

함정(재사용)

  • 세트 교체 직후 같은 이펙트에서 새 세트를 쓰면 안 된다 — 어댑터가 다음 렌더에서 setEnv를 주입하기 전이라 requireEnv()가 던진다. 복원은 revision 재발화(비전환 경로)에서.
  • 첫 마운트는 교체하지 않는다(렌더에서 만든 첫 세트가 첫 오너의 세트). 교체하면 내비게이션 히스토리 설치가 불필요하게 두 번 돈다.
  • 이전 세트의 비행 중 작업: 새 인스턴스로 갈라지므로 늦은 응답은 구 인스턴스에 갇히지만, env 세터(React 상태)로 쓰는 경로가 있을 수 있어 떠나기에서 기존 세대 bump 리셋을 그대로 돌린다(이중 안전망).

다음

  • Phase 3 파일럿 바인딩(라이브 운동 화면): useOwnerStores()로 드래프트 스토어를 구독하는 WorkoutFlowBinding, renderCtx 드래프트 키 은퇴.