Files
sodalive-ios/docs/20260707_메인_콘텐츠_추천_전체보기/prd.md

14 KiB

PRD: 메인 콘텐츠 추천 전체보기

1. Overview

메인 하단 콘텐츠 탭의 내부 추천 탭에서 일부 콘텐츠 섹션에 전체보기 action을 추가한다. 새로 올라온 오디오, 오직 보이스온에서만, 무료 오디오, 포인트 오디오는 하단 콘텐츠 탭 내부의 상단 전체 탭으로 전환해 해당 타입과 정렬 상태를 보여준다.

New&Hot은 기존 전체 탭이 아니라 신규 콘텐츠 전체보기 화면을 만들어 GET /api/v2/contents API를 적용한다. New&Hot은 탭 외부 화면 전환이므로 AppStep route로 추가한다. 신규 화면은 Figma 482:15105 기준으로 상단 title bar와 2열 오디오 카드 grid를 제공하고, 목록에는 스크롤 페이징을 적용한다.

Figma 참조:

  • 신규 콘텐츠 전체보기 화면: 482:15105, 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=482-15105&m=dev

2. Problem

  • 현재 V2 MainContentRecommendationView의 추천 섹션 title은 전체보기 action을 받지 않아 chevron이 표시되지 않는다.
  • SectionTitle은 이미 action을 제공하면 chevron을 표시할 수 있으므로, 섹션별 전체보기 이동 callback을 연결해야 한다.
  • 대부분의 추천 섹션 전체보기는 이미 구현된 하단 콘텐츠 탭 내부 전체 탭으로 대체할 수 있지만, New&Hot은 별도 API와 별도 화면이 필요하다.
  • 신규 GET /api/v2/contents 응답은 기존 AudioCardResponse / MainContentAudioResponse와 필드명이 일부 달라 adapter 또는 전용 모델이 필요하다.

3. Goals

  • 추천 탭에서 전체보기가 필요한 섹션에 action을 추가해 title 우측 chevron을 표시한다.
  • 새로 올라온 오디오 전체보기는 하단 콘텐츠 탭의 상단 전체 탭에서 오디오 타입, 최신순 정렬로 전환한다.
  • 오직 보이스온에서만 전체보기는 하단 콘텐츠 탭의 상단 전체 탭에서 오리지널 타입, 최신순 정렬로 전환한다.
  • 무료 오디오 전체보기는 하단 콘텐츠 탭의 상단 전체 탭에서 무료 타입, 인기순 정렬로 전환한다.
  • 포인트 오디오 전체보기는 하단 콘텐츠 탭의 상단 전체 탭에서 포인트 타입, 인기순 정렬로 전환한다.
  • New&Hot 전체보기는 AppStep route 기반 신규 콘텐츠 전체보기 화면으로 이동하고 type = NEW_AND_HOT_AUDIO를 요청한다.
  • 신규 전체보기 화면은 GET /api/v2/contents를 호출하고 기본 query 값은 page = 0, size = 20, type = NEW_AND_HOT_AUDIO로 둔다.
  • 신규 전체보기 화면은 hasNext == true일 때 다음 page를 append한다.
  • 신규 전체보기 화면의 오디오 카드는 V2 공용 AudioContentThumbnailCard 재사용을 우선한다.

