docs(live): 현재 진행 라이브 리스트 문서를 추가한다
This commit is contained in:
149
docs/20260626_현재_진행_중인_라이브_리스트_페이지/prd.md
Normal file
149
docs/20260626_현재_진행_중인_라이브_리스트_페이지/prd.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# PRD: 현재 진행 중인 라이브 리스트 페이지
|
||||
|
||||
## 1. Overview
|
||||
메인 홈 추천 탭 최상단의 라이브 섹션에서 전체 라이브 리스트 화면으로 이동하고, `GET /api/v2/home/on-air-lives` 응답을 Figma `live_detail_001` 디자인 기준으로 표시한다.
|
||||
|
||||
---
|
||||
|
||||
## 2. Problem
|
||||
- 메인 홈 추천 탭 최상단 라이브 아이템은 현재 클릭 콜백이 비어 있어 터치해도 아무 동작을 하지 않는다.
|
||||
- 기존 레거시 `LiveNowAllActivity`는 별도 `/live/room` API와 그리드 UI를 사용하므로, v2 홈 추천의 Figma 리스트 디자인과 API 계약에 맞지 않는다.
|
||||
- 라이브 입장은 비공개방, 유료방, 이미 결제한 방, 방장 입장, 성인 인증/콘텐츠 설정 등 기존 정책을 따라야 한다.
|
||||
- 신규 목록 API는 리스트 표시용 정보만 제공하므로, 아이템 터치 시 기존 라이브 상세 조회 후 입장 정책을 결정해야 한다.
|
||||
|
||||
---
|
||||
|
||||
## 3. Goals
|
||||
- 홈 추천 최상단 라이브 섹션의 전체보기/더보기 항목 또는 진입 지점에서 현재 진행 중인 라이브 리스트 페이지를 연다.
|
||||
- `GET /api/v2/home/on-air-lives?page={page}`를 호출해 0부터 시작하는 페이지 단위로 현재 진행 중인 라이브 목록을 표시한다.
|
||||
- 서버 `size`는 20으로 고정되므로 앱은 `size` query parameter를 보내지 않는다.
|
||||
- 리스트 아이템은 Figma 기준으로 프로필 이미지, `LIVE ${라이브 시작시간}`, 제목, 크리에이터 닉네임, 가격/무료 정보를 표시한다.
|
||||
- `beginDateTimeUtc`는 디바이스 Timezone으로 변환한 뒤 `HH:mm` 형태로 표시한다.
|
||||
- 유료 라이브는 `ic_bar_cash`와 가격, `입장 캔` 문구를 표시한다.
|
||||
- 무료 라이브는 cash 아이콘을 숨기고 `무료`라고 표시한다.
|
||||
- 아이템 터치 시 기존 `getRoomDetail(roomId)` 조회 후 상세 응답 기준으로 입장/비밀번호/결제/성인 인증 흐름을 결정한다.
|
||||
- 기존 레거시 라이브 입장 정책은 직접 수정하지 않고, v2 신규 화면에서 호출/재사용한다.
|
||||
|
||||
---
|
||||
|
||||
## 4. Non-Goals
|
||||
- 이번 작업에서 서버 API 구현은 포함하지 않는다.
|
||||
- 기존 레거시 `LiveNowAllActivity` 그리드 UI를 리팩터링하지 않는다.
|
||||
- 기존 `LiveRoomActivity`, `LiveViewModel`, `LiveRepository`, `LiveApi`의 입장 정책 자체를 변경하지 않는다.
|
||||
- 검색, 정렬, 필터, pull-to-refresh, skeleton loading은 이번 범위에 포함하지 않는다.
|
||||
- Figma에 없는 별도 마케팅/빈 상태 화면을 새로 설계하지 않는다.
|
||||
- 라이브 종료/삭제/네트워크 오류에 대한 신규 정책을 만들지 않고 기존 unknown error toast/loading 패턴을 따른다.
|
||||
|
||||
---
|
||||
|
||||
## 5. Target Users
|
||||
- 홈 추천 탭에서 현재 진행 중인 라이브를 더 많이 보고 바로 입장하려는 사용자.
|
||||
- 무료/유료 라이브 여부와 시작 시각을 리스트에서 빠르게 확인하려는 사용자.
|
||||
- 기존 라이브 입장 정책을 유지하면서 v2 홈 UI를 확장해야 하는 Android 개발자.
|
||||
|
||||
---
|
||||
|
||||
## 6. User Stories
|
||||
- 사용자는 홈 추천 탭의 라이브 영역에서 전체 현재 라이브 리스트를 열고 싶다.
|
||||
- 사용자는 리스트에서 라이브 제목, 크리에이터, 시작 시각, 가격을 확인하고 싶다.
|
||||
- 사용자는 유료 라이브와 무료 라이브를 명확히 구분하고 싶다.
|
||||
- 사용자는 라이브 아이템을 터치했을 때 기존과 동일하게 비밀번호 입력, 결제 확인, 성인 인증 안내를 거쳐 입장하고 싶다.
|
||||
- 개발자는 새 목록 API와 화면은 v2 하위에 두되, 기존 입장 플로우는 중복 구현하지 않고 재사용하고 싶다.
|
||||
|
||||
---
|
||||
|
||||
## 7. Core Features
|
||||
|
||||
### 현재 진행 중인 라이브 리스트 API
|
||||
#### Endpoint Contract
|
||||
- Method: `GET`
|
||||
- Path: `/api/v2/home/on-air-lives`
|
||||
- Header: `Authorization: Bearer {accessToken}` optional
|
||||
- Query:
|
||||
- `page`: optional, default `0`, 0부터 시작하는 page index
|
||||
- `size`: 앱에서 보내지 않음. 서버에서 20으로 고정
|
||||
|
||||
#### Android Response Contract
|
||||
```kotlin
|
||||
data class HomeOnAirLivePageResponse(
|
||||
val items: List<HomeOnAirLiveResponse>,
|
||||
val page: Int,
|
||||
val size: Int,
|
||||
val hasNext: Boolean
|
||||
)
|
||||
|
||||
data class HomeOnAirLiveResponse(
|
||||
val roomId: Long,
|
||||
val creatorNickname: String,
|
||||
val creatorProfileImage: String,
|
||||
val title: String,
|
||||
val price: Int,
|
||||
val beginDateTimeUtc: String
|
||||
)
|
||||
```
|
||||
|
||||
#### Requirements
|
||||
- DTO는 `@Keep`, `@SerializedName`을 사용해 기존 v2 data layer 관례를 따른다.
|
||||
- Retrofit API는 `@GET("/api/v2/home/on-air-lives")`와 nullable `Authorization` header를 사용한다.
|
||||
- 토큰이 비어 있으면 Authorization header를 보내지 않는다.
|
||||
- Repository/ViewModel은 기존 `Api -> Repository -> ViewModel -> Activity` 흐름을 따른다.
|
||||
- 첫 진입 시 `page = 0`을 요청한다.
|
||||
- `hasNext = true`이고 리스트 하단에 도달하면 다음 page를 요청한다.
|
||||
- 중복 로딩 방지를 위해 loading 중 추가 page 요청은 무시한다.
|
||||
|
||||
### 리스트 UI
|
||||
#### Requirements
|
||||
- 화면 배경은 검은색을 유지한다.
|
||||
- 상단 title bar는 Figma처럼 뒤로가기 + `On Air` 제목을 표시한다.
|
||||
- 리스트 좌우 여백은 Figma 기준 14dp를 따른다.
|
||||
- 아이템은 세로 리스트로 표시한다.
|
||||
- 프로필 이미지는 75dp 원형으로 표시한다.
|
||||
- 상단 메타 텍스트는 `LIVE HH:mm` 형태로 표시한다.
|
||||
- `HH:mm`은 `beginDateTimeUtc`를 UTC로 파싱한 뒤 디바이스 Timezone으로 변환한 시작 시각이다.
|
||||
- 제목은 18sp bold, 한 줄 말줄임으로 표시한다.
|
||||
- 크리에이터 닉네임은 14sp regular, 회색으로 표시한다.
|
||||
- 유료 라이브는 `ic_bar_cash`, 가격, `입장 캔`을 표시한다.
|
||||
- 무료 라이브는 cash 아이콘을 숨기고 `무료` 텍스트만 표시한다.
|
||||
- 이미지 로드는 기존 `loadUrl` 또는 기존 Glide 확장 관례를 따른다.
|
||||
|
||||
### 라이브 입장
|
||||
#### Requirements
|
||||
- 아이템 터치 시 바로 `LiveRoomActivity`를 열지 않는다.
|
||||
- 터치 시 `LiveViewModel.getRoomDetail(roomId)`를 호출한다.
|
||||
- 상세 응답을 받은 뒤 기존 `LiveNowAllActivity.enterLiveRoom`과 동일한 정책을 적용한다.
|
||||
- 방장(`manager.id == SharedPreferenceManager.userId`)이면 `enterRoom` 후 `LiveRoomActivity`를 연다.
|
||||
- 이미 결제했거나 무료인 방은 비공개 여부에 따라 비밀번호 다이얼로그 또는 직접 입장을 수행한다.
|
||||
- 유료 미결제 방은 비공개 여부에 따라 비밀번호 다이얼로그 또는 `LivePaymentDialog`를 표시한다.
|
||||
- 성인방은 기존 `ensureLoginAndAdultAuth` 정책을 v2 화면에 맞춰 재사용한다.
|
||||
- 입장 성공 시 오디오 재생 서비스를 중지한 뒤 `Constants.EXTRA_ROOM_ID`와 함께 `LiveRoomActivity`를 실행한다.
|
||||
|
||||
---
|
||||
|
||||
## 8. UX / UI Expectations
|
||||
- 첫 진입 시 기존 `LoadingDialog` 패턴으로 로딩 상태를 표시한다.
|
||||
- 추가 페이지 로딩은 기존 화면 스타일을 해치지 않는 최소 처리로 구현한다.
|
||||
- API 실패 또는 상세 조회 실패는 기존 unknown error toast 패턴을 따른다.
|
||||
- 빈 목록이면 리스트를 비우고 과도한 신규 빈 화면 디자인은 추가하지 않는다.
|
||||
- 뒤로가기는 현재 리스트 화면을 종료한다.
|
||||
|
||||
---
|
||||
|
||||
## 9. Technical Constraints
|
||||
- 신규 `Activity`, `ViewModel`, DTO, Repository, adapter/helper는 `kr.co.vividnext.sodalive.v2` 하위에 작성한다.
|
||||
- 현재 진행 중인 라이브 리스트 화면의 신규 화면/API/Repository/ViewModel/adapter/model은 `kr.co.vividnext.sodalive.v2.live.onair` 패키지 하위에 작성한다.
|
||||
- 메인 홈 추천 탭 코드는 신규 화면으로 이동하는 진입점 연결만 담당한다.
|
||||
- 레거시 파일은 직접 수정하지 않는다. 필요한 기능은 기존 public API를 호출해 사용한다.
|
||||
- `LiveViewModel`은 기존 Koin 등록을 재사용한다.
|
||||
- 기존 `BuildConfig` 값, token, URL을 로그/Toast에 노출하지 않는다.
|
||||
- Compose로 전환하지 않고 기존 XML View/ViewBinding/RecyclerView 패턴을 따른다.
|
||||
|
||||
---
|
||||
|
||||
## 10. Metrics
|
||||
- 별도 분석 이벤트는 이번 범위에 추가하지 않는다.
|
||||
- 기능 검증 기준은 API 호출, 페이지네이션, 가격 표시, 시작 시각 표시, 상세 조회 후 입장 분기 동작이다.
|
||||
|
||||
---
|
||||
|
||||
## 11. Open Questions
|
||||
- 없음. `LIVE ${라이브 시작시간}`은 `beginDateTimeUtc`를 디바이스 Timezone으로 변환한 `HH:mm` 표시로 확정한다.
|
||||
Reference in New Issue
Block a user