Files
sodalive-android/docs/prd/20260520_캐릭터채팅썸네일컴포넌트_prd.md

10 KiB

PRD: 캐릭터 채팅 썸네일 컴포넌트

1. Overview

Figma 24:5032 디자인을 기준으로 캐릭터 이미지, 총 채팅 개수, 캐릭터 이름, 캐릭터 소개, 원작 작품명을 표시하는 Android XML Views 기반 캐릭터 채팅 썸네일 컴포넌트를 문서화한다.


2. Problem

  • 캐릭터 목록/추천 영역에서 캐릭터 이미지 위에 총 채팅 개수를 함께 보여야 한다.
  • 캐릭터 이름과 소개가 길어질 경우 카드의 고정된 이미지/텍스트 영역을 밀어내지 않아야 한다.
  • 원작 웹툰/웹소설 작품이 없는 캐릭터도 카드 높이를 유지해야 하므로 원작명 영역은 gone이 아닌 invisible 상태가 필요하다.
  • Figma의 chat-thumbnail 형태를 기존 v2 widget 패턴에 맞는 재사용 가능한 계약으로 분리해야 한다.

3. Goals

  • Figma 24:5032 기준 캐릭터 채팅 썸네일 UI를 제공한다.
  • 프로필/캐릭터 이미지는 Figma 기준 185dp x 185dp 고정 영역에 표시한다.
  • 카드 왼쪽 상단에는 ic_chat_message_count 아이콘과 이 캐릭터의 총 채팅 개수를 표시한다.
  • 총 채팅 개수가 100 미만이면 채팅 수 badge 전체를 표시하지 않는다.
  • 캐릭터 이름은 최대 1줄, 초과 시 끝 말줄임으로 표시한다.
  • 캐릭터 소개는 최대 2줄, 초과 시 끝 말줄임으로 표시한다.
  • hasOriginal == true이면 최하단 원작 작품명을 표시한다.
  • hasOriginal == false이면 원작 작품명 영역을 View.INVISIBLE로 숨겨 카드 높이를 유지한다.
  • 실제 이미지 로딩은 컴포넌트 내부에 고정하지 않고 호출부가 기존 Coil/Glide 정책으로 처리할 수 있게 한다.

4. Non-Goals

  • 이번 문서 범위에서는 코드, 리소스, 레이아웃 파일을 구현하지 않는다.
  • 서버 API, DTO 필드명, 정렬, pagination, filtering 정책을 변경하지 않는다.
  • Compose 컴포넌트 또는 Compose Theme를 추가하지 않는다.
  • Figma에 없는 pressed animation, skeleton loading, shimmer, 신규 badge, 차단/성인/유료 상태 표시는 추가하지 않는다.
  • 이미지 로딩 라이브러리 교체를 수행하지 않는다.
  • 채팅방 진입 또는 캐릭터 상세 이동 정책을 컴포넌트 내부에서 결정하지 않는다.

5. Target Users

  • 캐릭터 목록에서 대화할 캐릭터를 탐색하는 앱 사용자.
  • 캐릭터 카드 UI를 XML layout, RecyclerView, v2 widget 패턴으로 재사용해야 하는 Android 개발자.

6. User Stories

  • 사용자는 캐릭터 카드에서 해당 캐릭터의 총 채팅 개수를 즉시 확인하고 싶다.
  • 사용자는 긴 캐릭터 이름이나 소개가 있어도 카드 UI가 깨지지 않는 목록을 보고 싶다.
  • 사용자는 원작이 있는 캐릭터의 작품명을 카드 하단에서 확인하고 싶다.
  • 개발자는 원작이 없는 캐릭터도 같은 카드 높이로 정렬되도록 바인딩하고 싶다.

7. Core Features

Character Chat Thumbnail Widget

캐릭터 프로필 이미지와 텍스트 정보를 Figma chat-thumbnail 카드로 표시한다.

Figma References

