From f3f175fcc65d8248572b728e85611c13a6546c39 Mon Sep 17 00:00:00 2001 From: klaus Date: Tue, 30 Jun 2026 02:42:46 +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=20PRD=EB=A5=BC=20=EB=B3=B4=EC=99=84=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/20260608_크리에이터_랭킹_페이지/prd.md | 73 +++++++++++++++++++-- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/docs/20260608_크리에이터_랭킹_페이지/prd.md b/docs/20260608_크리에이터_랭킹_페이지/prd.md index 58f0ac92..f6633b23 100644 --- a/docs/20260608_크리에이터_랭킹_페이지/prd.md +++ b/docs/20260608_크리에이터_랭킹_페이지/prd.md @@ -29,7 +29,7 @@ - 크리에이터 랭킹 위젯의 순위별 카드 variant 정책 자체를 새로 설계하지 않는다. - Figma에 없는 skeleton, shimmer, pagination, pull-to-refresh, 추가 배너, 광고 영역은 구현하지 않는다. - 서버 API 스키마를 클라이언트에서 임의로 변경하지 않는다. -- Compose 전환, ViewPager2 기반 tab swipe 전환, tab별 신규 Fragment 대량 분리는 이번 범위에 포함하지 않는다. +- ViewPager2 기반 tab swipe 전환, tab별 신규 Fragment 대량 분리는 이번 범위에 포함하지 않는다. --- @@ -142,6 +142,43 @@ - `creatorId=0`인 차단 관계 item은 상세 이동을 막고, 기존 차단 상태 위젯 정책에 따라 이미지 블러와 이름 비노출/대체문구를 적용한다. - 동일 rank가 중복되면 서버 데이터 오류로 보고 클라이언트는 받은 순서 또는 `rank` 정렬 결과를 그대로 표시한다. 중복 보정 UI는 추가하지 않는다. +### Creator Ranking View Rewrite Follow-up +크리에이터 랭킹 view는 후속 구현에서 기존 view를 부분 보정하지 않고 새로 작성한다. 이 문서 갱신은 rewrite 요구사항과 구현 계획만 정리하며, mapper/API 동작 변경이나 production code 변경은 포함하지 않는다. + +#### Figma References +- 1 per row: Figma `24:5659` +- 2 per row: Figma `24:5660` +- 3 per row: Figma `24:5668` +- 11~20: Figma `24:5670` + +#### Rewrite Requirements +- 신규 크리에이터 랭킹 view는 `ConstraintLayout`을 사용해 작성한다. +- 신규 크리에이터 랭킹 view에는 `FrameLayout`을 사용하지 않는다. +- adapter view type은 두 개만 둔다. + - ranks `1~10` + - ranks `11~20` +- `rank > 20` 값은 이번 문서 갱신에서 mapper/API 동작을 바꾸지 않는다. 별도 요구가 있기 전까지 현재 구현의 lower-row 처리 방식은 유지할 수 있다. +- rank change와 `NEW` 표시 로직은 `CreatorRankingDeltaPresentation`과 `HomeCreatorRankingMappers`의 기존 의미를 유지한다. +- `isNew`, `rankChange`, `showRankChange`, `RankingChangeType` 매핑 의미는 변경하지 않는다. + +#### Text Size Policy +| Rank group | Row basis | Rank | Name | Delta | +| --- | --- | --- | --- | --- | +| `1~10` | 1 item row | `96sp` | `32sp` | `16sp` | +| `1~10` | 2 item row | `54sp` | `22sp` | `16sp` | +| `1~10` | 3 item row | `36sp` | `14sp` | `14sp` | +| `11~20` | lower-row Figma basis | `40sp` | `18sp` | 기존 lower-row 표시 정책 유지 | + +#### View Size Policy +- XML/Kotlin에서 layout sizing 목적으로 고정 width/height를 새로 도입하지 않는다. +- layout sizing은 `wrap_content`, `match_parent`, margins, padding, constraints, match-constraint, 측정된 available width, aspect handling을 필요에 따라 조합한다. +- 텍스트 크기, rank/name/delta 배치 모델, image aspect 계산처럼 화면 표현을 결정하는 값은 순수 로직으로 분리해 테스트할 수 있게 한다. + +#### Testing Policy +- 테스트는 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는 작성하지 않는다. +- `CreatorRankingDeltaPresentation`과 `HomeCreatorRankingMappers`의 기존 rank change 및 `NEW` 의미가 유지되는지는 로직 테스트로 확인한다. + --- ## 8. UX / UI Expectations @@ -149,9 +186,11 @@ - TitleBar와 Text Tab bar는 Figma `24:5654` 및 기존 홈 추천 구현과 동일한 위치/스타일을 유지한다. - Capsule Tab bar를 제거한 상태에서도 Text Tab bar 아래 여백이 과도하게 남지 않아야 한다. - 랭킹 목록 좌우 margin과 item gap은 기존 `CreatorRankingAdapter`와 Figma 목록 폭을 기준으로 맞춘다. -- 순위 숫자는 Figma의 시각적 margin을 임의로 추가하지 않고, variant별 고정 텍스트 박스 크기 안에서 중앙 정렬해 표시한다. -- 1위, 2~7위, 8~10위, 11위 이후 순위 영역의 고정 박스 크기와 위치는 Figma `24:5658`의 최신 기준값을 따른다. -- `rank-num`은 Figma 기준 위치를 따른다. 1위는 `top=116`, 2~7위는 `top=70`, 8~10위는 `top=50`, 11위 이후는 rank group 내부 배치를 유지한다. +- 순위 숫자 `TextView`의 XML 및 Kotlin layout width/height는 `wrap_content`를 유지하고, Kotlin은 variant별 텍스트 크기와 rank area의 spacing/margin만 조정한다. +- 1위, 2~7위, 8~10위, 11위 이후 순위 영역은 rank 숫자와 rank-num을 하나의 세로 rank group으로 묶어 해당 영역 안에서 가운데 정렬한다. +- `rank-num`은 순위 숫자 아래에서 같은 rank area의 중앙 정렬 흐름을 따르며, 11위 이후 Horizontal은 기존 `ll_creator_ranking_rank_group`의 vertical/center 배치를 유지한다. +- 8~10위 Compact small은 두 자리 순위(`10`)가 잘리지 않도록 rank group도 고정 폭이 아닌 `wrap_content`로 유지하고, rank와 rank-num 사이 간격을 Kotlin margin으로 더 좁힌다. +- 8~10위 Compact small 닉네임은 3열 카드 폭에서 답답하지 않도록 기존 14sp보다 작게 표시한다. - `랭킹` 탭 선택 상태가 흰색 텍스트로 명확히 드러나야 한다. - 1위~20위까지 응답이 내려오면 Figma 예시처럼 20위까지 자연스럽게 스크롤로 확인할 수 있어야 한다. - 긴 닉네임은 기존 위젯의 ellipsize/line 제한 정책을 따른다. @@ -174,8 +213,10 @@ - `랭킹` 탭 선택 시 `GET /api/v2/home/rankings/creators` 응답 item이 `CreatorRankingAdapter`에 전달된다. - Figma `24:5654`의 Capsule Tab bar는 화면에 존재하지 않는다. - 1위, 2~7위, 8~10위, 11위 이후 variant가 기존 위젯 정책과 일치한다. -- 순위 숫자는 Figma `24:5658`의 고정 텍스트 박스 내부에서 중앙 정렬되어 동일한 시각적 좌측 여백으로 보인다. -- 1위 순위 박스는 `86x116`, 2~7위는 `56x70`, 8~10위는 `52x50`, 11위 이후 순위 텍스트는 `48x52` 기준으로 표시된다. +- 순위 숫자 `TextView`는 모든 variant에서 `wrap_content` width/height, `Gravity.CENTER`, `includeFontPadding=false`를 유지한다. +- 1위, 2~7위, 8~10위, 11위 이후 rank group은 순위 숫자와 rank-num을 같은 rank area 중앙에 세로 정렬한다. +- Kotlin은 Compact 2열 순위 `54sp`/닉네임 `22sp`/rank-num `16sp`, Compact 3열 순위 `36sp`/닉네임 `13sp`/rank-num `14sp` 텍스트 크기 계약을 유지한다. +- Compact 3열 rank group은 `wrap_content` width를 유지하고, `rank=10`도 전체 숫자가 표시되어야 한다. - `isNew=true` item은 New badge로 표시된다. - `isNew=false && (rankChange=null || rankChange=0)` item은 유지 상태로 표시된다. - `rankChange > 0` item은 상승, `rankChange < 0` item은 하락으로 표시된다. @@ -185,6 +226,11 @@ - API 응답은 클라이언트에서 `rank` 기준 오름차순으로 한 번 더 정렬된다. - 빈 응답, API 실패, 이미지 실패가 crash 없이 처리된다. - 관련 mapper/unit test, `HomeMainFragment` layout test, `compileDebugKotlin`, `ktlintCheck`가 성공한다. +- 후속 rewrite에서는 신규 크리에이터 랭킹 view가 `ConstraintLayout` 기반이고 `FrameLayout`을 사용하지 않는다. +- 후속 rewrite에서는 adapter view type이 ranks `1~10`, ranks `11~20` 두 개뿐이다. +- 후속 rewrite에서는 ranks `1~10` 텍스트 크기가 1 item row `96sp/32sp/16sp`, 2 item row `54sp/22sp/16sp`, 3 item row `36sp/14sp/14sp` rank/name/delta 정책을 따른다. +- 후속 rewrite에서는 ranks `11~20`이 Figma `24:5670` lower-row 기준으로 rank `40sp`, name `18sp`를 사용한다. +- 후속 rewrite 테스트는 logic contract 중심이며, UI layout/visual 속성 검증 테스트는 작성하지 않는다. --- @@ -195,6 +241,10 @@ ## 12. References - Figma: https://www.figma.com/design/HmN1yNdJ3EIpqknFL0Hkab/-%EA%B3%B5%EC%9C%A0%EC%9A%A9-%EB%B3%B4%EC%9D%B4%EC%8A%A4%EC%98%A8-UI-UX-%EA%B8%B0%ED%9A%8D%EB%AC%B8%EC%84%9C?node-id=24-5654&m=dev +- Figma 1 per row: `24:5659` +- Figma 2 per row: `24:5660` +- Figma 3 per row: `24:5668` +- Figma 11~20 lower row: `24:5670` - 기존 크리에이터 랭킹 위젯 PRD: `docs/prd/20260520_크리에이터랭킹위젯컴포넌트_prd.md` - 기존 홈 추천 PRD: `docs/20260601_메인_홈_추천_UI와_API_연동/prd.md` - 기존 위젯 패키지: `app/src/main/java/kr/co/vividnext/sodalive/v2/widget/creatorranking` @@ -202,6 +252,15 @@ --- ## 13. Verification Log +- 2026-06-29: 크리에이터 랭킹 view rewrite를 완료했다. `CreatorRankingAdapter`는 ranks `1~10` top-card와 ranks `11+` lower-row 두 view type만 사용하며, `CreatorRankingTopCardView`와 `CreatorRankingLowerRowView`는 `ConstraintLayout` 기반으로 작성했다. 기존 `FrameLayout` 기반 Large/Compact/Horizontal view와 layout calculator/card variant는 creator ranking 경로에서 제거했다. +- 2026-06-29: rank change와 `NEW` 표시는 `CreatorRankingDeltaPresentation`, API mapper 의미는 `HomeCreatorRankingMappers`를 유지했다. 텍스트 크기는 `CreatorRankingTextStyle` 순수 로직으로 분리했고, 테스트는 placement/text-style/mapper/delta/item behavior 같은 logic contract 중심으로 정리했다. 최종 검증으로 creator ranking tests, main.home tests, mapper test, `mergeDebugResources`, `compileDebugKotlin`, `ktlintCheck`, `git diff --check`, obsolete reference/FrameLayout 검색이 통과했다. +- 2026-06-29: 후속 요구사항으로 8~10위 Compact small에서 rank와 rank-num 간격이 넓고 `10` 표시가 답답해 보이는 문제를 확인했다. 원인은 rank `TextView`가 아니라 `CreatorRankingCompactCardView.positionSmall()`에서 parent `ll_creator_ranking_rank_group` 폭이 `52 * scale`로 고정되는 점으로 정리했다. PRD에 Compact small rank group `wrap_content`, `rank=10` 표시 보장, rank/rank-num 간격 축소, 닉네임 13sp 요구사항을 반영했다. +- 2026-06-29: Compact small 보정으로 `ll_creator_ranking_rank_group` width를 `WRAP_CONTENT`로 변경하고, 닉네임을 `13sp`로 줄였으며, rank-num top margin을 `-4 * scale`로 조정했다. `CreatorRankingAdapterLayoutTest`, `mergeDebugResources`, `compileDebugKotlin`, `ktlintCheck`, `git diff --check`가 통과했다. +- 2026-06-29: 후속 요구사항으로 크리에이터 랭킹 카드 rank-area 계약을 갱신했다. 모든 variant의 `tv_creator_ranking_rank` XML/Kotlin width/height는 `wrap_content`를 유지하고, Kotlin은 Compact medium `54sp/22sp/16sp`, Compact small `36sp/14sp/14sp` 텍스트 크기와 rank group/delta spacing만 조정하며, Large/Compact/Horizontal 모두 순위 숫자와 rank-num을 rank area 중앙에 세로 정렬해야 한다. +- 2026-06-29: `CreatorRankingAdapterLayoutTest`를 새 계약으로 갱신한 뒤 production 수정 전 실행해 Large/Compact rank group 미구현 및 Horizontal rank `TextView` 고정 layoutParams 때문에 실패함을 확인했다. 이후 Large/Compact XML에 rank group을 추가하고 Kotlin의 rank `TextView` 고정 width/height 설정을 제거했으며, `./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 `wrap_content` 유지도 확인했다. +- 2026-06-29: Horizontal rank-num 간격도 XML 고정 margin 대신 Kotlin scale 기반 spacing으로 옮겼다. 재검증으로 `CreatorRankingAdapterLayoutTest`, `mergeDebugResources`, `compileDebugKotlin`이 모두 `BUILD SUCCESSFUL`로 통과했고, `rg`로 XML 고정 margin 및 Kotlin rank `TextView` 고정 sizing 잔여 없음도 확인했다. +- 2026-06-29: 후속 요구사항으로 Figma `24:5668`, `24:5661`, `24:5670`을 확인했다. 메인 홈 랭킹 탭에서 item 간격은 `8dp`, 3열 Compact는 순위 `36sp`/닉네임 `14sp`/rank-num 숫자 `14sp`, 2열 Compact는 순위 `54sp`/닉네임 `22sp`/rank-num 숫자 `16sp`, 11위 이후 Horizontal은 순위와 New/순위 변동 표시가 rank group 내부에서 바로 이어지는 세로 배치를 유지해야 한다. +- 2026-06-29: 위 기준에 따라 `CreatorRankingCompactCardView`, `CreatorRankingAdapter`, `HomeMainFragment`를 최소 수정했다. 3열 Compact 순위/변동 텍스트 크기, item 폭 계산 기준, 실제 RecyclerView item decoration 간격 `8dp`를 보정했고, 2열 Compact 및 11위 이후 Horizontal 배치는 회귀 테스트로 유지했다. 리뷰 게이트에서 지적된 실제 `GridLayoutManager` 간격 보장 문제는 전용 `CreatorRankingItemDecoration`과 Fragment 연결 테스트를 추가해 보완했다. - 2026-06-25: Figma `24:5659`의 rank component screenshot을 확인했다. rank 숫자와 rank-num은 좌표상 분리되어 있으나, 실제 구현에서는 `includeFontPadding=false`가 이미 적용된 상태에서도 Pattaya glyph가 고정 rank box 하단에 붙어 보여 rank-num과 시각적으로 붙는 문제가 발생할 수 있음을 확인했다. - 2026-06-25: 후속 요구사항으로 크리에이터 랭킹 카드의 기존 Figma 위치값(`rank-num` top: 1위 116, 2~7위 70, 8~10위 50, 11위 이후 rank group 내부 배치)은 유지하고, 순위 숫자 `TextView` 내부 하단 padding만 보정해 폰트별 glyph 하단 차이가 rank-num 간격을 침범하지 않도록 한다. - 2026-06-25: 크리에이터 랭킹 Large/Compact/Horizontal 카드에 scale 기반 하단 padding을 적용하고, `CreatorRankingAdapterLayoutTest`에서 `includeFontPadding=false`와 padding 값을 검증하도록 했다. `CreatorRankingAdapterLayoutTest`, `creatorranking.*`, `mergeDebugResources`, `compileDebugKotlin`은 통과했고, `ktlintCheck`는 기존 전역 위반으로 실패했다. @@ -215,3 +274,5 @@ - 2026-06-09: 순위 TextView 내부 중앙 정렬 보정 후 `./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`가 모두 `BUILD SUCCESSFUL`로 통과했다. - 2026-06-09: Figma `24:5658` design context와 screenshot을 재확인해 순위 숫자 박스 및 rank-num 위치의 최신 기준값을 후속 보정 요구사항으로 반영했다. - 2026-06-09: 최신 Figma 수치 보정 후 `./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:ktlintCheck`가 모두 `BUILD SUCCESSFUL`로 통과했다. +- 2026-06-29: 후속 rewrite 범위로 크리에이터 랭킹 view를 새로 작성하는 요구사항을 추가했다. 신규 view는 `ConstraintLayout`을 사용하고 `FrameLayout`을 사용하지 않으며, adapter view type은 ranks `1~10`과 ranks `11~20` 두 개만 둔다. `rank > 20`은 이번 문서 갱신에서 mapper/API 동작을 바꾸지 않고, 별도 요구 전까지 현재 lower-row 처리를 유지할 수 있다고 기록했다. +- 2026-06-29: Figma `24:5659`, `24:5660`, `24:5668`, `24:5670` 기준과 ranks `1~10`, ranks `11~20` 텍스트 크기 정책을 추가했다. rank change와 `NEW` 로직은 `CreatorRankingDeltaPresentation` 및 `HomeCreatorRankingMappers` 의미를 유지하고, 테스트는 placement, text-style model, mapper, delta presentation, item behavior 같은 logic contract 중심으로 제한한다고 기록했다.