Files

8.1 KiB

PRD: 크리에이터 채널 오디오 탭

1. Overview

크리에이터 채널 공통 shell의 오디오 탭에서 크리에이터의 오디오 콘텐츠 목록, 테마 필터, 정렬, 소장률 정보를 제공한다. 상단 title bar, header, sticky tab-bar는 기존 크리에이터 채널 홈 구현을 재사용하고, tab-bar 아래 콘텐츠만 오디오 탭 전용 API 응답으로 구성한다.

API는 GET /api/v2/creator-channels/{creatorId}/audio를 사용한다. 기본 query는 page=0, size=20, sort=LATEST이며 themeId는 전체 선택 상태에서 보내지 않는다. 서버 응답의 themes에는 전체 항목이 포함되지 않으므로 클라이언트에서 맨 앞에 전체 탭을 추가한다.

Figma 참조:

  • 전체 화면: 290:9015, 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=290-9015&m=dev
  • 소장률: 290:9029, 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=290-9029&m=dev
  • Empty: 290:8965, 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=290-8965&m=dev
  • 본인 채널 CTA: 665:19008, 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=665-19008&m=dev

2. Problem

  • 현재 CreatorChannelTab.audio는 placeholder로 표시되어 실제 오디오 목록, 테마 필터, 소장률, 페이지네이션이 없다.
  • 오디오 탭은 라이브 탭과 같은 정렬 선택 UX를 사용해야 하지만, 테마 필터와 소장률 표시 조건이 추가된다.
  • 본인 채널에서는 일반 사용자용 소장률 대신 오디오 업로드 CTA를 제공해야 한다.

3. Goals

  • CreatorChannelTab.audio 선택 시 오디오 탭 API를 호출하고 응답 데이터로 화면을 구성한다.
  • page, size, sort, 선택된 themeId를 query parameter로 전달한다.
  • 기본값은 page=0, size=20, sort=LATEST, themeId=nil이다.
  • theme list는 CapsuleTabBar를 사용하고, 맨 앞에 전체 항목을 합성한다.
  • 정렬 선택 방식은 라이브 탭과 동일한 CreatorChannelSortBar + context popup을 재사용한다.
  • sort-bar는 audioContentCount0 이상이면 전체 {audioContentCount}를 표시한다.
  • 콘텐츠 item은 CreatorChannelAudioContentListItem을 재사용한다.
  • 전체 테마이고 본인 채널이 아닐 때만 소장률 UI를 표시한다.
  • 본인 채널의 오디오 탭에는 ic_new_upload_audio 아이콘을 쓰는 하단 CTA를 표시한다.

