Files
sodalive-android/docs/20260608_크리에이터_랭킹_페이지/plan-task.md

33 KiB

크리에이터 랭킹 페이지 Plan / Task

For agentic workers: 구현 시 superpowers:subagent-driven-development 또는 superpowers:executing-plans를 사용해 task 단위로 진행한다. 각 단계는 체크박스(- [ ])로 추적하고, 완료 즉시 - [x]로 갱신한다.

Goal: HomeMainFragment의 Text Tab bar에서 랭킹 선택 시 GET /api/v2/home/rankings/creators 응답을 기존 creatorranking 위젯으로 표시한다.

Architecture: 신규 홈 크리에이터 랭킹 API, Repository, ViewModel, DTO/UI model/mapper는 기존 홈 추천 패턴과 같은 kr.co.vividnext.sodalive.v2.main.home 하위에 둔다. 화면은 HomeMainFragmentfragment_v2_main_home.xml을 최소 확장하고, 기존 kr.co.vividnext.sodalive.v2.widget.creatorranking 위젯은 showRankChange=false 숨김 옵션만 필요한 만큼 확장한다.

Tech Stack: Kotlin, Android XML Views, ViewBinding, RecyclerView, RxJava3, Retrofit, Gson, Koin, Coil, Robolectric/local unit test.


전제와 성공 기준

  • PRD: docs/20260608_크리에이터_랭킹_페이지/prd.md
  • Figma: 24:5654
  • Capsule Tab bar(주간 인기, 지금 뜨는 중, 남성 인기, 여성 인기)는 배치하지 않는다.
  • rankChangenull/0 -> Stay, 양수 -> Increase, 음수 -> Decrease로 매핑한다.
  • isNew=truerankChange보다 우선해 New로 매핑한다.
  • showRankChange=false이면 모든 rank-num 영역을 완전히 숨긴다.
  • API 응답은 서버에서 rank 오름차순으로 내려오지만, 클라이언트에서도 한 번 더 rank 기준 오름차순 정렬한다.
  • creatorId=0은 차단 관계로 보고 isBlocked=true, 클릭 불가로 처리한다.
  • creatorId>0 item만 UserProfileActivity로 이동하며, 별도 analytics/logging은 추가하지 않는다.
  • 구현 완료 후 최소 다음 명령을 실행한다.
    • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"
    • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*"
    • ./gradlew :app:mergeDebugResources
    • ./gradlew :app:compileDebugKotlin
    • ./gradlew :app:ktlintCheck

파일 구조

  • 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/data/HomeCreatorRankingModels.kt
    • HomeCreatorRankingResponse, HomeCreatorRankingItemResponse DTO를 정의한다.
  • 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/data/HomeCreatorRankingApi.kt
    • GET /api/v2/home/rankings/creators Retrofit endpoint를 정의한다.
  • 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/data/HomeCreatorRankingRepository.kt
    • API 호출을 감싸고 기존 repository 패턴과 동일하게 token을 전달한다.
  • 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/model/HomeCreatorRankingMappers.kt
    • API 응답을 CreatorRankingItem 목록으로 변환한다.
  • 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/model/HomeCreatorRankingUiState.kt
    • Loading, Content, Empty, Error 상태를 정의한다.
  • 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeCreatorRankingViewModel.kt
    • 랭킹 API 호출, loading, toast, state를 관리한다.
  • 수정: app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt
    • 신규 API, Repository, ViewModel을 Koin에 등록한다.
  • 수정: app/src/main/res/layout/fragment_v2_main_home.xml
    • TextTabBarView 아래에 랭킹 전용 RecyclerView를 추가한다.
  • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/main/HomeMainFragment.kt
    • 랭킹 탭 전환, 랭킹 adapter, ViewModel observe, 프로필 이동을 연결한다.
  • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingItem.kt
    • showRankChange 표시 계약을 추가한다.
  • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingLargeCardView.kt
  • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingCompactCardView.kt
  • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingHorizontalCardView.kt
    • showRankChange=false일 때 rank-num 영역을 GONE 처리한다.
  • 테스트 수정/생성:
    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingItemTest.kt
    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapterLayoutTest.kt
    • 생성: app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeCreatorRankingMapperTest.kt
    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragmentLayoutTest.kt

