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

85 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.


후속 Rewrite 전제

  • 후속 구현에서는 크리에이터 랭킹 view를 기존 view 부분 보정이 아니라 새 view로 다시 작성한다.
  • 신규 크리에이터 랭킹 view는 ConstraintLayout을 사용하고 FrameLayout을 사용하지 않는다.
  • Figma 기준은 1 per row 24:5659, 2 per row 24:5660, 3 per row 24:5668, 11~20 lower row 24:5670이다.
  • adapter view type은 ranks 1~10, ranks 11~20 두 개만 둔다.
  • rank > 20은 이번 문서 갱신 및 후속 rewrite 계획에서 mapper/API 동작을 변경하지 않는다. 별도 요구가 있기 전까지 현재 lower-row 처리 방식은 유지할 수 있다.
  • rank change와 NEW 표시 로직은 CreatorRankingDeltaPresentationHomeCreatorRankingMappers 의미를 유지한다.
  • ranks 1~10 텍스트 크기 정책은 1 item row rank/name/delta 96sp/32sp/16sp, 2 item row 54sp/22sp/16sp, 3 item row 36sp/14sp/14sp이다.
  • ranks 11~20은 Figma 24:5670 lower-row 기준으로 rank 40sp, name 18sp를 사용한다.
  • XML/Kotlin에서 layout sizing 목적으로 고정 width/height를 새로 도입하지 않는다. wrap_content, match_parent, margins, padding, constraints, match-constraint, 측정된 available width, aspect handling을 필요에 따라 사용한다.
  • 테스트는 placement, text-style model, mapper, delta presentation, item behavior 같은 logic contract에만 작성한다.
  • view size, margin, padding, constraints, TextView dimensions, inflated layout params, visibility attributes를 검증하는 UI layout/visual 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 누적.

Phase 10: 메인 홈 랭킹 탭 Figma 최신 시각 보정

  • Task 10.1: Figma 최신 텍스트 크기와 item 간격 RED 테스트 추가

    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapterLayoutTest.kt
    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingLayoutCalculatorTest.kt
    • 구현 내용:
      • Figma 24:5668 기준 3열 Compact 순위 36sp, 닉네임 14sp, rank-num 숫자 14sp를 검증한다.
      • Figma 24:5661 기준 2열 Compact 순위 54sp, 닉네임 22sp, rank-num 숫자 16sp를 회귀 검증한다.
      • Figma 24:5670 기준 11위 이후 Horizontal rank group 내부 세로 배치와 New/순위 변동 표시를 검증한다.
      • 랭킹 item 간격 8dp 기준으로 2열/3열 item 폭 계산을 검증한다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingLayoutCalculatorTest"
    • 기대 결과: production 수정 전 3열 Compact 순위/변동 텍스트 크기와 item 간격 assertion이 실패한다.
    • 검증 기록: production 수정 전 CreatorRankingAdapterLayoutTest를 실행해 3열 Compact 순위 텍스트 크기 assertion 실패를 확인했다. CreatorRankingLayoutCalculatorTest는 계산기에 8dp를 직접 전달하는 순수 계산 테스트라 기존 코드에서도 통과했으며, Adapter의 실제 간격 상수는 Task 10.2에서 함께 보정했다.
  • Task 10.2: Compact 텍스트 크기와 랭킹 item 간격 보정

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingCompactCardView.kt
    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapter.kt
    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt
    • 구현 내용:
      • 3열 Compact 순위 텍스트를 36sp, rank-num 숫자를 14sp로 보정한다.
      • 2열 Compact 순위 54sp, 닉네임 22sp, rank-num 숫자 16sp는 유지한다.
      • 랭킹 item 폭 계산 기준과 실제 RecyclerView item decoration 간격을 8dp로 보정한다.
      • 11위 이후 Horizontal rank group의 기존 세로 배치와 New badge 크기는 유지한다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingLayoutCalculatorTest"
    • 기대 결과: RED 테스트가 BUILD SUCCESSFUL로 전환된다.
    • 검증 기록: CreatorRankingCompactCardView에서 3열 Compact 순위 36sp, rank-num 숫자 14sp를 적용하고 2열 Compact rank-num 숫자 16sp를 명시 유지했다. CreatorRankingAdapter의 폭 계산 상수를 8dp로 보정하고, 실제 GridLayoutManager 배치에서도 인접 item offset 합이 8dp가 되도록 전용 CreatorRankingItemDecoration을 추가했다. HomeMainFragment에는 중복 추가 방지 조건과 함께 decoration을 연결했다. 병렬 Gradle 실행 중 Kotlin incremental cache 충돌이 발생해 ./gradlew --stop, ./gradlew clean 후 순차 재실행했고, CreatorRankingAdapterLayoutTest, CreatorRankingLayoutCalculatorTest, HomeMainFragmentLayoutTest.home ranking fragment wires adapter and grid layout manager가 모두 BUILD SUCCESSFUL로 통과했다.
  • Task 10.3: 후속 검증과 문서 기록 누적

    • 실행:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"
      • ./gradlew :app:mergeDebugResources
      • ./gradlew :app:compileDebugKotlin
      • ./gradlew :app:ktlintCheck
    • 수정: docs/20260608_크리에이터_랭킹_페이지/prd.md
    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 기대 결과: 신규 변경 관련 테스트와 빌드가 통과하고, ktlint 기존 전역 위반이 있으면 Verification Log에 누적한다.
    • 검증 기록: creatorranking.*, mergeDebugResources, compileDebugKotlin, ktlintCheck, git diff --check를 실행했다. 최초 ktlintCheck에서 변경 파일인 CreatorRankingAdapter.kt 긴 줄 1건과 기존 전역 위반이 함께 보고되어 변경 파일 줄바꿈만 수정했고, 이후 ktlintCheckBUILD SUCCESSFUL로 통과했다.

