Files
sodalive-android/docs/20260620_크리에이터_채널_시리즈_탭/prd.md

18 KiB
Raw Blame History

PRD: 크리에이터 채널 시리즈 탭

1. Overview

크리에이터 채널의 시리즈 탭에서 시리즈 수, 정렬, 시리즈 목록, 시리즈별 콘텐츠 소장 진행 정보와 스크롤 pagination을 제공한다.


2. Problem

  • 크리에이터 채널 컨테이너와 , 라이브, 오디오 탭은 별도 문서에서 정의되었지만, 시리즈 탭의 API 계약과 Figma 기반 UI 요구사항은 별도 정의가 필요하다.
  • 사용자는 크리에이터 채널에서 전체 시리즈 수와 각 시리즈의 발행 요일, 총 콘텐츠 수, 연재/완결 상태를 한 화면에서 확인할 수 있어야 한다.
  • 사용자는 내 채널이 아닌 크리에이터 채널에서 시리즈별 유료 콘텐츠 소장 진행률을 확인할 수 있어야 한다.
  • 크리에이터 본인의 채널에서는 소장률 정보가 아니라 시리즈 기본 정보만 표시되어야 한다.
  • 시리즈 목록은 길어질 수 있으므로 CreatorChannelSeriesTabResponse.hasNext == true일 때 다음 페이지를 자동 로딩해야 한다.
  • 정렬 선택 방식은 이미 구현된 오디오 탭과 동일하게 유지해 탭 간 사용성이 일관되어야 한다.

3. Goals

  • Figma 전체 화면 290:9031 기준으로 크리에이터 채널 시리즈 탭 UI 요구사항을 정의한다.
  • Figma 시리즈 item 290:9036을 기준으로 목록 item 구조와 표시 규칙을 정의한다.
  • Figma 시리즈 콘텐츠 소장률 290:9038을 기준으로 소장 진행 정보 표시 규칙을 정의한다.
  • API endpoint GET /api/v2/creator-channels/{creatorId}/series를 기준으로 최초 조회, 정렬 변경, pagination 요구사항을 정의한다.
  • 최초 조회 query parameter 기본값은 page=0, size=20, sort=LATEST로 둔다.
  • 정렬 선택 방식은 오디오 탭과 동일하게 구현한다.
  • 정렬 옵션은 기존 ContentSort enum에 존재하는 LATEST, POPULAR, OWNED, PRICE_HIGH, PRICE_LOW 5개만 사용한다.
  • Figma 정렬 팝업에 보이는 추천순은 이번 시리즈 탭 정렬 옵션에서 제외한다.
  • Sort-bar에는 전체 시리즈 수와 현재 정렬 label을 표시한다.
  • 시리즈 item 우측 끝의 버튼 영역은 표시하지 않는다.
  • 우측 버튼 왼쪽의 info/소장률 영역은 버튼이 사라진 공간까지 사용할 수 있어야 한다.
  • 이미지처럼 크기 제한이 필요한 영역 외에는 불필요한 고정 상수를 두지 않고 match_parent 또는 wrap_content를 우선 사용한다.
  • 내 채널이 아닌 경우 시리즈 item에 콘텐츠 소장 진행 정보와 progress bar를 표시한다.
  • 내 채널인 경우 시리즈 item의 소장률 영역을 숨기고 상단 info만 표시한다.
  • 응답의 hasNexttrue이면 현재 page + 1 페이지를 추가 로딩한다.

4. Non-Goals

  • 크리에이터 채널 상단 header, title bar, 공통 main tab-bar 구조 자체를 재설계하지 않는다.
  • , 라이브, 오디오, 화보, 커뮤니티, 팬Talk, 후원 탭의 상세 구현은 이번 범위에서 제외한다.
  • 시리즈 상세, 오디오 상세, 결제, 대여, 소장, 재생 플로우 내부 동작 변경은 이번 범위에서 제외한다.
  • 시리즈 생성/수정/삭제 또는 콘텐츠 업로드 진입점은 이번 범위에서 제외한다.
  • API schema를 임의 변경하거나 서버 응답 필드명을 클라이언트에서 새로 정의하지 않는다.
  • 정렬 외 별도 검색, 테마/카테고리 필터, pull-to-refresh, skeleton/shimmer는 이번 범위에서 제외한다.
  • Figma asset을 localhost URL 그대로 앱 코드에 직접 의존하지 않는다.
  • Figma 정렬 팝업에 보이는 추천순 정렬은 ContentSort 계약에 없으므로 이번 범위에서 제외한다.
  • 시리즈 item 우측 버튼의 전체소장 또는 play button은 이번 범위에서 표시하지 않는다.