Phase 1: 기존 구조 확인과 작업 경계 고정

  • Task 1.1: 기존 홈/랭킹 위젯/DI 구조 확인

    • 확인: app/src/main/java/kr/co/vividnext/sodalive/v2/main/HomeMainFragment.kt
    • 확인: app/src/main/res/layout/fragment_v2_main_home.xml
    • 확인: app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt
    • 확인: app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/data/HomeRecommendationApi.kt
    • 확인: app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeRecommendationViewModel.kt
    • 확인: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapter.kt
    • 확인: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingItem.kt
    • 검증: 기존 추천 content는 nsv_home_recommendation_content 아래에 있고, 랭킹 content는 별도 container가 필요함을 확인한다.
  • Task 1.2: 구현 제외 범위 재확인

    • 확인: docs/20260608_크리에이터_랭킹_페이지/prd.md
    • 제외:
      • Capsule Tab bar
      • 팔로잉 탭 content
      • analytics/logging
      • ViewPager2/swipe 전환
    • 검증: 계획 문서의 모든 phase가 위 제외 범위를 침범하지 않는지 확인한다.

Phase 2: creatorranking 위젯 rank-num 숨김 계약 확장

  • Task 2.1: CreatorRankingItem 표시 계약 테스트 추가

    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingItemTest.kt
    • 추가 테스트:
      • 기본 showRankChangetrue
      • showRankChange=false인 item은 rank change 표시 대상이 아님
      • creatorId=0, isBlocked=true item은 isTouchable=false
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingItemTest"
    • 기대 결과: showRankChange 속성 미구현으로 RED 실패.
  • Task 2.2: CreatorRankingItemshowRankChange 추가

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingItem.kt
    • 구현 내용:
      • val showRankChange: Boolean = true를 기본값 있는 마지막 파라미터로 추가한다.
      • 기존 테스트/호출부가 깨지지 않도록 기본값을 유지한다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingItemTest"
    • 기대 결과: PASS.
  • Task 2.3: rank-num 숨김 view 테스트 추가

    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapterLayoutTest.kt
    • 추가 테스트:
      • Large, Compact, Horizontal card에 showRankChange=false item을 bind하면 ll_creator_ranking_deltaGONE
      • showRankChange=true item을 bind하면 기존처럼 ll_creator_ranking_deltaVISIBLE
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"
    • 기대 결과: view bind 미구현으로 RED 실패.
  • Task 2.4: rank-num 숨김 구현

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingLargeCardView.kt
    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingCompactCardView.kt
    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingHorizontalCardView.kt
    • 구현 내용:
      • bindDelta(item) 시작부에서 item.showRankChange == false이면 delta container를 View.GONE으로 설정하고 return한다.
      • item.showRankChange == true이면 delta container를 View.VISIBLE로 복구한 뒤 기존 presentation 적용을 유지한다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"
    • 기대 결과: PASS.

Phase 3: 홈 크리에이터 랭킹 API/DTO/mapper 작성

  • Task 3.1: mapper RED 테스트 작성

    • 생성: app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeCreatorRankingMapperTest.kt
    • 테스트 케이스:
      • 응답 item을 rank 오름차순으로 재정렬한다.
      • isNew=trueRankingChangeType.New, amount 0으로 매핑한다.
      • rankChange=null 또는 0RankingChangeType.Stay, amount 0으로 매핑한다.
      • rankChange=5RankingChangeType.Increase, amount 5로 매핑한다.
      • rankChange=-3RankingChangeType.Decrease, amount 3으로 매핑한다.
      • showRankChange=false이면 모든 CreatorRankingItem.showRankChange=false로 매핑한다.
      • creatorId=0isBlocked=true, isTouchable=false로 매핑한다.
      • rank < 1 item은 제외한다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeCreatorRankingMapperTest"
    • 기대 결과: DTO/mapper 미구현으로 RED 실패.
  • Task 3.2: API DTO와 mapper 구현

    • 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/data/HomeCreatorRankingModels.kt
    • 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/model/HomeCreatorRankingMappers.kt
    • 구현 내용:
      • data class HomeCreatorRankingResponse(val showRankChange: Boolean, val items: List<HomeCreatorRankingItemResponse>)
      • data class HomeCreatorRankingItemResponse(val rank: Int, val rankChange: Int?, val isNew: Boolean, val creatorId: Long, val nickname: String, val profileImageUrl: String)
      • fun HomeCreatorRankingResponse.toCreatorRankingItems(): List<CreatorRankingItem>
      • rank >= 1 filtering, rank sorting, RankingChangeType mapping, abs(rankChange) amount mapping
      • creatorId == 0L -> isBlocked=true
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeCreatorRankingMapperTest"
    • 기대 결과: PASS.
  • Task 3.3: API/Repository 작성

    • 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/data/HomeCreatorRankingApi.kt
    • 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/data/HomeCreatorRankingRepository.kt
    • 구현 내용:
      • @GET("/api/v2/home/rankings/creators")
      • fun getCreatorRankings(@Header("Authorization") authHeader: String): Single<ApiResponse<HomeCreatorRankingResponse>>
      • repository는 getCreatorRankings(token: String)으로 API를 위임한다.
    • 검증 명령: ./gradlew :app:compileDebugKotlin
    • 기대 결과: 신규 API/Repository 컴파일 성공.

