17 KiB
17 KiB
크리에이터 채널 시리즈 탭 구현 계획
기준 문서
- PRD:
docs/20260704_크리에이터_채널_시리즈_탭/prd.md - 기존 오디오 탭 PRD:
docs/20260704_크리에이터_채널_오디오_탭/prd.md - 기존 오디오 탭 구현 계획:
docs/20260704_크리에이터_채널_오디오_탭/plan-task.md - 코드 스타일:
docs/agent-guides/code-style.md - 빌드/검증:
docs/agent-guides/build-test-verification.md - Figma 전체 화면:
290:9031,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-9031&m=dev - Figma 시리즈 아이템:
290:9036,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-9036&m=dev - Figma 시리즈 콘텐츠 소장률:
290:9038,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-9038&m=dev
브레인스토밍 결과
- 선택지 A: 홈 탭
CreatorChannelSeriesResponse를 확장한다.- 장점: 타입 수가 적다.
- 단점: 홈 탭 카드 데이터와 시리즈 탭 리스트 데이터의 필드가 달라 모델 책임이 섞인다.
- 선택지 B: 오디오 콘텐츠 list item을 변형해 시리즈 item으로 사용한다.
- 장점: 레이아웃 작업이 일부 줄어든다.
- 단점: 오디오 콘텐츠의 가격/소장/재생 상태와 시리즈의 요일/진행/콘텐츠 수 표시 규칙이 달라 조건 분기가 커진다.
- 선택지 C:
Series/**하위에 시리즈 탭 전용 모델, ViewModel, View, item을 둔다.- 장점: API 응답과 UI 책임이 명확하고 오디오/홈 탭 영향이 작다.
- 결정: 선택지 C를 사용한다.
구현 원칙
- 기존
CreatorChannelView의 공통 shell, header, sticky tab-bar, title bar 동작은 유지한다. CreatorChannelTab.series콘텐츠만 신규CreatorChannelSeriesTabView로 교체한다.ContentSort,CreatorChannelSortBar, 정렬 context popup을 재사용한다.- 정렬 값은 오디오 탭과 동일한
LATEST,POPULAR,PRICE_HIGH,PRICE_LOW만 사용한다. - 홈 탭의 시리즈 카드/모델은 유지하되, 홈 탭 모델명은
CreatorChannelHomeSeriesResponse로 변경한다. - 시리즈 탭 API 응답은 별도 모델로 두고, item 모델명은 API 명세와 동일하게
CreatorChannelSeriesResponse로 둔다. - 시리즈 아이템의 가장 우측 버튼은 구현하지 않는다.
- 숨긴 버튼 왼쪽 UI는 썸네일 overlay asset이 아니라 아이템 가로 레이아웃에서 우측 버튼 바로 왼쪽에 있는 정보 영역을 의미한다.
- 해당 정보 영역은 play button 영역까지 차지하도록 유연한 레이아웃을 사용한다.
- 썸네일 overlay는
isOriginal == true일 때ic_series_original+img_new_only를 조합한ONLY표시만 담당한다. - Figma
290:9036기준 아이템 우측 성인 태그 위치는top: 6,right: 6이다. - 아이템 우측 성인 태그는
CreatorChannelAudioAdultTag().padding(.top, 6).padding(.trailing, 6)형태로 재사용한다. - 이미지 크기처럼 제한이 필요한 경우가 아니라면 고정 크기 상수를 추가하지 않는다.
- 본인 채널에서는 소장률을 숨기고 상단 info만 표시한다.
주요 대상 파일
생성
SodaLive/Sources/V2/CreatorChannel/Series/Models/CreatorChannelSeriesTabResponse.swiftSodaLive/Sources/V2/CreatorChannel/Series/Repository/CreatorChannelSeriesApi.swiftSodaLive/Sources/V2/CreatorChannel/Series/Repository/CreatorChannelSeriesRepository.swiftSodaLive/Sources/V2/CreatorChannel/Series/CreatorChannelSeriesViewModel.swiftSodaLive/Sources/V2/CreatorChannel/Series/CreatorChannelSeriesTabView.swiftSodaLive/Sources/V2/CreatorChannel/Series/Components/CreatorChannelSeriesListItem.swiftSodaLive/Sources/V2/CreatorChannel/Series/Components/CreatorChannelSeriesOwnershipRateView.swift
수정
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swiftSodaLive/Sources/V2/CreatorChannel/Home/Models/CreatorChannelHomeResponse.swiftSodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelSeriesSection.swiftSodaLive/Sources/I18n/I18n.swift- 필요 시
SodaLive.xcodeproj/project.pbxproj
TASK 체크리스트
Phase 1: 문서와 정렬 요구사항 확정
-
Task 1.1: PRD와 계획 문서 생성
- 대상 파일:
- 생성:
docs/20260704_크리에이터_채널_시리즈_탭/prd.md - 생성:
docs/20260704_크리에이터_채널_시리즈_탭/plan-task.md
- 생성:
- 검증 기준:
- 실행 명령:
rg "290:9031|290:9036|290:9038|CreatorChannelSeriesTabResponse|CreatorChannelSeriesResponse|CreatorChannelHomeSeriesResponse|PRICE_LOW" docs/20260704_크리에이터_채널_시리즈_탭 - 기대 결과: Figma URL, 응답 모델, 홈 탭 모델명 변경, 시리즈 탭 item 모델명, 정렬 범위가 문서에 기록된다.
- 실행 명령:
- 대상 파일:
-
Task 1.2: 브레인스토밍 기반 설계 확장
- 대상 파일:
- 수정:
docs/20260704_크리에이터_채널_시리즈_탭/prd.md - 수정:
docs/20260704_크리에이터_채널_시리즈_탭/plan-task.md
- 수정:
- 작업 내용:
- 홈 탭 모델 확장, 오디오 item 변형, 시리즈 전용 모듈 생성 선택지를 비교한다.
- 시리즈 전용 모듈 생성 결정을 문서에 기록한다.
OWNED는 필요 없다는 사용자 결정을 반영해 정렬 범위를 4개 값으로 고정한다.- 홈 탭 기존 모델은
CreatorChannelHomeSeriesResponse, 시리즈 탭 신규 모델은CreatorChannelSeriesResponse로 분리한다.
- 검증 기준:
- 실행 명령:
rg "브레인스토밍|선택지 C|OWNED|필요 없|LATEST|POPULAR|PRICE_HIGH|PRICE_LOW" docs/20260704_크리에이터_채널_시리즈_탭 - 기대 결과: 선택지 검토와
OWNED제외 결정이 문서에 기록된다.
- 실행 명령:
- 대상 파일:
Phase 2: API 모델, API, Repository
-
Task 2.1: 시리즈 탭 Response model 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Series/Models/CreatorChannelSeriesTabResponse.swift
- 생성:
- 작업 내용:
CreatorChannelSeriesTabResponse와CreatorChannelSeriesResponse를Decodable로 생성한다.CreatorChannelSeriesTabResponse.series는[CreatorChannelSeriesResponse]로 선언한다.- Kotlin
Long필드인seriesId는 SwiftInt로 선언한다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelSeriesTabResponse|seriesCount|series: \\[CreatorChannelSeriesResponse\\]|struct CreatorChannelSeriesResponse|publishedDaysOfWeek|isProceeding|purchasedPaidContentRate" SodaLive/Sources/V2/CreatorChannel/Series/Models/CreatorChannelSeriesTabResponse.swift
- 실행 명령:
- 대상 파일:
-
Task 2.2: 홈 탭 시리즈 모델명 변경
- 대상 파일:
- 수정:
SodaLive/Sources/V2/CreatorChannel/Home/Models/CreatorChannelHomeResponse.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelSeriesSection.swift - 확인/수정:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
- 수정:
- 작업 내용:
- 기존 홈 탭
CreatorChannelSeriesResponse타입명을CreatorChannelHomeSeriesResponse로 변경한다. CreatorChannelHomeResponse.series는[CreatorChannelHomeSeriesResponse]로 변경한다.- 홈 탭 시리즈 섹션과 preview의 타입 참조를 함께 변경한다.
- 기존 홈 탭
- 검증 기준:
- 실행 명령:
rg "CreatorChannelHomeSeriesResponse|CreatorChannelSeriesResponse" SodaLive/Sources/V2/CreatorChannel/Home SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 기대 결과: 홈 탭에서는
CreatorChannelHomeSeriesResponse를 사용하고, 신규 시리즈 탭 외부의 기존 홈 탭 타입명 충돌이 사라진다.
- 실행 명령:
- 대상 파일:
-
Task 2.3: 시리즈 탭 API endpoint 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Series/Repository/CreatorChannelSeriesApi.swift
- 생성:
- 작업 내용:
CreatorChannelSeriesApi.getSeries(creatorId:page:size:sort:)를 만든다.- path는
/api/v2/creator-channels/{creatorId}/series로 구성한다. - query는
sort,page,size를 포함한다.
- 검증 기준:
- 실행 명령:
rg "CreatorChannelSeriesApi|getSeries|/api/v2/creator-channels/|/series|sort|page|size|URLEncoding.queryString" SodaLive/Sources/V2/CreatorChannel/Series/Repository/CreatorChannelSeriesApi.swift
- 실행 명령:
- 대상 파일:
-
Task 2.4: 시리즈 탭 Repository 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Series/Repository/CreatorChannelSeriesRepository.swift
- 생성:
- 작업 내용:
MoyaProvider<CreatorChannelSeriesApi>를 사용하는getSeries(...)publisher를 제공한다.
- 검증 기준:
- 실행 명령:
rg "CreatorChannelSeriesRepository|MoyaProvider<CreatorChannelSeriesApi>|AnyPublisher<Response, MoyaError>|getSeries" SodaLive/Sources/V2/CreatorChannel/Series/Repository/CreatorChannelSeriesRepository.swift
- 실행 명령:
- 대상 파일:
Phase 3: ViewModel
- Task 3.1: 시리즈 탭 ViewModel 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Series/CreatorChannelSeriesViewModel.swift
- 생성:
- 작업 내용:
- 상태는 loading, response, series list, selectedSort, page, size, hasNext, hasLoaded, error toast를 둔다.
- 최초 진입 시
page=0,size=20,sort=.latest로 조회한다. - 정렬 변경 시 첫 페이지부터 다시 조회한다.
- 다음 페이지 조회 시 기존 목록에 append한다.
- 검증 기준:
- 실행 명령:
rg "CreatorChannelSeriesViewModel|selectedSort|fetchFirstPage|fetchNextPageIfNeeded|selectSort|page|hasNext|series" SodaLive/Sources/V2/CreatorChannel/Series/CreatorChannelSeriesViewModel.swift
- 실행 명령:
- 대상 파일:
Phase 4: Figma 섹션별 UI
-
Task 4.1: 시리즈 콘텐츠 소장률 UI 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Series/Components/CreatorChannelSeriesOwnershipRateView.swift
- 생성:
- 작업 내용:
purchasedContentCount,paidContentCount,purchasedPaidContentRate를 표시한다.- progress 값은
purchasedPaidContentRate / 100을 0...1 범위로 clamp한다. - 본인 채널 여부에 따른 progress/count 숨김은 상위 view에서 제어한다.
- 본인 채널에서 재사용할 수 있도록 상단 info 영역과 progress/count 영역을 분리 가능한 구조로 만든다.
- 검증 기준:
- 실행 명령:
rg "CreatorChannelSeriesOwnershipRateView|purchasedContentCount|paidContentCount|purchasedPaidContentRate|ProgressView|progress" SodaLive/Sources/V2/CreatorChannel/Series/Components/CreatorChannelSeriesOwnershipRateView.swift
- 실행 명령:
- 대상 파일:
-
Task 4.2: 시리즈 리스트 item 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Series/Components/CreatorChannelSeriesListItem.swift
- 생성:
- 작업 내용:
- Figma
290:9036기준으로 title, published days, original/adult/proceeding 상태, content count를 표시한다. isOriginal == true이면 썸네일 overlay에ic_series_original과img_new_only를 조합한ONLY표시를 노출한다.isAdult == true이면 Figmatop: 6,right: 6기준에 맞춰 아이템 우측에CreatorChannelAudioAdultTag().padding(.top, 6).padding(.trailing, 6)를 표시한다.- 가장 우측 버튼은 표시하지 않는다.
- 버튼 왼쪽 UI는 썸네일 overlay asset이 아니라 우측 버튼 바로 왼쪽의 정보 영역으로 정의한다.
- 해당 정보 영역은 play button 영역까지 확장되도록
maxWidth: .infinity와Spacer(minLength:)기반으로 구성한다. - 이미지 또는 아이콘 크기처럼 필요한 항목만 고정 크기를 사용한다.
- Figma
- 검증 기준:
- 실행 명령:
rg "CreatorChannelSeriesListItem|publishedDaysOfWeek|isOriginal|isAdult|isProceeding|contentCount|maxWidth: \\.infinity" SodaLive/Sources/V2/CreatorChannel/Series/Components/CreatorChannelSeriesListItem.swift
- 실행 명령:
- 대상 파일:
-
Task 4.3: 시리즈 탭 화면 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Series/CreatorChannelSeriesTabView.swift - 수정:
SodaLive/Sources/I18n/I18n.swift
- 생성:
- 작업 내용:
CreatorChannelSortBar와CreatorChannelSortContextPopup을 오디오 탭과 동일하게 배치한다.seriesCount를 sort-bar에 전달한다.- 본인 채널이 아니고 소장률 값이 모두 있을 때만
CreatorChannelSeriesOwnershipRateView를 표시한다. - 본인 채널이면 소장률 progress/count를 숨기고 상단 info만 표시한다.
seriesCount == 0이면 empty UI를 표시한다.- 리스트 하단에서
fetchNextPageIfNeeded를 호출한다.
- 검증 기준:
- 실행 명령:
rg "CreatorChannelSeriesTabView|CreatorChannelSortBar|CreatorChannelSortContextPopup|seriesCount|CreatorChannelSeriesOwnershipRateView|CreatorChannelSeriesListItem|fetchNextPageIfNeeded" SodaLive/Sources/V2/CreatorChannel/Series/CreatorChannelSeriesTabView.swift SodaLive/Sources/I18n/I18n.swift
- 실행 명령:
- 대상 파일:
Phase 5: CreatorChannelView 연결과 검증
-
Task 5.1: 시리즈 탭 콘텐츠 연결
- 대상 파일:
- 수정:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
- 수정:
- 작업 내용:
CreatorChannelTab.seriesplaceholder를CreatorChannelSeriesTabView로 교체한다.creatorId, 본인 채널 여부,showSeriesDetail(_:)액션을 전달한다.
- 검증 기준:
- 실행 명령:
rg "CreatorChannelSeriesTabView|selectedTab == \\.series|showSeriesDetail" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
- 실행 명령:
- 대상 파일:
-
Task 5.2: 프로젝트 파일 등록과 정적 검증
- 대상 파일:
- 확인/수정:
SodaLive.xcodeproj/project.pbxproj
- 확인/수정:
- 검증 기준:
- 실행 명령:
git diff --check -- docs/20260704_크리에이터_채널_시리즈_탭 SodaLive/Sources/V2/CreatorChannel SodaLive/Sources/I18n/I18n.swift SodaLive.xcodeproj/project.pbxproj - 기대 결과: 공백 오류 없이 성공한다.
- 실행 명령:
plutil -lint SodaLive.xcodeproj/project.pbxproj - 기대 결과:
OK를 출력한다. - 실행 명령:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build - 기대 결과: 빌드 성공.
- 실행 명령:
- 대상 파일:
검증 기록
- 2026-07-04: 사용자 제공 API 명세, 정렬 방식, Figma 링크, 본인 채널 소장률 표시 조건을 기준으로 PRD와 계획 문서를 생성했다.
- 2026-07-04:
sed와rg로 기존 오디오 탭 문서,CreatorChannelAudioTabResponse,ContentSort,CreatorChannelSortBar,CreatorChannelSortContextPopup, 홈 탭CreatorChannelSeriesResponse,showSeriesDetail(_:)경로를 확인했다. - 2026-07-04: 현재 Swift
ContentSort가 오디오 탭 정렬 4개(LATEST,POPULAR,PRICE_HIGH,PRICE_LOW)를 제공하는 것을 확인했다. - 2026-07-04: 사용자 확인에 따라
OWNED는 시리즈 탭 정렬 범위에서 제외했다. - 2026-07-04:
superpowers:brainstorming관점으로 홈 탭 모델 확장, 오디오 item 변형, 시리즈 전용 모듈 생성 선택지를 비교했고, 시리즈 전용 모듈 방식을 문서에 반영했다. - 2026-07-04: "버튼 왼쪽 UI"는 썸네일 overlay asset이 아니라 시리즈 item 우측 버튼 바로 왼쪽의 정보 영역을 의미하는 것으로 명확히 정리했다.
- 2026-07-04: 썸네일 overlay는
isOriginal == true일 때ic_series_original+img_new_only로 표시하고, 우측 성인 태그는CreatorChannelAudioAdultTag().padding(.top, 6).padding(.trailing, 6)로 재사용하도록 반영했다. - 2026-07-04: Figma
290:9036의 design context에서 성인 태그 위치가top: 6,right: 6임을 확인해 padding 값을 유지했다. - 2026-07-04: 기존 홈 탭 시리즈 모델은
CreatorChannelHomeSeriesResponse로 변경하고, 신규 시리즈 탭 API 모델은 명세와 동일한CreatorChannelSeriesResponse를 사용하도록 결정했다. - 2026-07-04:
CreatorChannelSeriesTabResponse,CreatorChannelSeriesApi,CreatorChannelSeriesRepository,CreatorChannelSeriesViewModel을 추가하고 홈 탭 시리즈 모델명을CreatorChannelHomeSeriesResponse로 변경했다. - 2026-07-04:
CreatorChannelSeriesOwnershipRateView,CreatorChannelSeriesListItem,CreatorChannelSeriesTabView를 추가하고CreatorChannelView의.series탭을 신규 탭 화면에 연결했다. - 2026-07-04: 신규 Series Swift 파일을
SodaLive.xcodeproj/project.pbxproj의 CreatorChannel group과 세 Sources build phase에 등록했다. - 2026-07-04: 계획 문서의
rg검증,git diff --check,plutil -lint SodaLive.xcodeproj/project.pbxproj,xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build를 실행해 통과를 확인했다. - 2026-07-04: 현재
SodaLive.xcodeproj/project.pbxproj와docs/agent-guides/build-test-verification.md기준으로 XCTest 번들 타깃이 확인되지 않아 RED/GREEN 단위 테스트는 수행하지 못했고, 정적 검증과 실제 앱 빌드로 대체했다. - 2026-07-04: 리뷰 게이트에서 지적된 썸네일 컨텍스트를 반영해 시리즈 item 모델에 optional
coverImageUrl을 추가하고, 값이 있을 때DownsampledKFImage로 표시하도록 보강했다. - 2026-07-04: 본인 채널에서는 소장률 progress/count 영역을 렌더링하지 않고 시리즈 제목/요일/상태 정보만 남도록 수정했으며, QA/컨텍스트 재리뷰에서 blocking 이슈 해소를 확인했다.