5. Target Users

  • 크리에이터 채널에서 시리즈 목록을 탐색하는 앱 사용자.
  • 특정 크리에이터의 시리즈별 콘텐츠 구성과 연재 상태를 확인하려는 앱 사용자.
  • 특정 시리즈의 유료 콘텐츠 중 자신이 얼마나 소장했는지 확인하려는 앱 사용자.
  • 본인 채널에서 사용자에게 보이는 시리즈 정보를 확인하려는 크리에이터.
  • kr.co.vividnext.sodalive.v2 하위 크리에이터 채널 탭을 구현/유지보수하는 Android 개발자.

6. User Stories

  • 사용자는 크리에이터 채널의 시리즈 탭에서 전체 시리즈 수를 확인하고 싶다.
  • 사용자는 시리즈 제목, 발행 요일, 총 콘텐츠 수, 연재/완결 상태를 목록에서 확인하고 싶다.
  • 사용자는 오디오 탭과 동일한 방식으로 시리즈 목록 정렬을 변경하고 싶다.
  • 사용자는 내 채널이 아닌 크리에이터의 시리즈별 소장 화수와 전체 유료 화수 대비 소장률을 확인하고 싶다.
  • 사용자는 본인 채널의 시리즈 탭에서는 소장률 정보 없이 시리즈 기본 정보만 보고 싶다.
  • 사용자는 시리즈 목록 하단까지 스크롤하면 다음 페이지가 자연스럽게 이어서 로딩되길 기대한다.
  • 사용자는 크리에이터가 아직 시리즈를 준비 중인 경우 불필요한 정렬 UI 없이 empty 문구만 보고 싶다.

7. Core Features

Creator Channel Series Tab API

시리즈 탭 진입, 정렬 변경, 추가 로딩 시 크리에이터별 시리즈 탭 데이터를 조회한다.

Requirements

  • API endpoint는 GET /api/v2/creator-channels/{creatorId}/series이다.
  • creatorId는 path variable로 전달한다.
  • Query parameters는 sort, page, size를 사용한다.
  • 최초 조회 기본값은 page=0, size=20, sort=ContentSort.LATEST이다.
  • sort는 기존 ContentSort enum 값을 그대로 전달한다.
  • ContentSort는 기존에 만들어져 있는 타입을 재사용한다.
  • 시리즈 item의 이미지 표시는 CreatorChannelSeriesResponse.coverImageUrl을 사용한다.
  • hasNext == true일 때 다음 페이지 요청은 현재 응답의 page + 1 값을 사용한다.
  • 중복 pagination 요청이 발생하지 않도록 loading 중 추가 요청을 막아야 한다.
  • 정렬 변경 시 기존 목록과 page 상태를 초기화하고 첫 페이지부터 다시 조회한다.

Response Contract

data class CreatorChannelSeriesTabResponse(
    val seriesCount: Int,
    val series: List<CreatorChannelSeriesResponse>,
    val sort: ContentSort,
    val page: Int,
    val size: Int,
    val hasNext: Boolean
)

data class CreatorChannelSeriesResponse(
    val seriesId: Long,
    val title: String,
    val coverImageUrl: String,
    val publishedDaysOfWeek: String,
    val isOriginal: Boolean,
    val isAdult: Boolean,
    val isProceeding: Boolean,
    val contentCount: Int,
    val purchasedContentCount: Int?,
    val paidContentCount: Int?,
    val purchasedPaidContentRate: Int?
)

enum class ContentSort {
    LATEST,
    POPULAR,
    OWNED,
    PRICE_HIGH,
    PRICE_LOW
}