Phase 4: ViewModel과 DI 등록

  • Task 4.1: UI state와 ViewModel 작성

    • 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/model/HomeCreatorRankingUiState.kt
    • 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeCreatorRankingViewModel.kt
    • 구현 내용:
      • HomeCreatorRankingUiState.Loading
      • HomeCreatorRankingUiState.Content(val items: List<CreatorRankingItem>)
      • HomeCreatorRankingUiState.Empty
      • HomeCreatorRankingUiState.Error(val message: String?)
      • rankingStateLiveData, isLoading, toastLiveData
      • loadCreatorRankings()
      • 기존 HomeRecommendationViewModel과 동일하게 SharedPreferenceManager.token, RxJava scheduler, unknown error toast 패턴 사용
    • 검증 명령: ./gradlew :app:compileDebugKotlin
    • 기대 결과: ViewModel 컴파일 성공.
  • Task 4.2: Koin DI 등록

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt
    • 구현 내용:
      • import 추가: HomeCreatorRankingApi, HomeCreatorRankingRepository, HomeCreatorRankingViewModel
      • networkModulesingle { ApiBuilder().build(get(), HomeCreatorRankingApi::class.java) }
      • repositoryModulefactory { HomeCreatorRankingRepository(get()) }
      • viewModelModuleviewModel { HomeCreatorRankingViewModel(get()) }
    • 검증 명령: ./gradlew :app:compileDebugKotlin
    • 기대 결과: Koin 등록과 import 컴파일 성공.

Phase 5: 홈 레이아웃과 탭 전환 UI 연결

  • Task 5.1: 홈 레이아웃에 랭킹 목록 추가 RED 테스트 작성

    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragmentLayoutTest.kt
    • 추가 테스트:
      • fragment_v2_main_home.xmlrv_home_creator_rankings가 존재한다.
      • rv_home_creator_rankingsTextTabBarView 아래에 직접 constraint 된다.
      • Capsule Tab bar 관련 view id가 존재하지 않는다.
      • 초기 visibility는 GONE이다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLayoutTest.home ranking layout*"
    • 기대 결과: 신규 RecyclerView 미존재로 RED 실패.
  • Task 5.2: fragment_v2_main_home.xml에 랭킹 RecyclerView 추가

    • 수정: app/src/main/res/layout/fragment_v2_main_home.xml
    • 구현 내용:
      • androidx.recyclerview.widget.RecyclerView 추가
      • id: @+id/rv_home_creator_rankings
      • width/height: 0dp
      • top: @id/text_tab_bar_home bottom
      • bottom/start/end: parent
      • android:visibility="gone"
      • android:clipToPadding="false"
      • android:paddingHorizontal="@dimen/spacing_14"
      • android:paddingTop="@dimen/spacing_14"
      • android:paddingBottom="@dimen/spacing_28"
    • 제외: Capsule Tab bar view 추가 금지.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLayoutTest.home ranking layout*"./gradlew :app:mergeDebugResources
    • 기대 결과: PASS.
  • Task 5.3: HomeMainFragment 탭 전환/adapter 연결 테스트 작성

    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragmentLayoutTest.kt
    • 추가 테스트:
      • CreatorRankingAdapter.createGridLayoutManager()가 랭킹 RecyclerView에 사용되는 소스 계약
      • 랭킹 index 선택 시 추천 content는 GONE, 랭킹 RecyclerView는 VISIBLE
      • 추천 index 선택 시 추천 content는 VISIBLE, 랭킹 RecyclerView는 GONE
      • creatorId=0 item은 프로필 이동 intent를 만들지 않는다.
      • creatorId>0 item은 UserProfileActivity + Constants.EXTRA_USER_ID intent를 만든다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLayoutTest.home ranking*"
    • 기대 결과: Fragment 연결 미구현으로 RED 실패.
  • Task 5.4: HomeMainFragment에 랭킹 탭 content 연결

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/main/HomeMainFragment.kt
    • 구현 내용:
      • private val homeCreatorRankingViewModel: HomeCreatorRankingViewModel by viewModel()
      • private val creatorRankingAdapter = CreatorRankingAdapter { openCreatorRankingProfile(it) }
      • rvHomeCreatorRankings.layoutManager = CreatorRankingAdapter.createGridLayoutManager(requireContext())
      • rvHomeCreatorRankings.adapter = creatorRankingAdapter
      • tab index 상수: HOME_TAB_RECOMMENDATION = 0, HOME_TAB_RANKING = 1, HOME_TAB_FOLLOWING = 2
      • setOnTabSelectedListener에서 추천/랭킹만 content 전환 처리한다.
      • 랭킹 최초 선택 시 homeCreatorRankingViewModel.loadCreatorRankings()를 호출한다.
      • HomeCreatorRankingUiState.Content이면 creatorRankingAdapter.submitItems(items)
      • Empty/Error이면 빈 목록을 submit한다.
      • openCreatorRankingProfile(item)item.creatorId > 0일 때만 UserProfileActivityConstants.EXTRA_USER_ID와 함께 실행한다.
      • 별도 analytics/logging은 추가하지 않는다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLayoutTest.home ranking*"./gradlew :app:compileDebugKotlin
    • 기대 결과: PASS.

