Files

8.3 KiB

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

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:mmbeginDateTimeUtc를 UTC로 파싱한 뒤 디바이스 Timezone으로 변환한 시작 시각이다.
  • 제목은 18sp bold, 한 줄 말줄임으로 표시한다.
  • 크리에이터 닉네임은 14sp regular, 회색으로 표시한다.
  • 유료 라이브는 ic_bar_cash와 가격을 표시한다.
  • 무료 라이브는 cash 아이콘을 숨기고 무료 텍스트만 표시한다.
  • 이미지 로드는 기존 loadUrl 또는 기존 Glide 확장 관례를 따른다.

라이브 입장

Requirements

  • 아이템 터치 시 바로 LiveRoomActivity를 열지 않는다.
  • 터치 시 LiveViewModel.getRoomDetail(roomId)를 호출한다.
  • 상세 응답을 받은 뒤 기존 LiveNowAllActivity.enterLiveRoom과 동일한 정책을 적용한다.
  • 방장(manager.id == SharedPreferenceManager.userId)이면 enterRoomLiveRoomActivity를 연다.
  • 이미 결제했거나 무료인 방은 비공개 여부에 따라 비밀번호 다이얼로그 또는 직접 입장을 수행한다.
  • 유료 미결제 방은 비공개 여부에 따라 비밀번호 다이얼로그 또는 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 표시로 확정한다.