Phase 11: rank-area wrap_content 계약 보정

  • Task 11.1: PRD/계획 문서에 후속 계약 반영

    • 수정: docs/20260608_크리에이터_랭킹_페이지/prd.md
    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 구현 내용:
      • 순위 숫자 TextView의 XML/Kotlin width/height는 모든 variant에서 wrap_content를 유지한다.
      • Kotlin은 순위 숫자/닉네임/rank-num 텍스트 크기와 rank area의 spacing/margin만 조정한다.
      • 순위 숫자와 rank-num은 Large/Compact/Horizontal의 rank area 안에서 함께 가운데 정렬한다.
    • 검증: 구현 전 문서에 Phase 11 후속 범위와 성공 기준을 한국어로 기록한다.
    • 검증 기록: 구현 전 PRD와 plan-task에 rank TextView wrap_content 유지, Kotlin의 텍스트 크기/spacing/margin 조정 범위, rank와 rank-num의 rank area 중앙 정렬 계약을 기록했다.
  • Task 11.2: rank-area 계약 테스트 갱신

    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapterLayoutTest.kt
    • 구현 내용:
      • Large, Compact medium, Compact small, Horizontal의 tv_creator_ranking_rank width/height가 ViewGroup.LayoutParams.WRAP_CONTENT인지 검증한다.
      • 순위 TextViewGravity.CENTER, includeFontPadding=false 계약을 유지한다.
      • Compact medium 순위 54sp/닉네임 22sp/rank-num 16sp, Compact small 순위 36sp/닉네임 14sp/rank-num 14sp 계약을 유지한다.
      • Horizontal은 ll_creator_ranking_rank_groupLinearLayout.VERTICAL, Gravity.CENTER, rank child wrap_content를 유지하는지 검증한다.
      • Large/Compact는 rank group 안에서 순위와 rank-num이 함께 중앙 정렬되는지 검증한다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"
    • 기대 결과: production 수정 전 고정 width/height assertion 변경에 따라 실패한다.
    • 검증 기록: production 수정 전 실행 결과 Large/Compact는 ll_creator_ranking_rank_group 미구현으로 실패했고, Horizontal은 rank TextView 고정 layoutParams 때문에 wrap_content assertion이 실패했다.
  • Task 11.3: Large/Compact/Horizontal rank-area 최소 구현

    • 수정: 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
    • 수정: 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
    • 구현 내용:
      • Large/Compact는 순위 숫자와 ll_creator_ranking_delta를 rank group으로 묶고 group을 rank area 중앙 정렬 기준으로 배치한다.
      • Horizontal은 기존 rank group 세로/중앙 정렬을 유지하되 rank TextView 고정 width/height 설정을 제거한다.
      • Kotlin에서 tv_creator_ranking_rank에 고정 width/height를 설정하지 않고, 텍스트 크기와 rank/delta spacing만 조정한다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"
    • 기대 결과: 갱신된 rank-area 계약 테스트가 BUILD SUCCESSFUL로 통과한다.
    • 검증 기록: Large/Compact XML에 rank group을 추가해 순위 숫자와 ll_creator_ranking_delta를 함께 세로 중앙 정렬했고, Large/Compact/Horizontal Kotlin에서 rank TextView 고정 width/height 설정을 제거했다. 동일 CreatorRankingAdapterLayoutTestBUILD SUCCESSFUL로 통과했다.
  • Task 11.4: 후속 검증과 문서 기록 누적

    • 실행:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"
      • ./gradlew :app:mergeDebugResources
      • ./gradlew :app:compileDebugKotlin
    • 수정: docs/20260608_크리에이터_랭킹_페이지/prd.md
    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 기대 결과: 모두 BUILD SUCCESSFUL, Verification Log에 한국어로 결과 누적.
    • 검증 기록: CreatorRankingAdapterLayoutTest, mergeDebugResources, compileDebugKotlin이 모두 BUILD SUCCESSFUL로 통과했다. rg로 Kotlin 내 rank TextView 고정 sizing 잔여 없음과 XML wrap_content 유지를 확인했다.

Phase 12: 8~10위 Compact small 순위 표시 보정

  • Task 12.1: 8~10위 Compact small 문제 원인 확인과 문서 반영

    • 수정: docs/20260608_크리에이터_랭킹_페이지/prd.md
    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 구현 내용:
      • tv_creator_ranking_rank 자체는 wrap_content지만, Compact small parent ll_creator_ranking_rank_group 폭이 52 * scale로 고정되어 10 표시가 답답해질 수 있음을 기록한다.
      • 8~10위 Compact small rank group은 wrap_content로 유지한다.
      • 8~10위 Compact small rank와 rank-num 간격은 Kotlin margin으로 더 좁힌다.
      • 8~10위 Compact small 닉네임은 14sp보다 작게 표시한다.
    • 검증 기록: 직접 파일 확인과 병렬 explore 결과 모두 CreatorRankingCompactCardView.positionSmall()의 rank group 고정 폭을 핵심 원인으로 지목했다. 구현 전 PRD와 plan-task에 Phase 12 범위와 성공 기준을 반영했다.
  • Task 12.2: Compact small rank=10/parent wrap_content RED 테스트 갱신

    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapterLayoutTest.kt
    • 구현 내용:
      • 실제 3열 카드 폭에 가까운 119x119 조건에서 rank=10 bind 후 순위 텍스트가 10인지 검증한다.
      • Compact small rank group width가 WRAP_CONTENT인지 검증한다.
      • Compact small 닉네임 텍스트 크기가 13sp인지 검증한다.
      • Compact small rank-num top margin이 음수 보정되어 rank와 rank-num 간격이 줄어드는지 검증한다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"
    • 기대 결과: production 수정 전 rank group fixed width, 닉네임 14sp, rank-num margin 미보정으로 실패한다.
    • 검증 기록: production 수정 전 실행해 Compact small rank group width assertion 실패를 확인했다.
  • Task 12.3: Compact small rank group/간격/닉네임 최소 보정

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingCompactCardView.kt
    • 구현 내용:
      • Compact small에서 rank group width를 WRAP_CONTENT로 변경한다.
      • Compact small 닉네임 텍스트 크기를 13sp로 줄인다.
      • Compact small rank-num top margin을 scale 기반 음수 margin으로 설정해 rank와 rank-num 간격을 좁힌다.
      • Large, Compact medium, Horizontal, API/ViewModel/Adapter 동작은 변경하지 않는다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"
    • 기대 결과: 갱신된 테스트가 BUILD SUCCESSFUL로 통과한다.
    • 검증 기록: CreatorRankingCompactCardView.positionSmall()에서 rank group width를 WRAP_CONTENT로 변경하고, 닉네임을 13sp로 줄였으며, rank-num top margin을 -4 * scale로 보정했다. 동일 테스트가 BUILD SUCCESSFUL로 통과했다.
  • Task 12.4: 후속 검증과 문서 기록 누적

    • 실행:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"
      • ./gradlew :app:mergeDebugResources
      • ./gradlew :app:compileDebugKotlin
      • ./gradlew :app:ktlintCheck
    • 수정: docs/20260608_크리에이터_랭킹_페이지/prd.md
    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 기대 결과: 모두 BUILD SUCCESSFUL, Verification Log에 한국어로 결과 누적.
    • 검증 기록: CreatorRankingAdapterLayoutTest, mergeDebugResources, compileDebugKotlin, ktlintCheck, git diff --check가 모두 통과했다. 병렬 Gradle 실행 중 Kotlin incremental cache 충돌이 있었으나 ./gradlew --stop 후 순차 재실행으로 통과했다.

