docs(ranking): 반응형 크기 요구를 기록한다

This commit is contained in:
2026-07-10 10:15:54 +09:00
parent bf5cc1d7bb
commit 2b2cb66dfc
2 changed files with 466 additions and 0 deletions

View File

@@ -0,0 +1,163 @@
# PRD: 메인 랭킹 UI 반응형 크기 조정
## 1. Overview
메인 홈 `랭킹` 탭의 크리에이터 랭킹과 메인 콘텐츠 `랭킹` 탭의 콘텐츠 랭킹에서 순위/순위 변동/타이틀/닉네임 크기를 402dp 기준으로 반응형 조정한다.
---
## 2. Problem
- 현재 랭킹 UI는 카드 구간별 고정 `sp`/`dp` 값 중심으로 구성되어 있어 402dp 미만 폭의 기기에서 동일한 시각 밀도를 유지하기 어렵다.
- 크리에이터 랭킹 순위 숫자 폰트는 요구사항상 `Pattaya`로 맞춰야 한다.
- 기존 글자 크기 자체는 402dp 이상 기기에서 유지해야 하므로, 무조건적인 크기 변경이 아니라 화면 폭 기준 축소 정책이 필요하다.
- 크리에이터 랭킹과 콘텐츠 랭킹이 유사한 랭킹 구조를 사용하므로, 402dp 기준 동작을 두 위젯에 일관되게 적용해야 한다.
---
## 3. Goals
- 크리에이터 랭킹 순위 숫자 폰트를 `Pattaya`로 표시한다.
- 크리에이터 랭킹의 현재 순위 글자 크기, 순위 변동 UI 크기, 닉네임 글자 크기는 `device width >= 402dp`에서 그대로 유지한다.
- 크리에이터 랭킹의 위 항목은 `device width < 402dp`에서 `device width / 402` 비율로 축소한다.
- 콘텐츠 랭킹도 크리에이터 랭킹과 동일하게 `402dp` 기준 반응형 축소 정책을 적용한다.
- 콘텐츠 랭킹의 콘텐츠 닉네임은 현재 설정 크기를 `device width >= 402dp`에서 그대로 유지하고, `device width < 402dp`에서 비율대로 축소한다.
- 구현 전 현재 설정값과 변경 대상 파일을 계획 문서에서 검증 가능하게 정리한다.
---
## 4. Non-Goals
- 이번 요청에서는 코드, 리소스, 테스트 파일을 수정하지 않는다.
- API 스키마, 랭킹 정렬, 랭킹 데이터 매핑, 클릭 이동, 차단/접근 불가 정책은 변경하지 않는다.
- 랭킹 카드의 순위 구간 정책은 변경하지 않는다.
- 크리에이터 랭킹: 1위, 2~7위, 8~10위, 11위 이상
- 콘텐츠 랭킹: 1위 Large, 2~7위 MediumGrid, 8~10위 SmallGrid, 11위 이상 Horizontal
- 레거시 오디오 콘텐츠 랭킹 화면과 기존 `AudioContentRankingAllActivity` 계열은 수정하지 않는다.
- 새 화면, 새 API, 새 탭, 추가 필터, 디자인 리팩터링은 포함하지 않는다.
- 402dp 이상 기기의 현재 글자 크기를 키우거나 줄이지 않는다.
---
## 5. Target Users
- 402dp 미만 폭의 Android 기기에서 메인 홈/콘텐츠 랭킹을 확인하는 앱 사용자.
- 랭킹 카드에서 순위, 순위 변동, 콘텐츠/크리에이터 이름을 읽는 앱 사용자.
- `kr.co.vividnext.sodalive.v2.widget.creatorranking``kr.co.vividnext.sodalive.v2.widget.contentranking` 위젯을 유지보수하는 Android 개발자.
---
## 6. User Stories
- 사용자는 좁은 기기에서도 랭킹 순위와 이름이 과도하게 커 보이지 않길 원한다.
- 사용자는 402dp 이상 기기에서는 현재 랭킹 UI와 동일한 크기를 기대한다.
- 사용자는 크리에이터 랭킹과 콘텐츠 랭킹에서 동일한 기준으로 축소되는 UI를 기대한다.
- 개발자는 랭킹별 현재 기준값과 축소 기준을 문서로 확인한 뒤 최소 변경으로 구현하고 싶다.
---
## 7. Core Features
### Responsive Ranking Size Policy
402dp를 기준 폭으로 사용하고, 기준 폭 미만에서만 현재 설정 크기를 비율대로 축소한다.
#### Requirements
- 기준 폭은 `402dp`이다.
- `device width >= 402dp`이면 scale은 `1.0`이다.
- `device width < 402dp`이면 scale은 `device width / 402`이다.
- 축소 대상은 다음 항목이다.
- 순위 숫자 글자 크기
- 순위 변동 숫자 글자 크기
- 순위 변동 caret/New 아이콘 크기
- 순위 변동 pill의 현재 padding/margin 중 시각 크기에 직접 영향을 주는 값
- 크리에이터 랭킹 닉네임 글자 크기
- 콘텐츠 랭킹 타이틀 글자 크기
- 콘텐츠 랭킹 닉네임 글자 크기
- 스케일 계산은 px 기반 parent width가 아니라 기기 폭 dp 기준으로 정의한다.
- 402dp 이상에서 현재 값과 동일해야 하므로 `fontScale`, 접근성 설정, display density에 따른 Android 기본 변환을 임의로 우회하지 않는다.
#### Edge Cases
- `screenWidthDp`를 확인할 수 없는 환경에서는 scale `1.0`을 사용해 기존 UI를 유지한다.
- scale 적용 후 너무 작은 값 방지를 위한 최소값은 별도 요구가 없으므로 임의로 추가하지 않는다.
- 기존 콘텐츠 랭킹 `SmallGrid`의 조건부 크기 정책은 현재 동작을 기준값으로 유지하고, 선택된 기준값에 scale을 곱한다.
### Creator Ranking UI
메인 홈 `랭킹` 탭의 크리에이터 랭킹 위젯에 폰트와 반응형 크기 정책을 적용한다.
#### Current Baseline
| Rank group | 순위 글자 | 순위 변동 숫자 | 순위 변동 아이콘 | 크리에이터 닉네임 |
| --- | ---: | ---: | ---: | ---: |
| 1위 | `96sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `32sp` |
| 2~7위 | `54sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `22sp` |
| 8~10위 | `36sp` | `14sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `14sp` |
| 11위 이상 | `40sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `18sp` |
#### Requirements
- 순위 숫자 폰트는 `Pattaya`를 사용한다.
- 위 baseline 값은 `device width >= 402dp`에서 동일해야 한다.
- `device width < 402dp`에서는 baseline 값에 scale을 곱해 표시한다.
- 기존 `CreatorRankingPlacement`의 rank group 분류는 유지한다.
- 기존 `RankingChangeType.Increase`, `Decrease`, `Stay`, `New` 표시 의미는 유지한다.
#### Edge Cases
- `showRankChange=false` item은 기존처럼 순위 변동 UI를 숨긴다.
- `RankingChangeType.New`는 숫자 텍스트 없이 NEW 아이콘만 표시하는 기존 의미를 유지한다.
- 긴 닉네임의 `ellipsize`, `maxLines` 정책은 변경하지 않는다.
### Content Ranking UI
메인 콘텐츠 `랭킹` 탭의 콘텐츠 랭킹 위젯에 크리에이터 랭킹과 동일한 반응형 크기 정책을 적용한다.
#### Current Baseline
| Rank group | 순위 글자 | 순위 변동 숫자 | 순위 변동 아이콘 | 콘텐츠 타이틀 | 콘텐츠 닉네임 |
| --- | ---: | ---: | ---: | ---: | ---: |
| 1위 Large | `96sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `22sp` | `12sp` |
| 2~7위 MediumGrid | `54sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `22sp` | `12sp` |
| 8~10위 SmallGrid | 조건부 | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | 조건부 | `12sp` |
| 11위 이상 Horizontal | `40sp` | `16sp` | 기본 `14dp x 14dp`, NEW `36dp x 23dp` | `18sp` | `14sp` |
#### SmallGrid Baseline Detail
- 현재 `SmallGrid`는 카드 폭 기준으로 분기한다.
- `widthPx <= 140`이면 순위 `36sp`, 타이틀 `14sp`를 사용한다.
- `widthPx > 140`이면 순위 `54sp`, 타이틀 `22sp`를 사용한다.
- 반응형 구현 시 이 분기 자체를 바꾸지 않고, 분기 결과로 선택된 baseline 값에 402dp scale을 적용한다.
#### Requirements
- 콘텐츠 랭킹도 `device width >= 402dp`이면 현재 baseline 값을 유지한다.
- `device width < 402dp`이면 크리에이터 랭킹과 동일한 scale을 적용한다.
- 콘텐츠 닉네임은 현재 설정 크기를 기준으로 유지/축소한다.
- 콘텐츠 랭킹 순위 숫자 폰트는 기존 `Pattaya` 계열 표시를 유지한다.
- 기존 `ContentRankingPlacement`, card variant, layout 계산 정책은 유지한다.
#### Edge Cases
- 접근 불가 콘텐츠의 대체 텍스트 표시 정책은 변경하지 않는다.
- `showRankChange=false` item은 기존처럼 순위 변동 UI를 숨긴다.
- 긴 콘텐츠 타이틀/닉네임의 `ellipsize`, `maxLines` 정책은 변경하지 않는다.
---
## 8. UX / UI Expectations
- 402dp 이상 기기에서는 사용자가 기존과 동일한 랭킹 UI 크기를 보아야 한다.
- 402dp 미만 기기에서는 랭킹 숫자, 순위 변동 UI, 타이틀/닉네임이 동일 비율로 줄어 화면 폭에 맞아야 한다.
- 크리에이터 랭킹과 콘텐츠 랭킹의 축소 체감은 일관되어야 한다.
- 순위 변동 pill, caret, NEW 아이콘은 텍스트와 따로 커지거나 작아 보여서는 안 된다.
- 텍스트 크기 축소가 기존 정렬, 말줄임, 카드 variant 구분을 깨지 않아야 한다.
---
## 9. Technical Constraints
- Android XML Views, ViewBinding, RecyclerView 기반 기존 구조를 유지한다.
- 신규 구현이 필요할 경우 기존 `v2.widget.creatorranking`, `v2.widget.contentranking`, 공통 `v2.widget.ranking` 하위 구조를 우선 검토한다.
- 신규 `Activity`, `Fragment`, `ViewModel`은 만들지 않는다.
- 레거시 파일은 직접 수정하지 않는다.
- 구현 전 `docs/20260710_메인_랭킹_UI_반응형_크기_조정/plan-task.md`의 checklist를 먼저 갱신한 뒤 진행한다.
---
## 10. Metrics
- `device width >= 402dp`에서 크리에이터 랭킹 baseline 크기가 유지된다.
- `device width < 402dp`에서 크리에이터 랭킹 baseline 크기에 `device width / 402` scale이 적용된다.
- `device width >= 402dp`에서 콘텐츠 랭킹 baseline 크기가 유지된다.
- `device width < 402dp`에서 콘텐츠 랭킹 baseline 크기에 `device width / 402` scale이 적용된다.
- 크리에이터 랭킹 순위 숫자 폰트가 `Pattaya`로 표시된다.
- 콘텐츠 닉네임은 402dp 이상에서 현재 크기, 402dp 미만에서 비율 축소 크기를 사용한다.
- 기존 API/mapper/click routing 관련 테스트나 컴파일 결과가 회귀하지 않는다.
---
## 11. Decisions
- `Font - Pattaya` 적용 대상은 크리에이터 랭킹의 순위 숫자 텍스트로 확정한다.
- 402dp 미만 축소는 device width 기준 비율 적용이므로 별도 최소 글자 크기 하한은 두지 않는다.