4. Non-Goals

  • 실제 구현과 Xcode 프로젝트 수정은 이번 PRD 작성 범위에 포함하지 않는다.
  • 추천 탭의 기존 API GET /api/v2/audio/recommendations 응답 구조를 변경하지 않는다.
  • 새로 올라온 오디오, 오직 보이스온에서만, 무료 오디오, 포인트 오디오용 별도 전체보기 화면을 새로 만들지 않는다.
  • 처음부터 함께 성장! 섹션과 FIRST_AUDIO_CONTENT 전체보기 진입은 이번 범위에 포함하지 않는다.
  • 콘텐츠 탭 - 전체의 기존 API GET /api/v2/audio/contents 명세를 변경하지 않는다.
  • API 명세에 없는 신규 type 값을 임의로 추가하지 않는다.
  • Figma localhost asset URL을 앱 코드에 직접 사용하지 않는다.
  • 외부 라이브러리를 추가하지 않는다.
  • Pods/**, generated/**, build/**는 수정하지 않는다.

5. Target Users

  • 추천 탭에서 관심 섹션의 콘텐츠를 더 많이 탐색하려는 사용자
  • 새롭거나 반응이 좋은 오디오를 연속해서 보고 싶은 사용자
  • 첫 콘텐츠, 무료, 포인트, 오리지널 등 조건별 콘텐츠를 빠르게 훑고 상세로 이동하려는 사용자

6. User Stories

  • 사용자는 추천 탭 섹션 title 우측 chevron을 눌러 해당 섹션의 전체 콘텐츠를 보고 싶다.
  • 사용자는 새로 올라온 오디오 전체보기에서 최신 오디오 목록을 바로 보고 싶다.
  • 사용자는 무료 오디오포인트 오디오 전체보기에서 인기순 목록을 바로 보고 싶다.
  • 사용자는 New&Hot 전체보기에서 Figma처럼 2열 카드 목록을 스크롤하며 더 많은 콘텐츠를 보고 싶다.
  • 사용자는 전체보기 목록의 콘텐츠 카드를 누르면 기존 오디오 상세 화면으로 이동하기를 기대한다.

7. Core Requirements

7.1 추천 탭 섹션 action

  • 전체보기 action이 필요한 섹션은 title 우측 chevron을 표시한다.
  • SectionTitle(title:action:)의 기존 chevron 표시 동작을 우선 재사용한다.
  • action이 없는 섹션은 기존처럼 chevron을 표시하지 않는다.
  • 기존 추천 섹션의 empty 조건은 유지한다. 섹션 item이 비어 화면에 보이지 않는 경우 chevron도 표시하지 않는다.

대상 섹션과 이동 규칙:

  • 새로 올라온 오디오
    • 이동 대상: 하단 콘텐츠 탭 내부 상단 전체
    • 초기 타입: MainContentAllType.audio
    • 초기 정렬: ContentSort.latest
  • 오직 보이스온에서만
    • 이동 대상: 하단 콘텐츠 탭 내부 상단 전체
    • 초기 타입: MainContentAllType.original
    • 초기 정렬: ContentSort.latest
  • 무료 오디오
    • 이동 대상: 하단 콘텐츠 탭 내부 상단 전체
    • 초기 타입: MainContentAllType.free
    • 초기 정렬: ContentSort.popular
  • 포인트 오디오
    • 이동 대상: 하단 콘텐츠 탭 내부 상단 전체
    • 초기 타입: MainContentAllType.point
    • 초기 정렬: ContentSort.popular
  • New&Hot
    • 이동 대상: AppStep route 기반 신규 콘텐츠 전체보기 화면
    • API type: ContentOverviewType.newAndHotAudio

7.2 신규 콘텐츠 전체보기 API

  • Method: GET
  • Path: /api/v2/contents
  • 인증: 기존 V2 API 인증 헤더 패턴을 따른다.
  • 응답 래퍼: 기존 V2 관례대로 ApiResponse<ContentOverviewPageResponse> 디코딩을 우선한다.

Query parameter:

  • page: Int
  • size: Int
  • type: ContentOverviewType

기본값:

  • page = 0
  • size = 20
  • type = NEW_AND_HOT_AUDIO

Swift enum:

enum ContentOverviewType: String, Decodable, Encodable, Hashable {
    case newAndHotAudio = "NEW_AND_HOT_AUDIO"
}

Swift response model:

struct ContentOverviewPageResponse: Decodable {
    let type: ContentOverviewType
    let items: [ContentOverviewItemResponse]
    let page: Int
    let size: Int
    let hasNext: Bool
}

struct ContentOverviewItemResponse: Decodable, Identifiable {
    let contentId: Int
    let title: String
    let coverImage: String?
    let price: Int
    let isPointAvailable: Bool
    let creatorNickname: String
    let isAdult: Bool
    let isFirstContent: Bool
    let isOriginalSeries: Bool

    var id: Int { contentId }
}

7.3 신규 콘텐츠 전체보기 화면

  • 화면은 SodaLive/Sources/V2/** 하위에 신규 View, ViewModel, Repository, Models를 작성한다.
  • 신규 화면은 AppStep에 route를 추가하고 ContentView에서 해당 route를 화면에 매핑한다.
  • 화면 title은 New&Hot으로 표시한다.
  • Figma 기준 상단 title bar는 좌측 back chevron과 title을 가진다.
  • 콘텐츠 목록은 2열 grid로 표시한다.
  • 각 카드는 정사각형 cover image, title, creator nickname, 태그를 표시한다.
  • 카드 태그는 응답 필드에 따라 기존 AudioContentThumbnailCard의 태그 표시 규칙을 따른다.
    • isOriginalSeries == true: original tag
    • isFirstContent == true: first tag
    • isPointAvailable == true: point tag
    • price == 0: free tag
    • isAdult == true: adult tag
  • 카드 tap 시 contentId로 기존 오디오 상세 화면에 진입한다.
  • 첫 페이지 로딩, 빈 목록, 실패, pagination loading 상태는 기존 V2 콘텐츠 탭 패턴을 따른다.

7.4 Paging

  • page = 0 응답은 기존 목록을 교체한다.
  • page > 0 응답은 기존 목록 뒤에 append한다.
  • hasNext == false이면 추가 요청을 막는다.
  • 이미 다음 페이지를 로딩 중이면 중복 요청을 막는다.
  • 첫 페이지 실패 시 empty/error 상태를 표시한다.
  • 다음 페이지 실패 시 기존 목록은 유지하고 toast 또는 error message를 표시한다.

7.5 하단 콘텐츠 탭 내부 전체 탭 전환

  • New&Hot을 제외한 추천 섹션 전체보기는 별도 route를 추가하지 않고 하단 콘텐츠 탭 내부에서 처리한다.
  • 추천 탭에서 하단 콘텐츠 탭 내부 상단 전체 탭으로 이동할 때 MainContentView의 내부 탭을 .all로 전환한다.
  • 전환 직후 MainContentAllViewModel에 목표 타입과 정렬을 적용하고 첫 페이지를 다시 요청한다.
  • 같은 타입/정렬 상태로 다시 진입하는 경우 불필요한 중복 요청은 피한다.
  • 기존 MainContentAllViewModel 상태 유지 구조는 보존하되, 추천 섹션 전체보기 진입 시 명시적으로 선택 상태를 갱신할 수 있어야 한다.

8. Reusable V2 Candidates

  • SodaLive/Sources/V2/Component/SectionTitle.swift
    • action이 있으면 ic_chevron_right를 표시하므로 추천 섹션 title chevron에 재사용 가능하다.
  • SodaLive/Sources/V2/Component/AudioContent/AudioContentThumbnailCard.swift
    • Figma 신규 전체보기의 2열 오디오 카드와 태그 표시 구조가 일치한다.
    • ContentOverviewItemResponseAudioContentThumbnailCardItem으로 바꾸는 initializer 추가만으로 재사용 가능하다.
  • SodaLive/Sources/V2/Main/Content/All/MainContentAllView.swift
    • 하단 콘텐츠 탭 내부 상단 전체 탭 전환 대상 화면으로 재사용한다.
    • 외부에서 초기 타입/정렬을 주입하거나 갱신하는 API가 필요하다.
  • SodaLive/Sources/V2/Main/Content/All/MainContentAllViewModel.swift
    • 타입/정렬 선택, 첫 페이지 reload, append paging 구조가 이미 있다.
    • 추천 전체보기 진입용 apply(type:sort:) 같은 최소 API 추가 후보이다.
  • SodaLive/Sources/V2/Main/Content/Recommendation/Components/MainContentAudioHorizontalCardSection.swift
    • 새로 올라온 오디오, 무료 오디오, 포인트 오디오 섹션에 action parameter를 추가하는 후보이다.
  • SodaLive/Sources/V2/Main/Content/Recommendation/Components/MainContentAudioListCarouselSection.swift
    • New&Hot 섹션에 action parameter를 추가하는 후보이다.
  • SodaLive/Sources/V2/Main/Content/Recommendation/Components/MainContentVoiceOnOnlySection.swift
    • 오직 보이스온에서만 섹션에 action parameter를 추가하는 후보이다.
  • SodaLive/Sources/V2/Component/DefaultTitleBar.swift / SodaLive/Sources/V2/Component/TitleBar.swift
    • 신규 전체보기 화면 title bar 재사용 후보이다. Figma의 좌측 back chevron 구조와 정확히 맞지 않으면 기존 title bar 패턴 안에서 최소 확장한다.
  • SodaLive/Sources/V2/Main/Content/Recommendation/Repository/MainContentRecommendationApi.swift
    • V2 Moya TargetType, bearer token header 패턴 참고 대상이다.
  • SodaLive/Sources/V2/Main/Content/All/Repository/MainContentAllApi.swift
    • query parameter 기반 V2 API 구현 패턴 참고 대상이다.
  • SodaLive/Sources/V2/Main/Content/Recommendation/Components/MainContentAudioEmptyStateView.swift
    • 신규 전체보기의 빈 목록/실패 상태 재사용 후보이다.

9. Technical Constraints

  • 기능 변경은 SodaLive/Sources/**, 신규 V2 코드는 SodaLive/Sources/V2/** 하위에서 해결한다.
  • 공용 컴포넌트 변경은 재사용성이 명확할 때만 SodaLive/Sources/V2/Component/**에서 최소 수정한다.
  • 특정 화면 내부에서만 쓰는 컴포넌트는 해당 화면 폴더 하위 Components에 둔다.
  • 기존 navigation은 AppState.shared.setAppStep(step:) 패턴을 따른다.
  • New&Hot 신규 전체보기 화면은 탭 외부 전환이므로 AppStepContentView mapping을 추가한다.
  • New&Hot을 제외한 섹션 전체보기는 AppStep route를 추가하지 않고 MainContentView 내부 탭 상태 변경으로 처리한다.
  • 인증 헤더는 기존 V2 API와 동일하게 Authorization: Bearer <token> 패턴을 따른다.
  • Long id는 기존 V2 모델 관례에 맞춰 Swift Int를 우선 사용한다.
  • 기존 AudioContentThumbnailCardimageUrl 필드명을 사용하므로 coverImage adapter가 필요하다.
  • 구현 시 빌드/검증 명령은 docs/agent-guides/build-test-verification.md를 따른다.

10. Success Criteria

  • 전체보기 대상 추천 섹션 title 우측에 chevron이 표시된다.
  • 새로 올라온 오디오 chevron tap 시 하단 콘텐츠 탭 내부 상단 전체 > 오디오 > 최신순 상태로 전환된다.
  • 오직 보이스온에서만 chevron tap 시 하단 콘텐츠 탭 내부 상단 전체 > 오리지널 > 최신순 상태로 전환된다.
  • 무료 오디오 chevron tap 시 하단 콘텐츠 탭 내부 상단 전체 > 무료 > 인기순 상태로 전환된다.
  • 포인트 오디오 chevron tap 시 하단 콘텐츠 탭 내부 상단 전체 > 포인트 > 인기순 상태로 전환된다.
  • New&Hot chevron tap 시 AppStep route로 신규 전체보기 화면에 진입하고 GET /api/v2/contents?page=0&size=20&type=NEW_AND_HOT_AUDIO를 요청한다.
  • 신규 전체보기 화면은 Figma 기준 2열 오디오 card grid, title bar, back navigation을 제공한다.
  • 신규 전체보기 화면은 hasNext 기반 다음 페이지 append를 제공한다.
  • 신규 전체보기 화면의 card tap은 기존 오디오 상세 이동과 동일하게 동작한다.
  • 기존 추천 탭 섹션의 item tap, banner tap, series tap 동작은 회귀하지 않는다.

11. Open Questions

  • 신규 API 실패 시 toast 문구와 empty state 문구의 정확한 I18n 문구는 확인이 필요하다.