Phase 13: Rewrite 문서 요구사항 정리

  • Task 13.1: PRD에 rewrite scope와 제약 추가

    • 수정: docs/20260608_크리에이터_랭킹_페이지/prd.md
    • 구현 내용:
      • 크리에이터 랭킹 view를 새로 작성하는 후속 범위를 추가한다.
      • 신규 view는 ConstraintLayout을 사용하고 FrameLayout을 사용하지 않는다고 명시한다.
      • adapter view type은 ranks 1~10, ranks 11~20 두 개만 둔다고 명시한다.
      • rank > 20은 이번 문서 갱신에서 mapper/API 동작을 바꾸지 않고, 별도 요구 전까지 현재 lower-row 처리를 유지할 수 있다고 기록한다.
    • 검증: PRD에 production code 변경 없이 rewrite 요구사항만 반영되어 있다.
  • Task 13.2: plan-task에 Phase 13 이후 구현 계획 추가

    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 구현 내용:
      • Phase 13 이후를 unchecked 상태로 추가한다.
      • 단계 순서는 docs, logic-only test rewrite, placement/text-style logic, adapter two-view rewrite, ConstraintLayout view rewrite, obsolete FrameLayout cleanup, home integration cleanup, final validation이다.
      • 기존 Verification Log는 삭제하거나 덮어쓰지 않고 새 기록만 추가한다.
    • 검증: Phase 12 이후에 Phase 13 이상이 이어지고 모든 신규 task가 - [ ] 상태다.

Phase 14: Logic-only 테스트 재작성

  • Task 14.1: 기존 UI layout/visual 테스트 제거 대상 분류

    • 확인: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapterLayoutTest.kt
    • 확인: app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragmentLayoutTest.kt
    • 구현 내용:
      • view size, margin, padding, constraints, TextView dimensions, inflated layout params, visibility attributes 검증을 제거 대상으로 분류한다.
      • placement, text-style model, mapper, delta presentation, item behavior 검증은 logic contract 테스트로 유지하거나 이동한다.
    • 검증: 후속 테스트 작업에서 삭제할 UI layout/visual assertion과 유지할 logic assertion이 구분되어 있다.
  • Task 14.2: logic contract 테스트로 재작성

    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingItemTest.kt
    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingLayoutCalculatorTest.kt
    • 수정 또는 생성: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingPlacementTest.kt
    • 수정 또는 생성: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTextStyleTest.kt
    • 구현 내용:
      • ranks 1~10, ranks 11~20 구분을 순수 로직으로 검증한다.
      • 1 item row, 2 item row, 3 item row, lower-row text style model을 검증한다.
      • CreatorRankingDeltaPresentation의 기존 NEW, 상승, 하락, 유지 의미를 유지한다.
      • HomeCreatorRankingMappers의 기존 rank change 및 showRankChange 의미를 유지한다.
    • 제외:
      • 실제 view 크기, margin, padding, constraints, inflated layout params, visibility attributes assertion 추가 금지.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"
    • 기대 결과: logic contract 테스트만 남고 UI layout/visual test는 없다.

Phase 15: Placement와 text-style 로직 작성

  • Task 15.1: rank placement model 작성

    • 수정 또는 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingPlacement.kt
    • 구현 내용:
      • adapter position과 rank를 기준으로 1 item row, 2 item row, 3 item row, lower row를 결정한다.
      • ranks 1~10은 상위 view type 안에서 row basis를 결정한다.
      • ranks 11~20은 lower-row basis를 사용한다.
      • rank > 20은 mapper/API 동작 변경 없이 현재 lower-row 처리와 호환되게 둔다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingPlacementTest"
    • 기대 결과: placement logic contract가 통과한다.
  • Task 15.2: text-style model 작성

    • 수정 또는 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTextStyle.kt
    • 구현 내용:
      • 1 item row rank/name/delta 96sp/32sp/16sp
      • 2 item row rank/name/delta 54sp/22sp/16sp
      • 3 item row rank/name/delta 36sp/14sp/14sp
      • ranks 11~20 lower-row rank/name 40sp/18sp
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingTextStyleTest"
    • 기대 결과: text-style logic contract가 통과한다.

Phase 16: Adapter two-view rewrite

  • Task 16.1: adapter view type을 두 개로 축소

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapter.kt
    • 구현 내용:
      • view type은 ranks 1~10, ranks 11~20 두 개만 둔다.
      • ranks 1~10 view holder는 placement model로 1 item row, 2 item row, 3 item row 표현을 선택한다.
      • ranks 11~20 view holder는 lower-row 표현을 사용한다.
      • rank > 20은 별도 mapper/API 변경 없이 현재 lower-row 처리와 호환되게 둔다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"
    • 기대 결과: adapter view type logic 테스트가 통과한다.
  • Task 16.2: adapter item behavior 유지

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingAdapter.kt
    • 구현 내용:
      • CreatorRankingItem.isTouchable와 click listener 동작을 유지한다.
      • showRankChange=false 의미는 delta presentation 적용 경로에서 유지한다.
      • creatorId=0 item 클릭 불가 계약을 유지한다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingItemTest"
    • 기대 결과: 기존 item behavior가 회귀하지 않는다.

