Files
sodalive-android/docs/20260627_콘텐츠_전체보기/plan-task.md

713 lines
67 KiB
Markdown

# 콘텐츠 전체보기 구현 계획/TASK
> **For agentic workers:** REQUIRED SUB-SKILL: 구현 시 `superpowers:subagent-driven-development` 또는 `superpowers:executing-plans`를 사용해 task 단위로 진행한다. 각 단계는 체크박스(`- [ ]`)로 추적하고, 완료 즉시 `- [x]`로 갱신한다. 구현 범위 변경이 생기면 이 문서를 먼저 수정한 뒤 코드에 반영한다.
**Goal:** 콘텐츠 추천 섹션의 전체보기 chevron을 연결하고, 기존 콘텐츠 `전체` 탭 이동을 먼저 적용한 뒤 `New&Hot` 전용 신규 전체보기 화면을 제공한다.
**Architecture:** 구현 순서는 `chevron 표시 -> 기존 콘텐츠 전체 탭 이동 -> 신규 전체보기 페이지/API`로 고정한다. 기존 화면 이동은 `MainV2Activity`, `ContentMainFragment`, `ContentAllTabViewModel`에 작은 public navigation contract를 추가해 처리한다. 신규 전체보기 화면은 마지막 단계에서 `kr.co.vividnext.sodalive.v2.main.content.overview` 하위 Activity/ViewModel/API/Repository/DTO/UI model/adapter로 격리한다.
**Tech Stack:** Kotlin, Android XML Views, ViewBinding, RecyclerView, Retrofit, Gson, RxJava3, Koin, JUnit4/Robolectric local unit test.
---
## 전제와 성공 기준
- PRD: `docs/20260627_콘텐츠_전체보기/prd.md`
- 구현 순서:
- 1순위: 콘텐츠 추천 섹션 chevron 표시.
- 2순위: 신규 페이지가 필요 없는 섹션을 기존 콘텐츠 `전체` 탭으로 이동.
- 3순위: 신규 콘텐츠 전체보기 페이지/API 생성 및 신규 페이지 대상 섹션 이동.
- 전체보기 chevron 표시 섹션:
- 콘텐츠 추천 탭: `오직 보이스온에서만!`, `새로 올라온 오디오`, `New&Hot`, `무료 오디오`, `포인트 오디오`
- 기존 콘텐츠 `전체` 탭 이동 섹션:
- `오직 보이스온에서만!` -> 콘텐츠 탭 `전체` -> `오리지널` 카테고리
- `새로 올라온 오디오` -> 콘텐츠 탭 `전체` -> `오디오` 카테고리
- `무료 오디오` -> 콘텐츠 탭 `전체` -> `무료` 카테고리 -> `인기순`
- `포인트 오디오` -> 콘텐츠 탭 `전체` -> `포인트` 카테고리 -> `인기순`
- 신규 전체보기 페이지 이동 섹션:
- 콘텐츠 추천 탭 `New&Hot` -> 신규 콘텐츠 전체보기 -> `NEW_AND_HOT_AUDIO`
- `댓글 많은 오디오`, `추천 오디오`에는 chevron을 표시하지 않는다.
- 신규 API endpoint는 `GET /api/v2/contents`이다.
- 신규 API query parameter key는 소문자 `page`, `size`, `type`만 사용한다.
- 신규 API 기본값은 `page=0`, `size=20`, `type=NEW_AND_HOT_AUDIO`다.
- 앱 구현 DTO annotation은 Gson `@SerializedName`을 사용한다.
- 신규 전체보기 화면 title은 `NEW_AND_HOT_AUDIO`일 때 `New&Hot`이다.
- 신규 전체보기 화면은 Figma node `482:15105` 기준 2열 오디오 카드 grid를 사용한다.
- 구현 완료 후 최소 다음 명령을 실행한다.
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*"`
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*"`
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"`
- `./gradlew :app:mergeDebugResources`
- `./gradlew :app:compileDebugKotlin`
- `./gradlew :app:ktlintCheck`
- `git diff --check`
---
## Phase 순서
- Phase 1: 기존 구조 확인과 작업 경계 고정
- Phase 2: 홈/콘텐츠 추천 섹션 chevron 표시
- Phase 3: 기존 콘텐츠 `전체` 탭 이동 contract 추가
- Phase 4: 기존 콘텐츠 `전체` 탭 이동 섹션 연결
- Phase 5: 신규 전체보기 API, DTO, Repository, UI model 추가
- Phase 6: 신규 전체보기 ViewModel, Activity, Adapter 구현
- Phase 7: 신규 전체보기 대상 섹션 이동 연결
- Phase 8: 통합 검증과 수동 확인
---
## Figma 참조 필요 Phase
- Phase 1: 제한 참조
- 기존 홈/콘텐츠 추천 섹션 title, 콘텐츠 전체 탭, MainV2 navigation 구조 확인 중심으로 진행한다.
- Phase 2: 제한 참조
- chevron 표시는 기존 `view_section_title.xml`과 홈/콘텐츠 추천 섹션 구조를 따른다.
- Phase 3~4: Figma 참조 불필요
- 기존 콘텐츠 `전체` 탭 이동은 기존 `ContentAllTabViewModel`의 type/sort 계약과 MainV2 tab 전환 구조를 따른다.
- Phase 5: Figma 참조 불필요
- API/DTO/Repository/UI model/mapper/ViewModel은 PRD 서버 계약과 기존 V2 data layer/paging 패턴을 따른다.
- Phase 6: 필수 참조
- 신규 전체보기 Activity layout은 Figma `482:15105`의 title bar, black background, 2열 grid, card spacing을 기준으로 확인한다.
- Phase 7~8: 필수 참조
- 신규 페이지 대상 섹션 이동과 최종 수동 화면 검증은 PRD의 Figma reference와 실제 화면을 대조한다.
---
## 파일 구조
### 기존 화면 이동 선행 범위
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt`
- 콘텐츠 추천 섹션 chevron 표시, 기존 콘텐츠 `전체` 탭 이동, 신규 페이지 이동을 단계별로 추가한다.
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentAllTabViewModel.kt`
- 외부 진입용 type/sort 선택 API를 추가한다.
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2Activity.kt`
- 콘텐츠 탭 내부 `전체`를 특정 type/sort로 여는 public method와 기존 fragment 재사용 처리를 추가한다.
- Modify: `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragmentSourceTest.kt`
- 콘텐츠 추천 섹션 chevron/routing/source를 검증한다.
- Modify: `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/ContentAllTabViewModelTest.kt`
- 외부 type/sort 선택 API를 검증한다.
- Modify: `app/src/test/java/kr/co/vividnext/sodalive/v2/main/MainV2ActivitySourceTest.kt`
- 콘텐츠 탭 내부 `전체` type/sort routing contract를 검증한다.
### 신규 전체보기 후행 범위
- Create: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/data/ContentOverviewApi.kt`
- `GET /api/v2/contents` Retrofit endpoint를 정의한다.
- Create: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/data/ContentOverviewModels.kt`
- `ContentOverviewPageResponse`, `ContentOverviewType`, `ContentOverviewItemResponse` DTO를 정의한다.
- Create: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/data/ContentOverviewRepository.kt`
- API 호출을 repository method로 감싼다.
- Create: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/model/ContentOverviewUiState.kt`
- `Loading`, `Content`, `Empty`, `Error` 상태와 paging/loading-more 상태를 정의한다.
- Create: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/model/ContentOverviewUiModels.kt`
- 신규 전체보기 화면 item/title/type UI model을 정의한다.
- Create: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/model/ContentOverviewMappers.kt`
- DTO를 UI model로 변환하고 `AudioContentTag`를 매핑한다.
- Create: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/ContentOverviewViewModel.kt`
- type/page/hasNext/loading-more/API 상태를 관리한다.
- Create: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/ContentOverviewActivity.kt`
- title bar, 2열 RecyclerView, paging, empty/error/loading, 상세 routing을 연결한다.
- Create: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/ui/ContentOverviewAdapter.kt`
- `AudioContentCardView` 기반 2열 grid item을 바인딩한다.
- Create: `app/src/main/res/layout/activity_content_overview.xml`
- 신규 전체보기 화면 layout이다.
- Modify: `app/src/main/AndroidManifest.xml`
- `ContentOverviewActivity`를 등록한다.
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt`
- 신규 API, Repository, ViewModel을 Koin에 등록한다.
- Create: `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/overview/ContentOverviewMapperTest.kt`
- DTO -> UI model/tag/title mapping을 검증한다.
- Create: `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/overview/ContentOverviewViewModelTest.kt`
- 첫 페이지, load-more, 실패, stale response 방지를 검증한다.
- Create: `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/overview/ContentOverviewActivitySourceTest.kt`
- layout id, 2열 grid, intent extra, 상세 이동 source를 검증한다.
---
### Phase 1: 기존 구조 확인과 작업 경계 고정
- [x] **Task 1.1: PRD와 기존 구현 상태 대조**
- 확인:
- `docs/20260627_콘텐츠_전체보기/prd.md`
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt`
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt`
- `app/src/main/res/layout/view_section_title.xml`
- 작업:
- `HomeMainFragment``ViewSectionTitleBinding.setTitle(titleResId, showMore)`가 chevron 표시를 이미 지원하는지 확인한다.
- `ContentMainFragment``ViewSectionTitleBinding.setTitle(titleResId)`가 현재 chevron을 항상 숨기는지 확인한다.
- 이번 작업에서 레거시 `audio_content/*` 파일을 직접 수정하지 않는 것을 확인한다.
- 검증:
- Run: `rg -n "setTitle\\(|ivSectionTitleChevron|viewHomeFirstAudioTitle|viewContentNewAndHotTitle|viewContentOriginalSeriesTitle" app/src/main/java/kr/co/vividnext/sodalive/v2/main app/src/main/res/layout/view_section_title.xml`
- Expected: 홈 title helper와 콘텐츠 title helper, chevron view id가 확인된다.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 실행: `rg -n "setTitle\(|ivSectionTitleChevron|viewHomeFirstAudioTitle|viewContentNewAndHotTitle|viewContentOriginalSeriesTitle" app/src/main/java/kr/co/vividnext/sodalive/v2/main app/src/main/res/layout/view_section_title.xml`
- 결과: `view_section_title.xml``iv_section_title_chevron`, `HomeMainFragment``setTitle(titleResId, showMore)`, `ContentMainFragment`의 section title 설정 지점을 확인했다.
- 확인: 홈 title helper는 `showMore`로 chevron 표시를 이미 지원하며 `viewHomeFirstAudioTitle``showMore = true` 상태였다. 콘텐츠 title helper는 기존에 chevron을 숨기고 있어 Phase 2에서 helper 확장이 필요했다.
- 확인: 이번 Phase 1~2 범위에서는 레거시 `audio_content/*` 파일을 직접 수정하지 않았다.
- [x] **Task 1.2: 기존 콘텐츠 전체 탭 이동 가능 지점 확인**
- 확인:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2Activity.kt`
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt`
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentAllTabViewModel.kt`
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/data/MainContentAllTabModels.kt`
- 작업:
- `MainV2Activity`의 bottom tab 전환과 fragment 재사용 위치를 확인한다.
- `ContentMainFragment``showAllContent()``ContentAllTabViewModel` type/sort 변경 위치를 확인한다.
- `MainContentAllType.ORIGINAL`, `AUDIO`, `FREE`, `POINT``ContentSort.POPULAR`, `LATEST`가 기존 목적지 요구를 충족하는지 확인한다.
- 검증:
- Run: `rg -n "MainContentAllType|ContentSort|showAllContent|changeType|changeSort|clickTab\\(MainV2Tab.CONTENT\\)" app/src/main/java/kr/co/vividnext/sodalive/v2/main`
- Expected: type/sort 선택과 bottom tab 전환 지점이 확인된다.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 실행: `rg -n "MainContentAllType|ContentSort|showAllContent|changeType|changeSort|clickTab\(MainV2Tab.CONTENT\)" app/src/main/java/kr/co/vividnext/sodalive/v2/main`
- 결과: `MainV2Activity.clickTab(MainV2Tab.CONTENT)`, `ContentMainFragment.showAllContent()`, `ContentAllTabViewModel.changeType/changeSort`, `MainContentAllType.ORIGINAL/AUDIO/FREE/POINT`, `ContentSort` 사용 지점을 확인했다.
- 확인: Phase 1에서는 기존 콘텐츠 전체 탭 이동 가능 지점만 확인했고, 실제 contract/API 추가는 Phase 3 범위로 남겼다.
---
### Phase 2: 홈/콘텐츠 추천 섹션 chevron 먼저 표시
- [x] **Task 2.1: 홈 추천 탭 FIRST 섹션 chevron 표시**
- 수정:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt`
- 테스트:
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragmentSourceTest.kt`
- 작업:
- `viewHomeFirstAudioTitle.setTitle(..., showMore = true)` 상태를 유지하거나 누락되어 있으면 추가한다.
- 이 Task에서는 신규 페이지 이동 click listener를 연결하지 않는다.
- source test는 `viewHomeFirstAudioTitle.setTitle` 호출이 `showMore = true`임을 검증한다.
- 검증:
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentSourceTest"`
- Expected: 홈 FIRST chevron 표시 source 테스트 PASS.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 확인: `HomeMainFragment``viewHomeFirstAudioTitle.setTitle(R.string.home_recommendation_section_first_audio_contents, showMore = true)`가 이미 적용되어 있었다.
- 2026-06-27 테스트 추가: `HomeMainFragmentSourceTest`를 생성해 FIRST 섹션 `showMore = true`와 Phase 2 범위에서 click listener가 아직 연결되지 않았음을 검증했다.
- 2026-06-27 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentSourceTest"`
- 결과: PASS.
- [x] **Task 2.2: 콘텐츠 추천 탭 section title helper 확장**
- 수정:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt`
- 테스트:
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragmentSourceTest.kt`
- 작업:
- 콘텐츠 탭의 `ViewSectionTitleBinding.setTitle(titleResId)``setTitle(titleResId, showMore = false)`로 확장한다.
- `오직 보이스온에서만!`, `새로 올라온 오디오`, `New&Hot`, `무료 오디오`, `포인트 오디오``showMore = true`로 설정한다.
- `댓글 많은 오디오`, `추천 오디오``showMore = false`를 유지한다.
- 이 Task에서는 기존 전체 탭 이동과 신규 페이지 이동 click listener를 연결하지 않는다.
- 검증:
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"`
- Expected: 콘텐츠 추천 chevron 표시/숨김 source 테스트 PASS.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 RED 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"`
- RED 결과: 신규 `content recommendation section titles show only Phase 2 chevrons` 테스트가 `ContentMainFragmentSourceTest.kt:463`에서 실패했다. 원인은 콘텐츠 title helper가 `showMore`를 지원하지 않고 chevron을 항상 숨기는 기존 구현이었다.
- 2026-06-27 구현: `ContentMainFragment``ViewSectionTitleBinding.setTitle(titleResId, showMore = false)`를 추가하고 `오직 보이스온에서만!`, `새로 올라온 오디오`, `New&Hot`, `무료 오디오`, `포인트 오디오`에만 `showMore = true`를 지정했다. `댓글 많은 오디오`, `추천 오디오`는 기본값 `false`를 유지했다.
- 2026-06-27 GREEN 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"`
- GREEN 결과: PASS.
- 참고: 홈/콘텐츠 source 테스트를 병렬 실행하던 중 한 번 `:app:kspDebugKotlin` generated file 접근 오류가 발생했으나, 동일 콘텐츠 테스트 단독 재실행 시 정상 PASS했다.
---
### Phase 3: 기존 콘텐츠 전체 탭 이동 contract 추가
- [x] **Task 3.1: ContentAllTabViewModel 외부 선택 API 추가**
- 수정:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentAllTabViewModel.kt`
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/ContentAllTabViewModelTest.kt`
- 작업:
- `fun selectTypeAndSort(type: MainContentAllType, sort: ContentSort)`를 추가한다.
- 함수는 `selectedType`, `selectedSort`, `selectedDayOfWeek`를 갱신하고 `page=0`부터 재조회한다.
- `ORIGINAL`, `AUDIO`, `FREE`, `POINT``dayOfWeek = null`로 요청한다.
- 기존 `changeType`, `changeSort`, `loadInitial` 테스트를 깨지 않는다.
- 검증:
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentAllTabViewModelTest"`
- Expected: 기존 테스트와 신규 외부 선택 테스트 PASS.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 구현: `ContentAllTabViewModel.selectTypeAndSort(type, sort)`를 추가해 `selectedType`, `selectedSort`, `selectedDayOfWeek`를 갱신하고 첫 페이지를 재조회하도록 했다. `SERIES`가 아닌 type은 `selectedDayOfWeekFor(type)` 경로로 `dayOfWeek = null`을 유지한다.
- 2026-06-27 테스트 추가: `ContentAllTabViewModelTest`에 외부 선택 요청 `FREE` + `POPULAR`, `ORIGINAL` + `LATEST`가 모두 `page=0`, `dayOfWeek=null`로 호출되는 검증을 추가했다.
- 2026-06-27 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentAllTabViewModelTest"`
- 결과: PASS.
- [x] **Task 3.2: ContentMainFragment에 내부 전체 탭 선택 API 추가**
- 수정:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt`
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragmentSourceTest.kt`
- 작업:
- `fun selectAllTab(type: MainContentAllType, sort: ContentSort = ContentSort.LATEST)`를 추가한다.
- 함수는 `binding.textTabBarContent.root`의 선택을 `전체`로 전환하고 `showContentTab(CONTENT_TAB_ALL)`을 호출한다.
- 이후 `contentAllTabViewModel.selectTypeAndSort(type, sort)`를 호출한다.
- fragment view가 아직 생성되지 않은 경우를 대비해 pending type/sort를 fragment field에 저장하고 `onViewCreated` 이후 적용한다.
- 검증:
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"`
- Expected: 내부 전체 탭 선택 source 테스트 PASS.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 구현: `ContentMainFragment.selectAllTab(type, sort)`를 추가하고 view 생성 전 호출은 `pendingAllTabSelection`에 저장한 뒤 `onViewCreated` 이후 적용하도록 했다.
- 2026-06-27 확인: pending 적용 시 `hasSelectedAllTab = true`를 먼저 설정한 뒤 `textTabBarContent.root.selectTab(CONTENT_TAB_ALL)``showContentTab(CONTENT_TAB_ALL)`을 호출해 `TextTabBarView.selectTab` listener가 유발할 수 있는 기본 `loadInitial()` 중복 호출을 피했다. 실제 데이터 재조회는 `contentAllTabViewModel.selectTypeAndSort(...)` 단일 경로로 수행한다.
- 2026-06-27 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"`
- 결과: PASS.
- [x] **Task 3.3: MainV2Activity 콘텐츠 전체 탭 진입 API 추가**
- 수정:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2Activity.kt`
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/MainV2ActivitySourceTest.kt`
- 작업:
- `fun openContentAllTab(type: MainContentAllType, sort: ContentSort = ContentSort.LATEST)`를 추가한다.
- 현재 탭을 `MainV2Tab.CONTENT`로 전환한다.
- `changeFragment` 이후 기존 또는 신규 `ContentMainFragment``selectAllTab(type, sort)`를 전달한다.
- 이미 콘텐츠 탭에 있는 경우 fragment를 중복 생성하지 않고 현재 fragment method를 호출한다.
- 검증:
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.MainV2ActivitySourceTest"`
- Expected: MainV2 콘텐츠 전체 탭 routing source 테스트 PASS.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 구현: `MainV2Activity.openContentAllTab(type, sort)`를 추가해 CONTENT 탭이 아니면 `viewModel.clickTab(MainV2Tab.CONTENT)``changeFragment(MainV2Tab.CONTENT)`로 콘텐츠 Fragment를 준비한 뒤 기존/new `ContentMainFragment.selectAllTab(type, sort)`를 호출하도록 했다.
- 2026-06-27 확인: 이미 CONTENT 탭인 경우 `changeFragment`를 직접 호출하지 않고 기존 `ContentMainFragment`를 찾아 `selectAllTab`만 호출하므로 fragment 중복 생성을 피한다.
- 2026-06-27 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.MainV2ActivitySourceTest"`
- 결과: PASS.
---
### Phase 4: 기존 콘텐츠 전체 탭 이동 섹션 연결
- [x] **Task 4.1: 콘텐츠 추천 탭 기존 전체 탭 목적지 연결**
- 수정:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt`
- 테스트:
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragmentSourceTest.kt`
- 작업:
- `오직 보이스온에서만!` chevron은 `MainContentAllType.ORIGINAL`, `ContentSort.LATEST``MainV2Activity.openContentAllTab`을 호출한다.
- `새로 올라온 오디오` chevron은 `MainContentAllType.AUDIO`, `ContentSort.LATEST`로 호출한다.
- `무료 오디오` chevron은 `MainContentAllType.FREE`, `ContentSort.POPULAR`로 호출한다.
- `포인트 오디오` chevron은 `MainContentAllType.POINT`, `ContentSort.POPULAR`로 호출한다.
- `New&Hot`은 신규 페이지 대상이므로 이 Phase에서는 click listener를 연결하지 않는다.
-`처음부터 함께 성장!`은 신규 페이지 대상이므로 이 Phase에서는 click listener를 연결하지 않는다.
- 검증:
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"`
- Expected: 기존 전체 탭 이동 섹션별 목적지 source 테스트 PASS.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 구현: `오직 보이스온에서만!`, `새로 올라온 오디오`, `무료 오디오`, `포인트 오디오` chevron click listener를 `ensureMainV2NavigationAllowed`로 감싸고 `(activity as? MainV2Activity)?.openContentAllTab(...)` 경로에 연결했다.
- 2026-06-27 확인: routing destination은 각각 `ORIGINAL/LATEST`, `AUDIO/LATEST`, `FREE/POPULAR`, `POINT/POPULAR`로 지정했다. `New&Hot` 및 홈 `처음부터 함께 성장!` click listener는 Phase 4 범위에서 연결하지 않았다.
- 2026-06-27 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"`
- 결과: PASS.
- [ ] **Task 4.2: 기존 전체 탭 이동 수동 검증**
- 확인:
- 콘텐츠 추천 탭 `오직 보이스온에서만!` chevron 클릭 시 콘텐츠 `전체` -> `오리지널` 진입.
- 콘텐츠 추천 탭 `새로 올라온 오디오` chevron 클릭 시 콘텐츠 `전체` -> `오디오` 진입.
- 콘텐츠 추천 탭 `무료 오디오` chevron 클릭 시 콘텐츠 `전체` -> `무료` + `인기순` 진입.
- 콘텐츠 추천 탭 `포인트 오디오` chevron 클릭 시 콘텐츠 `전체` -> `포인트` + `인기순` 진입.
- 콘텐츠 추천 탭 `New&Hot`과 홈 `처음부터 함께 성장!`은 chevron만 표시되고 신규 페이지 이동은 아직 연결되지 않음.
- 검증 기록:
- 구현 시 이 Task 아래에 테스트 기기/빌드 variant/API 응답 조건과 확인 결과를 한국어로 누적한다.
- 2026-06-27 상태: BLOCKED/미완료. 현재 작업 환경에서 Android 기기 또는 에뮬레이터를 통한 실제 화면 조작을 수행할 수 없어 수동 검증을 완료하지 못했다.
- 2026-06-27 대체 확인: source 테스트로 Phase 4 click listener 연결 대상과 미연결 대상(`New&Hot`)은 검증했으나, 실제 앱 화면에서 chevron 클릭 후 콘텐츠 `전체` 탭 UI/type/sort 표시까지는 확인하지 못했다.
---
### Phase 5: 신규 전체보기 API, DTO, Repository, UI model 추가
- [x] **Task 5.1: ContentOverview API/DTO/Repository 추가**
- 생성:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/data/ContentOverviewApi.kt`
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/data/ContentOverviewModels.kt`
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/data/ContentOverviewRepository.kt`
- 수정:
- `app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt`
- 작업:
- `ContentOverviewApi.getContents(authHeader, page, size, type)``@GET("/api/v2/contents")`로 정의한다.
- query annotation 이름은 `page`, `size`, `type`만 사용한다.
- DTO는 `@Keep``@SerializedName`을 사용한다.
- `ContentOverviewType``NEW_AND_HOT_AUDIO`, `FIRST_AUDIO_CONTENT`만 정의한다.
- Repository는 `Single<ApiResponse<ContentOverviewPageResponse>>`를 반환한다.
- Koin `networkModule`, `repositoryModule`에 신규 API/Repository를 등록한다.
- 검증:
- Run: `./gradlew :app:compileDebugKotlin`
- Expected: 신규 data layer와 DI 등록이 컴파일된다.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 구현: `ContentOverviewApi`, `ContentOverviewPageResponse`, `ContentOverviewType`, `ContentOverviewItemResponse`, `ContentOverviewRepository`를 추가했다. endpoint는 `GET /api/v2/contents`, query key는 `page`, `size`, `type`만 사용한다.
- 2026-06-27 DI 등록: `AppDI``networkModule``ContentOverviewApi`, `repositoryModule``ContentOverviewRepository`를 등록했다. ViewModel DI는 Phase 6.5에서 등록하도록 이 Task에서는 제외했다.
- 2026-06-27 실행: `./gradlew :app:compileDebugKotlin`
- 결과: PASS.
- 2026-06-27 코드 리뷰 확인: PRD/계획서의 응답 필드 계약은 `items`, `contentId`, `coverImage`인데 현재 DTO는 `contents`, `audioContentId`, `imageUrl`, `totalCount`를 사용한다. 서버 최신 계약 변경이 아니라면 API 응답 파싱 실패 위험이 있어 수정이 필요하다.
- 2026-06-27 리뷰 후속 RED 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"`
- RED 결과: 테스트 fixture를 문서 계약인 `items`, `contentId`, `coverImage`로 변경하자 기존 DTO의 `contents`, `audioContentId`, `imageUrl`, `totalCount` 생성자와 맞지 않아 컴파일 실패했다.
- 2026-06-27 리뷰 후속 구현: `ContentOverviewPageResponse``items` 기반으로, `ContentOverviewItemResponse``contentId`, `coverImage` 기반으로 수정하고 mapper도 동일 계약을 사용하도록 변경했다.
- [x] **Task 5.2: Mapper RED 테스트 작성**
- 생성:
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/overview/ContentOverviewMapperTest.kt`
- 테스트 케이스:
- `NEW_AND_HOT_AUDIO` title은 `New&Hot`이다.
- `FIRST_AUDIO_CONTENT` title은 `처음부터 함께 성장!`이다.
- `price == 0`이면 `AudioContentTag.Free`가 포함된다.
- `isPointAvailable == true`이면 `AudioContentTag.Point`가 포함된다.
- `isFirstContent == true`이면 `AudioContentTag.First`가 포함된다.
- `isOriginalSeries == true`이면 `AudioContentTag.Original`이 포함된다.
- `isAdult == true`이면 `showAdultBadge == true`다.
- `page`, `size`, `hasNext`, `type`은 UI state에 보존된다.
- 검증:
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewMapperTest"`
- Expected: mapper 구현 전 RED 실패.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 RED 테스트 추가: `ContentOverviewMapperTest`를 생성해 type title resource, tag mapping, adult badge, paging metadata/type 보존을 검증하도록 했다.
- 2026-06-27 RED 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewMapperTest"`
- RED 결과: `overview.model` mapper/UI model 미구현으로 `Unresolved reference 'model'`, `toTitleResId`, `toUiModel`, `toContent` 컴파일 실패를 확인했다.
- [x] **Task 5.3: UI model과 mapper 구현**
- 생성:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/model/ContentOverviewUiState.kt`
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/model/ContentOverviewUiModels.kt`
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/model/ContentOverviewMappers.kt`
- 작업:
- `ContentOverviewUiState.Loading`, `Content`, `Empty`, `Error`를 정의한다.
- `ContentOverviewUiModel``contentId`, `title`, `coverImage`, `creatorNickname`, `tags`, `showAdultBadge`를 포함한다.
- `ContentOverviewType.toTitleResId()`를 정의한다.
- `NEW_AND_HOT_AUDIO``R.string.content_recommendation_section_new_and_hot`, `FIRST_AUDIO_CONTENT``R.string.home_recommendation_section_first_audio_contents`로 매핑한다.
- `ContentOverviewItemResponse.toUiModel()`에서 PRD tag mapping을 구현한다.
- `ContentOverviewPageResponse.toContent()`에서 paging metadata와 item list를 보존한다.
- 검증:
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewMapperTest"`
- Expected: mapper 테스트 PASS.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 구현: `ContentOverviewUiState`, `ContentOverviewUiModel`, `ContentOverviewType.toTitleResId()`, `ContentOverviewPageResponse.toContent()`, `ContentOverviewItemResponse.toUiModel()`을 추가했다.
- 2026-06-27 확인: `NEW_AND_HOT_AUDIO``New&Hot`, `FIRST_AUDIO_CONTENT``처음부터 함께 성장!` title resource로 매핑하고, `Original/First/Point/Free` tag 및 adult badge를 DTO boolean/price 기준으로 매핑했다.
- 2026-06-27 GREEN 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewMapperTest"`
- GREEN 결과: PASS.
---
### Phase 6: 신규 전체보기 ViewModel, Activity, Adapter 구현
- [x] **Task 6.1: ViewModel RED 테스트 작성**
- 생성:
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/overview/ContentOverviewViewModelTest.kt`
- 테스트 케이스:
- 초기 로드는 전달받은 type으로 `page=0`, `size=20`을 요청한다.
- 첫 페이지 성공 + items 있음은 `Content` 상태를 emit한다.
- 첫 페이지 성공 + items empty는 `Empty` 상태를 emit한다.
- 첫 페이지 실패는 `Error` 상태와 toast를 emit한다.
- `hasNext = true` 상태에서 `loadMore()`는 다음 page를 요청하고 append한다.
- `hasNext = false`이면 `loadMore()`가 repository를 추가 호출하지 않는다.
- 추가 페이지 실패 시 기존 items를 유지하고 pagination error message를 emit한다.
- type 변경 또는 새 화면 생성 상태 간 page/items를 공유하지 않는다.
- 검증:
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewViewModelTest"`
- Expected: ViewModel 구현 전 RED 실패.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 RED 테스트 추가: `ContentOverviewViewModelTest`를 생성해 초기 load, Content/Empty/Error, toast, load-more append, `hasNext=false` 추가 요청 방지, pagination error 보존, stale response 방지를 검증하도록 했다.
- 2026-06-27 RED 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewViewModelTest"`
- RED 결과: `ContentOverviewViewModel` 미구현으로 `Unresolved reference 'ContentOverviewViewModel'`, `loadFirstPage`, `loadMore`, `overviewStateLiveData` 컴파일 실패를 확인했다.
- [x] **Task 6.2: ViewModel 구현**
- 생성:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/ContentOverviewViewModel.kt`
- 작업:
- `loadFirstPage(type: ContentOverviewType)`를 구현한다.
- `loadMore()``Content` 상태, `hasNext`, `isLoadingMore`를 확인한 뒤 다음 page만 요청한다.
- `requestGeneration`으로 stale response가 현재 화면 상태를 덮어쓰지 않게 한다.
- auth header는 기존 ViewModel 패턴대로 `Bearer ${SharedPreferenceManager.token}`를 사용한다.
- 첫 페이지 loading은 `isLoading` LiveData로 처리하고, 추가 페이지 loading은 `Content.isLoadingMore`로 처리한다.
- 검증:
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewViewModelTest"`
- Expected: ViewModel 테스트 PASS.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 구현: `ContentOverviewViewModel`을 추가해 `page=0`, `size=20`, `Bearer ${SharedPreferenceManager.token}`, `requestGeneration`, 첫 페이지 `isLoading`, 추가 페이지 `Content.isLoadingMore`/`paginationErrorMessage` 패턴을 구현했다.
- 2026-06-27 GREEN 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewViewModelTest"`
- GREEN 결과: PASS.
- [x] **Task 6.3: Activity layout과 Adapter 구현**
- 생성:
- `app/src/main/res/layout/activity_content_overview.xml`
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/ui/ContentOverviewAdapter.kt`
- 수정:
- `app/src/main/AndroidManifest.xml`
- 작업:
- layout root는 black background를 사용한다.
- title bar는 60dp 높이, 좌측 back chevron, 22sp bold title을 배치한다.
- RecyclerView는 2열 `GridLayoutManager`로 표시한다.
- RecyclerView item은 기존 `item_content_audio_card.xml``AudioContentCardView`를 재사용한다.
- Adapter는 `setGridItemWidthPx(widthPx)`를 호출해 2열 item width를 적용한다.
- 이미지 로딩은 기존 `loadUrl` 확장을 사용한다.
- manifest에 `kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewActivity`를 등록한다.
- 검증:
- Run: `./gradlew :app:mergeDebugResources`
- Expected: 신규 layout과 resource reference가 merge된다.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 구현: Figma `482:15105` 기준으로 black root, 60dp title bar, 좌측 `ic_new_bar_back`, 22sp bold title(`Typography.Heading2`), 2열 RecyclerView layout을 추가했다.
- 2026-06-27 구현: `ContentOverviewAdapter`를 추가해 `item_content_audio_card.xml`/`AudioContentCardView`를 재사용하고 `setGridItemWidthPx`, `setContent`, `setTags`, `setAdultVisible`, `loadUrl`을 바인딩했다.
- 2026-06-27 구현: `AndroidManifest.xml``.v2.main.content.overview.ContentOverviewActivity`를 등록했다.
- 2026-06-27 실행: `./gradlew :app:mergeDebugResources`
- 결과: PASS.
- [x] **Task 6.4: Activity source RED 테스트 작성**
- 생성:
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/overview/ContentOverviewActivitySourceTest.kt`
- 테스트 케이스:
- `ContentOverviewActivity.newIntent(context, type)`가 type extra를 포함한다.
- layout에 back button, title TextView, RecyclerView, empty/error TextView가 있다.
- Activity가 `GridLayoutManager(this, CONTENT_OVERVIEW_GRID_SPAN_COUNT)`로 2열 grid를 설정한다.
- scroll bottom에서 `viewModel.loadMore()`를 호출한다.
- item click은 `Constants.EXTRA_AUDIO_CONTENT_ID``AudioContentDetailActivity`를 연다.
- 검증:
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewActivitySourceTest"`
- Expected: Activity 구현 전 또는 연결 전 RED 실패.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 RED 테스트 추가: `ContentOverviewActivitySourceTest`를 생성해 `newIntent`, intent extra, Figma layout id, 2열 `GridLayoutManager`, 하단 scroll `loadMore`, 상세 이동 extra, manifest 등록, Phase 7 라우팅 미추가를 검증하도록 했다.
- 2026-06-27 RED 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewActivitySourceTest"`
- RED 결과: layout/manifest/Phase 7 미연결 검증은 통과했고 `ContentOverviewActivity.kt` 미생성으로 Activity source 관련 테스트 2건이 `FileNotFoundException`으로 실패하는 것을 확인했다.
- [x] **Task 6.5: Activity 구현과 ViewModel 연결**
- 생성:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/ContentOverviewActivity.kt`
- 수정:
- `app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt`
- 작업:
- `newIntent(context, type)` companion method를 제공한다.
- intent type extra가 없거나 enum parsing에 실패하면 `NEW_AND_HOT_AUDIO`를 fallback으로 사용한다.
- title은 type mapping으로 표시한다.
- back button은 `finish()`를 호출한다.
- `Content`, `Empty`, `Error`, `Loading` 상태별 UI를 바인딩한다.
- item click은 `AudioContentDetailActivity`를 열고 `Constants.EXTRA_AUDIO_CONTENT_ID``contentId`를 전달한다.
- 성인 콘텐츠 접근 제한은 기존 `AudioContentDetailActivity` 정책을 따른다.
- Koin `viewModelModule``ContentOverviewViewModel`을 등록한다.
- 검증:
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"`
- Expected: overview mapper/ViewModel/source 테스트 PASS.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 구현: `ContentOverviewActivity`를 추가해 `newIntent(context, type)`, type title, back `finish()`, `Loading/Content/Empty/Error` 렌더링, 2열 grid width 계산, scroll bottom `loadMore()`, `AudioContentDetailActivity` 상세 이동을 연결했다.
- 2026-06-27 구현: `AppDI.viewModelModule``ContentOverviewViewModel`을 등록했다. intent type extra가 없거나 파싱 실패하면 계획서 기본값인 `NEW_AND_HOT_AUDIO`를 사용한다.
- 2026-06-27 GREEN 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"`
- GREEN 결과: PASS.
- 2026-06-27 추가 검증: 포맷 수정 후 동일 overview 테스트 재실행 결과 PASS.
- 2026-06-27 코드 리뷰 확인: PRD edge case의 `contentId <= 0` 상세 이동 무시 조건이 현재 `ContentOverviewActivity.openAudioContentDetail(contentId)` 또는 adapter click 경로에 반영되어 있지 않다. 잘못된 id 응답 시 상세 화면을 열 수 있어 수정이 필요하다.
- 2026-06-27 리뷰 후속 RED 테스트 추가: `ContentOverviewActivitySourceTest`에 Activity의 `if (contentId <= 0) return` 및 Adapter의 `return@setOnClickListener` 검증을 추가했다.
- 2026-06-27 리뷰 후속 구현: `ContentOverviewActivity.openAudioContentDetail(contentId)``ContentOverviewAdapter` click listener에 `contentId <= 0` 상세 이동 무시 조건을 추가했다.
- [x] **Task 6.6: 신규 전체보기 loading UI 표시 후속 수정**
- 수정:
- `app/src/main/res/layout/activity_content_overview.xml`
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/ContentOverviewActivity.kt`
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/overview/ContentOverviewActivitySourceTest.kt`
- 작업:
- 첫 페이지 `Loading` 상태에서 사용자에게 보이는 중앙 progress view를 표시한다.
- `Content.isLoadingMore`가 true일 때 기존 목록은 유지하고 하단 progress view를 표시한다.
- `Empty`, `Error`, `Content`의 비로딩 상태에서는 progress view를 숨긴다.
- skeleton loading, 신규 정렬/필터, Phase 7 신규 전체보기 라우팅은 추가하지 않는다.
- 검증:
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewActivitySourceTest"`
- Expected: first-page/loading-more progress source 테스트 PASS.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 작업 결정: PRD의 첫 페이지 로딩/추가 페이지 로딩 상태 구분 요구를 엄격히 충족하기 위해 `LoadingDialog`가 아닌 inline progress view 2개를 추가하는 최소 수정으로 진행한다.
- 2026-06-27 RED 테스트 추가: `ContentOverviewActivitySourceTest`에 first-page progress id, load-more progress id, `viewModel.isLoading.observe(this)`, `renderLoading()` progress 표시, `state.isLoadingMore`에 따른 load-more progress 표시 검증을 추가했다.
- 2026-06-27 RED 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewActivitySourceTest"`
- RED 결과: `ContentOverviewActivitySourceTest.kt:48`, `ContentOverviewActivitySourceTest.kt:59`에서 예상 실패했다. 원인은 `activity_content_overview.xml`에 progress view가 없고 `ContentOverviewActivity`가 로딩 progress를 바인딩하지 않았기 때문이다.
- 2026-06-27 구현: `activity_content_overview.xml``pb_content_overview_initial_loading`, `pb_content_overview_load_more`를 추가하고, `ContentOverviewActivity`에서 `viewModel.isLoading``Content.isLoadingMore`에 따라 progress visibility를 제어하도록 했다.
- 2026-06-27 GREEN 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewActivitySourceTest"`
- GREEN 결과: PASS.
- 2026-06-27 코드 리뷰 및 검증 재확인: 첫 페이지/loading-more progress view와 Activity binding이 유지되어 있고, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"` 재실행 결과 PASS.
---
### Phase 7: 신규 전체보기 대상 섹션 이동 연결
- [x] **Task 7.1: 홈 FIRST 신규 전체보기 이동 연결**
- 수정:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt`
- 테스트:
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragmentSourceTest.kt`
- 작업:
- `viewHomeFirstAudioTitle.ivSectionTitleChevron.setOnClickListener`를 추가한다.
- 클릭 시 `ContentOverviewActivity.newIntent(requireContext(), ContentOverviewType.FIRST_AUDIO_CONTENT)`로 이동한다.
- `ensureMainV2NavigationAllowed`로 기존 홈 navigation guard 패턴을 따른다.
- 검증:
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentSourceTest"`
- Expected: 홈 FIRST 신규 전체보기 이동 source 테스트 PASS.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 RED 테스트 수정: `HomeMainFragmentSourceTest`의 Phase 2 미연결 assertion을 Phase 7 라우팅 assertion으로 변경해 `ContentOverviewActivity`/`ContentOverviewType` import, `viewHomeFirstAudioTitle.ivSectionTitleChevron.setOnClickListener`, `FIRST_AUDIO_CONTENT` intent 생성을 요구하도록 했다.
- 2026-06-27 RED 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentSourceTest"`를 production 구현 전 병렬 실행했으나 Gradle/Kotlin daemon cache 충돌 및 동시 compile 오류로 테스트 assertion 결과까지 도달하지 못했다. 이후 `./gradlew --stop`으로 daemon을 정리하고 순차 검증으로 전환했다.
- 2026-06-27 구현: `HomeMainFragment``ContentOverviewActivity`, `ContentOverviewType` import를 추가하고 `viewHomeFirstAudioTitle.ivSectionTitleChevron.setOnClickListener`에서 `ensureMainV2NavigationAllowed`를 거쳐 `ContentOverviewActivity.newIntent(requireContext(), ContentOverviewType.FIRST_AUDIO_CONTENT)`를 실행하도록 연결했다.
- 2026-06-27 GREEN 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentSourceTest"`
- GREEN 결과: PASS.
- 2026-06-27 리뷰 후속 보강: `HomeMainFragmentSourceTest``openFirstAudioOverview()` 함수 내부에서 `ensureMainV2NavigationAllowed``startActivity`보다 먼저 호출되고 `FIRST_AUDIO_CONTENT` intent를 생성하는 순서를 검증하도록 보강했다.
- [x] **Task 7.2: 콘텐츠 New&Hot 신규 전체보기 이동 연결**
- 수정:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt`
- 테스트:
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragmentSourceTest.kt`
- 작업:
- `viewContentNewAndHotTitle.ivSectionTitleChevron.setOnClickListener`를 추가한다.
- 클릭 시 `ContentOverviewActivity.newIntent(requireContext(), ContentOverviewType.NEW_AND_HOT_AUDIO)`로 이동한다.
- `ensureMainV2NavigationAllowed`로 기존 콘텐츠 navigation guard 패턴을 따른다.
- 기존 전체 탭 이동 대상 섹션 click listener는 Phase 4 동작을 유지한다.
- 검증:
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"`
- Expected: 콘텐츠 New&Hot 신규 전체보기 이동 source 테스트 PASS.
- 검증 기록:
- 구현 시 이 Task 아래에 명령, 결과, 확인 내용을 한국어로 누적한다.
- 2026-06-27 RED 테스트 수정: `ContentMainFragmentSourceTest``New&Hot` 미연결 assertion을 Phase 7 라우팅 assertion으로 변경해 `ContentOverviewActivity`/`ContentOverviewType` import, `viewContentNewAndHotTitle.ivSectionTitleChevron.setOnClickListener`, `NEW_AND_HOT_AUDIO` 이동 helper를 요구하도록 했다.
- 2026-06-27 RED 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"`를 production 구현 전 병렬 실행했으나 Gradle/Kotlin daemon cache 충돌 및 동시 compile 오류로 테스트 assertion 결과까지 도달하지 못했다. 이후 `./gradlew --stop`으로 daemon을 정리하고 순차 검증으로 전환했다.
- 2026-06-27 구현: `ContentMainFragment``ContentOverviewActivity`, `ContentOverviewType` import를 추가하고 `viewContentNewAndHotTitle.ivSectionTitleChevron.setOnClickListener`에서 `ensureMainV2NavigationAllowed`를 거쳐 `ContentOverviewActivity.newIntent(requireContext(), ContentOverviewType.NEW_AND_HOT_AUDIO)` 경로로 이동하도록 연결했다. 기존 전체 탭 이동 대상 섹션의 `openContentAllTab` 연결은 유지했다.
- 2026-06-27 GREEN 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"`
- GREEN 결과: PASS. 최초 GREEN 시도에서는 source assertion이 helper 구조가 아닌 literal intent 호출을 기대해 1회 실패했고, production 코드는 유지한 채 `openContentOverview(ContentOverviewType.NEW_AND_HOT_AUDIO)`/`ContentOverviewActivity.newIntent(requireContext(), type)` 구조를 검증하도록 테스트를 조정한 뒤 PASS했다.
- 2026-06-27 리뷰 후속 보강: `ContentMainFragmentSourceTest``openContentOverview(type)` 함수 내부에서 `ensureMainV2NavigationAllowed``startActivity`보다 먼저 호출되고 `ContentOverviewActivity.newIntent(requireContext(), type)`를 실행하는 순서를 검증하도록 보강했다.
---
### Phase 8: 통합 검증과 수동 확인
- [x] **Task 8.1: 단위/source 테스트 실행**
- 실행:
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*"`
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*"`
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"`
- 기대 결과:
- 수정된 홈/콘텐츠/MainV2 source 테스트와 신규 overview 테스트가 모두 PASS한다.
- 검증 기록:
- 구현 시 이 Task 아래에 실행 명령과 결과를 한국어로 누적한다.
- 2026-06-27 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*"`
- 결과: PASS.
- 2026-06-27 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*"`
- 결과: PASS.
- 2026-06-27 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"`
- 결과: PASS.
- [x] **Task 8.2: 빌드/리소스/린트 검증**
- 실행:
- `./gradlew :app:mergeDebugResources`
- `./gradlew :app:compileDebugKotlin`
- `./gradlew :app:ktlintCheck`
- `git diff --check`
- 기대 결과:
- resource merge, Kotlin compile, ktlint, whitespace 검증이 모두 PASS한다.
- 검증 기록:
- 구현 시 이 Task 아래에 실행 명령과 결과를 한국어로 누적한다.
- 2026-06-27 실행: `./gradlew :app:mergeDebugResources`
- 결과: PASS.
- 2026-06-27 실행: `./gradlew :app:compileDebugKotlin`
- 결과: PASS.
- 2026-06-27 실행: `./gradlew :app:ktlintCheck`
- 결과: PASS.
- 2026-06-27 실행: `git diff --check`
- 결과: PASS(출력 없음).
- [ ] **Task 8.3: 수동 화면 검증**
- 확인:
- 홈 추천 탭 `처음부터 함께 성장!` title 우측 chevron 표시.
- 콘텐츠 추천 탭 `오직 보이스온에서만!`, `새로 올라온 오디오`, `New&Hot`, `무료 오디오`, `포인트 오디오` title 우측 chevron 표시.
- 콘텐츠 추천 탭 `댓글 많은 오디오`, `추천 오디오`에는 chevron이 표시되지 않음.
- 콘텐츠 추천 탭 `오직 보이스온에서만!` chevron 클릭 시 콘텐츠 `전체` -> `오리지널` 진입.
- 콘텐츠 추천 탭 `새로 올라온 오디오` chevron 클릭 시 콘텐츠 `전체` -> `오디오` 진입.
- 콘텐츠 추천 탭 `무료 오디오` chevron 클릭 시 콘텐츠 `전체` -> `무료` + `인기순` 진입.
- 콘텐츠 추천 탭 `포인트 오디오` chevron 클릭 시 콘텐츠 `전체` -> `포인트` + `인기순` 진입.
- 홈 추천 탭 `처음부터 함께 성장!` chevron 클릭 시 `처음부터 함께 성장!` 신규 전체보기 진입.
- 콘텐츠 추천 탭 `New&Hot` chevron 클릭 시 `New&Hot` 신규 전체보기 진입.
- 신규 전체보기 화면 title bar, back button, 2열 grid, tag, 성인 badge, 상세 이동.
- 신규 전체보기 화면 하단 스크롤 시 `page + 1` 추가 요청.
- 검증 기록:
- 구현 시 이 Task 아래에 테스트 기기/빌드 variant/API 응답 조건과 확인 결과를 한국어로 누적한다.
- 2026-06-27 상태: BLOCKED/미완료. 현재 작업 환경에서 Android 기기 또는 에뮬레이터를 통한 실제 화면 조작을 수행할 수 없어 홈/콘텐츠 chevron 표시, 기존 전체 탭 이동, 신규 전체보기 화면 진입/스크롤/상세 이동을 수동으로 확인하지 못했다.
- 2026-06-27 대체 확인: Task 8.1의 source/unit 테스트와 Task 8.2의 resource merge/compile/ktlint/whitespace 검증은 모두 PASS했다. 실제 API 응답 기반 화면 표시와 사용자 조작 검증은 기기 또는 에뮬레이터가 준비된 환경에서 후속 확인이 필요하다.
---
## Verification Log
- 구현 완료 후 여러 Phase에 걸친 통합 검증, 회귀 검증, 최종 수동 확인 기록을 이 섹션에 누적한다.
- 2026-06-27 Phase 3~4 범위 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentAllTabViewModelTest"` 결과 PASS.
- 2026-06-27 Phase 3~4 범위 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"` 결과 PASS.
- 2026-06-27 Phase 3~4 범위 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.MainV2ActivitySourceTest"` 결과 PASS.
- 2026-06-27 Phase 3~4 범위 실행: `./gradlew :app:compileDebugKotlin` 결과 PASS.
- 2026-06-27 Phase 3~4 범위 실행: `./gradlew :app:ktlintCheck`는 신규 source 테스트의 긴 줄로 1회 실패 후 포맷 수정, 재실행 결과 PASS. 기존 `.editorconfig``disabled_rules` deprecation 경고는 출력되었으나 실패 원인은 아니었다.
- 2026-06-27 Phase 3~4 범위 실행: `git diff --check` 결과 PASS(출력 없음).
- 2026-06-27 수동 화면 검증: Android 기기/에뮬레이터를 사용할 수 없어 Phase 4 기존 전체 탭 이동 수동 클릭 검증은 완료하지 못했다. Task 4.2에 BLOCKED/미완료로 기록했다.
- 2026-06-27 Phase 5~6 범위 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"` 결과 PASS.
- 2026-06-27 Phase 5~6 인접 회귀 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"` 결과 PASS.
- 2026-06-27 Phase 5~6 인접 회귀 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentSourceTest"` 결과 PASS.
- 2026-06-27 Phase 5~6 범위 실행: `./gradlew :app:mergeDebugResources` 결과 PASS.
- 2026-06-27 Phase 5~6 범위 실행: `./gradlew :app:compileDebugKotlin` 결과 PASS.
- 2026-06-27 Phase 5~6 범위 실행: `./gradlew :app:ktlintCheck`는 신규 overview 테스트의 긴 줄/unused import로 1회 실패 후 포맷 수정, 재실행 결과 PASS. 기존 `.editorconfig``disabled_rules` deprecation 경고는 출력되었으나 실패 원인은 아니었다.
- 2026-06-27 Phase 5~6 범위 실행: `git diff --check` 결과 PASS(출력 없음).
- 2026-06-27 Phase 5~6 범위 확인: `rg -n "viewHomeFirstAudioTitle\.ivSectionTitleChevron\.setOnClickListener|viewContentNewAndHotTitle\.ivSectionTitleChevron\.setOnClickListener" app/src/main/java/kr/co/vividnext/sodalive/v2/main/home app/src/main/java/kr/co/vividnext/sodalive/v2/main/content` 결과 매치 없음. Phase 7 신규 전체보기 이동 라우팅은 아직 추가하지 않았다.
- 2026-06-27 Phase 5~6 코드 리뷰 확인: 문서 기준 발견 사항 2건을 확인했다. 1) 신규 API DTO 필드명이 PRD/계획서의 `items/contentId/coverImage`와 달리 `contents/audioContentId/imageUrl`로 구현되어 서버 계약 확인 또는 수정이 필요하다. 2) `contentId <= 0` item 상세 이동 무시 조건이 누락되어 수정이 필요하다.
- 2026-06-27 Phase 5~6 재검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"` 결과 PASS.
- 2026-06-27 Phase 5~6 재검증 실행: `./gradlew :app:mergeDebugResources`는 sandbox의 `~/.gradle` lock 접근 제한으로 1회 실패 후 권한 상승 재실행 결과 PASS.
- 2026-06-27 Phase 5~6 재검증 실행: `./gradlew :app:compileDebugKotlin` 결과 PASS.
- 2026-06-27 Phase 5~6 재검증 실행: `./gradlew :app:ktlintCheck` 결과 PASS.
- 2026-06-27 Phase 5~6 재검증 실행: `git diff --check` 결과 PASS(출력 없음).
- 2026-06-27 Phase 5~6 인접 회귀 재검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"` 결과 PASS.
- 2026-06-27 Phase 5~6 인접 회귀 재검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentSourceTest"` 결과 PASS.
- 2026-06-27 Phase 5~6 리뷰 후속 RED 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"` 결과 예상 실패. 테스트가 문서 계약 `items/contentId/coverImage`와 invalid `contentId <= 0` guard를 요구하지만 production이 아직 이전 DTO 계약과 guard 누락 상태였음을 확인했다.
- 2026-06-27 Phase 5~6 리뷰 후속 GREEN 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"` 결과 PASS.
- 2026-06-27 Phase 5~6 리뷰 후속 확인: `rg -n "totalCount|contents|audioContentId|imageUrl" "app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview" "app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/overview"` 실행 결과 `audioContentId`, `imageUrl` 잔여 참조는 없고 `contents`는 API path/문자열 이름의 정상 매치만 남았다.
- 2026-06-27 Phase 5~6 리뷰 후속 재검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"` 결과 PASS.
- 2026-06-27 Phase 5~6 리뷰 후속 재검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"` 결과 PASS.
- 2026-06-27 Phase 5~6 리뷰 후속 재검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentSourceTest"` 결과 PASS.
- 2026-06-27 Phase 5~6 리뷰 후속 재검증 실행: `./gradlew :app:compileDebugKotlin` 결과 PASS.
- 2026-06-27 Phase 5~6 리뷰 후속 재검증 실행: `./gradlew :app:ktlintCheck`는 테스트 fixture 들여쓰기 문제로 1회 실패 후 수정, 재실행 결과 PASS. 기존 `.editorconfig``disabled_rules` deprecation 경고는 출력되었으나 실패 원인은 아니었다.
- 2026-06-27 Phase 5~6 리뷰 후속 재검증 실행: `git diff --check` 결과 PASS(출력 없음).
- 2026-06-27 Git 상태 확인: `app/src/main/res/drawable-mdpi/ic_new_arrow_up_gray.png`, `app/src/main/res/drawable-mdpi/ic_new_arrow_up_white.png``AD` 상태이며 현재 소스/문서에서 참조되지 않는다. 커밋 전 포함 여부 정리가 필요하다.
- 2026-06-27 Phase 5~6 코드 리뷰 재확인: `ContentOverviewActivity.renderLoading()`은 RecyclerView와 empty/error TextView를 숨기기만 하고, `activity_content_overview.xml`에도 loading/progress view가 없어 PRD의 첫 페이지 로딩/추가 페이지 로딩 상태 구분 요구가 사용자에게 표시되지 않는다. `ContentOverviewViewModel.isLoading`도 Activity에서 observe하지 않는다. 코드 수정이 필요하다.
- 2026-06-27 Phase 5~6 fresh 검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"` 결과 PASS.
- 2026-06-27 Phase 5~6 fresh 검증 실행: `./gradlew :app:compileDebugKotlin` 결과 PASS.
- 2026-06-27 Phase 5~6 fresh 검증 실행: `./gradlew :app:ktlintCheck` 결과 PASS.
- 2026-06-27 Phase 5~6 fresh 검증 실행: `git diff --check` 결과 PASS(출력 없음).
- 2026-06-27 Phase 5~6 fresh 검증 실행: `./gradlew :app:mergeDebugResources`는 sandbox의 `~/.gradle` wrapper lock 접근 제한으로 1회 실패 후 권한 상승 재실행 결과 PASS.
- 2026-06-27 Phase 5~6 인접 회귀 fresh 검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest"` 결과 PASS.
- 2026-06-27 Phase 5~6 인접 회귀 fresh 검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentSourceTest"` 결과 PASS.
- 2026-06-27 Phase 5~6 loading UI 후속 작업 시작: PRD의 첫 페이지 로딩/추가 페이지 로딩 상태 구분 요구를 사용자에게 보이는 UI로 반영하기 위해 Task 6.6을 추가했다. Phase 7 라우팅과 legacy 파일 수정은 범위에서 제외한다.
- 2026-06-27 Phase 5~6 loading UI 후속 RED 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewActivitySourceTest"` 결과 예상 실패. layout progress id와 Activity 로딩 바인딩이 아직 없음을 확인했다.
- 2026-06-27 Phase 5~6 loading UI 후속 GREEN 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewActivitySourceTest"` 결과 PASS.
- 2026-06-27 Phase 5~6 loading UI 후속 검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"` 결과 PASS.
- 2026-06-27 Phase 5~6 loading UI 후속 검증 실행: `./gradlew :app:mergeDebugResources` 결과 PASS.
- 2026-06-27 Phase 5~6 loading UI 후속 검증 실행: `./gradlew :app:compileDebugKotlin` 결과 PASS.
- 2026-06-27 Phase 5~6 loading UI 후속 검증 실행: `./gradlew :app:ktlintCheck` 결과 PASS. 기존 `.editorconfig``disabled_rules` deprecation 경고는 출력되었으나 실패 원인은 아니었다.
- 2026-06-27 Phase 5~6 loading UI 후속 검증 실행: `git diff --check` 결과 PASS(출력 없음).
- 2026-06-27 Phase 5~6 코드 리뷰 및 검증 재확인: Phase 5 API/DTO/Repository/UI model과 Phase 6 ViewModel/Activity/Adapter 구현을 PRD/계획서 기준으로 재검토했고 추가 코드 수정이 필요한 발견 사항은 없었다. `Task 6.6`은 코드와 검증 기록이 완료 상태라 체크박스를 완료로 갱신했다.
- 2026-06-27 Phase 5~6 재검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"` 결과 PASS.
- 2026-06-27 Phase 5~6 재검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*"` 결과 PASS.
- 2026-06-27 Phase 5~6 재검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*"` 결과 PASS.
- 2026-06-27 Phase 5~6 재검증 실행: `./gradlew :app:mergeDebugResources`는 sandbox의 `~/.gradle` wrapper lock 접근 제한으로 1회 실패 후 권한 상승 재실행 결과 PASS.
- 2026-06-27 Phase 5~6 재검증 실행: `./gradlew :app:compileDebugKotlin` 결과 PASS.
- 2026-06-27 Phase 5~6 재검증 실행: `./gradlew :app:ktlintCheck` 결과 PASS.
- 2026-06-27 Phase 5~6 재검증 실행: `git diff --check` 결과 PASS(출력 없음).
- 2026-06-27 Phase 7 범위 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentSourceTest" --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest" --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewActivitySourceTest"` 결과 PASS.
- 2026-06-27 Phase 7 범위 실행: `./gradlew :app:compileDebugKotlin` 결과 PASS.
- 2026-06-27 Phase 7 범위 실행: `./gradlew :app:ktlintCheck``HomeMainFragmentSourceTest`의 긴 assertion 줄로 1회 실패 후 포맷 수정, 재실행 결과 PASS. 기존 `.editorconfig``disabled_rules` deprecation 경고는 출력되었으나 실패 원인은 아니었다.
- 2026-06-27 Phase 7 범위 실행: `git diff --check` 결과 PASS(출력 없음).
- 2026-06-27 Phase 7 수동 화면 검증: 현재 작업 환경에서 Android 기기 또는 에뮬레이터를 통한 실제 화면 조작을 수행할 수 없어 홈 `처음부터 함께 성장!` 및 콘텐츠 `New&Hot` chevron 클릭 후 신규 전체보기 화면 진입은 실제 앱 화면에서 확인하지 못했다. source 테스트와 compile/ktlint로 라우팅 계약은 검증했다.
- 2026-06-27 Phase 7 리뷰 게이트 결과: source 테스트가 신규 overview 라우팅의 `ensureMainV2NavigationAllowed` guard 경유를 충분히 고정하지 못한다는 지적으로 1회 Reject를 받았다. production 코드는 유지하고 홈/콘텐츠 source 테스트의 guard 내부 순서 검증을 보강했다.
- 2026-06-27 Phase 7 리뷰 후속 재검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentSourceTest" --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest" --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewActivitySourceTest"` 결과 PASS.
- 2026-06-27 Phase 7 리뷰 후속 재검증 실행: `./gradlew :app:compileDebugKotlin` 결과 PASS.
- 2026-06-27 Phase 7 리뷰 후속 재검증 실행: `./gradlew :app:ktlintCheck` 결과 PASS. 기존 `.editorconfig``disabled_rules` deprecation 경고는 출력되었으나 실패 원인은 아니었다.
- 2026-06-27 Phase 7 리뷰 후속 재검증 실행: `git diff --check` 결과 PASS(출력 없음).
- 2026-06-27 Phase 7 코드 리뷰 및 점검: 홈 `처음부터 함께 성장!`과 콘텐츠 `New&Hot` chevron이 각각 `ContentOverviewType.FIRST_AUDIO_CONTENT`, `ContentOverviewType.NEW_AND_HOT_AUDIO``ContentOverviewActivity.newIntent(...)`를 호출하고, 두 경로 모두 `ensureMainV2NavigationAllowed` guard를 먼저 경유하는 것을 확인했다. 추가 코드 수정이 필요한 발견 사항은 없었다.
- 2026-06-27 Phase 7 코드 리뷰 및 점검 재검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentSourceTest" --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentSourceTest" --tests "kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewActivitySourceTest"` 결과 PASS.
- 2026-06-27 Phase 7 코드 리뷰 및 점검 재검증 실행: `./gradlew :app:compileDebugKotlin` 결과 PASS.
- 2026-06-27 Phase 7 코드 리뷰 및 점검 재검증 실행: `./gradlew :app:ktlintCheck` 결과 PASS.
- 2026-06-27 Phase 7 코드 리뷰 및 점검 재검증 실행: `git diff --check` 결과 PASS(출력 없음).
- 2026-06-27 Phase 8 통합 검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*"` 결과 PASS.
- 2026-06-27 Phase 8 통합 검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*"` 결과 PASS.
- 2026-06-27 Phase 8 통합 검증 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"` 결과 PASS.
- 2026-06-27 Phase 8 빌드/리소스/린트 검증 실행: `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check` 결과 모두 PASS.
- 2026-06-27 Phase 8 수동 화면 검증: Android 기기/에뮬레이터를 사용할 수 없어 실제 화면 조작 검증은 BLOCKED로 남겼다. 자동 테스트와 빌드 검증은 모두 통과했다.
- 2026-06-29: 홈 추천 탭 `처음부터 함께 성장!` 섹션 제거에 따라 `FIRST_AUDIO_CONTENT` 신규 전체보기 진입을 제거했다. 회귀 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*" --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*" :app:mergeDebugResources :app:compileDebugKotlin :app:ktlintCheck`가 BUILD SUCCESSFUL임을 확인했고, `git diff --check` 출력 없음과 `app/src/main` production 참조 제거를 확인했다. Android 기기/에뮬레이터 접근이 없어 실제 화면 조작은 수행하지 못했다.
## 2026-06-29 변경: 홈 `처음부터 함께 성장!` 제거 반영
- 홈 추천 탭 `처음부터 함께 성장!` 섹션 제거에 따라 `FIRST_AUDIO_CONTENT` 신규 전체보기 진입도 제거한다.
- 현재 신규 전체보기 유지 대상은 콘텐츠 추천 탭 `New&Hot` -> `NEW_AND_HOT_AUDIO`뿐이다.
- 기존 Phase별 완료 로그는 당시 검증 이력으로 유지하며, 후속 구현은 이 변경 항목을 현재 계약으로 우선한다.