47 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 실패한다.
- 생성:
-
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한다.
- 생성 후보:
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에 성공한다.
- 생성:
-
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가 컴파일된다.
- 생성:
-
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한다.
- 생성:
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 정책은 유지된다.
- 수정:
-
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 아래에 한국어로 누적 기록한다.
- 확인 항목:
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개 실패가 재현됐다.