Phase 17: ConstraintLayout view rewrite

  • Task 17.1: ranks 1~10 view를 ConstraintLayout으로 작성

    • 수정 또는 생성: app/src/main/res/layout/view_creator_ranking_top_card.xml
    • 수정 또는 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTopCardView.kt
    • 구현 내용:
      • root는 ConstraintLayout을 사용한다.
      • FrameLayout은 사용하지 않는다.
      • Figma 24:5659, 24:5660, 24:5668 기준으로 1 item row, 2 item row, 3 item row 표현을 처리한다.
      • 고정 width/height를 layout sizing 목적으로 새로 도입하지 않는다.
      • wrap_content, match_parent, margins, padding, constraints, match-constraint, 측정된 available width, aspect handling을 필요에 따라 사용한다.
    • 검증 명령: ./gradlew :app:mergeDebugResources
    • 기대 결과: 신규 XML resource가 빌드된다.
  • Task 17.2: ranks 11~20 view를 ConstraintLayout으로 작성

    • 수정 또는 생성: app/src/main/res/layout/view_creator_ranking_lower_row.xml
    • 수정 또는 생성: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingLowerRowView.kt
    • 구현 내용:
      • root는 ConstraintLayout을 사용한다.
      • FrameLayout은 사용하지 않는다.
      • Figma 24:5670 lower-row basis를 사용한다.
      • rank 40sp, name 18sp를 적용한다.
      • rank change와 NEW 표시 의미는 CreatorRankingDeltaPresentation 경로를 유지한다.
    • 검증 명령: ./gradlew :app:mergeDebugResources
    • 기대 결과: lower-row XML resource가 빌드된다.

Phase 18: Obsolete FrameLayout cleanup

  • Task 18.1: obsolete FrameLayout 기반 view 제거

    • 수정 또는 삭제: 기존 creatorranking legacy card view XML/Kotlin 중 더 이상 참조되지 않는 파일
    • 구현 내용:
      • 새 adapter가 참조하지 않는 FrameLayout 기반 card view 파일을 제거한다.
      • 참조가 남은 legacy 파일은 삭제하지 않고 호출 경로를 먼저 끊는다.
      • 리소스 id, binding import, unused import 중 이번 변경으로 생긴 잔여만 정리한다.
    • 검증 명령: ./gradlew :app:compileDebugKotlin
    • 기대 결과: obsolete view 제거 후 컴파일이 통과한다.
  • Task 18.2: FrameLayout 신규 사용 금지 확인

    • 확인: app/src/main/res/layout/
    • 확인: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/
    • 구현 내용:
      • 후속 rewrite로 추가한 creator ranking view에 FrameLayout이 없는지 확인한다.
      • production code 또는 tests에 불필요한 obsolete view 참조가 남지 않았는지 확인한다.
    • 검증: 검색 결과에서 신규 creator ranking view의 FrameLayout 사용이 없다.

Phase 19: Home integration cleanup

  • Task 19.1: 홈 랭킹 연결부 정리

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/main/HomeMainFragment.kt
    • 구현 내용:
      • 새 adapter와 view holder 생성 경로를 연결한다.
      • 기존 HomeCreatorRankingMappers 의미를 바꾸지 않는다.
      • 기존 tab 전환, 최초 로드, empty/error 처리, profile 이동 guard를 유지한다.
    • 검증 명령: ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*"
    • 기대 결과: 홈 랭킹 mapper와 item behavior가 회귀하지 않는다.
    • 검증 기록: fragment_v2_main_home.xmltools:listitem을 새 view_creator_ranking_lower_row로 갱신했고, HomeMainFragment는 기존 CreatorRankingAdapter, tab 전환, 최초 로드, empty/error 처리, profile 이동 guard 경로를 유지했다. 랭킹 관련 layout 속성 assertion은 logic/source contract 중심으로 축소했다. ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*"BUILD SUCCESSFUL로 통과했다.
  • Task 19.2: home integration 문서 기록 누적

    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 수정: docs/20260608_크리에이터_랭킹_페이지/prd.md
    • 구현 내용:
      • home integration cleanup에서 유지한 mapper/API, profile 이동, rank change 의미를 Verification Log에 누적한다.
      • 기존 Verification Log는 삭제하거나 덮어쓰지 않는다.
    • 검증: 문서 기록과 실제 구현 범위가 일치한다.
    • 검증 기록: home integration cleanup에서 mapper/API, profile 이동, rank change 의미를 변경하지 않았고, 검증 결과를 Verification Log에 누적했다.

Phase 20: Final validation

  • Task 20.1: logic-only targeted test 실행

    • 실행:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*"
    • 기대 결과: logic contract 테스트가 BUILD SUCCESSFUL로 통과한다.
    • 제외: UI layout/visual 속성 검증 테스트를 새로 작성하거나 실행 대상으로 추가하지 않는다.
    • 검증 기록: ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*", ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*", ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeCreatorRankingMapperTest"가 모두 BUILD SUCCESSFUL로 통과했다.
  • Task 20.2: build와 style 검증

    • 실행:
      • ./gradlew :app:mergeDebugResources
      • ./gradlew :app:compileDebugKotlin
      • ./gradlew :app:ktlintCheck
    • 기대 결과: 모두 BUILD SUCCESSFUL.
    • 참고: 기존 전역 경고나 기존 전역 위반이 있으면 신규 변경과 분리해 Verification Log에 기록한다.
    • 검증 기록: ./gradlew :app:mergeDebugResources, ./gradlew --no-daemon :app:compileDebugKotlin, ./gradlew --no-daemon :app:ktlintCheck, git diff --check가 모두 통과했다. 병렬 Gradle 실행 중 Kotlin incremental cache 삭제/backup 오류와 timeout이 발생했으나 ./gradlew --stop--no-daemon 순차 재실행으로 통과했다. Gradle deprecated feature warning과 기존 Kotlin warning은 신규 변경과 무관한 기존 경고로 보고 수정하지 않았다.
  • Task 20.3: 최종 문서 검증 기록 누적

    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 수정: docs/20260608_크리에이터_랭킹_페이지/prd.md
    • 구현 내용:
      • 실행한 검증 명령과 결과를 Verification Log에 누적한다.
      • ConstraintLayout 사용, FrameLayout 미사용, two-view adapter, logic-only test 정책 준수 여부를 기록한다.
      • 기존 Verification Log는 삭제하거나 덮어쓰지 않는다.
    • 검증: Phase 13~20의 체크 상태, 실제 구현 상태, 최종 검증 기록이 일치한다.
    • 검증 기록: Phase 13~20 체크 상태와 실제 구현/검증 상태를 맞추고, ConstraintLayout 사용, FrameLayout 미사용, two-view adapter, logic-only test 정책 준수 결과를 Verification Log에 누적했다.

