From 3ce5cd0e3bbd834b8c8c1159eab3c6d905a7c897 Mon Sep 17 00:00:00 2001 From: klaus Date: Tue, 30 Jun 2026 02:42:56 +0900 Subject: [PATCH] =?UTF-8?q?docs(creator-ranking):=20=EB=B7=B0=20=EC=9E=AC?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20=EC=9E=91=EC=97=85=EC=9D=84=20=EA=B8=B0?= =?UTF-8?q?=EB=A1=9D=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plan-task.md | 512 ++++++++++++++++++ 1 file changed, 512 insertions(+) diff --git a/docs/20260608_크리에이터_랭킹_페이지/plan-task.md b/docs/20260608_크리에이터_랭킹_페이지/plan-task.md index 7abf6426..60294dc5 100644 --- a/docs/20260608_크리에이터_랭킹_페이지/plan-task.md +++ b/docs/20260608_크리에이터_랭킹_페이지/plan-task.md @@ -10,6 +10,21 @@ --- +## 후속 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` 표시 로직은 `CreatorRankingDeltaPresentation`과 `HomeCreatorRankingMappers` 의미를 유지한다. +- 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` @@ -375,7 +390,497 @@ --- +### Phase 10: 메인 홈 랭킹 탭 Figma 최신 시각 보정 + +- [x] **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에서 함께 보정했다. + +- [x] **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`로 통과했다. + +- [x] **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건과 기존 전역 위반이 함께 보고되어 변경 파일 줄바꿈만 수정했고, 이후 `ktlintCheck`가 `BUILD SUCCESSFUL`로 통과했다. + +--- + +### Phase 11: rank-area wrap_content 계약 보정 + +- [x] **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 중앙 정렬 계약을 기록했다. + +- [x] **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`인지 검증한다. + - 순위 `TextView`의 `Gravity.CENTER`, `includeFontPadding=false` 계약을 유지한다. + - Compact medium 순위 `54sp`/닉네임 `22sp`/rank-num `16sp`, Compact small 순위 `36sp`/닉네임 `14sp`/rank-num `14sp` 계약을 유지한다. + - Horizontal은 `ll_creator_ranking_rank_group`이 `LinearLayout.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이 실패했다. + +- [x] **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 설정을 제거했다. 동일 `CreatorRankingAdapterLayoutTest`가 `BUILD SUCCESSFUL`로 통과했다. + +- [x] **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 순위 표시 보정 + +- [x] **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 범위와 성공 기준을 반영했다. + +- [x] **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 실패를 확인했다. + +- [x] **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`로 통과했다. + +- [x] **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 문서 요구사항 정리 + +- [x] **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 요구사항만 반영되어 있다. + +- [x] **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 테스트 재작성 + +- [x] **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이 구분되어 있다. + +- [x] **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 로직 작성 + +- [x] **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가 통과한다. + +- [x] **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 + +- [x] **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 테스트가 통과한다. + +- [x] **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 + +- [x] **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가 빌드된다. + +- [x] **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 + +- [x] **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 제거 후 컴파일이 통과한다. + +- [x] **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 + +- [x] **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.xml`의 `tools: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`로 통과했다. + +- [x] **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 + +- [x] **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`로 통과했다. + +- [x] **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은 신규 변경과 무관한 기존 경고로 보고 수정하지 않았다. + +- [x] **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 보정 + +- [x] **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 동작은 변경하지 않는다. + - 검증: 후속 구현 범위와 제외 범위가 문서에 명확히 기록되어 있다. + +- [x] **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 테스트가 요청 수치를 검증한다. + +- [x] **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_group`과 `tv_creator_ranking_name`에 적용한다. + - `CreatorRankingDeltaPresentation`, delta icon margin, 순위 텍스트와 delta 사이 간격, `CreatorRankingLowerRowView`는 변경하지 않는다. + - 검증: top-card margin policy가 bind 시 적용되고 lower-row/delta spacing 변경이 없다. + +- [x] **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 표시 보정 + +- [x] **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 변경이 제외되어 있다. + +- [x] **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되지 않도록 측정된다. + +- [x] **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 적용 대상 보정 + +- [x] **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 적용 대상으로 제한되어 있다. + +- [x] **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_rank`의 `MarginLayoutParams.marginStart`만 rank별 값으로 적용한다. + - `ll_creator_ranking_rank_group`, `ll_creator_ranking_delta`, `CreatorRankingDeltaPresentation`은 변경하지 않는다. + - 검증: rank별 값은 기존 Phase 21 수치를 유지하고 적용 대상만 rank text로 제한된다. + +- [x] **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 변경 롤백 + +- [x] **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` 변경에 한정되어 있다. + +- [x] **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` + - 구현 내용: + - `rankTextStartDp`를 `rankGroupStartDp`로 되돌린다. + - `CreatorRankingTopCardView.bind()`에서 `ll_creator_ranking_rank_group`의 `MarginLayoutParams.marginStart`에 rank별 값을 다시 적용한다. + - Phase 21의 닉네임 margin 값은 유지한다. + - 검증: rank group margin application이 복원된다. + +- [x] **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` 변경을 롤백했다. `CreatorRankingTopCardMargin`은 `rankGroupStartDp` 명칭으로 복원했고, `CreatorRankingTopCardView.bind()`는 `ll_creator_ranking_rank_group`의 `MarginLayoutParams.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.rankGroupStartDp`를 `rankTextStartDp`로 정리하고, `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_name`의 `MarginLayoutParams`에만 정책을 적용했다. `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`는 출력 없이 통과했다. `compileDebugKotlin`과 `mergeDebugResources`는 위 테스트 실행 중 성공 또는 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`/`CreatorRankingLowerRowView` 및 `view_creator_ranking_top_card.xml`/`view_creator_ranking_lower_row.xml`을 `ConstraintLayout` root로 작성했다. 기존 `CreatorRankingLargeCardView`, `CreatorRankingCompactCardView`, `CreatorRankingHorizontalCardView`, `CreatorRankingLayoutCalculator`, `CreatorRankingCardVariant`와 old layout 세 개는 참조 제거 후 삭제했고, `fragment_v2_main_home.xml`의 `tools: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 순수 로직 계약만 남겼다. `CreatorRankingPlacement`는 `CreatorRankingViewType.TopTen/Lower`와 `itemsPerRow` 계약으로 갱신했고, `CreatorRankingTextStyle` 및 `CreatorRankingTextStyleTest`를 추가했다. 고정 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.xml`에 `ll_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 구현 범위에서 제외했다. @@ -399,3 +904,10 @@ - 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건이 실패해 정리했고, 이후 `CreatorRankingAdapterLayoutTest`와 `ktlintCheck`가 `BUILD SUCCESSFUL`로 통과했다. Gradle deprecated feature warning은 기존 빌드 경고로 보고 수정하지 않았다. - 2026-06-25: Phase 9.1로 `CreatorRankingAdapterLayoutTest`에 순위 `TextView`의 `includeFontPadding=false` 유지와 variant별 하단 padding(1위 10px, 2~7위 6px, 8~10위 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 실패를 확인했다. `CreatorRankingLayoutCalculatorTest`는 `8dp` 입력 기준 계산 테스트라 기존 코드에서도 통과했다. +- 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 테스트 정책을 계획 문서에 반영했다.