13 KiB
13 KiB
PRD: 크리에이터 랭킹 위젯 컴포넌트
1. Overview
Figma 20:3702, 20:3709, 20:3711, 20:3713 디자인을 기준으로 크리에이터 랭킹을 순위 구간별 카드 형태로 표현하는 Android XML Views 기반 위젯 컴포넌트를 개발한다.
2. Problem
- 크리에이터 랭킹은 순위 구간에 따라 카드 UI와 한 줄 배치 개수가 달라져야 한다.
- 기기 폭이 하나로 고정되지 않으므로 Figma metadata size를 실제 이미지 크기로 고정하면 다양한 화면 폭에서 재사용하기 어렵다.
- 2위~10위는 순위 구간별 row count는 다르지만 카드 UI는 동일하므로, 별도 medium/small 컴포넌트로 나누면 중복 구현이 생긴다.
- 순위 변동, 신규 진입, 차단 상태, 터치 가능 여부가 함께 표시되어야 하므로 데이터와 UI 상태 계약을 명확히 해야 한다.
3. Goals
- Figma 4개 노드 기준의 크리에이터 랭킹 카드 variant와 row 배치 정책을 제공한다.
- 이미지 크기는 컴포넌트 내부에서 고정하지 않고 실제 사용하는 row container 폭과 row count에 맞춰 계산한다.
- 순위 구간별 한 줄 배치 규칙을 제공한다.
- 1위: 한 줄에 1개, Figma
20:3702, 큰 정사각형 카드. - 2위~7위: 한 줄에 2개, Figma
20:3709, 기본 정사각형 카드. - 8위~10위: 한 줄에 3개, Figma
20:3711, 기본 정사각형 카드. - 11위 이후: 가로형으로 한 줄에 1개, Figma
20:3713, 가로형 카드.
- 1위: 한 줄에 1개, Figma
- 2위
7위와 8위10위는 UI가 동일하므로 하나의 기본 정사각형 카드 컴포넌트로 통일한다. - 1위 큰 카드는 순위 표시 부분이 다르므로 별도 큰 카드 컴포넌트로 작성한다.
rank-num영역은 이전 순위와 비교한 변동 상태를 표시한다.- 차단 관계인 크리에이터는 이미지 블러, 이름 비노출 또는 대체문구, 터치 불가 상태로 표시한다.
- 기존 화면 일괄 적용은 구현 계획에서 별도 task로 제한하고, 컴포넌트 계약을 우선 고정한다.
4. Non-Goals
- 이번 범위에서는 서버 API 설계나 응답 필드명을 확정하지 않는다. 필요한 클라이언트 데이터 계약만 문서화한다.
- 팔로우 버튼, 후원 랭킹, 콘텐츠 랭킹, 라이브 랭킹 UI는 변경하지 않는다.
- Compose 컴포넌트 또는 Compose Theme를 추가하지 않는다.
- Figma에 없는 skeleton loading, shimmer, pressed animation, 별도 badge, 광고 영역, 페이지네이션 UI를 추가하지 않는다.
- 차단/차단 해제 기능 자체를 새로 만들지 않는다.
- 내가 차단했는지, 나를 차단했는지를 UI에서 구분해 표시하지 않는다.
- 이미지 로딩 라이브러리 교체를 수행하지 않는다.
5. Target Users
- 크리에이터 랭킹 화면을 보는 앱 사용자.
- XML 레이아웃과 RecyclerView 기반 랭킹 UI를 구현/유지보수하는 Android 개발자.
6. User Stories
- 사용자는 크리에이터 랭킹의 상위 순위를 더 큰 카드로 빠르게 확인하고 싶다.
- 사용자는 순위가 올랐는지, 내려갔는지, 유지됐는지, 신규 진입했는지 알고 싶다.
- 사용자는 차단 관계에 있는 크리에이터의 상세 정보가 노출되지 않기를 기대한다.
- 개발자는 순위 구간별 UI를 하나의 명확한 계약으로 바인딩하고 싶다.
7. Core Features
Creator Ranking Widget
크리에이터 랭킹 목록을 순위 구간별 카드 variant와 행 배치 규칙으로 표시한다.
Figma References
- Rank 1 large card: 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=20-3702&m=dev
- Rank 2~7 compact card: 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=20-3709&m=dev
- Rank 8~10 compact card: 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=20-3711&m=dev
- Rank 11+ horizontal card: 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=20-3713&m=dev
Variant and Row Requirements
| Rank range | Figma node | Row count | UI variant | Size policy |
|---|---|---|---|---|
| 1 | 20:3702 |
한 줄에 1개 | Large |
실제 사용 영역 폭을 1등분해 정사각형으로 표시 |
| 2~7 | 20:3709 |
한 줄에 2개 | Compact |
실제 사용 영역 폭을 2등분해 정사각형으로 표시 |
| 8~10 | 20:3711 |
한 줄에 3개 | Compact |
실제 사용 영역 폭을 3등분해 정사각형으로 표시 |
| 11+ | 20:3713 |
한 줄에 1개 | Horizontal |
실제 사용 영역 폭을 1등분하고 Figma 가로형 비율로 표시 |
Variant Details
Large: 1위 전용 카드다. 순위 숫자와 순위 변동 표시 영역이 다른 정사각형 카드와 다르므로 별도 layout/custom view로 작성한다.Compact: 2위10위 공통 정사각형 카드다. 2위7위와 8위~10위는 row count만 다르고 UI 구조는 동일하다.Horizontal: 11위 이후 전용 가로형 카드다.- Figma metadata size는 참고용 비율 확인에만 사용하고, 구현에서 고정 dp 크기로 사용하지 않는다.
Figma Token Requirements
- 공통 카드 이미지 radius는
radius_14또는14dp를 사용한다. - 공통 dim gradient는 위쪽
rgba(0,0,0,0), 아래쪽 black, opacity50%, 전환 시작점64.423%기준으로 구현한다. - 공통
rank-num배경은gray_900(#202020), radius4dp, horizontal padding4dp, gap2dp를 사용한다. - 공통
rank-num숫자는 Pretendard Variable Medium,16sp, line-height1.45, color white를 사용한다. - 공통 caret icon 크기는
14dp x 14dp를 기준으로 한다. - 순위 숫자는 Pattaya Regular를 사용하고 white~
#EEEEEEvertical gradient와0px 0px 4px rgba(0,0,0,0.48)shadow를 적용한다. Largecreator name은 Pretendard Variable Bold,32sp, line-height1.45, color white를 기준으로 한다.- 2열
Compactcreator name은 Pretendard Variable Bold,22sp, line-height1.45, color white를 기준으로 한다. - 3열
Compactcreator name은 Pretendard Variable Bold,14sp, line-height normal, color white를 기준으로 한다. Horizontalcreator name은 Pretendard Variable Bold,18sp, line-height1.45, color white를 기준으로 한다.
Display Requirements
- 모든 variant는 현재 순위 숫자를 표시한다.
rank-num영역은 순위 변동 상태를 표시한다.- 순위 상승:
ic_rank_caret_increase. - 순위 하락:
ic_rank_caret_decrease. - 순위 동일: 숫자 없이
ic_rank_caret_stay아이콘만 표시. - 신규 진입:
rank-num대신ic_rank_new이미지.
- 순위 상승:
- 신규 진입이 아니고 순위 동일이 아닌 경우
rank-num에는 이전 순위 대비 변동 숫자를 표시한다. - 1위~10위의 카드 이름 영역은 정상 접근 가능 상태에서만 크리에이터 이름을 표시한다.
- 11위 이후 가로형 카드는 정상 접근 가능 상태에서 크리에이터 이름을 표시한다.
Blocked Creator Requirements
- 내가 차단했거나 나를 차단한 크리에이터는 하나의 차단 관계 상태로만 전달받는다.
- 차단 관계 상태에서는 프로필/대표 이미지를 블러 처리한다.
- 차단 관계 상태의 1위~10위 카드는 크리에이터 이름을 표시하지 않는다.
- 차단 관계 상태의 1위~10위 카드는 이름을 숨겨도 하단 dim gradient 영역은 유지한다.
- 차단 관계 상태의 11위 이후 가로형 카드는 크리에이터 이름 대신
접근할 수 없는 정보입니다.를 표시한다. - 차단 관계 상태의 카드는 터치할 수 없다.
- 접근 가능 상태의 카드는 터치할 수 있고, 터치 시 호출부가 크리에이터 상세 이동 등 후속 동작을 처리한다.
Data Contract Requirements
- 최소 데이터 계약은 다음 정보를 포함해야 한다.
creatorId: 크리에이터 식별자.rank: 현재 순위. 1부터 시작한다.previousRank: 이전 순위. 신규 진입이면 null 허용.rankChangeType:increase,decrease,stay,new중 하나.rankChangeAmount: 신규 진입이 아닌 경우 표시할 변동 숫자.creatorName: 크리에이터 이름.imageUrl: 카드 이미지 URL.isBlocked: 내가 차단했거나 나를 차단한 차단 관계 여부.
- UI는
isBlocked만 사용하고 차단 방향은 구분하지 않는다. - 순위 변동 타입은 크리에이터 랭킹 전용 타입이 아니라 콘텐츠 랭킹과 공유하는 공용
RankingChangeType을 사용한다.
Edge Cases
- 랭킹 데이터가 0개이면 위젯 영역은 표시하지 않거나 호출부의 empty 정책을 따른다.
- 랭킹 데이터가 1~10개이면 존재하는 순위까지만 구간 규칙을 적용한다.
rank가 누락되거나 1보다 작으면 호출부 데이터 오류로 간주하고 해당 항목을 표시하지 않는다.rankChangeType이new이면previousRank와rankChangeAmount가 없어도 된다.rankChangeType이stay이면rankChangeAmount가 있어도 숫자를 표시하지 않는다.rankChangeType이increase또는decrease인데rankChangeAmount가 없으면 구현 단계에서 데이터 검증 정책을 정한다.- 이미지 로딩 실패 시 placeholder 정책은 기존 이미지 로딩 계층 또는 호출 화면 정책을 따른다.
8. UX / UI Expectations
- 전체 위젯은 어두운 배경 위에서 사용하는 것을 전제로 한다.
- Figma 스크린샷 기준 카드 이미지는 rounded corner를 가진다.
- 카드 이미지는 공통 dim gradient를 가진다. 차단 관계 상태에서 이름을 숨기더라도 1위~10위의 gradient overlay는 유지한다.
Large카드는 1위 전용 순위 표시 형태를 따른다.Compact카드는 2위~10위에서 동일 UI를 사용하고, row count에 따라 표시 크기만 달라진다.Horizontal카드는 좌측 순위, 중앙 이미지, 우측 이름 영역을 가진다.- 이미지 크기는 고정 dp로 박지 않고 row container 폭에서 계산한다.
- 정사각형 variant는 계산된 카드 폭과 동일한 높이로 표시한다.
- 가로형 variant는 부모 폭을 채우고 Figma 가로형 비율에 맞는 높이를 유지한다.
- 차단 관계 상태는 사용자가 상세로 들어갈 수 없음을 시각적으로 알 수 있어야 한다.
9. Technical Constraints
- 현재 프로젝트는 Android XML Views + ViewBinding + RecyclerView 기반이므로 XML 레이아웃과 Kotlin custom view/adapter 패턴을 우선한다.
- 신규 Kotlin 코드는
kr.co.vividnext.sodalive.v2패키지 하위에 작성한다. - 재사용 가능한 위젯은
kr.co.vividnext.sodalive.v2.widget또는 기능 범위에 맞는 하위 패키지에 둔다. - 기존
CreatorRankingAdapter와item_home_creator.xml는 레거시 홈 크리에이터 카드이므로, 기존 화면 변경 없이 새 컴포넌트의 참고 대상으로만 사용한다. - 기존 프로젝트의 이미지 로딩 방식이 화면별로 Glide/Coil을 함께 사용하므로, 컴포넌트 내부에 특정 이미지 로더를 강제하지 않는 API를 우선한다.
- 차단 관계 이미지 블러는 기존
kr.co.vividnext.sodalive.common.image.BlurTransformation등 기존 blur 구현의 재사용 가능성을 먼저 검토한다. ic_rank_caret_increase,ic_rank_caret_decrease,ic_rank_caret_stay,ic_rank_new리소스가 없으면 구현 단계에서 디자인 에셋 추가가 필요하다.- 기존
CreatorRankingChangeType은RankingChangeType으로 rename/move해 크리에이터 랭킹과 콘텐츠 랭킹이 같은 타입을 참조하도록 한다.
10. Metrics
- 순위 구간별 row count가 요구사항과 일치한다.
- 1위는
Large, 2위~10위는Compact, 11위 이후는Horizontalvariant로 바인딩된다. rankChangeType별 아이콘/숫자 표시가 문서와 일치한다.stay상태에서는 숫자 없이ic_rank_caret_stay만 표시된다.- 차단 관계 상태에서 이미지 블러, 이름 비노출/대체문구, 터치 불가가 모두 적용된다.
- 차단 관계 상태에서 1위~10위 카드의 gradient overlay가 유지된다.
- 이미지 크기가 고정 dp가 아닌 부모 폭과 row count 기반으로 계산된다.
- 관련 unit test와 Android resource merge/build가 성공한다.
11. Open Questions
- 서버 응답에 이전 순위, 신규 진입 여부, 차단 관계 여부가 이미 포함되는지 확인이 필요하다. 없으면 API/DTO 확장이 별도 백엔드 협의 항목이다.
- Figma
get_design_context재확인 결과 typography/color/radius 토큰은 본 문서의Figma Token Requirements에 반영했다. rankChangeAmount가 순위 동일일 때는 숫자 없이ic_rank_caret_stay아이콘만 표시하는 것으로 확정했다.- 차단 관계 상태에서 1위~10위 카드의 이름 영역을 숨길 때 gradient 영역은 유지하는 것으로 확정했다.
- 순위 변동 타입은 콘텐츠 랭킹과 같은 데이터이므로 공용
RankingChangeType으로 사용하는 것으로 확정했다.