Phase 6: 통합 검증과 문서 기록

  • Task 6.1: targeted test 실행

    • 실행:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeCreatorRankingMapperTest"
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLayoutTest"
    • 기대 결과: 모두 BUILD SUCCESSFUL.
    • 실패 시: 실패 원인을 이 문서의 Verification Log에 누적하고, 수정 전 관련 task 체크박스를 되돌린다.
  • Task 6.2: compile/resource/lint 검증

    • 실행:
      • ./gradlew :app:mergeDebugResources
      • ./gradlew :app:compileDebugKotlin
      • ./gradlew :app:ktlintCheck
    • 기대 결과: 모두 BUILD SUCCESSFUL.
    • 참고: 기존 .editorconfig disabled_rules deprecation warning은 신규 실패가 아니면 별도 수정하지 않는다.
  • Task 6.3: 최종 문서 검증 기록 누적

    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 수정: docs/20260608_크리에이터_랭킹_페이지/prd.md
    • 구현 내용:
      • 실행한 명령, 성공/실패 결과, 실패 시 원인과 보완 내용을 Verification Log에 누적한다.
      • 기존 Verification Log는 삭제하거나 덮어쓰지 않는다.
    • 검증: PRD와 plan-task의 완료 상태와 실제 구현 상태가 일치한다.

Phase 7: 순위 텍스트 고정 박스 정렬 보정

  • Task 7.1: 순위 텍스트 박스 정렬 RED 테스트 추가

    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapterLayoutTest.kt
    • 구현 내용:
      • Large, Compact medium, Compact small, Horizontal variant의 순위 영역 박스 크기/위치와 내부 중앙 정렬을 검증한다.
      • Figma margin 값을 임의로 추가하지 않고 기존 박스 크기 안의 정렬만 검증한다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"
    • 기대 결과: production 수정 전 중앙 정렬 assertion이 실패한다.
  • Task 7.2: 순위 텍스트 박스 내부 정렬 보정

    • 수정: app/src/main/res/layout/view_creator_ranking_large_card.xml
    • 수정: app/src/main/res/layout/view_creator_ranking_compact_card.xml
    • 수정: app/src/main/res/layout/view_creator_ranking_horizontal_card.xml
    • 구현 내용:
      • 기존 Kotlin 코드의 고정 박스 크기/left/top 계산은 유지한다.
      • 순위 TextView가 박스 내부에서 중앙 정렬되도록 최소 속성만 추가한다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"
    • 기대 결과: RED 테스트가 BUILD SUCCESSFUL로 전환된다.
  • Task 7.3: 후속 검증과 문서 기록 누적

    • 실행:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"
      • ./gradlew :app:mergeDebugResources
    • 수정: docs/20260608_크리에이터_랭킹_페이지/prd.md
    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 기대 결과: 모두 BUILD SUCCESSFUL, Verification Log 누적.