4. Non-Goals

  • 크리에이터 채널 공통 shell, header, sticky tab-bar 동작을 다시 설계하지 않는다.
  • 오디오 콘텐츠 상세, 구매, 재생, 업로드 화면 자체를 새로 구현하지 않는다.
  • 신규 정렬 enum을 추가하지 않고 기존 ContentSort를 재사용한다.
  • CreatorChannelAudioContentListItem의 표시 규칙을 이번 범위에서 재설계하지 않는다.
  • Figma localhost asset URL을 앱 코드에 직접 사용하지 않는다.
  • Pods/**, generated/**, build/**는 수정하지 않는다.

5. Core Requirements

5.1 API

  • Method: GET
  • Path: /api/v2/creator-channels/{creatorId}/audio
  • Path parameter: creatorId
  • Query parameters:
    • sort
    • page
    • size
    • themeId
  • themeId == nil이면 query parameter에서 제외한다.
  • 응답 래퍼는 기존 패턴대로 ApiResponse<CreatorChannelAudioTabResponse>로 디코딩한다.
data class CreatorChannelAudioTabResponse(
    val audioContentCount: Int,
    val paidAudioContentCount: Int,
    val purchasedAudioContentCount: Int,
    val purchasedAudioContentRate: Double,
    val themes: List<CreatorChannelAudioThemeResponse>,
    val audioContents: List<CreatorChannelAudioContentResponse>,
    val sort: ContentSort,
    val themeId: Long?,
    val page: Int,
    val size: Int,
    val hasNext: Boolean
)

data class CreatorChannelAudioThemeResponse(
    val themeId: Long,
    val themeName: String
)
  • ContentSortCreatorChannelAudioContentResponse는 기존 타입을 재사용한다.
  • Kotlin Long은 기존 V2 모델 관례대로 Swift Int로 선언한다.

5.2 Theme filter

  • 서버 응답 themes 조회가 완료된 뒤 맨 앞에 클라이언트 전용 전체 항목을 추가한다.
  • 서버 응답 themeId == nil이면 전체가 선택된 상태여야 한다.
  • 테마 선택 시 첫 페이지부터 다시 조회한다.
  • 전체 선택 시 themeId를 보내지 않는다.

5.3 Ownership rate

  • 소장률 UI는 전체 테마이고 본인 채널이 아닐 때만 표시한다.
  • 테마별 필터 상태에서는 표시하지 않는다.
  • 본인 채널에서는 표시하지 않는다.
  • purchasedAudioContentRate는 percent 값으로 내려오므로 그대로 % 문구에 사용한다.
  • 우측 카운트는 purchasedAudioContentCount/paidAudioContentCount개 형식으로 표시한다.
  • progress 값은 purchasedAudioContentRate / 100을 0...1로 clamp해서 사용한다.

5.4 Audio contents

  • audioContentsduration == nil 또는 빈 문자열인 콘텐츠는 숨긴다.
  • Empty 상태 판정은 서버의 audioContentCount == 0 기준으로 한다.
  • Empty 문구는 크리에이터가 오디오를 준비 중입니다.\n기대해 주세요!를 표시하고, UI 표시 방식은 라이브 탭 empty와 동일하게 한다.
  • 목록 하단 도달 시 hasNext == true이면 page + 1을 조회해 append한다.

5.5 Own channel CTA

  • 본인 채널이면 소장률 UI를 숨긴다.
  • 본인 채널이고 selectedTab == .audio일 때 하단 고정 CTA를 표시한다.
  • CTA 표시 방식은 라이브 탭의 라이브 시작하기 CTA와 동일한 full-width capsule 버튼이다.
  • CTA icon은 ic_new_upload_audio를 사용한다.
  • CTA tap은 기존 showAudioContentUpload() 흐름을 재사용한다.

6. Success Criteria

  • 오디오 탭 진입 시 GET /api/v2/creator-channels/{creatorId}/audio?page=0&size=20&sort=LATEST가 호출되고, 전체 선택 상태에서는 themeId가 전송되지 않는다.
  • themes 앞에 전체 탭이 표시되고, 응답 themeId == nil이면 전체가 선택된다.
  • 테마 선택 시 선택한 themeId로 첫 페이지를 다시 조회한다.
  • 정렬 선택 UI는 BottomSheet가 아니라 sort-bar 우측 버튼 아래 anchored context popup으로 표시되고, 동작은 라이브 탭과 동일하다.
  • 본인 채널이 아니고 전체 테마일 때만 소장률 UI가 표시된다.
  • 본인 채널이거나 테마 필터 상태이면 소장률 UI가 표시되지 않는다.
  • duration이 없는 콘텐츠는 목록에 표시되지 않는다.
  • audioContentCount == 0이면 라이브 탭과 같은 방식으로 오디오 empty 문구가 표시된다.
  • 본인 채널의 오디오 탭 하단에는 ic_new_upload_audio 아이콘을 쓰는 CTA가 표시되고 오디오 콘텐츠 업로드로 이동한다.

7. Technical Constraints

  • 기능 변경은 SodaLive/Sources/V2/CreatorChannel/** 하위에서 해결한다.
  • 오디오 탭 전용 View, ViewModel, Repository, API, 모델은 SodaLive/Sources/V2/CreatorChannel/Audio/** 아래에 둔다.
  • 공용 item, sort bar, sort context popup, CapsuleTabBar는 기존 구현을 재사용한다.
  • 신규 문구는 SodaLive/Sources/I18n/I18n.swift에 ko/en/ja를 추가한다.

8. Verification Notes

  • 2026-07-04: Figma get_design_contextget_screenshot으로 290:9015, 290:9029, 290:8965, 665:19008을 확인했다.
  • 2026-07-04: CreatorChannelLiveTabView, CreatorChannelLiveViewModel, CreatorChannelSortBar, CapsuleTabBar, CreatorChannelAudioContentListItem 기존 구현을 확인해 재사용 경계를 확정했다.
  • 2026-07-04: Figma 290:9034, 290:9031을 추가 확인해 sort-bar 전체 개수 표시와 정렬 context popup 전환 요구사항을 반영했다.