Figma Token Requirements

  • Root card는 185dp 폭 기준, gray_900 (#202020) 배경, radius 14dp, overflow clipping 형태를 기준으로 한다.
  • 이미지 영역은 card top에 위치한 185dp x 185dp 고정 영역이다.
  • 이미지 영역에는 하단으로 갈수록 어두워지는 dim gradient를 올려 텍스트 가독성을 확보한다.
  • 채팅 수 badge는 이미지 왼쪽 상단 8dp, 8dp 위치에 둔다.
  • 채팅 수 badge는 black 60% 배경, radius 4dp, horizontal padding 4dp, vertical padding 2dp, icon/text gap 2dp를 기준으로 한다.
  • 채팅 수 icon은 ic_chat_message_count, 크기 18dp x 18dp를 사용한다.
  • 채팅 수 text는 Pretendard Regular 14sp, line-height 1.45, gray_100 (#F2F2F2)를 기준으로 한다.
  • 텍스트 column은 좌우 12dp, 이미지 하단 근처 top 176dp, 내부 gap 6dp를 기준으로 한다.
  • 캐릭터 이름은 Pretendard Bold 20sp, white, 최대 1줄이다.
  • 캐릭터 소개는 Pretendard Medium 14sp, line-height 1.45, white, 최대 2줄이다.
  • 원작 작품명은 Pretendard Medium 12sp, soda_300 (#4FD2F9), 최대 1줄이다.

Display Requirements

  • imageUrl은 Figma placeholder가 아니라 실제 캐릭터 이미지 URL을 표시한다.
  • 이미지 크기는 컴포넌트에서 고정하고, 호출부가 전달한 이미지가 영역 밖으로 늘어나지 않도록 centerCrop + clipping을 적용한다.
  • 채팅 수는 이 캐릭터의 전체 누적 채팅 개수를 표시한다.
  • chatMessageCount < 100이면 채팅 수 badge를 View.GONE 또는 미표시 상태로 처리한다.
  • chatMessageCount >= 100이면 채팅 수 badge를 표시한다.
  • 채팅 수 text는 Figma 예시처럼 만 단위 축약 표시를 허용하며, 10만 미만은 소수 1자리에서 반올림하지 않고 절삭한다. 만 앞 정수부가 2자리 이상이면 소수점을 제거해 정수 만 단위로 표시한다. 예: 14000 -> 1.4만, 19999 -> 1.9만, 109999 -> 10만.
  • 캐릭터 이름은 maxLines=1, ellipsize=end를 적용한다.
  • 캐릭터 소개는 maxLines=2, ellipsize=end를 적용한다.
  • 원작 작품명이 길면 maxLines=1, ellipsize=end를 적용한다.
  • hasOriginal == true이면 원작 작품명 TextView를 View.VISIBLE로 두고 originalTitle을 표시한다.
  • hasOriginal == false이면 원작 작품명 TextView를 View.INVISIBLE로 두고 height를 유지한다.
  • hasOriginal == true인데 originalTitle이 비어 있으면 빈 문자열을 표시하되 영역은 View.VISIBLE로 유지한다.
  • 터치 동작은 컴포넌트 내부에서 목적지를 결정하지 않고 호출부 callback으로 위임한다.

Data Contract Requirements

  • 최소 데이터 계약은 다음 정보를 포함해야 한다.
    • characterId: 캐릭터 식별자.
    • imageUrl: 카드에 표시할 캐릭터 이미지 URL.
    • characterName: 캐릭터 이름.
    • characterDescription: 캐릭터 소개.
    • chatMessageCount: 이 캐릭터의 총 채팅 개수.
    • hasOriginal: 원작 웹툰/웹소설 작품 존재 여부.
    • originalTitle: 원작 작품명. hasOriginal == true일 때 표시한다.
  • UI는 원작 타입이 웹툰인지 웹소설인지 구분하지 않고 작품명 문자열만 표시한다.
  • 채팅 수 서버 필드명은 이 문서에서 확정하지 않고, 구현 단계에서 기존 응답 필드 또는 신규 매핑 필드를 확인한다.

Edge Cases

  • imageUrl이 비어 있으면 호출부 이미지 로딩 정책에 따라 placeholder 또는 빈 상태를 표시한다.
  • characterName이 비어 있으면 이름 TextView는 빈 문자열로 유지한다.
  • characterDescription이 비어 있으면 소개 TextView는 빈 문자열로 유지한다.
  • chatMessageCount가 0이면 0으로 표시한다.
  • chatMessageCount가 0 이상 99 이하이면 채팅 수 badge를 표시하지 않는다.
  • chatMessageCount가 음수로 전달되면 데이터 오류로 간주하고 구현 단계에서 0으로 보정하거나 항목 제외 정책을 정한다.
  • 긴 한글/영문/숫자 혼합 텍스트는 지정된 줄 수에서 끝 말줄임 처리한다.

8. UX / UI Expectations

  • 전체 컴포넌트는 어두운 배경 위에서 사용하는 것을 전제로 한다.
  • 캐릭터 이미지는 Figma와 동일하게 카드 상단 영역을 채우고 카드 radius에 맞게 잘려야 한다.
  • 채팅 수 badge는 이미지 위에서도 읽을 수 있도록 반투명 검정 배경을 유지한다.
  • 원작 작품명 유무에 따라 카드 높이나 카드 간 정렬이 흔들리지 않아야 한다.
  • 장식용 dim gradient는 접근성 설명을 제공하지 않는다.
  • 채팅 수 아이콘은 의미 전달용이므로 badge 전체 또는 text에 접근성 설명을 제공할 수 있다.

9. Technical Constraints

  • 현재 프로젝트는 Android XML Views + Kotlin custom View + ViewBinding/resource 기반이므로 XML layout과 Kotlin custom view 패턴을 우선한다.
  • 신규 Kotlin 코드는 app/src/main/java/kr/co/vividnext/sodalive/v2 하위 패키지에 작성한다.
  • 재사용 가능한 위젯은 kr.co.vividnext.sodalive.v2.widget.characterchatthumbnail 하위에 둔다.
  • 기존 v2 widget처럼 custom view는 텍스트/상태를 바인딩하고, 실제 이미지 로딩은 imageView()를 통해 호출부가 처리할 수 있게 한다.
  • gray_900, gray_100, white, soda_300, radius/spacing/typography 등 기존 resource를 우선 재사용한다.
  • ic_chat_message_count 리소스가 없으면 구현 단계에서 Figma 에셋을 Android vector 또는 drawable로 추가한다.
  • 기존 캐릭터 목록 layout은 참고 대상으로만 사용하고, 이번 widget 계약에서 직접 변경하지 않는다.

10. Metrics

  • Figma 24:5032 기준 root radius, 이미지 고정 영역, 채팅 수 badge, 텍스트 배치가 구현 계획에 반영된다.
  • chatMessageCount >= 100이면 채팅 수 badge는 ic_chat_message_count와 총 채팅 개수 텍스트를 표시한다.
  • chatMessageCount < 100이면 채팅 수 badge가 표시되지 않는다.
  • 캐릭터 이름은 1줄 말줄임, 캐릭터 소개는 2줄 말줄임, 원작 작품명은 1줄 말줄임으로 제한된다.
  • hasOriginal == false일 때 원작 작품명 TextView는 View.INVISIBLE로 처리되어 카드 높이를 유지한다.
  • 실제 이미지 URL을 호출부에서 ImageView에 로드할 수 있다.
  • 컴포넌트 내부에는 Coil/Glide 등 이미지 로딩 라이브러리 import나 .load() 호출이 없다.
  • 문서 작성 범위에서는 코드, 리소스, 레이아웃 구현 파일을 변경하지 않는다.

11. Open Questions

  • chatMessageCount가 현재 API 응답에 이미 존재하는지 구현 전 확인이 필요하다.
  • 채팅 수 축약 포맷은 Figma 예시 1.4만을 기준으로 하되, 10만 미만은 소수 1자리 절삭 정책을 적용하고 10만 이상은 정수 만 단위로 표시한다. 예: 19999 -> 1.9만, 109999 -> 10만. 기존 공용 숫자 포맷터가 있으면 구현 단계에서 재사용한다.
  • 원작 작품명은 hasOriginal 기준으로만 표시 여부를 판단하며, originalTitle의 null/blank 여부만으로 표시 여부를 바꾸지 않는다.