Edge Cases

  • 최초 조회 실패 시 기존 크리에이터 채널 탭의 error/retry 패턴을 따른다.
  • 정렬 변경 실패 시 현재 프로젝트의 에러 표시/재시도 패턴을 구현 계획 단계에서 확인해 따른다.
  • 다음 페이지 로딩 실패 시 기존 목록은 유지하고 기존 pagination 실패 표시 정책을 따른다.
  • 다음 페이지 응답의 series가 비어 있어도 hasNext 값 기준으로 이후 로딩 가능 여부를 갱신한다.
  • 서버 응답의 sort, page, size가 요청 상태와 다를 경우 구현 계획 단계에서 기존 ViewModel 상태 동기화 패턴을 확인해 따른다.
  • coverImageUrl이 비어 있거나 이미지 로딩에 실패하면 기존 이미지 placeholder 정책을 따른다.

Sort Bar and Sort Menu

Sort-bar는 전체 시리즈 수와 현재 정렬 상태를 표시하고, 오디오 탭과 동일한 정렬 메뉴를 연다.

Requirements

  • Figma 전체 화면 기준 Sort-bar는 290:9031sort-bar이다.
  • 좌측에는 전체seriesCount를 표시한다.
  • 우측에는 현재 정렬 label과 정렬 icon을 표시한다.
  • 정렬 선택 방식은 오디오 탭과 동일하다.
  • 정렬 기본값은 ContentSort.LATEST이며 label은 한국어 기준 최신순이다.
  • 정렬 옵션은 기존 ContentSort enum에 존재하는 5개만 사용한다.
  • LATEST label은 최신순이다.
  • POPULAR label은 기존 프로젝트의 인기순 label을 따른다.
  • OWNED label은 기존 프로젝트의 소장순 label을 따른다.
  • PRICE_HIGH label은 기존 프로젝트의 높은 가격순 label을 따른다.
  • PRICE_LOW label은 기존 프로젝트의 낮은 가격순 label을 따른다.
  • Figma 정렬 팝업에 보이는 추천순은 표시하지 않는다.
  • 정렬 옵션을 선택하면 page=0, 선택된 sort로 API를 다시 조회한다.
  • 선택 중인 정렬 옵션을 다시 선택하면 API 재호출 없이 메뉴만 닫는다.

Edge Cases

  • 작은 화면에서 정렬 메뉴가 화면 우측 또는 하단을 벗어나지 않도록 오디오 탭과 동일한 위치 보정 정책을 적용한다.
  • 다국어 label 길이가 길어져도 Sort-bar text와 icon이 겹치지 않아야 한다.

Series Content List

시리즈 목록은 Figma의 목록형 item으로 표시하고, 각 item에서 시리즈 기본 정보와 조건부 소장 진행 정보를 제공한다.

Requirements

  • Figma 콘텐츠 item 기준 노드는 290:9036이다.
  • series를 세로 목록으로 표시한다.
  • 각 item의 좌측에는 coverImageUrl 기반 썸네일을 표시한다.
  • 썸네일은 Figma 기준 122dp x 172dp, radius 14dp 형태를 따른다.
  • isOriginal == true이면 썸네일 좌상단에 original tag를 표시한다.
  • isAdult == true이면 썸네일 우상단에 adult tag를 표시한다.
  • 제목 영역에는 title을 표시한다.
  • 부제 영역에는 publishedDaysOfWeek, contentCount, isProceeding을 조합해 표시한다.
  • 부제 문구 형식은 Figma 기준 매주 월 • 총 nn화 • 연재 또는 매주 월 • 총 nn화 • 완결이다.
  • isProceeding == true이면 연재로 표시한다.
  • isProceeding == false이면 완결로 표시한다.
  • item 우측 끝의 전체소장 또는 play button 영역은 표시하지 않는다.
  • 우측 버튼이 사라진 공간은 info 영역과 소장률 영역이 사용할 수 있어야 한다.
  • 이미지처럼 명확한 크기 제한이 필요한 썸네일 외에는 고정 width/height 상수를 최소화하고 match_parent 또는 wrap_content를 우선 사용한다.
  • item 터치 시 시리즈 상세 진입은 기존 프로젝트의 시리즈 상세 진입 정책을 구현 계획 단계에서 확인해 따른다.

