docs(content): 랭킹 탭 Phase 4-5 검증을 기록한다

This commit is contained in:
2026-06-24 14:45:53 +09:00
parent 2818f8d4a4
commit a9446ef5cc

View File

@@ -394,7 +394,7 @@
### Phase 4: ViewModel과 DI 등록
- [ ] **Task 4.1: UI state와 ViewModel 작성**
- [x] **Task 4.1: UI state와 ViewModel 작성**
- 생성:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/model/AudioRankingsUiState.kt`
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentRankingViewModel.kt`
@@ -412,9 +412,15 @@
- Run: `./gradlew :app:compileDebugKotlin`
- Expected: ViewModel 컴파일 성공.
- 검증 기록:
- 구현 시 실행 결과를 이 아래에 누적한다.
- 2026-06-24 RED: `ContentRankingViewModelTest`를 추가한 뒤 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentRankingViewModelTest"` 실행 시 `Unresolved reference 'AudioRankingsUiState'`, `Unresolved reference 'ContentRankingViewModel'`, `Unresolved reference 'loadRankings'` 등으로 실패해 UI state/ViewModel 미구현 상태를 확인했다.
- 2026-06-24 GREEN: `AudioRankingsUiState`, `ContentRankingViewModel`을 추가해 초기 `WEEKLY_POPULAR`, token/type API 호출, content/empty/error/throwable, 중복 호출 방지, force reload, stale response 무시를 구현했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentRankingViewModelTest"` 실행 결과 `BUILD SUCCESSFUL`.
- 2026-06-24: Kotlin LSP 진단은 환경에 `kotlin-lsp`가 설치되어 있지 않아 실행 불가(`Command not found: kotlin-lsp`). Gradle test/compile로 대체 검증했다.
- 2026-06-24 리뷰 보완 RED: 리뷰 게이트에서 이미 로드한 랭킹 타입 재선택 시 API 호출은 막히지만 캐시된 상태를 재방출하지 않아 이전 타입 목록이 남을 수 있음을 지적했다. `이미 로드한 type을 다시 선택하면 API 재호출 없이 캐시된 상태를 emit한다` 테스트를 추가한 뒤 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentRankingViewModelTest"` 실행 시 `ContentRankingViewModelTest.kt:146` assertion 실패로 RED를 확인했다.
- 2026-06-24 리뷰 보완 GREEN: `ContentRankingViewModel`의 `loadedTypes`를 `cachedStates`로 변경해 `Content`/`Empty` 성공 상태를 타입별로 저장하고, 이미 로드한 타입 재선택 시 API 재호출 없이 `_rankingStateLiveData`에 캐시 상태를 emit하도록 수정했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentRankingViewModelTest"` 실행 결과 `BUILD SUCCESSFUL`.
- 2026-06-24 Phase 4/5 리뷰 보완 RED: 이전 type 요청 응답이 늦게 도착하면 화면 상태 반영은 막히지만 `_isLoading=false`가 먼저 emit되어 현재 type 요청의 로딩 다이얼로그가 조기 종료될 수 있음을 확인했다. `이전 type 응답이 늦게 도착해도 현재 로딩 상태를 끄지 않는다` 테스트를 추가한 뒤 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentRankingViewModelTest"` 실행 시 `ContentRankingViewModelTest.kt:193` assertion 실패로 RED를 확인했다.
- 2026-06-24 Phase 4/5 리뷰 보완 GREEN: `ContentRankingViewModel`에 `latestRequestId`와 `isCurrentRequest(...)`를 추가해 최신 요청만 loading/state/toast를 마감하도록 수정했다. 캐시 상태 재방출 시에도 이전 pending 요청을 무효화하고 `_isLoading=false`를 emit하도록 정리했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentRankingViewModelTest"` 실행 결과 `BUILD SUCCESSFUL`.
- [ ] **Task 4.2: Koin DI 등록**
- [x] **Task 4.2: Koin DI 등록**
- 수정:
- `app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt`
- 구현:
@@ -426,13 +432,13 @@
- Run: `./gradlew :app:compileDebugKotlin`
- Expected: Koin 등록과 import 컴파일 성공.
- 검증 기록:
- 구현 시 실행 결과를 이 아래에 누적한다.
- 2026-06-24: `AppDI.kt`에 `AudioRankingsApi`, `AudioRankingsRepository`, `ContentRankingViewModel` 등록을 추가했다. `./gradlew :app:compileDebugKotlin` 실행 결과 `BUILD SUCCESSFUL`.
---
### Phase 5: 레이아웃과 탭 전환 UI 연결
- [ ] **Task 5.1: 랭킹 layout/source RED 테스트 추가**
- [x] **Task 5.1: 랭킹 layout/source RED 테스트 추가**
- 수정:
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragmentSourceTest.kt`
- 추가 테스트:
@@ -446,9 +452,10 @@
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"`
- Expected: layout id/ViewModel/adapter 연결 미구현으로 RED 실패.
- 검증 기록:
- 구현 시 실행 결과를 이 아래에 누적한다.
- 2026-06-24 RED: `ContentMainFragmentSourceTest`에 랭킹 layout id, capsule tab include, `ContentRankingViewModel`, `ContentRankingAdapter.createGridLayoutManager(requireContext())`, `AudioRankingType.WEEKLY_POPULAR`, Text Tab/Capsule Tab 연결 source assertion을 추가했다. 같은 시점의 테스트 컴파일은 Phase 4 RED 테스트의 `ContentRankingViewModel` 미구현 오류로 먼저 실패해 Fragment source 미구현 상태를 함께 확인했다.
- 2026-06-24 GREEN: Phase 5 production 연결 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"` 실행 결과 `BUILD SUCCESSFUL`.
- [ ] **Task 5.2: strings 추가**
- [x] **Task 5.2: strings 추가**
- 수정:
- `app/src/main/res/values/strings.xml`
- `app/src/main/res/values-en/strings.xml`
@@ -467,9 +474,9 @@
- Run: `./gradlew :app:mergeDebugResources`
- Expected: 문자열 리소스 merge 성공.
- 검증 기록:
- 구현 시 실행 결과를 이 아래에 누적한다.
- 2026-06-24: `values`, `values-en`, `values-ja`에 콘텐츠 Text Tab `랭킹`/`전체`와 랭킹 유형 6개 라벨 문자열을 추가했다. `./gradlew :app:mergeDebugResources` 실행 결과 `BUILD SUCCESSFUL`.
- [ ] **Task 5.3: `fragment_v2_main_content.xml`에 랭킹 container 추가**
- [x] **Task 5.3: `fragment_v2_main_content.xml`에 랭킹 container 추가**
- 수정:
- `app/src/main/res/layout/fragment_v2_main_content.xml`
- 구현:
@@ -509,9 +516,9 @@
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"`
- Expected: resource merge 성공, source test는 Fragment 연결 전 일부 RED 유지 가능.
- 검증 기록:
- 구현 시 실행 결과를 이 아래에 누적한다.
- 2026-06-24: `fragment_v2_main_content.xml`의 `text_tab_bar_content` 아래에 `view_content_ranking_type_tabs` include와 `rv_content_rankings`를 초기 `gone` 상태로 추가했다. `./gradlew :app:mergeDebugResources` 실행 결과 `BUILD SUCCESSFUL`, `ContentMainFragmentSourceTest`에서 layout id/source assertion `BUILD SUCCESSFUL`.
- [ ] **Task 5.4: `ContentMainFragment`에 Text Tab 전환과 랭킹 탭 UI 연결**
- [x] **Task 5.4: `ContentMainFragment`에 Text Tab 전환과 랭킹 탭 UI 연결**
- 수정:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt`
- 구현:
@@ -529,9 +536,9 @@
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"`
- Expected: Fragment source 연결 관련 assertion PASS.
- 검증 기록:
- 구현 시 실행 결과를 이 아래에 누적한다.
- 2026-06-24: `ContentMainFragment`에 `ContentRankingViewModel`, content tab 상수, `추천`/`랭킹`/`전체` Text Tab 메뉴와 visibility 전환을 연결했다. `랭킹` 최초 선택 시 `contentRankingViewModel.loadRankings(AudioRankingType.WEEKLY_POPULAR)`를 호출하고, `전체`는 별도 API/content 없이 추천/랭킹 surface를 숨기도록 유지했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"` 실행 결과 `BUILD SUCCESSFUL`.
- [ ] **Task 5.5: 랭킹 유형 Capsule Tab 연결**
- [x] **Task 5.5: 랭킹 유형 Capsule Tab 연결**
- 수정:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt`
- 구현:
@@ -543,9 +550,9 @@
- Run: `./gradlew :app:compileDebugKotlin`
- Expected: Capsule Tab 연결 컴파일 성공.
- 검증 기록:
- 구현 시 실행 결과를 이 아래에 누적한다.
- 2026-06-24: `view_content_ranking_type_tabs.root.setMenus(...)`에 `AudioRankingType.entries` 순서대로 6개 문자열 리소스 라벨을 설정하고, `setOnTabSelectedListener`에서 `AudioRankingType.entries[index]`를 `loadRankings(type)`로 연결했다. `./gradlew :app:compileDebugKotlin` 실행 결과 `BUILD SUCCESSFUL`.
- [ ] **Task 5.6: ranking observer와 adapter submit 연결**
- [x] **Task 5.6: ranking observer와 adapter submit 연결**
- 수정:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt`
- 구현:
@@ -558,7 +565,7 @@
- Run: `./gradlew :app:compileDebugKotlin`
- Expected: Fragment/adapter/ViewModel 연결 컴파일 성공.
- 검증 기록:
- 구현 시 실행 결과를 이 아래에 누적한다.
- 2026-06-24: `rv_content_rankings`에 `ContentRankingAdapter.createGridLayoutManager(requireContext())`와 `ContentRankingAdapter`를 연결하고, `rankingStateLiveData`의 `Content`는 `submitItems(state.items)`, `Empty`/`Error`는 `submitItems(emptyList())`로 처리했다. 추천/랭킹 loading 상태는 `updateLoadingDialog()`에서 함께 반영하고, ranking `toastLiveData`는 기존 `showToast` helper를 재사용했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*"`, `./gradlew :app:compileDebugKotlin` 실행 결과 모두 `BUILD SUCCESSFUL`.
---
@@ -632,3 +639,9 @@
- 2026-06-24: Kotlin LSP 진단은 환경에 `kotlin-lsp`가 설치되어 있지 않아 실행 불가(`Command not found: kotlin-lsp`). Gradle compile/test/ktlint로 대체 검증했다.
- 2026-06-24: 리뷰 게이트 보완 후 `AudioRankingResponse.type` 추가. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check` 재실행 결과 모두 통과했다.
- 2026-06-24: Phase 1~3 코드 리뷰 및 현재 워크트리 기준 재검증을 수행했다. Phase 1 구조 확인용 `rg` 3개 명령에서 기대 참조를 확인했고, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.contentranking.*"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check` 실행 결과 모두 통과했다. `./gradlew :app:mergeDebugResources`는 샌드박스 내 Gradle wrapper lock 접근 제한으로 1차 실패 후 권한 상승 실행에서 `BUILD SUCCESSFUL`을 확인했다.
- 2026-06-24: Phase 4~5 구현 중 병렬 Gradle 실행에서 KSP/Kotlin incremental cache 접근 충돌(`NoSuchFileException .../kspCaches/debug/backups`, `Storage ... lookups.tab is already registered`)이 발생했으나, 동일 명령을 순차 재실행해 실제 코드 오류가 아님을 분리했다.
- 2026-06-24: Phase 4~5 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check` 실행 결과 모두 통과했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고는 기존 설정 경고로 남아 있다.
- 2026-06-24: Figma `24:6857`, `24:6882`를 참조해 Text Tab `추천`/`랭킹`/`전체`, Capsule Tab `주간 인기`/`지금 뜨는 중`/`매출`/`판매량`/`댓글수`/`좋아요` 순서와 랭킹 목록 위치를 확인했다. 에뮬레이터 실기 화면 수동 검증은 Phase 6 범위로 남겨두었다.
- 2026-06-24: 리뷰 게이트 보완 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check` 재실행 결과 모두 통과했다.
- 2026-06-24: Phase 4~5 코드 리뷰에서 stale response loading 조기 종료 문제를 발견해 RED/GREEN 테스트로 보완했다. Figma `24:6857` 스크린샷으로 Text Tab `추천`/`랭킹`/`전체`, Capsule Tab `주간 인기`/`지금 뜨는 중`/`매출`/`판매량`/`댓글수`/`좋아요` 순서와 랭킹 목록 위치를 재확인했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check` 실행 결과 모두 통과했다. `:app:mergeDebugResources`는 샌드박스 내 Gradle wrapper lock 접근 제한으로 1차 실패 후 권한 상승 실행에서 `BUILD SUCCESSFUL`을 확인했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고는 기존 설정 경고로 남아 있다.
- 2026-06-24: Phase 4~5 현재 워크트리 기준 코드 리뷰 및 재검증을 수행했다. `ContentRankingViewModel`의 캐시 재방출, stale response 무시, loading 종료 조건과 `ContentMainFragment`의 Text Tab/Capsule Tab 연결, visibility 전환, ranking adapter 연결, loading dialog 통합, routing guard를 확인했고 추가 결함은 발견하지 못했다. Figma `24:6857`, `24:6882` design context와 screenshot으로 `추천`/`랭킹`/`전체`, `주간 인기`/`지금 뜨는 중`/`매출`/`판매량`/`댓글수`/`좋아요` 순서와 랭킹 목록 위치를 대조했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check` 실행 결과 모두 통과했다. `:app:mergeDebugResources`는 샌드박스 내 Gradle wrapper lock 접근 제한으로 1차 실패 후 권한 상승 실행에서 `BUILD SUCCESSFUL`을 확인했다.