Phase 8: Figma 최신 순위 영역 수치 보정

  • Task 8.1: 순위 영역 최신 수치 RED 테스트 추가

    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapterLayoutTest.kt
    • 구현 내용:
      • Figma 24:5658 기준 1위, 27위, 810위, 11위 이후 순위 숫자 박스 크기와 rank-num 위치를 검증한다.
      • rank-num 상승/하락/유지/New 표시의 기존 노출 정책은 유지한다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"
    • 기대 결과: production 수정 전 1위/810위 순위 박스와 1위/810위 rank-num 위치 assertion이 실패한다.
  • Task 8.2: 순위 숫자 박스와 rank-num 위치 보정

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingLargeCardView.kt
    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingCompactCardView.kt
    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingHorizontalCardView.kt
    • 구현 내용:
      • 1위 순위 숫자 박스는 86x116, rank-num은 left=20, top=116 기준으로 맞춘다.
      • 2~7위 순위 숫자 박스는 56x70, rank-num은 left=10, top=70 기준으로 맞춘다.
      • 8~10위 순위 숫자 박스는 52x50, left=0, rank-num은 left=10, top=50 기준으로 맞춘다.
      • 11위 이후 순위 텍스트는 rank group 내부에서 48x52 기준으로 맞춘다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"
    • 기대 결과: RED 테스트가 BUILD SUCCESSFUL로 전환된다.
  • Task 8.3: 후속 검증과 문서 기록 누적

    • 실행:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"
      • ./gradlew :app:mergeDebugResources
      • ./gradlew :app:ktlintCheck
    • 수정: docs/20260608_크리에이터_랭킹_페이지/prd.md
    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 기대 결과: 모두 BUILD SUCCESSFUL, Verification Log 누적.

Phase 9: rank-num 간격 시각 보정

  • Task 9.1: rank 텍스트 하단 보정 회귀 테스트 추가

    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapterLayoutTest.kt
    • 구현 내용:
      • Large, Compact medium, Compact small, Horizontal variant의 순위 TextViewincludeFontPadding=false를 유지하는지 검증한다.
      • 순위 TextView에 variant별 하단 padding이 적용되어 Pattaya glyph가 rank-num 영역에 붙어 보이지 않도록 검증한다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"
    • 기대 결과: production 수정 전 padding assertion이 실패한다.
  • Task 9.2: rank 텍스트 내부 하단 padding 보정

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingLargeCardView.kt
    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingCompactCardView.kt
    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingHorizontalCardView.kt
    • 구현 내용:
      • 기존 Figma 좌표값과 rank-num top/left는 변경하지 않는다.
      • 순위 숫자 TextView 내부에 scale 기반 하단 padding을 적용해 폰트 glyph가 위쪽으로 보정되도록 한다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"
    • 기대 결과: RED 테스트가 BUILD SUCCESSFUL로 전환된다.
  • Task 9.3: 후속 검증과 문서 기록 누적

    • 실행:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"
      • ./gradlew :app:mergeDebugResources
      • ./gradlew :app:ktlintCheck
    • 수정: docs/20260608_크리에이터_랭킹_페이지/prd.md
    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 기대 결과: 모두 BUILD SUCCESSFUL, Verification Log 누적.