Phase 21: 상위 랭킹 카드 margin 보정

  • Task 21.1: margin-only 후속 범위 문서화

    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 구현 내용:
      • ranks 1~10 top-card의 닉네임 margin과 순위 left margin만 보정한다.
      • rank 1 닉네임 margin은 좌/우 20dp, 아래 24dp로 적용한다.
      • ranks 2~10 닉네임 margin은 좌/우/아래 10dp로 적용한다.
      • 순위 left margin은 rank 1 10dp, ranks 2~7 8dp, ranks 8~10 6dp로 적용한다.
      • 이번 단계에서는 순위 텍스트와 delta 사이 간격, ranks 11+ lower-row delta 동작은 변경하지 않는다.
    • 검증: 후속 구현 범위와 제외 범위가 문서에 명확히 기록되어 있다.
  • Task 21.2: top-card margin policy logic 추가

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTopCardMargin.kt
    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTopCardMarginTest.kt
    • 구현 내용:
      • rank 구간별 닉네임 좌/우/아래 margin과 rank group start margin을 순수 로직으로 분리한다.
      • ranks 1, 2~7, 8~10 값을 검증한다.
      • ranks 11+와 delta spacing은 테스트 대상에 포함하지 않는다.
    • 검증: margin policy 테스트가 요청 수치를 검증한다.
  • Task 21.3: top-card view에 margin policy 적용

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTopCardView.kt
    • 구현 내용:
      • CreatorRankingTopCardView.bind()에서 rank별 margin policy를 ll_creator_ranking_rank_grouptv_creator_ranking_name에 적용한다.
      • CreatorRankingDeltaPresentation, delta icon margin, 순위 텍스트와 delta 사이 간격, CreatorRankingLowerRowView는 변경하지 않는다.
    • 검증: top-card margin policy가 bind 시 적용되고 lower-row/delta spacing 변경이 없다.
  • Task 21.4: 후속 검증과 문서 기록 누적

    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 실행:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"
      • ./gradlew :app:mergeDebugResources
      • ./gradlew :app:compileDebugKotlin
      • ./gradlew :app:ktlintCheck
      • git diff --check
    • 기대 결과: 모두 BUILD SUCCESSFUL 또는 출력 없음.
    • 검증 기록: 실행 결과와 lower-row/delta spacing 제외 여부를 Verification Log에 누적한다.

Phase 22: 하위 랭킹 delta 표시 보정

  • Task 22.1: lower-row delta 표시 보정 범위 문서화

    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 구현 내용:
      • ranks 1~10과 ranks 11~20의 delta 표시 정책은 동일하게 showRankChange를 따른다.
      • ranks 11~20에서만 delta가 보이지 않는 문제는 mapper/API 의미 변경이 아니라 lower-row layout/measurement clipping 가능성으로 처리한다.
      • top-card rank/delta/name 및 lower-row rank/delta/name TextView는 이미 includeFontPadding=false이므로, 이번 단계에서는 top-card 순위 텍스트와 delta 사이 간격을 변경하지 않는다.
      • 3열 grid의 delta amount text size는 14sp이고, NEW 표시는 text가 아니라 36dp x 23dp image presentation임을 확인한다.
    • 검증: 구현 범위가 lower-row delta visibility 보정으로 제한되고 API/mapper/top-card spacing 변경이 제외되어 있다.
  • Task 22.2: lower-row measurement clipping 최소 보정

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingLowerRowView.kt
    • 구현 내용:
      • lower-row의 기존 Figma 비율 height를 기본값으로 유지하되, rank group content가 잘리지 않도록 필요한 최소 height를 함께 고려한다.
      • showRankChange=false 숨김 의미와 CreatorRankingDeltaPresentation 적용 의미는 변경하지 않는다.
      • HomeCreatorRankingMappers, API DTO, CreatorRankingTopCardView, top-card XML은 변경하지 않는다.
    • 검증: ranks 11~20 lower-row에서 delta group이 clipping되지 않도록 측정된다.
  • Task 22.3: 후속 검증과 문서 기록 누적

    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 실행:
      • ./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
      • git diff --check
    • 기대 결과: 모두 BUILD SUCCESSFUL 또는 출력 없음.
    • 검증 기록: lower-row delta visibility 보정, top-card spacing 미변경, 3열 delta text/NEW image 차이를 Verification Log에 누적한다.

Phase 23: 상위 랭킹 순위 텍스트 margin 적용 대상 보정

  • Task 23.1: rank text margin 대상 보정 범위 문서화

    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 구현 내용:
      • Phase 21의 순위 left margin은 rank/delta를 감싸는 ll_creator_ranking_rank_group이 아니라 tv_creator_ranking_rank에만 적용한다.
      • rank delta 위치와 rank group 자체 위치는 변경하지 않는다.
      • 닉네임 margin 정책은 기존 Phase 21 값을 유지한다.
    • 검증: 보정 범위가 rank text start margin 적용 대상으로 제한되어 있다.
  • Task 23.2: top-card margin policy와 적용 대상 보정

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTopCardMargin.kt
    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTopCardView.kt
    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTopCardMarginTest.kt
    • 구현 내용:
      • margin policy 명칭을 rank group start가 아닌 rank text start 의미로 정리한다.
      • CreatorRankingTopCardView.bind()에서 tv_creator_ranking_rankMarginLayoutParams.marginStart만 rank별 값으로 적용한다.
      • ll_creator_ranking_rank_group, ll_creator_ranking_delta, CreatorRankingDeltaPresentation은 변경하지 않는다.
    • 검증: rank별 값은 기존 Phase 21 수치를 유지하고 적용 대상만 rank text로 제한된다.
  • Task 23.3: 후속 검증과 문서 기록 누적

    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 실행:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"
      • ./gradlew :app:mergeDebugResources
      • ./gradlew :app:compileDebugKotlin
      • ./gradlew :app:ktlintCheck
      • git diff --check
    • 기대 결과: 모두 BUILD SUCCESSFUL 또는 출력 없음.
    • 검증 기록: rank text margin 적용 대상 보정 결과를 Verification Log에 누적한다.

