29 KiB
현재 진행 중인 라이브 리스트 페이지 구현 계획/TASK
For agentic workers: REQUIRED SUB-SKILL: 구현 시
superpowers:executing-plans를 사용해 task 단위로 진행한다. 각 단계는 체크박스(- [ ])로 추적하고, 완료 즉시- [x]로 갱신한다. 구현 범위 변경이 생기면 이 문서를 먼저 수정한 뒤 코드에 반영한다.
Goal: GET /api/v2/home/on-air-lives 응답을 기반으로 현재 진행 중인 라이브 리스트 화면을 만들고, 아이템 터치 시 기존 라이브 상세 조회 후 입장/비밀번호/결제 흐름을 재사용한다.
Architecture: 신규 화면/API/Repository/ViewModel/adapter/model은 kr.co.vividnext.sodalive.v2.live.onair 하위에 둔다. 기존 홈 추천 라이브 섹션의 더보기 진입점은 새 Activity를 여는 역할만 담당하고, 실제 라이브 입장 정책은 기존 LiveViewModel.getRoomDetail()과 enterRoom()을 호출해 중복 구현을 최소화한다.
Tech Stack: Kotlin, Android XML Views, ViewBinding, RecyclerView, Retrofit, Gson, RxJava3, Koin, JUnit4 local unit test.
전제와 성공 기준
- PRD:
docs/20260626_현재_진행_중인_라이브_리스트_페이지/prd.md - Figma 전체:
185:4506 - Figma 아이템:
185:4509 - 신규 기능 본체의 Kotlin package는
kr.co.vividnext.sodalive.v2.live.onair로 고정한다. - 메인 홈 추천 탭은
HomeOnAirLiveActivity진입 연결만 추가하고, on-air live API/data/model 구현을 홈 패키지에 두지 않는다. - API endpoint는
GET /api/v2/home/on-air-lives이다. - 앱은
sizequery parameter를 보내지 않는다. HomeOnAirLiveResponse에는beginDateTimeUtc: String이 포함된다.- 목록 아이템은
LIVE HH:mm을 표시하며,HH:mm은beginDateTimeUtc를 디바이스 Timezone으로 변환한 라이브 시작 시각이다. - 유료 라이브는
ic_bar_cash와 가격을 표시한다. - 무료 라이브는 cash 아이콘 없이
무료를 표시한다. - 아이템 터치 시
getRoomDetail(roomId)호출 후 기존 입장 정책을 따른다. - 구현 완료 후 최소 다음 명령을 실행한다.
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*"./gradlew :app:mergeDebugResources./gradlew :app:compileDebugKotlin./gradlew :app:ktlintCheckgit diff --check
파일 구조
- Create:
app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/data/HomeOnAirLiveApi.kt/api/v2/home/on-air-livesRetrofit endpoint를 정의한다.
- Create:
app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/data/HomeOnAirLiveModels.ktHomeOnAirLivePageResponse,HomeOnAirLiveResponseDTO를 정의한다.
- Create:
app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/data/HomeOnAirLiveRepository.kt- API 호출을 repository method로 감싼다.
- Create:
app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/model/HomeOnAirLiveUiModels.kt- 리스트 item UI model, page state, 시간/가격 표시 모델을 정의한다.
- Create:
app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/model/HomeOnAirLiveMappers.kt- DTO를 UI model로 변환하고
beginDateTimeUtc를HH:mm으로 변환한다.
- DTO를 UI model로 변환하고
- Create:
app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/model/HomeOnAirLiveAuthHeader.kt- blank token이면
null, 값이 있으면Bearer {token}을 반환한다.
- blank token이면
- Create:
app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/HomeOnAirLiveViewModel.kt- 첫 페이지/추가 페이지 로딩, loading/error/page 상태를 관리한다.
- Create:
app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/HomeOnAirLiveActivity.kt- 화면 구성, pagination, 상세 조회 후 입장 흐름을 연결한다.
- Create:
app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/ui/HomeOnAirLiveAdapter.kt- 리스트 아이템을 바인딩한다.
- Create:
app/src/main/res/layout/activity_home_on_air_live.xml- title bar와 RecyclerView 컨테이너를 정의한다.
- Create:
app/src/main/res/layout/item_home_on_air_live.xml- Figma 기준 라이브 리스트 아이템을 정의한다.
- Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/ui/HomeLiveAdapter.kt- 더보기 항목 클릭 콜백을 받을 수 있게 한다.
- Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt- 홈 추천 라이브 더보기에서
HomeOnAirLiveActivity를 연다.
- 홈 추천 라이브 더보기에서
- Modify:
app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt- 신규 API/Repository/ViewModel을 Koin에 등록한다.
- Modify:
app/src/main/AndroidManifest.xmlHomeOnAirLiveActivity를 등록한다.
- Modify:
app/src/main/res/values/strings.xmlOn Air,무료등 필요한 문자열을 추가하거나 기존 문자열을 재사용한다.
- Modify:
app/src/main/res/values-en/strings.xml- 신규 문자열 번역을 추가한다.
- Modify:
app/src/main/res/values-ja/strings.xml- 신규 문자열 번역을 추가한다.
- Create:
app/src/test/java/kr/co/vividnext/sodalive/v2/live/onair/HomeOnAirLiveAuthHeaderTest.kt- optional auth header 생성 규칙을 검증한다.
- Create:
app/src/test/java/kr/co/vividnext/sodalive/v2/live/onair/HomeOnAirLiveMapperTest.kt- DTO to UI mapping,
LIVE HH:mm, 가격/무료 표시를 검증한다.
- DTO to UI mapping,
Phase 1: 문서와 기존 구조 확인
-
Task 1.1: 기존 홈 라이브 클릭 동작 확인
- 확인:
app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/main/home/ui/HomeLiveAdapter.kt
- 결과:
- 홈 추천 최상단 라이브 아이템 클릭은
onLiveClick()으로 연결되어 있으나 현재 구현은Unit이다. - 더보기 항목은
setOnClickListener(null)로 클릭 동작이 없다.
- 홈 추천 최상단 라이브 아이템 클릭은
- 검증:
- Run:
rg -n "onLiveClick|setOnLiveClick|MoreViewHolder|setOnClickListener\\(null\\)" app/src/main/java/kr/co/vividnext/sodalive/v2/main/home - Expected: 클릭 콜백과 미구현 지점이 확인된다.
- Run:
- 확인:
-
Task 1.2: 기존 라이브 입장 정책 확인
- 확인:
app/src/main/java/kr/co/vividnext/sodalive/live/now/all/LiveNowAllActivity.ktapp/src/main/java/kr/co/vividnext/sodalive/live/LiveViewModel.ktapp/src/main/java/kr/co/vividnext/sodalive/live/room/detail/GetRoomDetailResponse.kt
- 결과:
- 기존 입장은
getRoomDetail(roomId)후manager.id,price,isPaid,isPrivateRoom,beginDateTimeUtc를 기준으로 분기한다. LiveViewModel.enterRoom(roomId, onSuccess, password)를 재사용할 수 있다.
- 기존 입장은
- 검증:
- Run:
rg -n "fun enterLiveRoom|fun getRoomDetail|fun enterRoom|data class GetRoomDetailResponse" app/src/main/java/kr/co/vividnext/sodalive/live - Expected: 상세 조회와 입장 API 호출 지점이 확인된다.
- Run:
- 확인:
Phase 2: API, DTO, mapper, ViewModel 추가
-
Task 2.1: optional auth header 테스트 작성
- 생성:
app/src/test/java/kr/co/vividnext/sodalive/v2/live/onair/HomeOnAirLiveAuthHeaderTest.kt
- 검증:
- Run:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.HomeOnAirLiveAuthHeaderTest" - Expected: helper 구현 전 RED 실패.
- Result: helper 구현 전
Unresolved reference 'model',Unresolved reference 'homeOnAirLiveAuthHeader'로 RED 실패 확인.
- Run:
- 생성:
-
Task 2.2: optional auth header helper 구현
- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/model/HomeOnAirLiveAuthHeader.kt
- 작업:
fun homeOnAirLiveAuthHeader(token: String): String?를 추가한다.token.trim().takeIf { it.isNotEmpty() }?.let { "Bearer $it" }규칙을 적용한다.
- 검증:
- Run:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.HomeOnAirLiveAuthHeaderTest" - Expected: PASS.
- Result:
--no-daemon재실행 기준 BUILD SUCCESSFUL.
- Run:
- 생성:
-
Task 2.3: mapper 테스트 작성
- 생성:
app/src/test/java/kr/co/vividnext/sodalive/v2/live/onair/HomeOnAirLiveMapperTest.kt
- 테스트 케이스:
beginDateTimeUtc를 디바이스 Timezone 기준HH:mm으로 변환한다.price > 0이면 유료 가격 표시 모델로 매핑한다.price == 0이면 무료 표시 모델로 매핑한다.- page 응답의
page,hasNext,items를 UI state로 유지한다.
- 검증:
- Run:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.HomeOnAirLiveMapperTest" - Expected: mapper 구현 전 RED 실패.
- Result: mapper 구현 전
Unresolved reference 'data',Unresolved reference 'model',Unresolved reference 'HomeOnAirLivePageResponse'로 RED 실패 확인.
- Run:
- 생성:
-
Task 2.4: API/DTO/Repository/model/mapper 구현
- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/data/HomeOnAirLiveApi.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/data/HomeOnAirLiveModels.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/data/HomeOnAirLiveRepository.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/model/HomeOnAirLiveUiModels.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/model/HomeOnAirLiveMappers.kt
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt
- 작업:
- Retrofit endpoint는
@GET("/api/v2/home/on-air-lives")로 정의한다. @Header("Authorization") authHeader: String?,@Query("page") page: Int만 사용한다.- DTO는
@Keep,@SerializedName을 사용한다. - mapper는
java.time사용 가능성을 확인하고, 프로젝트 minSdk 제약상 문제가 있으면 기존SimpleDateFormat패턴을 사용한다.
- Retrofit endpoint는
- 검증:
- Run:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.HomeOnAirLiveMapperTest" - Expected: PASS.
- Result:
--no-daemon재실행 기준 BUILD SUCCESSFUL.
- Run:
- 생성:
-
Task 2.5: ViewModel 구현
- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/HomeOnAirLiveViewModel.kt
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt
- 작업:
loadFirstPage()는 page 0부터 호출하고 기존 items를 교체한다.loadNextPage()는hasNext = true이고 loading 중이 아닐 때만 호출한다.- success이면 mapper 결과를 state로 발행한다.
- failure이면 기존 unknown error toast 패턴을 따른다.
- 검증:
- Run:
./gradlew :app:compileDebugKotlin - Expected: 신규 data/model/ViewModel/DI 코드가 컴파일된다.
- Result: auth header 테스트 GREEN 실행 중
:app:compileDebugKotlin성공. 추가로HomeOnAirLiveViewModelTest를 작성해 최초 page 0 로드, 다음 page append,hasNext=falseguard를 검증했고 BUILD SUCCESSFUL.
- Run:
- 생성:
Phase 3: 화면 UI와 홈 진입점 연결
-
Task 3.1: string/layout 추가
- 생성:
app/src/main/res/layout/activity_home_on_air_live.xmlapp/src/main/res/layout/item_home_on_air_live.xml
- 수정:
app/src/main/res/values/strings.xmlapp/src/main/res/values-en/strings.xmlapp/src/main/res/values-ja/strings.xml
- 작업:
On Airtitle, 무료 문자열은 기존 리소스가 있으면 재사용하고 부족한 값만 추가한다.item_home_on_air_live.xml은 75dp profile,LIVE HH:mm, title, creator, price/free 영역을 포함한다.
- 검증:
- Run:
./gradlew :app:mergeDebugResources - Expected: 신규 layout/string resource가 merge된다.
- Result: Figma item node
185:4509를Figma_get_design_context,Figma_get_screenshot으로 확인한 뒤75dpprofile,LIVEpill/time 분리, title, creator, price/free 영역을 반영했다.--no-daemon단독 실행 기준 BUILD SUCCESSFUL.
- Run:
- 생성:
-
Task 3.2: adapter 구현
- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/ui/HomeOnAirLiveAdapter.kt
- 작업:
submitItems(items)와onClickcallback을 제공한다.- 유료/무료 표시 모델에 따라 cash icon visibility와 텍스트를 바인딩한다.
- 이미지 로드는 기존
loadUrl확장을 사용한다.
- 검증:
- Run:
./gradlew :app:compileDebugKotlin - Expected: adapter가 컴파일된다.
- Result:
HomeOnAirLiveAdapter가loadUrl, paid/free visibility, item click callback을 바인딩하도록 구현했고--no-daemon실행 기준 BUILD SUCCESSFUL.
- Run:
- 생성:
-
Task 3.3: Activity 구현과 Manifest 등록
- 생성:
app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/HomeOnAirLiveActivity.kt
- 수정:
app/src/main/AndroidManifest.xml
- 작업:
newIntent(context)를 제공한다.RecyclerView와 pagination scroll listener를 연결한다.- item click 시
getRoomDetail(roomId)후 기존 입장 정책을 적용한다. - 오디오 재생 서비스 중지 후
LiveRoomActivity를 실행한다.
- 검증:
- Run:
./gradlew :app:compileDebugKotlin - Expected: Activity와 Manifest 등록이 컴파일된다.
- Result:
HomeOnAirLiveActivity.newIntent(context), 첫 페이지 로드, pagination, toast/loading/empty 표시, 기존getRoomDetail(roomId)후 입장/비밀번호/결제 흐름을 연결했고--no-daemon실행 기준 BUILD SUCCESSFUL.
- Run:
- 생성:
-
Task 3.4: 홈 추천 라이브 더보기 진입점 연결
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/ui/HomeLiveAdapter.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt
- 작업:
HomeLiveAdapter에setOnMoreClick()을 추가한다.- 더보기 항목 클릭 시
HomeOnAirLiveActivity.newIntent(requireContext())를 실행한다. - 기존 라이브 아이템 클릭은 이번 범위에서 직접 입장 연결하지 않고 기존
onLiveClick()미구현 상태를 유지한다.
- 검증:
- Run:
./gradlew :app:compileDebugKotlin - Expected: 홈 추천 더보기에서 신규 Activity 진입 코드가 컴파일된다.
- Result:
HomeLiveAdapter.setOnMoreClick()과HomeMainFragment.openHomeOnAirLive()를 연결했고 기존onLiveClick()은 미구현 상태로 유지했다.--no-daemon실행 기준 BUILD SUCCESSFUL.
- Run:
- 수정:
-
Task 3.5: Phase 3 코드 리뷰 및 검증
- 리뷰 결과:
HomeOnAirLiveActivity가LiveViewModel.getRoomDetail()/enterRoom()을 호출하지만liveViewModel.isLoading,liveViewModel.toastLiveData를 observe하지 않아 상세 조회/입장 실패 시 기존 loading/toast 패턴이 사용자에게 전달되지 않는다.GetRoomDetailResponse.isAdult기준의 기존ensureLoginAndAdultAuth정책이 신규 화면에 연결되어 있지 않아 성인 라이브에서 본인인증/콘텐츠 설정 가드가 누락된다.- 기존
LiveNowAllActivity는 상세 응답의channelName != null일 때만 입장 분기를 수행하지만, 신규 화면에는 해당 가드가 없어 종료/예약 상태 응답에서 입장을 시도할 수 있다.
- 반영:
- 로그인 확인 후
getRoomDetail(roomId)를 호출하고, 응답의isAdult기준으로 기존 성인 인증/성인 콘텐츠 설정 가드를 수행한다. LiveViewModel.isLoading과LiveViewModel.toastLiveData를 observe하고, 목록 로딩과 입장 로딩 상태를 OR 조건으로 합쳐LoadingDialog를 제어한다.channelName이 blank인 상세 응답은 입장 분기를 중단하도록 정책 함수를 추가한다.
- 로그인 확인 후
- 검증:
- Run:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" --no-daemon - Result: BUILD SUCCESSFUL.
- Run:
./gradlew :app:mergeDebugResources --no-daemon - Result: BUILD SUCCESSFUL.
- Run:
./gradlew :app:compileDebugKotlin --no-daemon - Result: BUILD SUCCESSFUL.
- Run:
./gradlew :app:ktlintCheck --no-daemon - Result: BUILD SUCCESSFUL.
- Run:
git diff --check - Result: whitespace error 없음.
- 종합: 리뷰 지적사항을 반영했고 빌드/린트/단위 테스트가 모두 통과했다.
- 추가 Run:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.HomeOnAirLiveEntryPolicyTest" - 추가 RED Result:
canEnterHomeOnAirLiveRoom미구현으로 컴파일 실패를 확인했다. - 추가 GREEN Result:
channelName이 blank인 상세 응답에서 입장 분기를 중단하는 정책 함수를 구현한 뒤 BUILD SUCCESSFUL. - 추가 Run:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" --no-daemon - 추가 Result: BUILD SUCCESSFUL.
- 추가 Run:
./gradlew :app:mergeDebugResources --no-daemon - 추가 Result: 최초 sandbox 실행은
~/.gradlewrapper lock 접근 제한으로 실패했고, 승인 실행 기준 BUILD SUCCESSFUL. - 추가 Run:
./gradlew :app:compileDebugKotlin --no-daemon - 추가 Result: BUILD SUCCESSFUL.
- 추가 Run:
./gradlew :app:ktlintCheck --no-daemon - 추가 Result: 기존
.editorconfig의disabled_rulesdeprecation 경고가 출력되었지만 BUILD SUCCESSFUL. - 추가 Run:
git diff --check - 추가 Result: whitespace error 없음.
- Run:
- 리뷰 결과:
Phase 4: 최종 검증
-
Task 4.1: 단위 테스트와 컴파일 검증
- 검증:
- Run:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" - Expected: on-air live 관련 단위 테스트 PASS.
- Result:
--no-daemon단독 실행 기준 BUILD SUCCESSFUL. - Run:
./gradlew :app:mergeDebugResources - Expected: resource merge PASS.
- Result:
--no-daemon단독 실행 기준 BUILD SUCCESSFUL. - Run:
./gradlew :app:compileDebugKotlin - Expected: Kotlin compile PASS.
- Result:
--no-daemon단독 실행 기준 BUILD SUCCESSFUL.
- Run:
- 검증:
-
Task 4.2: 린트/차이 검증
- 검증:
- Run:
./gradlew :app:ktlintCheck - Expected: ktlint PASS.
- Result:
--no-daemon단독 실행 기준 BUILD SUCCESSFUL. - Run:
git diff --check - Expected: whitespace error 없음.
- Result: 출력 없음. whitespace error 없음.
- Run:
- 검증:
Verification Log
- 2026-06-26 Phase 2 RED: production 구현 전
HomeOnAirLiveAuthHeaderTest,HomeOnAirLiveMapperTest실행 시 신규data/modelsymbol 미존재로 컴파일 실패를 확인했다. - 2026-06-26 Phase 2 GREEN:
HomeOnAirLiveAuthHeaderTest,HomeOnAirLiveMapperTest,HomeOnAirLiveViewModelTest각각--no-daemon실행 기준 BUILD SUCCESSFUL을 확인했다. - 2026-06-26 Phase 2 최종 검증:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" --no-daemon,./gradlew :app:mergeDebugResources --no-daemon,./gradlew :app:compileDebugKotlin --no-daemon,./gradlew :app:ktlintCheck --no-daemon,git diff --check모두 통과했다. - 2026-06-27 Phase 3 검증:
./gradlew :app:mergeDebugResources --no-daemon,./gradlew :app:compileDebugKotlin --no-daemon,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" --no-daemon,./gradlew :app:ktlintCheck --no-daemon,git diff --check모두 통과했다. 최초 병렬 실행 중mergeDebugResources가 stripped 중간 파일 경합으로 1회 실패했으나, 순차 단독 재실행에서 BUILD SUCCESSFUL을 확인했다. - 2026-06-27 Phase 3 Figma 재검증: 리뷰 지적에 따라
item_home_on_air_live.xml의 title을Typography.Heading4, LIVE badge를Typography.Caption3기반 pill, time/creator/price를Typography.Body6로 조정했다. 이후./gradlew :app:mergeDebugResources --no-daemon,./gradlew :app:compileDebugKotlin --no-daemon,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" --no-daemon,./gradlew :app:ktlintCheck --no-daemon,git diff --check모두 통과했다. - 2026-06-27 Phase 3 리뷰 반영:
HomeOnAirLiveActivity에 기존 라이브 입장 정책과 동일하게 로그인 확인,getRoomDetail(roomId)응답의isAdult기준 성인 인증/성인 콘텐츠 설정 가드,LiveViewModel.isLoading/toastLiveData관찰을 추가했다. 이후./gradlew :app:mergeDebugResources --no-daemon,./gradlew :app:compileDebugKotlin --no-daemon,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" --no-daemon,./gradlew :app:ktlintCheck --no-daemon,git diff --check모두 통과했다. - 2026-06-27 Phase 3 코드 리뷰 및 재검증:
HomeOnAirLiveActivity에LiveViewModelloading/toast 관찰과GetRoomDetailResponse.isAdult기준 성인 인증/성인 콘텐츠 설정 가드를 추가한 뒤./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" --no-daemon,./gradlew :app:mergeDebugResources --no-daemon,./gradlew :app:compileDebugKotlin --no-daemon,./gradlew :app:ktlintCheck --no-daemon,git diff --check를 순차 실행해 모두 통과했다. - 2026-06-27 Phase 4 최종 검증:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.*" --no-daemon,./gradlew :app:mergeDebugResources --no-daemon,./gradlew :app:compileDebugKotlin --no-daemon,./gradlew :app:ktlintCheck --no-daemon모두 BUILD SUCCESSFUL을 확인했다.git diff --check는 출력이 없어 whitespace error가 없음을 확인했다.
Phase 5: 홈 추천 라이브 아이템 직접 입장 보완
-
Task 5.1: HomeMainFragment 라이브 아이템 입장 source test 추가
- 수정:
app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragmentLoginGuardSourceTest.kt
- 작업:
onLiveClick()이Unitplaceholder가 아니고 login guard,getRoomDetail(roomId),roomDetail.isAdultguard, 기존 v2CreatorChannelLiveCoordinator입장 위임 순서를 갖는지 검증한다.
- 검증:
- Run:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLoginGuardSourceTest" --no-daemon - Expected RED: 기존
onLiveClick()미구현으로 신규 assertion 실패. - RED Result: 신규 테스트 추가 후 기존
onLiveClick = Unit상태에서HomeMainFragment 추천 라이브 아이템은 로그인과 성인 가드 후 기존 입장 흐름을 실행한다가 실패함을 확인했다.
- Run:
- 수정:
-
Task 5.2: HomeMainFragment 라이브 입장 흐름 구현
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt
- 작업:
LiveViewModel을 주입하고 추천 라이브 클릭에서ensureMainV2NavigationAllowed를 먼저 호출한다.- 상세 조회 후
roomDetail.isAdult기준으로 성인 guard를 수행하고, 기존 v2CreatorChannelLiveCoordinator의 라이브 입장 분기를 재사용한다. - 입장 전 오디오 재생 서비스를 중지한다.
- 검증:
- Run:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLoginGuardSourceTest" --no-daemon - Expected GREEN: 신규 source test 포함 전체 통과.
- GREEN Result:
HomeMainFragment가LiveViewModel.getRoomDetail(item.roomId)후requiresAdultContentAccess = roomDetail.isAdultguard를 거쳐CreatorChannelLiveCoordinator.enterLiveRoom(item.roomId, roomDetail)를 호출하도록 변경했고, 단일 source test가 BUILD SUCCESSFUL로 통과했다.
- Run:
- 수정:
-
Task 5.3: 컴파일 및 회귀 검증
- 검증:
- Run:
./gradlew :app:compileDebugKotlin --no-daemon - Expected: BUILD SUCCESSFUL.
- Run:
git diff --check - Expected: whitespace error 없음.
- Result:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.HomeOnAirLiveEntryPolicyTest" --no-daemon,./gradlew :app:compileDebugKotlin --no-daemon,git diff --check모두 통과했다. 최초 병렬 Gradle 실행은 Kotlin incremental cache 충돌로 실패했으나,./gradlew --stop후 순차 재실행에서 BUILD SUCCESSFUL을 확인했다.
- Run:
- 검증:
-
2026-07-06 Phase 5 검증: 홈 추천 라이브 클릭 source test를 RED 상태로 먼저 확인한 뒤,
HomeMainFragment에서 로그인 guard, 상세 조회,roomDetail.isAdult기반 성인 guard, 기존 v2CreatorChannelLiveCoordinator입장 위임을 연결했다. 이후HomeMainFragmentLoginGuardSourceTest,HomeOnAirLiveEntryPolicyTest,compileDebugKotlin,git diff --check가 모두 통과했다. -
2026-07-06 Phase 5 리뷰 반영: 코드 품질 리뷰에서
getRoomDetail콜백 lifecycle guard 부재와 여러 ViewModel의LoadingDialog직접 제어 race가 지적되어, 콜백 초입에if (!isAdded || view == null) return@getRoomDetail를 추가하고 recommendation/ranking/following/live entry loading state를updateLoadingDialog()로 통합했다. 이후./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLoginGuardSourceTest" --no-daemon,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.live.onair.HomeOnAirLiveEntryPolicyTest" --no-daemon,./gradlew :app:compileDebugKotlin --no-daemon,git diff --check가 모두 통과했다.
Phase 6: 전체 라이브 리스트 상단 제목 정정
Phase 결과: 메인 홈 추천 라이브 섹션의 전체에서 진입한 화면 상단에 locale과 관계없이 On Air가 표시된다.
Task 6.1: live_now locale 리소스 정정
Goal 실행 P6-T1: 기존 화면 연결을 유지하면서 기본·영어·일본어 live_now 값을 On Air로 통일한다.
- 시작 조건:
prd.md§13 승인과HomeOnAirLiveActivity의R.string.live_now소비 확인. - 완료 증거: 세 locale 리소스 값 대조, debug resource merge, focused 회귀 테스트,
git diff --check결과. - 범위 밖: Activity/layout/navigation 변경, 홈 추천 섹션 제목 변경, 레거시
screen_live_now_all_title변경. - TDD 예외 사유: 실행 로직이나 분기가 없는 UI 카피 전용 변경이며 영어 리소스는 이미 목표값이다. 신규 source test는 XML 구현 문자열을 중복 고정하므로 추가하지 않는다.
- 대체 검증 방법: 변경 전 기본·일본어 값이 각각
지금 라이브 중,ただいま配信中임을 확인하고, 변경 후 기본·영어·일본어 값을 직접 대조한 뒤 resource merge와 기존 진입 경로 회귀 테스트를 실행한다.
Files:
-
Modify:
app/src/main/res/values/strings.xml -
Modify:
app/src/main/res/values-ja/strings.xml -
Verify unchanged:
app/src/main/res/values-en/strings.xml -
Verify unchanged:
app/src/main/java/kr/co/vividnext/sodalive/v2/live/onair/HomeOnAirLiveActivity.kt -
기본 locale의
live_now값을On Air로 변경한다. -
일본어 locale의
live_now값을On Air로 변경한다. -
영어 locale과 세 locale의 최종값이 모두
On Air인지 확인한다. -
./gradlew --no-daemon :app:mergeDebugResources를 실행한다. -
./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLoginGuardSourceTest" --tests "kr.co.vividnext.sodalive.v2.live.onair.HomeOnAirLiveEntryPolicyTest"를 실행한다. -
가능한 연결 기기/에뮬레이터에서 진입 화면 상단 제목을 확인하고, 불가능하면 사유를 Verification Log에 기록한다.
-
git diff --check와 변경 파일 범위를 확인한다.
Phase 6 검증 시나리오
- Happy path: 기본 locale에서
HomeOnAirLiveActivity가 소비하는live_now의 병합값이 정확히On Air다. - Edge: 영어·일본어 locale에서도
live_now가 정확히On Air이며 빈 목록/오류 상태와 독립적인 toolbar 설정은 유지된다. - Adjacent regression: 홈 추천
전체진입 경로와screen_live_now_all_title값은 변경되지 않는다.
Verification Log 추가 기록
- 2026-08-03 Phase 6 계획: 기존 PRD §7의
On Air제목 요구사항과 구현의 기본·일본어live_now값 불일치를 확인했다. 사용자 승인에 따라 리소스 값만 정정하고 화면 코드와 레거시 제목은 유지한다. - 2026-08-03 Phase 6 구현: 기본·일본어
live_now값을On Air로 정정했고 영어값이 이미On Air임을 확인했다.screen_live_now_all_title은 세 locale 모두 기존값을 유지했다. - 2026-08-03 Phase 6 자동 검증:
xmllint --noout성공,./gradlew --no-daemon :app:mergeDebugResourcesBUILD SUCCESSFUL, focused 2개 테스트 클래스 BUILD SUCCESSFUL, 전체:app:testDebugUnitTestBUILD SUCCESSFUL,:app:assembleDebugBUILD SUCCESSFUL을 확인했다. 병합 산출물의 기본·일본어live_now도On Air였다. - 2026-08-03 Phase 6 실제 화면 검증:
Pixel_9_ProAVD에 debug APK를 설치하고 정상 홈 화면을 열었으나 현재 API 응답에 라이브 항목이 없어전체진입점이 렌더링되지 않았다. 내부 Activity 직접 실행은android:exported=false로 거부됐고, 일회성 계측 QA는 첫 시도에서 DEX 공백 메서드명 제약, 두 번째 시도에서 로그인 화면 전환으로 Activity가 종료돼 assertion 전에 실패했다. 임시 계측 테스트는 제거했으며 대상 화면 스크린샷 검증은 미완료로 기록한다. - 2026-08-03 Phase 6 리뷰 반영: Oracle 리뷰
REV-P6-001에서 실제git diff --check성공과 미완료 체크박스의 문서 불일치를 확인했다. 체크박스를 완료로 정정했고 프로덕션 변경이 리소스 2개 각 1줄뿐이며 기본·영어·일본어live_now가 모두On Air임을 재확인했다.