Verification Log

  • 2026-06-08: superpowers:writing-plans 지침, PRD docs/20260608_크리에이터_랭킹_페이지/prd.md, 기존 홈 추천 계획 문서, fragment_v2_main_home.xml, HomeMainFragment, AppDI, 기존 홈 추천 API/ViewModel, creatorranking 위젯 구조와 테스트 위치를 확인했다.
  • 2026-06-08: 이번 단계는 계획 문서 작성만 수행했으며 구현/빌드/테스트는 실행하지 않았다.
  • 2026-06-08: Phase 1 범위로 PRD와 기존 HomeMainFragment, fragment_v2_main_home.xml, AppDI, 홈 추천 API/Repository/ViewModel, creatorranking 위젯/테스트 구조를 재확인했다. Capsule Tab bar, 팔로잉 탭 content, analytics/logging, ViewPager2/swipe 전환은 Phase 1-3 구현 범위에서 제외했다.
  • 2026-06-08: Phase 2 TDD RED로 ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingItemTest"를 실행해 showRankChange 미구현 컴파일 실패를 확인했다. 이후 CreatorRankingItem.showRankChange 기본값을 추가하고 동일 명령이 BUILD SUCCESSFUL로 통과했다.
  • 2026-06-08: Phase 2 rank-num 숨김 TDD RED로 ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"를 실행했다. 최초 Robolectric 설정 누락으로 Koin 초기화 오류가 발생해 기존 위젯 테스트 패턴과 동일하게 @Config(sdk = [28], application = Application::class)를 적용했고, 이후 Large/Compact/Horizontal 숨김 assertion 3건 실패를 확인했다. 세 카드 view에 showRankChange=falsell_creator_ranking_deltaGONE 처리하도록 구현한 뒤 ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"BUILD SUCCESSFUL로 통과했다.
  • 2026-06-08: Phase 3 mapper TDD RED로 ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeCreatorRankingMapperTest"를 실행해 HomeCreatorRankingResponse, HomeCreatorRankingItemResponse, toCreatorRankingItems 미구현 컴파일 실패를 확인했다. 이후 DTO와 mapper를 추가하고 동일 명령이 BUILD SUCCESSFUL로 통과했다.
  • 2026-06-08: Phase 3 API/Repository를 추가한 뒤 ./gradlew :app:compileDebugKotlinBUILD SUCCESSFUL로 통과했다. 검증 중 병렬 Gradle 실행 1건에서 classes.jar zip header 오류가 발생했으나, 동일 타겟을 단독 재실행해 ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*", ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeCreatorRankingMapperTest", ./gradlew :app:compileDebugKotlin, ./gradlew :app:ktlintCheck 모두 BUILD SUCCESSFUL을 확인했다. .editorconfig disabled_rules deprecation warning은 기존 경고로 보고 수정하지 않았다.
  • 2026-06-08: Phase 4로 HomeCreatorRankingUiState, HomeCreatorRankingViewModel을 추가하고 AppDIHomeCreatorRankingApi, HomeCreatorRankingRepository, HomeCreatorRankingViewModel을 등록했다. 검증 명령 ./gradlew :app:compileDebugKotlinBUILD SUCCESSFUL로 통과했다. Gradle deprecated feature warning은 기존 빌드 경고로 보고 수정하지 않았다.
  • 2026-06-08: Phase 5.1 RED로 ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLayoutTest.home ranking layout*"를 실행해 R.id.rv_home_creator_rankings 미정의 컴파일 실패를 확인했다. 이후 fragment_v2_main_home.xmlrv_home_creator_rankingsTextTabBarView 아래 직접 constraint되는 GONE RecyclerView로 추가했고, 동일 테스트와 ./gradlew :app:mergeDebugResourcesBUILD SUCCESSFUL로 통과했다.
  • 2026-06-08: Phase 5.3 RED로 HomeMainFragmentLayoutTest에 랭킹 adapter/grid, 추천/랭킹 탭 visibility 전환, 최초 랭킹 load, ranking state observe/submit, creatorId > 0 프로필 이동 guard 계약 테스트를 추가하고 ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLayoutTest.home ranking*"를 실행해 5개 assertion 실패를 확인했다. 이후 HomeMainFragmentHomeCreatorRankingViewModel, CreatorRankingAdapter, CreatorRankingAdapter.createGridLayoutManager(requireContext()), tab index 상수, 최초 로드 guard, ranking observer, openCreatorRankingProfile guard를 연결했고 동일 테스트와 ./gradlew :app:compileDebugKotlinBUILD SUCCESSFUL로 통과했다. 기존 Gradle deprecated feature warning과 Kotlin/JDK deprecation warning은 신규 실패가 아니므로 수정하지 않았다.
  • 2026-06-08: Phase 6.1 targeted test로 ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*", ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeCreatorRankingMapperTest", ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLayoutTest"를 순차 실행했고 모두 BUILD SUCCESSFUL로 통과했다.
  • 2026-06-08: Phase 6.2 통합 검증으로 ./gradlew :app:mergeDebugResources, ./gradlew :app:compileDebugKotlin, ./gradlew :app:ktlintCheck를 순차 실행했고 모두 BUILD SUCCESSFUL로 통과했다. Gradle deprecated feature warning은 기존 빌드 경고로 보고 수정하지 않았다.
  • 2026-06-08: Phase 6.3으로 PRD와 plan-task 문서의 Verification Log를 누적하고 Phase 6 체크박스를 완료 처리했다. 이번 Phase 6에서는 신규 production code 변경이 없어 별도 RED 테스트 추가 없이 기존 targeted test와 build/lint 검증으로 완료했다.
  • 2026-06-09: 사용자 확인에 따라 순위 숫자에 별도 left margin을 추가하지 않고, Figma의 고정 텍스트 박스 내부 중앙 정렬을 맞추는 Phase 7 후속 작업을 추가했다.
  • 2026-06-09: Phase 7.1 RED로 CreatorRankingAdapterLayoutTest에 Large/Compact medium/Compact small/Horizontal 순위 박스 검증을 추가하고 ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"를 실행했다. Large/Compact medium/Compact small 3건이 Gravity.CENTER assertion에서 실패해 순위 TextView 내부 정렬 미반영을 확인했다.
  • 2026-06-09: Phase 7.2로 view_creator_ranking_large_card.xml, view_creator_ranking_compact_card.xml, view_creator_ranking_horizontal_card.xml의 순위 TextView에 android:gravity="center"를 추가했다. 동일 CreatorRankingAdapterLayoutTestBUILD SUCCESSFUL로 전환됐다.
  • 2026-06-09: Phase 7.3 검증으로 ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"./gradlew :app:mergeDebugResources를 실행했고 모두 BUILD SUCCESSFUL로 통과했다. Gradle deprecated feature warning은 기존 빌드 경고로 보고 수정하지 않았다.
  • 2026-06-09: Figma 24:5658 design context와 screenshot을 재확인했고, 순위 숫자 박스 및 rank-num 위치에서 현재 구현과 다른 최신 기준값을 Phase 8 후속 작업으로 추가했다.
  • 2026-06-09: Phase 8.1 RED로 CreatorRankingAdapterLayoutTest의 순위 숫자 박스/순위 변화 표시 위치 기대값을 Figma 24:5658 기준으로 갱신하고 실행했다. production 수정 전 1위/27위/810위 순위 박스, 11위 이후 rank group top, 1위/8~10위 rank-num 위치 assertion 6건 실패를 확인했다.
  • 2026-06-09: Phase 8.2로 CreatorRankingLargeCardView, CreatorRankingCompactCardView, CreatorRankingHorizontalCardView의 위치 계산을 Figma 기준으로 보정했다. 동일 CreatorRankingAdapterLayoutTestBUILD SUCCESSFUL로 전환됐다. New badge는 기존 PRD가 이미지 리소스 사용을 요구하고 ic_rank_new.png가 36x23으로 Figma 크기와 일치해 유지했다.
  • 2026-06-09: Phase 8.3 검증으로 ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*", ./gradlew :app:mergeDebugResources, ./gradlew :app:ktlintCheck를 실행했다. 최초 ktlint에서 테스트 파일 불필요한 빈 줄 2건이 실패해 정리했고, 이후 CreatorRankingAdapterLayoutTestktlintCheckBUILD SUCCESSFUL로 통과했다. Gradle deprecated feature warning은 기존 빌드 경고로 보고 수정하지 않았다.
  • 2026-06-25: Phase 9.1로 CreatorRankingAdapterLayoutTest에 순위 TextViewincludeFontPadding=false 유지와 variant별 하단 padding(1위 10px, 27위 6px, 810위 5px, 11위 이후 4px) 검증을 추가했다. Phase 9.2로 기존 Figma 좌표와 rank-num top/left는 유지하고 순위 TextView 내부 하단 padding만 scale 기반으로 적용했다.
  • 2026-06-25: Phase 9 검증 중 최초 병렬 Gradle 실행에서 Kotlin incremental cache 충돌과 timeout이 발생해 ./gradlew --stop, ./gradlew clean 후 순차 재실행했다. ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest", ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*", ./gradlew :app:mergeDebugResources, ./gradlew :app:compileDebugKotlin은 모두 BUILD SUCCESSFUL로 통과했다. ./gradlew :app:ktlintCheck는 변경 파일이 아닌 기존 전역 위반(Agora.kt, audio_content package-name, 기존 CreatorRankingAdapter.kt 긴 줄 등)으로 실패했으며, git diff --check는 출력 없이 통과했다.