Edge Cases

  • title이 긴 경우 Figma처럼 최대 2줄 또는 기존 목록 item 정책에 맞게 표시하고 이후 말줄임 처리한다.
  • 부제 문구가 긴 경우 한 줄 말줄임 처리한다.
  • publishedDaysOfWeek가 비어 있으면 빈 구분자나 불필요한 bullet이 보이지 않아야 한다.
  • contentCount == 0이어도 총 0화 표시 정책을 유지한다.
  • coverImageUrl이 비어 있거나 이미지 로딩 실패 시 기존 이미지 placeholder 정책을 따른다.

Series Possession Progress

시리즈 소장 진행 정보는 내 채널이 아닌 경우에만 표시한다.

Requirements

  • Figma 기준 노드는 290:9038이다.
  • 내 채널이 아닌 경우 item 하단에 소장 진행 정보를 표시한다.
  • 내 채널인 경우 소장 진행 정보 전체를 숨기고 item 상단 info만 표시한다.
  • 내 채널에서 표시하는 info는 제목, 발행 요일, 총 콘텐츠 수, 연재/완결 상태까지만 의미한다.
  • 내 채널에서는 purchasedContentCount, paidContentCount, purchasedPaidContentRate 기반 숫자와 progress bar를 표시하지 않는다.
  • 내 채널이 아닌 경우 purchasedContentCount, paidContentCount, purchasedPaidContentRate를 사용해 소장 진행 정보를 표시한다.
  • 소장 화수 문구는 Figma 기준 12/45화 형식으로 표시한다.
  • purchasedContentCount는 좌측 숫자로 표시한다.
  • paidContentCount는 우측 전체 유료 화수로 표시한다.
  • purchasedPaidContentRate는 우측 percent와 progress bar 채움 비율로 표시한다.
  • purchasedPaidContentRate는 서버에서 percent 값으로 내려오며, 클라이언트는 사용자 표시용 % 포맷만 적용한다.
  • progress bar는 Figma 기준 4dp height, soda color 채움, gray 배경을 따른다.

Edge Cases

  • 내 채널이 아닌데 purchasedContentCount, paidContentCount, purchasedPaidContentRate 중 하나라도 null이면 소장 진행 정보 전체를 숨긴다.
  • paidContentCount == 0이면 0 나누기 계산을 클라이언트에서 수행하지 않고, 서버의 purchasedPaidContentRate 또는 소장 진행 정보 숨김 정책을 따른다.
  • purchasedPaidContentRate가 0 미만 또는 100 초과로 내려오면 progress bar 표시값은 UI 안정성을 위해 0..100 범위로 clamp한다.
  • 긴 숫자에서도 소장 화수와 percent가 겹치지 않아야 한다.

Pagination

시리즈 목록은 스크롤 하단 접근 시 다음 페이지를 로딩한다.

Requirements

  • CreatorChannelSeriesTabResponse.hasNext == true일 때만 다음 페이지를 요청한다.
  • 다음 페이지는 마지막 성공 응답의 page + 1로 요청한다.
  • 다음 페이지 요청에는 현재 sort, size=20을 유지한다.
  • 다음 페이지 로딩 중에는 추가 page 요청을 중복으로 보내지 않는다.
  • 다음 페이지 성공 시 기존 series 뒤에 append한다.
  • 정렬 변경 시 pagination 상태를 초기화한다.

Edge Cases

  • 빠른 스크롤로 load-more trigger가 반복 발생해도 page가 중복 append되지 않아야 한다.
  • Fragment/View 재생성 후 현재 목록, 정렬, page 상태는 ViewModel 상태 보존 정책에 따라 유지되어야 한다.
  • 마지막 페이지 응답 이후 hasNext == false이면 이후 load-more trigger를 무시한다.

Empty State

시리즈가 없으면 시리즈가 있을 때 표시하는 UI를 숨기고 empty 문구만 표시한다.

