docs(home): 메인 전체 탭 유료 오디오 요구사항을 문서화한다

This commit is contained in:
2026-07-10 10:16:27 +09:00
parent 2403e8703c
commit 561e181859
2 changed files with 73 additions and 10 deletions

View File

@@ -1,7 +1,7 @@
# PRD: 메인 콘텐츠 전체 탭 API
## 1. Overview
메인 콘텐츠 탭의 내부 전체 탭에서 오디오, 시리즈, 오리지널, 무료, 포인트 구분별 공개 콘텐츠를 정렬과 페이징으로 조회하는 v2 API를 제공한다.
메인 콘텐츠 탭의 내부 전체 탭에서 유료 오디오, 시리즈, 오리지널, 무료, 포인트 구분별 공개 콘텐츠를 정렬과 페이징으로 조회하는 v2 API를 제공한다.
---
@@ -17,6 +17,8 @@
- 메인 콘텐츠 전체 탭 조회 API를 `kr.co.vividnext.sodalive.v2` 하위 신규 코드로 제공한다.
- 기존 패턴과 동일하게 API 조립 계층과 도메인 조회 계층을 분리한다.
- 구분은 `AUDIO`, `SERIES`, `ORIGINAL`, `FREE`, `POINT`를 지원한다.
- `AUDIO` 구분은 유료 오디오 콘텐츠만 조회한다.
- `FREE` 구분은 무료 오디오 콘텐츠만 조회하며, `AUDIO` 구분 결과와 가격 조건이 겹치지 않는다.
- 공개된 콘텐츠만 조회한다.
- 회원이 차단했거나 회원을 차단한 크리에이터의 콘텐츠는 노출하지 않는다.
- 비회원은 19금 콘텐츠를 노출하지 않는다.
@@ -48,7 +50,7 @@
---
## 6. User Stories
- 사용자는 오디오 콘텐츠 전체 목록을 최신순, 인기순, 가격순으로 보고 싶다.
- 사용자는 유료 오디오 콘텐츠 전체 목록을 최신순, 인기순, 가격순으로 보고 싶다.
- 사용자는 선택한 요일의 시리즈 목록을 보고 싶다.
- 사용자는 오리지널 시리즈만 따로 보고 싶다.
- 사용자는 무료 오디오만 따로 보고 싶다.
@@ -68,7 +70,7 @@
- 회원 조회 시 `@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?` 패턴을 사용한다.
- 요청 query parameter는 `type`, `sort`, `dayOfWeek`, `page`, `size`를 사용한다.
- `type` 값은 아래 enum으로 정의한다.
- `AUDIO`: 오디오
- `AUDIO`: 유료 오디오
- `SERIES`: 시리즈
- `ORIGINAL`: 오리지널
- `FREE`: 무료
@@ -117,13 +119,15 @@
### Feature C. 오디오 구분
#### Requirements
- `type=AUDIO`는 차단 관계가 아닌 모든 크리에이터의 공개 오디오 콘텐츠를 조회한다.
- 전체 개수는 같은 공개/차단/성인 콘텐츠 조건을 적용한 오디오 콘텐츠 개수다.
- `type=AUDIO`는 차단 관계가 아닌 모든 크리에이터의 유료 공개 오디오 콘텐츠를 조회한다.
- 유료 오디오는 `price > 0`인 공개 오디오로 정의한다.
- 전체 개수는 같은 공개/차단/성인 콘텐츠 조건과 유료 조건을 적용한 오디오 콘텐츠 개수다.
- 응답 목록은 `audios`에 내려주고 `series`는 빈 배열로 내려준다.
- 응답 item은 기존 추천 탭의 `AudioCardResponse` 필드 의미를 우선 재사용한다.
#### Edge Cases
- 시리즈에 속하지 않은 오디오도 목록에 포함한다.
- 시리즈에 속하지 않은 유료 오디오도 목록에 포함한다.
- 무료 오디오는 `type=AUDIO` 목록과 개수에서 제외하고 `type=FREE`에서만 조회한다.
- 오디오의 오리지널 여부는 기존 추천 탭과 동일하게 해당 오디오가 속한 시리즈의 `isOriginal` 기준으로 판단한다.
### Feature D. 시리즈 구분
@@ -161,7 +165,8 @@
#### Requirements
- `type=FREE`는 차단 관계가 아닌 모든 크리에이터의 무료 오디오 콘텐츠를 조회한다.
- 무료 오디오는 `price == 0`인 공개 오디오로 정의한다.
- 정렬, 페이징, 전체 개수, 성인 콘텐츠 정책은 `AUDIO`와 동일하다.
- 공개/차단/성인 콘텐츠 정책과 정렬, 페이징, 전체 개수 산정 방식은 오디오 공통 정책을 따른다.
- `type=FREE``type=AUDIO`의 유료 조건을 상속하지 않는다.
- 응답 목록은 `audios`에 내려주고 `series`는 빈 배열로 내려준다.
#### Edge Cases
@@ -172,7 +177,8 @@
#### Requirements
- `type=POINT`는 차단 관계가 아닌 모든 크리에이터의 포인트 사용 가능 오디오 콘텐츠를 조회한다.
- 포인트 오디오는 `isPointAvailable == true`인 공개 오디오로 정의한다.
- 정렬, 페이징, 전체 개수, 성인 콘텐츠 정책은 `AUDIO`와 동일하다.
- 공개/차단/성인 콘텐츠 정책과 정렬, 페이징, 전체 개수 산정 방식은 오디오 공통 정책을 따른다.
- `type=POINT``type=AUDIO`의 유료 조건을 상속하지 않고 `isPointAvailable == true` 조건만 추가한다.
- 응답 목록은 `audios`에 내려주고 `series`는 빈 배열로 내려준다.
#### Edge Cases
@@ -215,7 +221,7 @@ Authorization: Bearer {accessToken} (optional)
- 비회원 조회를 허용한다.
- `SecurityConfig``GET /api/v2/audio/contents` permitAll 설정을 추가한다.
- `type` 미지정 시 `AUDIO`를 기본값으로 사용한다.
- `type` 미지정 시 `AUDIO`를 기본값으로 사용하며, 유료 오디오만 조회한다.
- `sort` 미지정 또는 invalid 값은 `LATEST`로 fallback한다.
- `type=SERIES`에서 요일 선택이 필요하면 `dayOfWeek`를 함께 보낸다.
- 예: `GET /api/v2/audio/contents?type=SERIES&dayOfWeek=MON&sort=LATEST&page=0&size=20`
@@ -310,6 +316,8 @@ data class MainContentSeriesResponse(
- `LangContext`: 시리즈 제목 다국어 처리
### 구현 주의사항
- `type=AUDIO``price > 0` 조건을 적용하고, `type=FREE``price == 0` 조건을 적용해 두 구분의 결과가 겹치지 않게 한다.
- `type=POINT``isPointAvailable == true` 조건을 유지하며, `AUDIO` 전용 유료 필터를 암묵적으로 재사용하지 않는다.
- 기존 추천 탭의 무료/포인트 오디오는 랜덤 조회지만, 전체 탭은 사용자가 선택한 `sort` 기준으로 조회한다.
- 기존 legacy 요일별 시리즈 API는 `dayOfWeek` query parameter로 `SeriesPublishedDaysOfWeek` enum을 받으므로 v2 전체 탭도 같은 parameter 이름과 enum 값을 사용한다.
- 기존 v2 채널 오디오/시리즈 탭처럼 invalid parameter fallback을 유지하려면 controller에서는 `dayOfWeek: String?`으로 받고 policy/service 경계에서 `SeriesPublishedDaysOfWeek`로 보정한다.