Phase 24: rankTextStartDp 변경 롤백

  • Task 24.1: rankTextStartDp 롤백 범위 문서화

    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 구현 내용:
      • Phase 23의 rankTextStartDp 변경을 롤백한다.
      • margin policy 명칭과 적용 대상을 Phase 21의 rankGroupStartDp 기준으로 되돌린다.
      • 닉네임 margin, lower-row delta measurement, API/mapper 의미는 변경하지 않는다.
    • 검증: 롤백 범위가 rankTextStartDp 변경에 한정되어 있다.
  • Task 24.2: rankGroupStartDp 적용 복원

    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTopCardMargin.kt
    • 수정: app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTopCardView.kt
    • 수정: app/src/test/java/kr/co/vividnext/sodalive/v2/widget/creatorranking/CreatorRankingTopCardMarginTest.kt
    • 구현 내용:
      • rankTextStartDprankGroupStartDp로 되돌린다.
      • CreatorRankingTopCardView.bind()에서 ll_creator_ranking_rank_groupMarginLayoutParams.marginStart에 rank별 값을 다시 적용한다.
      • Phase 21의 닉네임 margin 값은 유지한다.
    • 검증: rank group margin application이 복원된다.
  • Task 24.3: 롤백 검증과 문서 기록 누적

    • 수정: docs/20260608_크리에이터_랭킹_페이지/plan-task.md
    • 실행:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*"
      • ./gradlew :app:mergeDebugResources
      • ./gradlew :app:compileDebugKotlin
      • ./gradlew :app:ktlintCheck
      • git diff --check
    • 기대 결과: 모두 BUILD SUCCESSFUL 또는 출력 없음.
    • 검증 기록: rankTextStartDp 변경 롤백 결과를 Verification Log에 누적한다.