Requirements

  • seriesCount == 0 또는 표시 가능한 series가 없는 전체 empty 상태이면 empty 상태를 표시한다.
  • empty 상태에서는 Sort-bar와 시리즈 목록을 표시하지 않는다.
  • empty 문구는 크리에이터가 시리즈를 준비 중입니다.\n기대해 주세요!이다.
  • empty 문구는 한국어/영어/일본어 다국어 문자열 리소스로 관리한다.
  • 영어 empty 문구는 The creator is preparing a series.\nPlease look forward to it!이다.
  • 일본어 empty 문구는 クリエイターがシリーズを準備中です。\n楽しみにお待ちください이다.
  • empty 상태 표시 방식은 라이브/오디오 탭 empty 상태와 동일하게 적용한다.

Edge Cases

  • API 최초 조회 실패 상태는 empty 상태로 취급하지 않고 기존 error/retry 패턴을 따른다.
  • seriesCount > 0이지만 응답 series가 비어 있는 첫 페이지 응답은 서버 상태 불일치 가능성이 있으므로 기존 목록 탭의 empty/error 정책을 구현 계획 단계에서 확인해 따른다.

8. UX / UI Expectations

  • 전체 화면은 기존 크리에이터 채널 컨테이너의 black background, sticky tab-bar, title-bar 동작을 유지한다.
  • 시리즈 main tab은 선택 상태로 표시하고, 선택 underline과 텍스트 색상은 기존 tab-bar 정책을 따른다.
  • Sort-bar 높이와 배치는 Figma 290:9031을 기준으로 하되 기존 오디오 탭 구현과 가능한 한 동일한 공통 UI를 사용한다.
  • 목록 item 간 간격은 Figma 기준 8dp 수준을 따른다.
  • 시리즈 item은 좌측 썸네일, 중앙 info/소장 진행 정보의 2영역 구조로 표시한다.
  • 사용자 요구에 따라 item 우측 버튼 영역은 표시하지 않는다.
  • 우측 버튼을 제거한 뒤에도 title, subtitle, 소장 진행 숫자, progress bar가 서로 겹치지 않아야 한다.
  • 이미지 썸네일처럼 크기 제한이 필요한 경우 외에는 고정 상수보다 match_parent 또는 wrap_content를 사용한다.
  • 모든 사용자 표시 문구는 문자열 리소스로 관리한다.
  • Figma localhost asset URL은 앱 코드에 직접 사용하지 않는다.

9. Technical Constraints

  • Android Gradle 단일 모듈 :app 안에서 구현한다.
  • 신규 Fragment, ViewModel 및 그와 연결된 하위 코드는 kr.co.vividnext.sodalive.v2 패키지 하위에 작성한다.
  • 기존 CreatorChannelActivityViewPager2 기반 탭 구조를 유지한다.
  • 기존 크리에이터 채널 API/Repository 패턴을 따른다.
  • 기존 ContentSort 타입과 오디오 탭의 정렬 선택 UI/동작을 재사용한다.
  • 서버 DTO 필드명과 타입은 PRD의 Response Contract를 따른다.
  • coverImageUrl은 시리즈 썸네일 이미지 URL로 사용한다.
  • API 기본값은 page=0, size=20, sort=LATEST이다.
  • 네트워크, 이미지 로딩, error/retry, pagination 중복 방지 방식은 기존 라이브/오디오 탭 패턴을 우선 따른다.
  • 비밀값, BuildConfig 값, 로컬 Figma asset URL을 로그/Toast/크래시 메시지에 노출하지 않는다.

10. Metrics

  • 시리즈 탭 최초 API 조회 성공/실패 여부.
  • 정렬 변경 후 첫 페이지 재조회 성공/실패 여부.
  • pagination 추가 로딩 성공/실패 여부.
  • 시리즈 item 클릭 후 상세 진입 성공 여부.
  • 내 채널 여부에 따른 소장 진행 정보 노출/숨김 정확도.

11. Open Questions

  • 시리즈 상세 진입 대상 Activity/Fragment와 전달 파라미터는 구현 계획 단계에서 기존 프로젝트 코드를 확인해 확정한다.