69 KiB
크리에이터 채널 라이브 탭 구현 계획/TASK
For agentic workers: 각 단계는 체크박스(
- [ ])로 추적하고, 완료 즉시- [x]로 갱신한다. 구현 범위 변경이 생기면 이 문서를 먼저 수정한 뒤 코드에 반영한다.
Goal: GET /api/v2/creator-channels/{creatorId}/live 응답을 기반으로 크리에이터 채널의 라이브 탭에 현재 라이브, 라이브 다시듣기 목록, 정렬, pagination, 본인 채널 전용 하단 라이브 시작하기 CTA를 표시한다.
Architecture: 기존 CreatorChannelActivity의 ViewPager2/CreatorChannelPagerAdapter 구조를 유지하고, CreatorChannelTab.Live의 placeholder를 신규 CreatorChannelLiveFragment로 교체한다. 라이브 탭 전용 Fragment/ViewModel/mapper/UI model/adapter/popup은 kr.co.vividnext.sodalive.v2.creator.channel.live 하위에 둔다. API/Repository는 홈 탭과 라이브 탭이 함께 쓰는 채널 공통 계층으로 보고 기존 CreatorChannelHomeApi/CreatorChannelHomeRepository를 CreatorChannelApi/CreatorChannelRepository로 rename한다. 홈 탭에서 이미 쓰는 CreatorChannelLiveResponse, CreatorChannelAudioContentResponse, 본인 판정, 라이브 시작 진입 흐름은 가능한 한 재사용한다.
Tech Stack: Kotlin, Android XML Views, ViewBinding, RecyclerView, Retrofit, Gson, RxJava3, Koin, JUnit4/Robolectric local unit test.
전제와 성공 기준
- PRD:
docs/20260617_크리에이터_채널_라이브_탭/prd.md - 기존 채널 컨테이너:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt - 기존 탭 adapter:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelPagerAdapter.kt - 기존 채널 API/DTO/Repository:
- rename 대상:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeApi.kt->app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelApi.kt - rename 대상:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeRepository.kt->app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelRepository.kt - 유지/확장:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeModels.kt
- rename 대상:
- 별도
CreatorChannelLiveApi,CreatorChannelLiveRepository는 생성하지 않는다. - Figma:
- 전체:
290:8945 - 전체 empty:
290:8959 - Sort-bar:
290:8949 - 현재 진행 중인 라이브:
290:8950 - 라이브 다시듣기 item:
290:8954,290:8956 - 정렬 컨텍스트 메뉴:
290:9041 - 본인 채널 하단 CTA:
665:19359,665:19371
- 전체:
- 첫 페이지
page는0이다. - 다음 페이지는 마지막 성공 응답의
page + 1로 요청한다. ContentSort기본값은LATEST이다.isOwned == true와isRented == true가 동시에 내려오면소장중을 우선 표시한다.seriesName은 라이브 다시듣기 item에 표시하지 않는다.isFirstContent,isOriginalSeries는 기존 오디오 item 정책과 동일하게 매핑한다.currentLive == null이고liveReplayContents.isEmpty()인 전체 empty 상태에서는 Sort-bar, 현재 라이브 카드, 라이브 다시듣기 리스트를 제거하고 중앙에크리에이터가 라이브를 준비 중입니다.\n기대해 주세요!문구를 표시한다.- 전체 empty 상태가 본인 채널에 표시되는 경우에도 empty 문구는 동일하게 표시하고, 하단
라이브 시작하기CTA는 본인 채널 정책에 따라 계속 표시한다. - 같은
creatorId로loadLive()가 재호출되면 Fragment/View 재생성 또는 탭 재바인딩으로 보고 기존 ViewModel 상태를 유지한다. 명시적 새로고침은 후속 필요 시 별도 refresh API로 분리한다. - 최초 조회 실패로
Error상태인 경우retryLive()를 통해 현재creatorId의 첫 페이지를 다시 요청한다. - 전체 error 상태에서는 안내 문구 아래 retry 버튼을 표시하고, retry 버튼은
CreatorChannelLiveViewModel.retryLive()를 호출한다. - drawable 리소스는 기존 파일을 재사용한다.
ic_new_sortic_new_shield_smallic_new_player_playic_new_create_live
- 구현 완료 후 최소 다음 명령을 실행한다.
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Live*"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"./gradlew :app:mergeDebugResources./gradlew :app:compileDebugKotlin./gradlew :app:ktlintCheck
Figma 참조 필요 Phase
- Phase 1: 부분 참조
- 기존 코드 경계와 리소스 존재 여부 확인이 중심이며, Figma는 PRD 기준만 확인한다.
- Phase 2: Figma 참조 불필요
- API/DTO/Repository/ViewModel 상태 모델은 서버 계약과 기존 코드 패턴을 따른다.
- Phase 3: 부분 참조
- mapper와 presenter 정책은 PRD와 Figma item variant의 상태 표시를 함께 확인한다.
- Phase 4: 필수 참조
fragment_creator_channel_live.xml, sort-bar, current live card, replay item layout, 전체 empty 상태는 Figma290:8949,290:8950,290:8954,290:8956,290:8959를 기준으로 구현한다.
- Phase 5: 필수 참조
- 정렬 컨텍스트 메뉴는 Figma
290:9041기준으로 구현한다.
- 정렬 컨텍스트 메뉴는 Figma
- Phase 6: 필수 참조
- 본인 채널 하단 CTA는 Figma
665:19359,665:19371기준으로 구현한다.
- 본인 채널 하단 CTA는 Figma
- Phase 7: 부분 참조
- 탭 연결, 화면 이동, pagination 동작은 기존 코드 패턴 중심으로 검증한다.
- Phase 8: 필수 참조
- 최종 수동 화면 검증은 PRD의 모든 Figma 노드와 실제 화면을 대조한다.
파일 구조
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelPagerAdapter.ktCreatorChannelTab.Live를 신규CreatorChannelLiveFragment로 연결한다.
- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.kt- 라이브 탭 UI, adapter, sort menu, pagination, CTA click 연결을 담당한다.
- 생성 후보:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveViewModel.kt- 라이브 탭 API 호출, 정렬 변경, pagination 상태, loading/error/content 상태를 관리한다.
- rename:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeApi.kt->app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelApi.kt- 홈 API와 라이브 API endpoint를 함께 가진 채널 공통 API로 변경한다.
- rename:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeRepository.kt->app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelRepository.kt- 홈 API, 라이브 API, 팔로우, 대화, 후원, 신고 등 채널 공통 동작을 제공한다.
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeModels.ktCreatorChannelAudioContentResponse에 라이브 탭 전용 필드isAdult,isOwned,isRented를 서버 계약에 맞춰 추가한다.
- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/common/data/ContentSort.kt- v2 API 공용 정렬 enum으로
ContentSort를 둔다.
- v2 API 공용 정렬 enum으로
- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/data/CreatorChannelLiveTabResponse.ktCreatorChannelLiveTabResponse를 크리에이터 채널 라이브 탭 응답 전용 모델로 둔다.
- 생성 후보:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/model/CreatorChannelLiveUiModels.kt- sort option, replay item status, pagination 상태, CTA 노출 여부를 순수 UI model로 정의한다.
- 생성 후보:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/model/CreatorChannelLiveMappers.kt- DTO를 UI model로 변환하고 소장/대여/무료/가격/포인트/19금 상태를 결정한다.
- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/ui/CreatorChannelLiveReplayAdapter.kt- 라이브 다시듣기 목록 RecyclerView adapter를 담당한다.
- 생성 후보:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/ui/CreatorChannelLiveSortPopup.kt- Sort-bar anchor 기준 컨텍스트 메뉴 표시를 담당한다.
- 생성:
app/src/main/res/layout/fragment_creator_channel_live.xml- sort-bar, current live card container, replay RecyclerView, owner CTA를 포함한다.
- 생성:
app/src/main/res/layout/item_creator_channel_live_replay.xml- 라이브 다시듣기 item layout이다.
- 생성 후보:
app/src/main/res/layout/view_creator_channel_live_sort_menu.xml- 정렬 컨텍스트 메뉴를 XML로 분리할 때만 추가한다.
- 수정:
app/src/main/res/values/strings.xml- 정렬 label,
소장중,대여중,라이브 시작하기, empty/error 문구를 추가한다.
- 정렬 label,
- 수정:
app/src/main/res/values-en/strings.xml,app/src/main/res/values-ja/strings.xml- 신규 문자열의 다국어 값을 추가한다.
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt- 신규 ViewModel/API/Repository binding이 필요하면 추가한다.
- 테스트 생성:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveMapperTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLivePaginationTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveViewModelTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragmentLayoutTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelPagerAdapterTest.kt
Phase 1: 기존 구조 확인과 작업 경계 고정
-
Task 1.1: 크리에이터 채널 탭 구조와 본인 판정 경로 확인
- 확인:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelPagerAdapter.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeFragment.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelHomeMappers.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelHomeUiModels.kt
- 작업:
CreatorChannelTab.Live가 현재 placeholder로 연결되는 지점을 확인한다.- 본인 여부(
isOwner)가 Activity와 탭 Fragment로 전달되는 기존 경로를 확인한다. - 라이브 시작 진입이 기존
CreatorChannelActivity의onOwnerFabLiveClicked()또는LiveRoomCreateActivity경로를 재사용할 수 있는지 확인한다.
- 검증:
- 라이브 탭 구현이 홈 탭 section adapter를 변경하지 않고 독립 Fragment로 추가 가능한지 기록한다.
- 검증 기록:
- 2026-06-17:
CreatorChannelPagerAdapter는 현재CreatorChannelTab.Home만CreatorChannelHomeFragment.newInstance(creatorId)로 연결하고,CreatorChannelTab.Live를 포함한 나머지 탭은CreatorChannelPlaceholderFragment.newInstance(tab)로 처리함을 확인했다. 따라서 Phase 7에서 Live 탭만 신규 Fragment로 교체해도 홈 탭 section adapter 변경 없이 독립 추가 가능하다. - 2026-06-17: 본인 여부는
CreatorChannelHomeMappers.toUiContent()에서creator.creatorId == currentMemberId로 계산되어CreatorChannelHeaderUiModel.isOwner와 donation section에 전달되고,CreatorChannelActivity는 이 값을 owner FAB/상단 액션/DM/후원 분기 조건으로 사용함을 확인했다. - 2026-06-17: 라이브 시작 진입은
CreatorChannelActivity.onOwnerFabLiveClicked()가liveRoomCreateLauncher.launch(Intent(this, LiveRoomCreateActivity::class.java))를 호출하는 기존 경로를 사용하며, 생성 결과는homeActionDelegate?.refreshHome()후Constants.EXTRA_ROOM_ID,Constants.EXTRA_ROOM_CHANNEL_NAME에 따라CreatorChannelLiveCoordinator.enterLiveRoom()또는 생성 완료 toast로 처리됨을 확인했다.
- 2026-06-17:
- 확인:
-
Task 1.2: 기존 오디오 item 정책과 drawable/string 리소스 확인
- 확인:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeAudioContentCardView.ktapp/src/main/res/layout/item_creator_channel_home_audio_content.xmlapp/src/main/java/kr/co/vividnext/sodalive/v2/widget/AudioContentTag.ktapp/src/main/res/drawable-mdpi/ic_new_sort.pngapp/src/main/res/drawable-mdpi/ic_new_shield_small.pngapp/src/main/res/drawable-mdpi/ic_new_player_play.pngapp/src/main/res/drawable-mdpi/ic_new_create_live.png
- 작업:
isFirstContent,isOriginalSeries, point/free/original tag의 기존 표시 정책을 정리한다.- 라이브 다시듣기 item에서
seriesName은 표시하지 않는다는 PRD 결정을 재확인한다.
- 검증:
- 위 4개 drawable 리소스가 존재함을 확인한다.
- 검증 기록:
- 2026-06-17: 기존 홈 오디오 item은
CreatorChannelHomeAudioContentCardView.bind()에서isOriginalSeries == true이면 original tag,isPointAvailable이면 point tag,isFirstContent이면 first tag,price <= 0이면 free tag를 표시한다. secondary text는 기존 홈 카드에서duration과seriesName을 조합하지만, 라이브 다시듣기 item에서는 PRD/계획 기준에 따라seriesName을 표시하지 않는 것으로 재확인했다. - 2026-06-17:
AudioContentTag의 top tag 순서는Original,First, bottom tag 순서는Point,Free로 정의되어 있음을 확인했다. - 2026-06-17:
test -f로app/src/main/res/drawable-mdpi/ic_new_sort.png,ic_new_shield_small.png,ic_new_player_play.png,ic_new_create_live.png가 모두 존재함을 확인했다.
- 2026-06-17: 기존 홈 오디오 item은
- 확인:
-
Task 1.3: 채널 공통 API/Repository rename
- rename:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeApi.kt->app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelApi.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeRepository.kt->app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelRepository.kt
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModel.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModelTest.ktapp/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt- 기타
CreatorChannelHomeApi,CreatorChannelHomeRepositoryimport 참조 파일
- 작업:
- class/interface 이름을
CreatorChannelApi,CreatorChannelRepository로 변경한다. - 기존 홈 탭 동작은 변경하지 않는다.
- 별도
CreatorChannelLiveApi,CreatorChannelLiveRepository는 만들지 않는다.
- class/interface 이름을
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"./gradlew :app:compileDebugKotlin
- 기대 결과:
- rename 후 기존 홈 탭 ViewModel 테스트와 컴파일이 PASS한다.
- 검증 기록:
- 2026-06-17: rename-only 변경으로
CreatorChannelHomeApi.kt/CreatorChannelHomeRepository.kt를 각각CreatorChannelApi.kt/CreatorChannelRepository.kt로 변경하고 interface/class/import/DI/test 참조를 갱신했다. 홈 endpointGET /api/v2/creator-channels/{creatorId}/home와 기존 repository method 동작은 변경하지 않았다. - 2026-06-17: 신규 동작 추가가 없는 rename-only 작업이므로 RED 테스트 신규 작성 대상에서 제외했다. 기존 회귀 검증은 아래 명령 실행 결과로 누적한다.
- 2026-06-17: 최초 병렬 검증 실행 중
:app:kspDebugKotlin이 KSP incremental cache(app/build/kspCaches/debug) 경합/손상으로 실패했다. 생성물 캐시만 삭제한 뒤 순차 재실행했다. - 2026-06-17:
./gradlew :app:compileDebugKotlin순차 재실행 결과BUILD SUCCESSFUL로 통과했다. 기존 deprecation/annotation 경고는 출력되었으나 rename 변경과 무관하다. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"순차 재실행 결과BUILD SUCCESSFUL로 통과했다.
- 2026-06-17: rename-only 변경으로
- rename:
Phase 2: API/DTO/Repository/ViewModel 계약 추가
-
Task 2.1: 라이브 탭 DTO와
ContentSort추가- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeModels.kt
- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/common/data/ContentSort.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/data/CreatorChannelLiveTabResponse.kt
- 작업:
CreatorChannelLiveTabResponse를 라이브 탭data/CreatorChannelLiveTabResponse.kt에@Keep,@SerializedName기반 data class로 추가한다.ContentSortenum에LATEST,POPULAR,OWNED,PRICE_HIGH,PRICE_LOW를 추가하고v2.common.data패키지에 둔다.- 기존
CreatorChannelAudioContentResponse에isAdult,isOwned,isRented필드를 추가할 때 홈 탭 API 하위 호환성이 깨지지 않는지 확인한다. - 하위 호환이 필요하면 라이브 탭 전용 DTO 분리 또는 nullable/default 정책을 테스트로 고정한다.
- 검증 명령:
./gradlew :app:compileDebugKotlin
- 기대 결과:
- DTO 추가 후 컴파일된다.
- 검증 기록:
- 2026-06-17:
CreatorChannelHomeModels.kt에CreatorChannelLiveTabResponse와ContentSort(LATEST, POPULAR, OWNED, PRICE_HIGH, PRICE_LOW)를 추가했다. 기존 홈 탭 테스트 fixture의 positional constructor 호환을 유지하기 위해CreatorChannelAudioContentResponse의 라이브 탭 전용isAdult,isOwned,isRented필드는 기본값이 있는 trailing field로 추가했다. - 2026-06-17:
./gradlew :app:compileDebugKotlin실행 결과BUILD SUCCESSFUL로 통과했다.
- 2026-06-17:
- 수정:
-
Task 2.1.1: 라이브 탭 응답 모델 파일 경계 분리
- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/common/data/ContentSort.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/data/CreatorChannelLiveTabResponse.kt
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeModels.ktdocs/20260617_크리에이터_채널_라이브_탭/prd.md
- 작업:
ContentSort는 v2 API 공용 정렬 enum이므로v2.common.data패키지로 분리한다.CreatorChannelLiveTabResponse는 크리에이터 채널 라이브 탭 응답 계약이므로v2.creator.channel.live.data패키지로 분리한다.- 홈 탭과 라이브 탭이 함께 쓰는
CreatorChannelLiveResponse,CreatorChannelAudioContentResponse는 기존 공용 DTO로 유지한다. - 별도
CreatorChannelLiveApi/CreatorChannelLiveRepository는 만들지 않고 기존 공통CreatorChannelApi/CreatorChannelRepository를 유지한다.
- 검증 명령:
rg -n "CreatorChannelLiveTabResponse|enum class ContentSort" app/src/main/java/kr/co/vividnext/sodalive/v2./gradlew :app:compileDebugKotlin
- 기대 결과:
ContentSort는v2/common/data/ContentSort.kt에 정의된다.CreatorChannelLiveTabResponse는v2/creator/channel/live/data/CreatorChannelLiveTabResponse.kt에 정의된다.- 모델 파일 분리 후 Kotlin 컴파일이 PASS한다.
- 검증 기록:
- 2026-06-17: 사용자 리뷰에 따라
CreatorChannelLiveTabResponse와ContentSort를CreatorChannelHomeModels.kt에서 라이브 탭 응답 전용 파일로 이동했다. 같은data패키지의 타입 이동이라 API/Repository/ViewModel의 패키지 import 계약은 유지된다. - 2026-06-17:
rg -n "CreatorChannelLiveTabResponse|enum class ContentSort" app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data실행 결과, 타입 정의가 라이브 탭 응답 전용 파일에만 있고CreatorChannelApi.kt의 응답 타입 참조만 남아 있음을 확인했다. - 2026-06-17:
./gradlew :app:compileDebugKotlin최초 실행은 sandbox가~/.gradlelock 파일 생성을 막아 실패했다. 동일 명령을 권한 승인 후 재실행해BUILD SUCCESSFUL in 24s로 통과했다. - 2026-06-17: 사용자 추가 지시에 따라
ContentSort는v2.common.data.ContentSort,CreatorChannelLiveTabResponse는v2.creator.channel.live.data.CreatorChannelLiveTabResponse로 이동하도록 계획과 PRD의 파일 경계를 갱신했다. - 2026-06-17:
rg -n "creator\\.channel\\.data\\.ContentSort|creator\\.channel\\.data\\.CreatorChannelLiveTabResponse|ContentSort|CreatorChannelLiveTabResponse" app/src/main/java app/src/test/java로 이전 패키지 import가 남지 않았고,ContentSort는v2.common.data,CreatorChannelLiveTabResponse는v2.creator.channel.live.data참조로 갱신됐음을 확인했다. - 2026-06-17:
./gradlew :app:compileDebugKotlin최초 실행은 sandbox가~/.gradlelock 파일 생성을 막아 실패했다. 동일 명령을 권한 승인 후 재실행해BUILD SUCCESSFUL in 12s로 통과했다. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"실행 결과BUILD SUCCESSFUL in 32s로 통과했다.
- 2026-06-17: 사용자 리뷰에 따라
- 생성:
-
Task 2.2: 라이브 탭 endpoint와 Repository method 추가
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelApi.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelRepository.kt
- 작업:
@GET("/api/v2/creator-channels/{creatorId}/live")endpoint를 추가한다.- query parameter
page,size,sort를 전달한다. sort는ContentSort.name또는 Retrofit enum 변환의 기존 정책을 확인해 서버 값이LATEST등 대문자로 나가도록 한다.
- 검증 명령:
./gradlew :app:compileDebugKotlin
- 기대 결과:
- API/Repository가 기존 Koin graph와 충돌 없이 컴파일된다.
- 검증 기록:
- 2026-06-17:
CreatorChannelApi에GET /api/v2/creator-channels/{creatorId}/liveendpoint를 추가하고page,size,sortquery와Authorizationheader를 전달하도록 했다.CreatorChannelRepository.getLive()는 별도 live repository를 만들지 않고 기존 공통 repository에서 API를 얇게 위임한다. - 2026-06-17:
sort는ContentSortenum query로 전달해LATEST등 enum name이 Retrofit query 값으로 사용되도록 했다. - 2026-06-17:
./gradlew :app:compileDebugKotlin실행 결과BUILD SUCCESSFUL로 통과했다.
- 2026-06-17:
- 수정:
-
Task 2.3: ViewModel RED 테스트 작성
- 생성:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveViewModelTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLivePaginationTest.kt
- 작업:
- 최초 로딩이
page=0,sort=LATEST로 호출되는지 검증한다. hasNext == true일 때page + 1로 다음 페이지를 요청하는지 검증한다.- loading 중 중복 load-more 요청이 막히는지 검증한다.
- 정렬 변경 시 목록과 page가 초기화되는지 검증한다.
- 선택 중인 정렬을 다시 선택하면 API를 재호출하지 않는지 검증한다.
- 최초 로딩이
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveViewModelTest"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLivePaginationTest"
- 기대 결과:
- ViewModel 미구현 상태에서 RED 실패한다.
- 검증 기록:
- 2026-06-17:
CreatorChannelLiveViewModelTest와CreatorChannelLivePaginationTest를 추가했다. 최초 로딩page=0/sort=LATEST,hasNext기반page + 1pagination, loading 중 중복 load-more 차단, 정렬 변경 시 page/list 초기화, 같은 정렬 재선택 no-op, 실패/empty 상태를 검증한다. - 2026-06-17: production 구현 전
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveViewModelTest"실행 결과ContentSort,CreatorChannelLiveTabResponse,CreatorChannelLiveViewModel,CreatorChannelRepository.getLive미구현으로:app:compileDebugUnitTestKotlin FAILED가 발생해 RED를 확인했다. - 2026-06-17:
최초 로드 전 정렬 변경은 기본 최신순 최초 로드 계약을 바꾸지 않는다테스트를 추가하고 production 보정 전 실행한 결과,changeSort(POPULAR)가 최초 로드 기본값을 오염시켜 테스트가 실패함을 확인한 뒤 guard를 구현했다. - 2026-06-17: 리뷰 코멘트에 따라 같은
creatorId로loadLive()가 재호출되면 기존 목록/page/load-more 결과를 유지해야 한다는 테스트를 추가했다. production 보정 전./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveViewModelTest"실행 결과 해당 테스트가 실패함을 확인했다.
- 2026-06-17:
- 생성:
-
Task 2.4:
CreatorChannelLiveViewModel구현- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveViewModel.kt
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt
- 작업:
- initial loading, content, empty, error, pagination loading, pagination error 상태를 정의한다.
page=0,size기본값,sort=LATEST초기값을 적용한다.- 정렬 변경과 pagination 요청 중복 방지 로직을 구현한다.
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveViewModelTest"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLivePaginationTest"
- 기대 결과:
- ViewModel/pagination 테스트가 PASS한다.
- 검증 기록:
- 2026-06-17:
CreatorChannelLiveViewModel을 추가하고Loading,Empty,Error,Content상태를 정의했다. 초기 로드는page=0,size=10,sort=LATEST로 요청하고, pagination은 마지막 성공 응답의page + 1로 append하며isLoadingMore로 중복 요청을 차단한다. - 2026-06-17: 정렬 변경은 기존 목록/page를 초기화해 첫 페이지를 다시 요청하고, 같은 정렬 재선택은 API를 재호출하지 않는다. 최초 로드 전 정렬 변경은 기본
LATEST최초 로드 계약을 바꾸지 않도록 no-op 처리했다. - 2026-06-17: 리뷰 게이트에서 정렬 변경 중 이전 첫 페이지/load-more 응답이 최신 상태를 덮어쓸 수 있다는 지적이 있어 RED 테스트를 추가했다. production 보정 전
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"실행 결과이전 첫 페이지 응답은 이후 정렬 변경 결과를 덮어쓰지 않는다,이전 load-more 응답은 이후 정렬 변경 목록에 append되지 않는다2개 테스트가 실패함을 확인했다. - 2026-06-17:
requestGenerationguard를 추가해 오래된 첫 페이지/load-more 성공 또는 실패 응답을 무시하도록 보정했다. 보정 후./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"실행 결과BUILD SUCCESSFUL로 통과했다. - 2026-06-17:
AppDI에CreatorChannelLiveViewModel(get())binding을 추가했다. 기존CreatorChannelApi/CreatorChannelRepositorybinding은 재사용했다. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"실행 결과BUILD SUCCESSFUL로 통과했다. - 2026-06-17: 같은
creatorId와 기존 상태가 있는loadLive()재호출은 no-op 하도록 보정해 Fragment/View 재생성 또는 탭 재바인딩 시 기존 정렬/page/list 상태를 유지한다. 보정 후./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveViewModelTest"실행 결과BUILD SUCCESSFUL로 통과했다. - 2026-06-17: 리뷰 코멘트의 empty 정책을 반영해 PRD/계획 문서에 Figma
290:8959기준 전체 empty 상태를 기록했다.CreatorChannelLiveUiState.Empty는 Sort-bar/list를 제거하고 중앙 문구를 표시하기 위한 상태로 유지하며, 본인 채널 하단 CTA는 Phase 6의 본인 채널 정책대로 유지한다. - 2026-06-17: 리뷰 코멘트에 따라
Error상태에서 retry 버튼이 현재creatorId첫 페이지를 재요청해야 한다는 테스트를 추가했다. production 보정 전./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveViewModelTest"실행 결과retryLive미구현으로:app:compileDebugUnitTestKotlin FAILED가 발생해 RED를 확인했다. - 2026-06-17: Android 샘플과 기존 retry 의미를 따라
loadLive()의 같은creatorId상태 보존 guard는 유지하고, 명시적retryLive()API를 추가했다. Phase 4 retry 버튼은retryLive()를 호출하면 된다. 보정 후./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveViewModelTest"및./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"실행 결과BUILD SUCCESSFUL로 통과했다.
- 2026-06-17:
- 생성:
Phase 3: UI model과 상태 표시 mapper 구현
-
Task 3.1: 라이브 다시듣기 표시 정책 RED 테스트 작성
- 생성:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveMapperTest.kt
- 작업:
isOwned && isRented동시 true면소장중상태가 선택되는지 검증한다.price == 0이면 무료 tag와 play CTA 상태가 선택되는지 검증한다.isAdult == true이면ic_new_shield_small표시 상태가 선택되는지 검증한다.isPointAvailable == true이면 point tag 표시 상태가 선택되는지 검증한다.seriesName은 secondary text에 포함되지 않는지 검증한다.isFirstContent,isOriginalSeries는 기존 오디오 item 정책과 동일한 tag 상태로 매핑되는지 검증한다.
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveMapperTest"
- 기대 결과:
- mapper 미구현 상태에서 RED 실패한다.
- 검증 기록:
- 2026-06-17:
CreatorChannelLiveMapperTest를 추가해isOwned && isRented동시 true 시소장중우선, 무료 콘텐츠의 free tag/play CTA, 19금 shield, point tag,seriesName미표시,isFirstContent/isOriginalSeriestag 정책,ContentSortlabel resource 매핑을 검증하도록 했다. - 2026-06-17: production mapper 구현 전
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveMapperTest"실행 결과CreatorChannelLiveReplayStatus,toReplayUiModel,toLabelResId미구현으로:app:compileDebugUnitTestKotlin FAILED가 발생해 RED를 확인했다.
- 2026-06-17:
- 생성:
-
Task 3.2: UI model/mapper 구현
- 생성 후보:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/model/CreatorChannelLiveUiModels.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/model/CreatorChannelLiveMappers.kt
- 작업:
- sort label resource, replay item CTA/status, tag 상태, current live 상태를 UI model로 분리한다.
- 가격/포인트/소장중/대여중/play button 상태 우선순위를 순수 함수로 고정한다.
ContentSort와 문자열 리소스 매핑을 구현한다.
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveMapperTest"
- 기대 결과:
- mapper 테스트가 PASS한다.
- 검증 기록:
- 2026-06-17:
CreatorChannelLiveReplayUiModel,CreatorChannelLiveReplayStatus,CreatorChannelLiveSortOptionUiModel을 추가하고CreatorChannelAudioContentResponse.toReplayUiModel(),ContentSort.toLabelResId(),ContentSort.toSortOptionUiModel()을 구현했다. - 2026-06-17: 가격/상태 우선순위는
소장중>대여중> 무료 play > 가격 표시로 고정했다. tag는 기존 오디오 정책과 동일하게isOriginalSeries == true이면Original,isFirstContent이면First,isPointAvailable이면Point,price == 0이면Free를 매핑한다.secondaryText는duration만 사용해seriesName을 표시하지 않는다. - 2026-06-17:
ContentSortlabel은LATEST/POPULAR/PRICE_HIGH/PRICE_LOW에 기존 리소스screen_audio_content_sort_newest,screen_audio_content_sort_popularity,screen_audio_content_sort_price_high,screen_audio_content_sort_price_low를 재사용하고, 기존 리소스가 없는OWNED의소장순label은creator_channel_live_sort_owned문자열로 추가했다. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveMapperTest"실행 결과BUILD SUCCESSFUL로 통과했다. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"실행 결과BUILD SUCCESSFUL로 통과했다. - 2026-06-17:
./gradlew :app:compileDebugKotlin실행 결과BUILD SUCCESSFUL로 통과했다. - 2026-06-17:
./gradlew :app:ktlintCheck실행 결과BUILD SUCCESSFUL로 통과했다. 기존.editorconfig의disabled_rulesdeprecation 경고는 출력되었으나 Phase 3 변경과 무관하다. - 2026-06-17: 리뷰 게이트에서
LATEST가최신 콘텐츠,OWNED가소장중리소스에 매핑되는 문제가 지적되어LATEST는screen_audio_content_sort_newest,OWNED는 신규creator_channel_live_sort_owned로 보정했다. - 2026-06-17: label 보정 후
./gradlew :app:mergeDebugResourcesPASS,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveMapperTest"PASS,./gradlew :app:compileDebugKotlinPASS,./gradlew :app:ktlintCheckPASS. 병렬 실행 중:app:dataBindingGenBaseClassesDebug가 Gradle 생성물 경합으로R-def.txt누락 실패했으나 동일 compile 명령 순차 재실행에서 PASS했다.
- 2026-06-17:
- 생성 후보:
Phase 4: 라이브 탭 Fragment와 목록 UI 구현
-
Task 4.1: Fragment layout과 replay item layout 추가
- 생성:
app/src/main/res/layout/fragment_creator_channel_live.xmlapp/src/main/res/layout/item_creator_channel_live_replay.xml
- 수정:
app/src/main/res/values/strings.xmlapp/src/main/res/values-en/strings.xmlapp/src/main/res/values-ja/strings.xml
- 작업:
- Figma 기준 sort-bar, current live card, replay list, owner CTA 영역을 배치한다.
- replay item은 88dp 썸네일, title 최대 2줄, duration 1줄, 우측 price/play/status 영역을 포함한다.
ic_new_shield_small,ic_new_player_play,ic_new_sort,ic_new_create_live를 layout 또는 binding에서 사용 가능하게 준비한다.
- 검증 명령:
./gradlew :app:mergeDebugResources
- 기대 결과:
- 신규 layout/string/drawable 참조가 resource merge에 성공한다.
- 검증 기록:
- 2026-06-17: Figma
290:8949,290:8950,290:8954,290:8959기준으로fragment_creator_channel_live.xml과item_creator_channel_live_replay.xml을 추가했다. sort-bar는 52dp, current live card는 78dp pill, replay item은 88dp 썸네일/최대 2줄 title/1줄 duration/우측 action 영역으로 구성했다. - 2026-06-17:
ic_new_sort,ic_new_shield_small,ic_new_player_play,ic_new_create_live는 기존 drawable을 재사용하고, live current/price/adult/retry 배경 drawable만 Phase 4 UI 표현에 필요한 최소 리소스로 추가했다. - 2026-06-17:
creator_channel_live_total_label, empty/error/retry/owner CTA 문자열을values,values-en,values-ja에 추가했다. - 2026-06-17:
./gradlew :app:mergeDebugResources실행 결과BUILD SUCCESSFUL로 통과했다.
- 2026-06-17: Figma
- 생성:
-
Task 4.2: Adapter와 Fragment 구현
- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/ui/CreatorChannelLiveReplayAdapter.kt
- 작업:
- ViewModel 상태를 관찰해 sort-bar, current live card, replay list, loading/empty/error를 갱신한다.
- error 상태에서는 Sort-bar, current live card, replay list를 숨기고 중앙 안내 문구와 그 아래 retry 버튼을 표시한다.
- retry 버튼 클릭은
CreatorChannelLiveViewModel.retryLive()를 호출해 현재creatorId첫 페이지를 재요청한다. - replay item click은 기존 오디오 컨텐츠 상세/재생 진입 정책을 확인해 연결한다.
- current live card click은 기존 홈 탭 라이브 진입 정책을 재사용한다.
- RecyclerView scroll listener로 하단 접근 시 ViewModel load-more를 호출한다.
- 검증 명령:
./gradlew :app:compileDebugKotlin
- 기대 결과:
- Fragment/adapter가 컴파일된다.
- 검증 기록:
- 2026-06-17:
CreatorChannelLiveFragment를 추가해CreatorChannelLiveViewModel.liveStateLiveData의Loading,Empty,Error,Content상태에 따라 sort-bar/current live/replay list/empty/error/retry visibility를 갱신하도록 했다. - 2026-06-17: error 상태 retry 버튼은
CreatorChannelLiveViewModel.retryLive()를 호출한다. RecyclerView 하단 접근 시loadMore()를 호출하며 중복/hasNext guard는 ViewModel 정책을 따른다. - 2026-06-17:
CreatorChannelLiveReplayAdapter를 추가해 mapper의CreatorChannelLiveReplayUiModel을 19금 shield, original/first/point/free tag, play/소장중/대여중/가격 상태로 바인딩한다. - 2026-06-17: replay item click은
CreatorChannelLiveFragment.Host.onCreatorChannelLiveReplayClicked(audioContentId)로 위임하고,CreatorChannelActivity에서 기존AudioContentDetailActivity진입 경로를 재사용하도록 연결했다. current live card click은 기존 홈 탭과 동일하게onCreatorChannelCurrentLiveClicked(live)를 재사용한다. - 2026-06-17: Phase 5 범위인 sort popup/정렬 변경 동작은 구현하지 않고, Phase 4에서는 sort-bar 표시와 icon 준비까지만 유지했다.
- 2026-06-17:
./gradlew :app:compileDebugKotlin실행 결과BUILD SUCCESSFUL로 통과했다. 병렬 Gradle 실행 중 Kotlin incremental cache/daemon 경합 로그가 출력되었으나, fallback/최종 실행은 성공했다.
- 2026-06-17:
- 생성:
-
Task 4.3: Fragment layout 테스트 추가
- 생성:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragmentLayoutTest.kt
- 작업:
fragment_creator_channel_live.xml에 sort-bar, RecyclerView, owner CTA가 존재하는지 검증한다.item_creator_channel_live_replay.xml에 19금 badge, point/free tag container, price/play/status 영역이 존재하는지 검증한다.ic_new_*리소스 참조가 layout 또는 코드 상수로 연결되는지 검증한다.
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveFragmentLayoutTest"
- 기대 결과:
- layout 테스트가 PASS한다.
- 검증 기록:
- 2026-06-17: production layout/code 추가 전
CreatorChannelLiveFragmentLayoutTest를 먼저 작성했다. RED 실행 결과fragment_creator_channel_live,item_creator_channel_live_replay및 필수 id 미존재로:app:compileDebugUnitTestKotlin FAILED가 발생해 실패를 확인했다. - 2026-06-17: layout/source 구현 후
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveFragmentLayoutTest"실행 결과BUILD SUCCESSFUL로 통과했다. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"실행 결과BUILD SUCCESSFUL로 통과해 Phase 4 layout 테스트와 기존 live ViewModel/mapper/pagination 테스트 회귀를 함께 확인했다.
- 2026-06-17: production layout/code 추가 전
- 생성:
Phase 5: 정렬 컨텍스트 메뉴 구현
-
Task 5.1: Sort popup 구현
- 생성 후보:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/ui/CreatorChannelLiveSortPopup.ktapp/src/main/res/layout/view_creator_channel_live_sort_menu.xml
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.kt
- 작업:
- Sort-bar 정렬 영역 아래에 Figma
290:9041형태의 컨텍스트 메뉴를 표시한다. - 현재 선택 항목은 focused 배경으로 표시한다.
- 메뉴 외부 터치, 같은 정렬 재선택, 새 정렬 선택 시 메뉴를 닫는다.
- 새 정렬 선택 시 ViewModel에 정렬 변경을 전달한다.
- Sort-bar 정렬 영역 아래에 Figma
- 검증:
- 작은 화면에서 메뉴가 화면 밖으로 벗어나지 않도록 위치 보정 기준을 코드에 남긴다.
- 생성 후보:
-
Task 5.2: Sort 동작 테스트 보강
- 수정:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveViewModelTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveMapperTest.kt
- 작업:
ContentSort별 label resource 매핑을 검증한다.- 정렬 변경 시 첫 페이지가 다시 로딩되는지 검증한다.
- 같은 정렬 재선택은 API 재호출을 하지 않는지 검증한다.
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"
- 기대 결과:
- sort 관련 테스트가 PASS한다.
- 수정:
Phase 6: 본인 채널 하단 CTA와 라이브 시작 진입 연결
-
Task 6.1: 본인 CTA 노출과 inset 처리 구현
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.ktapp/src/main/res/layout/fragment_creator_channel_live.xml
- 작업:
- 본인 채널일 때만 하단 CTA를 표시한다.
- 타인 채널 또는 본인 여부 로딩 전에는 CTA를 숨긴다.
- CTA 표시 시 RecyclerView 하단 padding을 추가해 마지막 item이 CTA에 가려지지 않도록 한다.
- navigation bar bottom inset을 CTA 영역에 반영한다.
- 버튼 icon은
ic_new_create_live, label은라이브 시작하기문자열 리소스를 사용한다.
- 검증 명령:
./gradlew :app:mergeDebugResources./gradlew :app:compileDebugKotlin
- 기대 결과:
- CTA resource와 inset 코드가 컴파일된다.
- 수정:
-
Task 6.2: 기존 라이브 시작 플로우 연결
- 확인:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.ktapp/src/main/java/kr/co/vividnext/sodalive/live/room/create/LiveRoomCreateActivity.kt
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.kt- 필요 시
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt
- 작업:
CreatorChannelActivity의 기존 owner FAB live action과 같은 진입 경로를 재사용한다.- 중복 터치를 방지한다.
- 라이브 생성 완료 후 기존 홈 refresh/라이브룸 진입 정책과 충돌하지 않도록 처리한다.
- 검증:
- 라이브 시작 진입 대상 Activity/Fragment와 전달 extra를 계획 문서 해당 Task의
검증 기록에 남긴다.
- 라이브 시작 진입 대상 Activity/Fragment와 전달 extra를 계획 문서 해당 Task의
- 확인:
Phase 7: 탭 연결과 통합 동작
-
Task 7.1:
CreatorChannelTab.Live를 실제 Fragment로 연결- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelPagerAdapter.kt
- 생성:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelPagerAdapterTest.kt
- 작업:
- Live 탭 position에서
CreatorChannelLiveFragment.newInstance(creatorId)를 반환한다. - 나머지 탭은 기존 placeholder 정책을 유지한다.
- Live 탭 position에서
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelPagerAdapterTest"
- 기대 결과:
- Live 탭만 실제 Fragment로 연결되고 나머지 placeholder 정책은 유지된다.
- 검증 기록:
- 2026-06-17: 리뷰 게이트 차단 이슈 보정으로
CreatorChannelPagerAdapter에서CreatorChannelTab.Live -> CreatorChannelLiveFragment.newInstance(creatorId)분기를 추가했다. Home/Live 탭은 실제 Fragment로 연결하고, 후속 탭은 기존 placeholder 정책을 유지한다. - 2026-06-17: 보정 후
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"PASS,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Live*"PASS,./gradlew :app:compileDebugKotlinPASS,./gradlew :app:ktlintCheckPASS.
- 2026-06-17: 리뷰 게이트 차단 이슈 보정으로
- 수정:
-
Task 7.2: DI와 lifecycle 통합
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.kt
- 작업:
- 신규 ViewModel/API/Repository injection이 기존 홈 탭과 충돌하지 않는지 확인한다.
- Fragment 재생성 후 정렬, page, 목록 상태가 ViewModel에 유지되는지 확인한다.
- 탭 전환 시 중복 최초 API 호출이 발생하지 않도록 초기 로딩 조건을 정리한다.
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"./gradlew :app:compileDebugKotlin
- 기대 결과:
- Live 탭 관련 테스트와 컴파일이 PASS한다.
- 수정:
Phase 8: 최종 검증과 문서 기록
-
Task 8.1: 자동 검증 실행
- 실행 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Live*"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"./gradlew :app:mergeDebugResources./gradlew :app:compileDebugKotlin./gradlew :app:ktlintCheck
- 기대 결과:
- 모든 명령이
BUILD SUCCESSFUL로 통과한다.
- 모든 명령이
- 검증 기록:
- 실행 일시, 명령, 결과, 기존 경고 여부를 이 Task 아래에 누적 기록한다.
- 실행 명령:
-
Task 8.2: 수동 확인
- 확인 항목:
라이브탭 진입 시page=0,sort=LATEST로 최초 조회된다.- Sort-bar에
전체 {count}와 현재 정렬 label,ic_new_sort가 표시된다. - 정렬 컨텍스트 메뉴가 Sort-bar 아래에 표시되고 선택/닫힘 동작이 정상이다.
currentLive != null일 때 현재 라이브 카드가 표시된다.- 라이브 다시듣기 item의 19금/포인트/무료/소장중/대여중/가격 상태가 DTO와 일치한다.
isOwned && isRented동시 true item은소장중으로 표시된다.seriesName은 표시되지 않는다.hasNext == true일 때 하단 스크롤로 다음 페이지가 append된다.- 본인 채널에서만 하단
라이브 시작하기CTA가 표시된다. - 타인 채널에서는 하단 CTA가 표시되지 않는다.
- CTA가 마지막 item을 가리지 않는다.
- 검증 기록:
- 실제 확인한 시나리오와 결과를 이 Task 아래에 한국어로 누적 기록한다.
- 확인 항목:
Phase 4 Review Fix: Lazy Load와 Empty/Error 중앙 정렬 보정
-
Task RF4.1: Live 탭 선택 시점 lazy load 보정
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt
- 작업:
- Live Fragment 생성 시점인
onViewCreated()에서는loadLive()를 호출하지 않는다. CreatorChannelTab.Live가 선택된 시점에만 Live Fragment에 명시적으로 로딩을 요청한다.- 같은 creatorId/state에 대한 중복 호출 방지는 기존
CreatorChannelLiveViewModel.loadLive()guard를 유지한다.
- Live Fragment 생성 시점인
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveFragmentLayoutTest"
- 기대 결과:
- Live 탭을 보지 않은 Activity 최초 진입에서는 Live API 요청이 시작되지 않고, Live 탭 선택 시점에 첫 조회가 시작된다.
- 검증 기록:
- 2026-06-17: production 보정 전 source 테스트에서
offscreenPageLimit = CreatorChannelTab.entries.size - 1,onViewCreated()즉시viewModel.loadLive(creatorId)호출, Live 선택 hook 미존재로 RED 실패를 확인했다. - 2026-06-17:
CreatorChannelLiveFragment.onViewCreated()의 즉시loadLive()호출을 제거하고onCreatorChannelLiveTabSelected()로 이동했다.CreatorChannelActivity.onPageSelected()는 Live 탭 선택 시viewPager.post { findLiveFragment()?.onCreatorChannelLiveTabSelected() }를 호출하며, 전체 탭 선생성을 유발하던offscreenPageLimit = CreatorChannelTab.entries.size - 1설정을 제거했다. - 2026-06-17: 보정 후
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"PASS,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveFragmentLayoutTest"PASS.
- 2026-06-17: production 보정 전 source 테스트에서
- 수정:
-
Task RF4.2: Empty/Error 상태 viewport 중앙 정렬 보정
- 수정:
app/src/main/res/layout/fragment_creator_channel_live.xmlapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveFragment.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt
- 작업:
- Live Fragment root가
ViewPager2page 높이를 채우도록 보장한다. - Empty/Error 상태 전환 시에도
ViewPager2높이 재측정을 요청한다. - Activity의
updateViewPagerHeight()는 현재 page의 최소 높이를 탭 viewport 기준으로 보정한다.
- Live Fragment root가
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveFragmentLayoutTest"./gradlew :app:mergeDebugResources
- 기대 결과:
- Live Empty 문구와 Error/Retry 그룹이 작은 wrap-content 영역이 아니라 탭 viewport 중앙에 표시된다.
- 검증 기록:
- 2026-06-17: production 보정 전 layout/source 테스트에서 Live root
wrap_content, Empty/Error 상태 height callback 미보장, Activity page minimumHeight 보정 미존재로 RED 실패를 확인했다. - 2026-06-17:
fragment_creator_channel_live.xmlroot 높이를match_parent로 변경하고,bindEmpty()/bindError()에서도host.onCreatorChannelLiveContentChanged()를 호출하도록 했다.CreatorChannelActivity.updateViewPagerHeight()는 현재 page 측정 전currentPage.minimumHeight = calculateCreatorChannelTabViewportHeight()를 적용해 탭 viewport 기준 최소 높이를 보장한다. - 2026-06-17: 보정 후
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"PASS,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveFragmentLayoutTest"PASS,./gradlew :app:mergeDebugResourcesPASS.
- 2026-06-17: production 보정 전 layout/source 테스트에서 Live root
- 수정:
-
Task RF4.3: Home delegate 보존과 load-more 메타데이터 보존 보정
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLiveViewModel.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/live/CreatorChannelLivePaginationTest.kt
- 작업:
- Live lazy load는 유지하되 Home 탭의
HomeActionDelegate가 후속 탭 이동 중 제거되지 않도록ViewPager2.offscreenPageLimit을 기존처럼 전체 탭 수 기준으로 복구한다. - 다음 페이지 성공 시 기존 첫 페이지의
currentLive,liveReplayContentCount,selectedSort를 보존하고, 목록 append와page/size/hasNext만 다음 응답 기준으로 갱신한다.
- Live lazy load는 유지하되 Home 탭의
- 검증 명령:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLivePaginationTest"./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Live*"./gradlew :app:compileDebugKotlin
- 기대 결과:
- Home 탭 delegate 기반 상단 액션/refresh 경로가 Live 및 후속 탭 이동 후에도 유지된다.
- 다음 페이지 응답이
currentLive == null이거나 총 개수가 부분 값이어도 현재 라이브 카드와 총 개수/정렬 label이 첫 페이지 상태를 유지한다.
- 검증 기록:
- 2026-06-17:
CreatorChannelActivity.setupTabsAndPager()에binding.viewPager.offscreenPageLimit = CreatorChannelTab.entries.size - 1를 복구해 Home 탭 Fragment와HomeActionDelegate가 후속 탭 이동 중 제거되지 않도록 했다.CreatorChannelActivitySourceTest의 기존 offscreenPageLimit 제거 기대는 복구 정책에 맞춰 갱신했다. - 2026-06-17:
CreatorChannelLiveViewModel.loadMore()성공 처리에서data.toContentState()로 전체 content metadata를 덮어쓰지 않고, 기존Content를copy()해liveReplayContentsappend와page/size/hasNext만 다음 응답 기준으로 갱신하도록 변경했다. - 2026-06-17:
CreatorChannelLivePaginationTest에 다음 페이지 응답이currentLive == null, 다른liveReplayContentCount, 다른sort를 내려줘도 첫 페이지의 현재 라이브/count/sort를 보존하는 회귀 테스트를 추가했다. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"최초 실행은 상충하던 기존 offscreenPageLimit 제거 assertion으로 실패했고, 테스트 계약 갱신 후 재실행 결과BUILD SUCCESSFUL로 통과했다. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLivePaginationTest"최초 실행은 신규 테스트 fixture의CreatorChannelLiveResponse필드명 오기로 컴파일 실패했고,coverImageUrl로 수정 후 재실행 결과BUILD SUCCESSFUL로 통과했다. - 2026-06-17: 추가 회귀 검증으로
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Live*",./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck를 실행했고 모두BUILD SUCCESSFUL로 통과했다.ktlintCheck에서는 기존.editorconfig의disabled_rulesdeprecation 경고가 계속 출력되었다.
- 2026-06-17:
- 수정:
Verification Log
- 2026-06-17: Phase 1 진행.
CreatorChannelHomeApi/CreatorChannelHomeRepository를CreatorChannelApi/CreatorChannelRepository로 rename하고 기존 홈 endpoint/repository method 동작은 유지했다. - 2026-06-17:
./gradlew :app:compileDebugKotlinPASS. 최초 병렬 실행은 KSP incremental cache 손상으로 실패했으나app/build/kspCaches/debug생성물 캐시 삭제 후 순차 재실행에서 통과했다. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"PASS. - 2026-06-17: Phase 2 진행. 라이브 탭 DTO/API/Repository/ViewModel 계약과 RED/GREEN 테스트를 추가했다. UI/layout/mapper/Fragment/tab 연결은 Phase 3 이후 범위라 변경하지 않았다.
- 2026-06-17: RED 확인. production 구현 전 live ViewModel 테스트 실행 시
ContentSort,CreatorChannelLiveTabResponse,CreatorChannelLiveViewModel,CreatorChannelRepository.getLive미구현으로:app:compileDebugUnitTestKotlin FAILED가 발생했다. - 2026-06-17: 추가 RED 확인. 최초 로드 전
changeSort(POPULAR)호출이 기본LATEST최초 로드 계약을 오염시키는 실패를 확인한 뒤 guard를 적용했다. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"PASS. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"PASS. - 2026-06-17:
./gradlew :app:compileDebugKotlinPASS. - 2026-06-17: 리뷰 게이트 지적으로 stale async response 보강. production 보정 전 stale first-page/load-more 테스트 2개가 실패했고,
requestGenerationguard 적용 후./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"PASS. - 2026-06-17: stale async response 보강 후
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"PASS. - 2026-06-17: stale async response 보강 후
./gradlew :app:compileDebugKotlinPASS. - 2026-06-17: 리뷰 코멘트 반영. Figma
290:8959기준 전체 empty 상태는 Sort-bar/list 없이 중앙 문구를 표시하고, 본인 채널 하단 CTA는 유지하는 것으로 PRD/계획 문서에 기록했다. - 2026-06-17: 같은
creatorId의loadLive()재호출 상태 보존 RED 테스트를 추가했다. 보정 전 테스트 실패 확인 후 기존 상태가 있으면 no-op 하도록 구현했고,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveViewModelTest"PASS. - 2026-06-17: 리뷰 코멘트 반영 후
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"PASS. - 2026-06-17: 리뷰 코멘트 반영 후
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"PASS. 병렬 실행 중 Robolectric 임시 DataStore 정리 경고가 한 차례 출력되었으나, 동일 명령 순차 재실행 결과BUILD SUCCESSFUL로 통과했다. - 2026-06-17: 리뷰 코멘트 반영 후
./gradlew :app:compileDebugKotlinPASS. - 2026-06-17: 리뷰 코멘트 반영.
loadLive()의 같은creatorId상태 보존 guard는 유지하고, Error 상태 재시도는 명시적retryLive()로 분리했다. production 보정 전retryLive미구현 컴파일 실패를 확인했고, 보정 후./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveViewModelTest"PASS. - 2026-06-17: Phase 4 UI 작업에 error 안내 문구 아래 retry 버튼을 표시하고, retry 버튼이
CreatorChannelLiveViewModel.retryLive()를 호출한다는 요구사항을 추가했다. - 2026-06-17:
retryLive()추가 후./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"PASS. - 2026-06-17:
retryLive()추가 후./gradlew :app:compileDebugKotlinPASS. - 2026-06-17:
retryLive()추가 후./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"최초 병렬 실행에서채널 후원 성공은 기존 후원 API를 호출하고 홈을 다시 로드한다가 실패했으나, 변경 범위와 무관한 SharedPreferenceManager 상태 간섭 가능성을 분리하기 위해 동일 명령을 순차 재실행했고BUILD SUCCESSFUL로 통과했다. - 2026-06-17: 전체 회귀 명령 실행. 최초 sandbox 실행은
~/.gradlewrapper lock 접근 제한으로 실패해 권한 승인 후 Gradle 명령을 재실행했다. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Live*"PASS. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"PASS. - 2026-06-17:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"FAIL.CreatorChannelActivitySourceTest의 기존 XML/source 문자열 검증 3개가 실패했다:activity_creator_channel.xml의ic_new_talk/ic_new_dm기대,item_creator_channel_home_donation.xml의196dp기대,item_creator_channel_home_series_content.xml의android:text="Only"기대. - 2026-06-17:
./gradlew :app:mergeDebugResourcesPASS. - 2026-06-17:
./gradlew :app:compileDebugKotlinPASS. - 2026-06-17:
./gradlew :app:ktlintCheck최초 실행에서 신규 live test 줄바꿈과CreatorChannelLiveModels.kt파일명 규칙 위반으로 FAIL. 테스트 helper 줄바꿈을 정리하고 응답 모델 파일명을CreatorChannelLiveTabResponse.kt로 변경한 뒤 재실행해 PASS. - 2026-06-17: ktlint 보정 후
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"PASS,./gradlew :app:compileDebugKotlinPASS,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Live*"PASS. - 2026-06-17: ktlint 보정 후
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"재실행 결과 동일한CreatorChannelActivitySourceTest3개 실패가 재현됐다. - 2026-06-17: Phase 3 진행. 라이브 다시듣기 UI model/mapper와 mapper RED/GREEN 테스트를 추가했다. Fragment/layout/sort popup/tab 연결은 Phase 4 이후 범위라 변경하지 않았다.
- 2026-06-17: Phase 3 RED 확인. production mapper 구현 전
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveMapperTest"실행 시CreatorChannelLiveReplayStatus,toReplayUiModel,toLabelResId미구현으로:app:compileDebugUnitTestKotlin FAILED가 발생했다. - 2026-06-17: Phase 3 GREEN 확인.
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveMapperTest"PASS. - 2026-06-17: Phase 3 회귀 검증.
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"PASS,./gradlew :app:compileDebugKotlinPASS,./gradlew :app:ktlintCheckPASS. ktlint 실행 중 기존.editorconfig의disabled_rulesdeprecation 경고가 출력되었다. - 2026-06-17: Phase 3 리뷰 게이트 보정.
LATESTlabel은최신순리소스screen_audio_content_sort_newest로,OWNEDlabel은 신규 다국어 리소스creator_channel_live_sort_owned로 변경했다. 보정 후./gradlew :app:mergeDebugResourcesPASS,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveMapperTest"PASS,./gradlew :app:compileDebugKotlinPASS,./gradlew :app:ktlintCheckPASS. - 2026-06-17: Phase 4 진행.
CreatorChannelLiveFragment,CreatorChannelLiveReplayAdapter,fragment_creator_channel_live.xml,item_creator_channel_live_replay.xml, 최소 배경 drawable/string, layout RED/GREEN 테스트를 추가했다. Sort popup/정렬 변경 동작과 owner CTA 실제 노출/inset/라이브 시작 연결은 Phase 5/6 범위로 남겼다. - 2026-06-17: Phase 4 RED 확인. production layout/code 추가 전
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveFragmentLayoutTest"실행 시 신규 layout/id/source 미존재로:app:compileDebugUnitTestKotlin FAILED가 발생했다. - 2026-06-17: Phase 4 GREEN 확인.
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveFragmentLayoutTest"PASS. - 2026-06-17: Phase 4 회귀 검증.
./gradlew :app:mergeDebugResourcesPASS,./gradlew :app:compileDebugKotlinPASS,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"PASS,./gradlew :app:ktlintCheckPASS. Gradle 병렬 실행 중 Kotlin daemon/incremental cache 경합 로그가 일부 출력되었으나 fallback/최종 결과는BUILD SUCCESSFUL이었다. 기존.editorconfig의disabled_rulesdeprecation 경고와 Kotlin/Android deprecation 경고는 변경 범위와 무관하게 계속 출력된다. - 2026-06-17: Phase 4 리뷰 보정 진행.
NestedScrollView가 스크롤을 소유하는 구조에서 Live pagination을 Fragment 내부RecyclerView.OnScrollListener가 아니라CreatorChannelActivity의 parent scroll bottom detection으로 전달하도록 보정했다. Live content bind 후onCreatorChannelLiveContentChanged()로ViewPager2높이 재측정을 요청하고, 현재 라이브 시간은 홈 탭의formatCreatorChannelLiveDateTime()을 재사용하도록 변경했다. Owned/Rented 다시듣기 item은 PRD 요구대로 play icon과 상태 텍스트를 함께 표시한다. - 2026-06-17: Phase 4 리뷰 보정 RED 확인. production 보정 전
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveFragmentLayoutTest"는 신규 Live fragment source 계약 미충족으로 FAIL,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"는 신규 NestedScrollView pagination/height callback 계약 미충족으로 FAIL했다. 같은 실행에서 기존 오디오 상세 이동 source assertion도startAudioContentDetail()helper 추출 이후의 현재 코드와 맞지 않아 테스트 계약만 갱신했다. - 2026-06-17: Phase 4 리뷰 보정 GREEN 확인. 병렬 Gradle 실행 중 Kotlin daemon/incremental cache 경합으로
Constants.class누락 및 fallback timeout이 발생했으나, daemon 정리 후 순차 재실행한./gradlew :app:compileDebugKotlin은BUILD SUCCESSFUL로 통과했다. 이어서./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveFragmentLayoutTest"PASS,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"PASS. - 2026-06-17: Phase 4 리뷰 보정 최종 검증.
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.*"PASS,./gradlew :app:mergeDebugResourcesPASS,./gradlew :app:ktlintCheckPASS,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Live*"PASS.ktlintCheck에서는 기존.editorconfig의disabled_rulesdeprecation 경고가 계속 출력되었으나 실패 원인은 아니었다. - 2026-06-17: Phase 4 리뷰 게이트에서
CreatorChannelPagerAdapter가 아직 Live 탭을CreatorChannelPlaceholderFragment로 생성해 Live 보정 코드가 실제 사용자 경로에서 실행되지 않는다는 차단 이슈가 발견됐다. 최소 보정으로CreatorChannelTab.Live -> CreatorChannelLiveFragment.newInstance(creatorId)분기를 추가하고, 기존 placeholder-only source test를 홈/라이브 실제 Fragment + 후속 탭 placeholder 계약으로 갱신했다. - 2026-06-17: Live pager 연결 보정 후
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"PASS,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Live*"PASS,./gradlew :app:compileDebugKotlinPASS,./gradlew :app:ktlintCheckPASS.ktlintCheck에서는 기존.editorconfig의disabled_rulesdeprecation 경고가 계속 출력되었다. - 2026-06-17: 리뷰 지적 2건 보정. Live 탭 API는 Live 탭 선택 시점 lazy load로 변경했고, Empty/Error는 Live page root와 Activity page minimumHeight 보정으로 탭 viewport 중앙 정렬을 보장했다. 최종 검증으로
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"PASS,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLiveFragmentLayoutTest"PASS,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Live*"PASS,./gradlew :app:mergeDebugResourcesPASS,./gradlew :app:compileDebugKotlinPASS,./gradlew :app:ktlintCheckPASS. 초기 병렬 RED 확인 중 Kotlin incremental cache 경합 로그가 출력됐으나 daemon 정리 후 순차 검증은 모두 통과했다. - 2026-06-17: 추가 리뷰 지적 2건 보정.
ViewPager2.offscreenPageLimit을 복구해 Home 탭의HomeActionDelegate기반 상단 액션/refresh 경로를 유지하고, Live load-more 성공 시 첫 페이지의 current live/count/sort metadata를 보존하도록 변경했다. 검증으로./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"PASS,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.live.CreatorChannelLivePaginationTest"PASS,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*Live*"PASS,./gradlew :app:compileDebugKotlinPASS,./gradlew :app:ktlintCheckPASS.ktlintCheck에서는 기존.editorconfig의disabled_rulesdeprecation 경고가 계속 출력되었다.