Verification Log

  • 2026-06-30: Phase 24로 사용자 요청에 따라 Phase 23의 rankTextStartDp 변경을 롤백했다. CreatorRankingTopCardMarginrankGroupStartDp 명칭으로 복원했고, CreatorRankingTopCardView.bind()ll_creator_ranking_rank_groupMarginLayoutParams.marginStart에 rank별 값을 다시 적용한다. 닉네임 margin, lower-row delta measurement, API/mapper 의미는 변경하지 않았다. 검증으로 ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*", ./gradlew --no-daemon :app:mergeDebugResources, ./gradlew --no-daemon :app:compileDebugKotlin, ./gradlew --no-daemon :app:ktlintCheck, git diff --check가 모두 BUILD SUCCESSFUL 또는 출력 없음으로 통과했다. Gradle deprecated warning과 .editorconfig disabled_rules deprecation warning은 기존 경고로 보고 수정하지 않았다.
  • 2026-06-30: Phase 23으로 Phase 21의 순위 left margin 적용 대상을 ll_creator_ranking_rank_group에서 tv_creator_ranking_rank로 보정했다. CreatorRankingTopCardMargin.rankGroupStartDprankTextStartDp로 정리하고, CreatorRankingTopCardView.bind()에서는 rank text의 MarginLayoutParams.marginStart에만 rank별 값을 적용한다. rank delta 위치와 rank group 자체 위치, 닉네임 margin 정책, CreatorRankingDeltaPresentation은 변경하지 않았다. 검증으로 ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*", ./gradlew --no-daemon :app:mergeDebugResources, ./gradlew --no-daemon :app:compileDebugKotlin, ./gradlew --no-daemon :app:ktlintCheck, git diff --check가 모두 BUILD SUCCESSFUL 또는 출력 없음으로 통과했다. Gradle deprecated warning과 .editorconfig disabled_rules deprecation warning은 기존 경고로 보고 수정하지 않았다.
  • 2026-06-30: Phase 22로 ranks 11~20 lower-row delta가 ranks 1~10과 동일하게 showRankChange 정책을 따르도록 유지하면서, delta가 보이지 않는 원인을 lower-row measurement clipping 가능성으로 보고 CreatorRankingLowerRowView.onMeasure()를 보정했다. 기존 Figma 비율 height를 기본값으로 유지하되 rank group measured height와 root vertical padding 합보다 작아지지 않도록 재측정한다. HomeCreatorRankingMappers, API DTO, CreatorRankingDeltaPresentation, showRankChange 의미, top-card rank/delta spacing은 변경하지 않았다. top-card/lower-row rank/delta/name은 이미 includeFontPadding=false라 추가 font padding 변경은 하지 않았고, 3열 grid delta amount text는 14sp, NEW는 text가 아니라 36dp x 23dp image presentation임을 확인했다. 검증으로 ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*", ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*", ./gradlew --no-daemon :app:mergeDebugResources, ./gradlew --no-daemon :app:compileDebugKotlin, ./gradlew --no-daemon :app:ktlintCheck, git diff --check가 모두 BUILD SUCCESSFUL 또는 출력 없음으로 통과했다. home test 실행 중 Kotlin incremental cache registration 오류가 있었으나 fallback 후 BUILD SUCCESSFUL로 종료했다. Gradle deprecated warning과 .editorconfig disabled_rules deprecation warning은 기존 경고로 보고 수정하지 않았다.
  • 2026-06-30: Phase 21 margin-only 후속으로 CreatorRankingTopCardMargin 순수 로직과 CreatorRankingTopCardMarginTest를 추가해 rank 1, 2~7, 8~10의 닉네임 좌/우/하단 margin 및 rank group start margin 값을 검증했다. CreatorRankingTopCardView.bind()에서는 기존 ll_creator_ranking_rank_group, tv_creator_ranking_nameMarginLayoutParams에만 정책을 적용했다. CreatorRankingDeltaPresentation, delta icon margin, showRankChange, CreatorRankingLowerRowView, lower-row XML, content ranking 파일은 변경하지 않았다. 검증으로 ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingTopCardMarginTest", ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*", ./gradlew :app:ktlintCheck가 모두 BUILD SUCCESSFUL로 통과했고, GIT_MASTER=1 git diff --check는 출력 없이 통과했다. compileDebugKotlinmergeDebugResources는 위 테스트 실행 중 성공 또는 up-to-date로 확인했다. Gradle deprecated feature warning과 .editorconfig disabled_rules deprecation warning은 기존 경고로 보고 수정하지 않았다.
  • 2026-06-29: Phase 19~20 최종 검증으로 fragment_v2_main_home.xml의 ranking list preview를 새 view_creator_ranking_lower_row로 갱신하고, HomeMainFragment의 기존 adapter 연결, tab 전환, 최초 로드, empty/error 처리, profile 이동 guard, mapper/API 의미가 유지됨을 확인했다. HomeMainFragmentLayoutTest의 랭킹 layout 속성 assertion은 logic/source contract 중심으로 축소했다.
  • 2026-06-29: 최종 검증으로 ./gradlew :app:mergeDebugResources, ./gradlew --no-daemon :app:compileDebugKotlin, ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*", ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeCreatorRankingMapperTest", ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLayoutTest", ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*", ./gradlew --no-daemon :app:ktlintCheck, git diff --check가 모두 BUILD SUCCESSFUL 또는 출력 없음으로 통과했다. rg로 신규 creator ranking XML/Kotlin에 FrameLayout 사용이 없고, old Large/Compact/Horizontal/LayoutCalculator/CardVariant/CardSize/setCardSize 참조가 creator ranking 범위에 남지 않았음을 확인했다. 병렬 Gradle 실행 중 Kotlin incremental cache 삭제/backup 오류와 timeout이 있었으나 ./gradlew --stop--no-daemon 순차 재실행으로 통과했다.
  • 2026-06-29: Phase 16~18로 CreatorRankingAdapter의 내부 view type을 ranks 1~10 top-card와 ranks 11+ lower-row 두 개로 축소하고, 새 CreatorRankingTopCardView/CreatorRankingLowerRowViewview_creator_ranking_top_card.xml/view_creator_ranking_lower_row.xmlConstraintLayout root로 작성했다. 기존 CreatorRankingLargeCardView, CreatorRankingCompactCardView, CreatorRankingHorizontalCardView, CreatorRankingLayoutCalculator, CreatorRankingCardVariant와 old layout 세 개는 참조 제거 후 삭제했고, fragment_v2_main_home.xmltools:listitem은 lower-row layout으로 갱신했다. mapper/API 동작과 content ranking 파일은 변경하지 않았고, rank gradient, CreatorRankingItem.displayName(...), isTouchable, adapter loadUrl + CreatorRankingBlur.transformations, CreatorRankingDeltaPresentation.from(...), showRankChange=false delta hide 경로, CreatorRankingTextStyle.fromRank(...) 텍스트 크기 적용을 유지했다. 검증으로 ./gradlew :app:mergeDebugResources, ./gradlew :app:compileDebugKotlin, ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*", ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeCreatorRankingMapperTest", GIT_MASTER=1 git diff --check가 모두 성공했다. rg로 creatorranking production 범위의 obsolete Large/Compact/Horizontal/LayoutCalculator/CardVariant/setCardSize/CardSize 참조와 신규 creator ranking XML/Kotlin의 FrameLayout 사용이 없음을 확인했다. Gradle deprecated feature warning 및 기존 전역 Kotlin warning은 기존 경고로 보고 수정하지 않았다.
  • 2026-06-29: Phase 14/15로 CreatorRankingAdapterLayoutTest의 Robolectric inflation 및 view size/margin/padding/constraint/TextView dimension/visibility assertion을 제거하고 span/decoration 순수 로직 계약만 남겼다. CreatorRankingPlacementCreatorRankingViewType.TopTen/LoweritemsPerRow 계약으로 갱신했고, CreatorRankingTextStyleCreatorRankingTextStyleTest를 추가했다. 고정 card dimension을 요구하던 CreatorRankingLayoutCalculatorTest는 삭제했다. 검증으로 ./gradlew :app:compileDebugKotlin, ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*", ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeCreatorRankingMapperTest"를 실행했고 모두 BUILD SUCCESSFUL로 통과했다. 최초 위젯 테스트 실행에서 Kotlin 증분 빌드 참조 오류가 한 번 발생했으나 compileDebugKotlin 재실행 후 동일 테스트가 성공했다. Gradle deprecated feature warning은 기존 경고로 보고 수정하지 않았다.
  • 2026-06-29: Phase 11 요구사항으로 rank-area 계약을 갱신했다. PRD와 계획 문서에 tv_creator_ranking_rank XML/Kotlin width/height wrap_content 유지, Kotlin의 텍스트 크기 및 spacing/margin 조정 범위, 순위 숫자와 rank-num의 rank area 중앙 정렬 기준을 먼저 반영했다.
  • 2026-06-29: Phase 11.2 RED로 ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest"를 실행해 4건 실패를 확인했다. Large/Compact는 rank group이 없어 실패했고, Horizontal은 rank TextView가 Kotlin에서 고정 layoutParams를 받아 wrap_content 계약을 위반했다.
  • 2026-06-29: Phase 11.3으로 view_creator_ranking_large_card.xml, view_creator_ranking_compact_card.xmlll_creator_ranking_rank_group을 추가해 rank와 delta를 함께 세로 중앙 정렬했다. CreatorRankingLargeCardView, CreatorRankingCompactCardView, CreatorRankingHorizontalCardView에서는 rank TextView 고정 width/height 설정을 제거하고 rank group/delta 배치만 조정했다.
  • 2026-06-29: Phase 11.4 검증으로 ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest", ./gradlew :app:mergeDebugResources, ./gradlew :app:compileDebugKotlin을 순차 실행했고 모두 BUILD SUCCESSFUL로 통과했다. rg로 Kotlin 내 rank TextView 고정 sizing 잔여 없음과 세 XML의 tv_creator_ranking_rank wrap_content 유지를 확인했다. Gradle deprecated feature warning은 기존 빌드 경고로 보고 수정하지 않았다.
  • 2026-06-29: 추가 확인 중 Horizontal rank-num 간격이 XML layout_marginTop에 남아 있어 사용자 요구사항의 Kotlin spacing 조정 범위와 맞지 않음을 확인했다. view_creator_ranking_horizontal_card.xml의 margin을 제거하고 CreatorRankingHorizontalCardView에서 scale 기반 topMargin을 설정하도록 보정했다. 이후 CreatorRankingAdapterLayoutTest, mergeDebugResources, compileDebugKotlin이 모두 BUILD SUCCESSFUL로 통과했고, rg로 XML 고정 margin 및 Kotlin rank TextView 고정 sizing 잔여 없음도 확인했다. 최초 병렬 Gradle 중 Kotlin incremental cache 충돌이 있었으나 fallback/재실행으로 성공했으며, 기존 deprecation warning은 수정하지 않았다.
  • 2026-06-29: Phase 12 요구사항으로 8~10위 Compact small의 rank/rank-num 간격 과다, rank parent 고정 폭 의심, 10 표시 문제, 닉네임 축소 요구를 분석했다. 직접 확인과 병렬 explore 결과 모두 CreatorRankingCompactCardView.positionSmall()에서 rank group 폭이 52 * scale로 고정되는 점을 핵심 원인으로 확인했고, rank TextView 자체는 XML/Kotlin 모두 wrap_content임을 확인했다.
  • 2026-06-29: Phase 12 RED로 CreatorRankingAdapterLayoutTest를 갱신해 실제 3열 폭에 가까운 119x119 조건에서 rank=10, rank group WRAP_CONTENT, 닉네임 13sp, rank-num topMargin=-4를 검증하도록 했다. production 수정 전에는 rank group fixed width assertion이 실패했고, CreatorRankingCompactCardView.positionSmall() 보정 후 동일 테스트가 BUILD SUCCESSFUL로 통과했다.
  • 2026-06-29: Phase 12 최종 검증으로 ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingAdapterLayoutTest", ./gradlew :app:mergeDebugResources, ./gradlew :app:compileDebugKotlin, ./gradlew :app:ktlintCheck, git diff --check가 통과했다. 병렬 Gradle 실행 중 Kotlin incremental cache 충돌이 있었으나 ./gradlew --stop 후 순차 재실행으로 통과했다.
  • 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는 출력 없이 통과했다.
  • 2026-06-29: Phase 10 요구사항으로 Figma 24:5668, 24:5661, 24:5670 design context와 screenshot을 확인했다. 3열 Compact는 순위 36sp, 닉네임 14sp, rank-num 숫자 14sp, 2열 Compact는 순위 54sp, 닉네임 22sp, rank-num 숫자 16sp, 11위 이후 Horizontal은 rank group 내부 세로 배치 유지, 랭킹 item 간격은 8dp로 정리했다.
  • 2026-06-29: Phase 10.1 RED로 CreatorRankingAdapterLayoutTest에 Compact 2열/3열 텍스트 크기와 Horizontal rank group 세로 배치 검증을 추가하고 실행했다. production 수정 전 3열 Compact 순위 텍스트 크기 assertion 실패를 확인했다. CreatorRankingLayoutCalculatorTest8dp 입력 기준 계산 테스트라 기존 코드에서도 통과했다.
  • 2026-06-29: Phase 10.2로 CreatorRankingCompactCardView의 3열 Compact 순위 텍스트를 36sp, rank-num 숫자를 14sp로 보정하고 2열 rank-num 숫자 16sp를 명시 유지했다. CreatorRankingAdapter의 랭킹 item 폭 계산 기준을 8dp로 변경하고, 실제 GridLayoutManager 배치에서 인접 item offset 합이 8dp가 되도록 CreatorRankingItemDecoration을 추가했다. HomeMainFragment에는 decoration을 중복 없이 적용했다.
  • 2026-06-29: Phase 10 리뷰 게이트에서 카드 폭 계산만 줄이면 실제 GridLayoutManager item 사이 간격이 8dp로 보장되지 않는다는 차단 이슈가 나왔다. 이에 CreatorRankingAdapterLayoutTest에 전용 decoration offset 계약을 추가하고, HomeMainFragmentLayoutTest.home ranking fragment wires adapter and grid layout manager에 decoration 연결 검증을 추가했다. production 수정 전에는 CreatorRankingItemDecoration 미구현 컴파일 실패를 확인했고, 구현 후 두 테스트가 BUILD SUCCESSFUL로 통과했다.
  • 2026-06-29: Phase 10 검증 중 최초 병렬 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.CreatorRankingLayoutCalculatorTest", ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.creatorranking.*", ./gradlew :app:mergeDebugResources, ./gradlew :app:compileDebugKotlin, ./gradlew :app:ktlintCheck가 모두 BUILD SUCCESSFUL로 통과했다. git diff --check도 출력 없이 통과했다.
  • 2026-06-29: Phase 13~20 후속 rewrite 계획을 추가했다. 순서는 docs, logic-only test rewrite, placement/text-style logic, adapter two-view rewrite, ConstraintLayout view rewrite, obsolete FrameLayout cleanup, home integration cleanup, final validation이며, 모든 신규 task는 구현 전 상태로 - [ ] 체크박스를 유지했다.
  • 2026-06-29: 후속 rewrite 전제로 ConstraintLayout 사용, FrameLayout 미사용, adapter view type 두 개(ranks 1~10, ranks 11~20), Figma 24:5659, 24:5660, 24:5668, 24:5670, 텍스트 크기 정책, mapper/API 변경 제외, logic-only 테스트 정책을 계획 문서에 반영했다.