80 KiB
크리에이터 채널 홈 구현 계획
기준 문서
- PRD:
docs/20260701_크리에이터_채널_홈/prd.md - 코드 스타일:
docs/agent-guides/code-style.md - 빌드/검증:
docs/agent-guides/build-test-verification.md - Figma 전체 화면:
296:14890 - Figma Unfollow title bar:
296:14287,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=296-14287&m=dev - Figma Follow + 알림 설정 title bar:
296:14288,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=296-14288&m=dev - Figma Follow + 알림 해제 title bar:
296:14289,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=296-14289&m=dev
구현 원칙
- API, Response model, Repository, ViewModel을 먼저 구현한 뒤 UI phase를 진행한다.
- 크리에이터 채널 진입점은
CreatorChannelView로 두고, 최초 선택 tab은.home으로 둔다. CreatorChannelView는 title bar, 크리에이터 프로필 header, tab-bar, 선택된 tab 상태, 홈 API 호출 상태를 소유한다.CreatorChannelHomeView는 tab-bar 아래 홈 탭 콘텐츠만 렌더링하며, 대화하기 action은 최신 코드 기준처럼CreatorChannelHeaderSection내부에서 렌더링한다.- 홈 API 응답의
creator정보는 공통 shell의 header/title/follow/notification/대화하기 action 상태가 공유한다. - 크리에이터 채널 공통 shell 구현은
SodaLive/Sources/V2/CreatorChannel/**아래에 둔다. - 크리에이터 채널 홈 탭 내부에서만 쓰는 UI는
SodaLive/Sources/V2/CreatorChannel/Home/Components/**아래에 둔다. - 크리에이터 채널 공통 shell 내부에서만 쓰는 UI는
SodaLive/Sources/V2/CreatorChannel/Components/**아래에 둔다. - 여러 화면에서 재사용할 근거가 명확한 UI만
SodaLive/Sources/V2/Component/**로 올린다. - 기존 V2 홈의
TargetType, Repository, ViewModel,ApiResponse<T>디코딩 패턴을 따른다. Long계열 id/count는 SwiftInt로 통일한다.- 빈 섹션은 section title과 empty state까지 포함해 표시하지 않는다.
- API 실패 시 전체 화면 error state로 전환하지 않고 title bar, tab-bar, 홈 외 tab placeholder처럼 서버 데이터 없이 가능한 기본 shell을 유지한다.
화보탭, 화보 섹션, 활동의 화보 row는 구현하지 않는다.- DM 버튼과 DM 진입은 구현하지 않는다.
- Figma localhost asset URL은 앱 코드에 사용하지 않는다.
- title bar 아이콘은
ic_new_bar_back,ic_new_follow,ic_new_following,ic_new_more,ic_bar_bell,ic_bar_bell_coloredasset을 사용한다. - SNS 아이콘은
ic_sns_instagram,ic_sns_youtube,ic_sns_x,ic_sns_kakao,ic_sns_fancimmasset을 사용한다. - 기존
AppStep.creatorDetail(userId:)진입은 새 크리에이터 채널 화면으로 연결한다.
주요 대상 파일
생성
SodaLive/Sources/V2/CreatorChannel/Home/Models/CreatorChannelHomeResponse.swiftSodaLive/Sources/V2/CreatorChannel/Models/CreatorChannelTab.swiftSodaLive/Sources/V2/CreatorChannel/Home/Repository/CreatorChannelHomeApi.swiftSodaLive/Sources/V2/CreatorChannel/Home/Repository/CreatorChannelHomeRepository.swiftSodaLive/Sources/V2/CreatorChannel/CreatorChannelViewModel.swiftSodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swiftSodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swiftSodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTitleBar.swiftSodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelHeaderSection.swiftSodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTabBar.swiftSodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelPlaceholderTabView.swiftSodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelTalkActionSection.swiftSodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelCurrentLiveSection.swiftSodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelLatestAudioSection.swiftSodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelDonationSection.swiftSodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelNoticeSection.swiftSodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelScheduleSection.swiftSodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelAudioSection.swiftSodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelSeriesSection.swiftSodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelCommunitySection.swiftSodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelFanTalkSection.swiftSodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelIntroduceSection.swiftSodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelActivitySection.swiftSodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelSnsSection.swift
수정
SodaLive/Sources/ContentView.swiftSodaLive/Sources/I18n/I18n.swift- 필요 시
SodaLive.xcodeproj/project.pbxproj
확인
SodaLive/Sources/V2/Main/Home/Ranking/Repository/MainHomeRankingApi.swiftSodaLive/Sources/V2/Main/Home/Ranking/MainHomeRankingViewModel.swiftSodaLive/Sources/V2/Main/Home/Following/Models/HomeFollowingTabResponse.swiftSodaLive/Sources/V2/Main/MainView.swiftSodaLive/Sources/Chat/ChatTabView.swiftSodaLive/Sources/User/UserApi.swiftSodaLive/Sources/Content/Series/Detail/SeriesDetailViewModel.swiftSodaLive/Sources/V2/Component/SectionTitle.swiftSodaLive/Sources/V2/Component/AudioContentCard.swiftSodaLive/Sources/V2/Component/Card/CommunityPostCard.swiftSodaLive/Sources/Explorer/Profile/Detail/CreatorDetailDialogView.swift
TASK 체크리스트
Phase 1: API와 상태 모델
-
Task 1.1: 크리에이터 채널 홈 Response model 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Models/CreatorChannelHomeResponse.swift - 확인:
SodaLive/Sources/V2/Main/Home/Following/Models/HomeFollowingTabResponse.swift
- 생성:
- 작업 내용:
- PRD의
CreatorChannelHomeResponse와 하위 응답 모델을 SwiftDecodablestruct로 작성한다. - Kotlin
Long필드는 SwiftInt로 선언한다. - list item은 필요한 경우
Identifiable을 채택하고 id는 서버 id 필드를 사용한다. CreatorActivityType은 기존 enum을 재사용하거나 공용 위치로 이동한다. 중복 enum을 만들지 않는다.- nullable URL 필드는 PRD nullable 여부에 맞춰 optional로 선언한다.
- PRD의
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelHomeResponse|struct CreatorChannelCreatorResponse|struct CreatorChannelLiveResponse|struct CreatorChannelAudioContentResponse|struct CreatorChannelDonationResponse|struct CreatorChannelScheduleResponse|struct CreatorChannelSeriesResponse|struct CreatorChannelCommunityPostResponse|struct CreatorChannelFanTalkSummaryResponse|struct CreatorChannelActivityResponse|struct CreatorChannelSnsResponse" SodaLive/Sources/V2/CreatorChannel/Home/Models/CreatorChannelHomeResponse.swift - 기대 결과: PRD의 응답 모델이 Swift 파일에 모두 존재하고 id/count 타입이
Int이다.
- 실행 명령:
- 대상 파일:
-
Task 1.2: 채널 tab enum 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Models/CreatorChannelHomeTab.swift
- 생성:
- 작업 내용:
CreatorChannelHomeTabenum을CaseIterable, Hashable로 만든다.- case는
home,live,audio,series,community,fanTalk,donation순서로 둔다. - title은
홈,라이브,오디오,시리즈,커뮤니티,팬Talk,후원을 반환한다. photo또는화보case는 만들지 않는다.
- 검증 기준:
- 실행 명령:
rg "enum CreatorChannelHomeTab|case home|case live|case audio|case series|case community|case fanTalk|case donation|화보|photo" SodaLive/Sources/V2/CreatorChannel/Home/Models/CreatorChannelHomeTab.swift - 기대 결과: 7개 tab case가 있고
화보/photocase가 없다.
- 실행 명령:
- 후속 구조 변경:
- tab enum은 홈 탭 전용이 아니라 채널 공통 shell 상태이므로 Task 2.4에서
CreatorChannelTab으로 이름과 위치를 정리한다.
- tab enum은 홈 탭 전용이 아니라 채널 공통 shell 상태이므로 Task 2.4에서
- 대상 파일:
-
Task 1.3: API endpoint 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Repository/CreatorChannelHomeApi.swift - 확인:
SodaLive/Sources/V2/Main/Home/Ranking/Repository/MainHomeRankingApi.swift
- 생성:
- 작업 내용:
CreatorChannelHomeApi를TargetType으로 만든다.- case는
getHome(creatorId: Int)하나로 시작한다. - path는
/api/v2/creator-channels/{creatorId}/home형식으로 구성한다. - method는
.get, task는.requestPlain로 둔다. - headers는 기존 V2 API와 동일하게
Authorization: Bearer {token}패턴을 따른다.
- 검증 기준:
- 실행 명령:
rg "enum CreatorChannelHomeApi|getHome\\(creatorId: Int\\)|/api/v2/creator-channels/|/home|TargetType|requestPlain|Authorization" SodaLive/Sources/V2/CreatorChannel/Home/Repository/CreatorChannelHomeApi.swift - 기대 결과: 신규 endpoint와 인증 헤더가 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 1.4: Repository 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Repository/CreatorChannelHomeRepository.swift - 확인:
SodaLive/Sources/V2/Main/Home/Ranking/Repository/MainHomeRankingRepository.swift
- 생성:
- 작업 내용:
CreatorChannelHomeRepository를 만들고MoyaProvider<CreatorChannelHomeApi>를 사용한다.getHome(creatorId:) -> AnyPublisher<Response, MoyaError>메서드를 제공한다.
- 검증 기준:
- 실행 명령:
rg "final class CreatorChannelHomeRepository|MoyaProvider<CreatorChannelHomeApi>|getHome\\(creatorId: Int\\)|AnyPublisher<Response, MoyaError>" SodaLive/Sources/V2/CreatorChannel/Home/Repository/CreatorChannelHomeRepository.swift - 기대 결과: 기존 V2 Repository와 같은 형태가 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 1.5: ViewModel 생성 및 API 실패 placeholder 상태 정의
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeViewModel.swift - 확인:
SodaLive/Sources/V2/Main/Home/Ranking/MainHomeRankingViewModel.swift - 확인:
SodaLive/Sources/User/UserApi.swift - 확인:
SodaLive/Sources/Content/Series/Detail/SeriesDetailViewModel.swift
- 생성:
- 작업 내용:
CreatorChannelHomeViewModel을ObservableObject로 만든다.@Published var isLoading,@Published var response,@Published var hasLoaded,@Published var selectedTab,@Published var isApiFailedPlaceholderVisible를 둔다.fetchHome(creatorId:)에서ApiResponse<CreatorChannelHomeResponse>를 디코딩한다.- 성공 시
response,selectedTab = .home,isApiFailedPlaceholderVisible = false를 갱신한다. - 실패/디코딩 실패 시
response = nil,isApiFailedPlaceholderVisible = true,hasLoaded = true로 두어 기본 shell은 유지할 수 있게 한다. - 초기 구현에서는
follow(creatorId:notify:),unfollow(creatorId:)에 기존UserRepository.creatorFollow,UserRepository.creatorUnFollow패턴을 재사용한다. - mutation 성공 시
response?.creator.isFollow,response?.creator.isNotify가 갱신될 수 있도록 모델 갱신 방식을 구현한다. struct 불변성 때문에 필요한 경우 creator 복사 helper를 둔다.
- 검증 기준:
- 실행 명령:
rg "final class CreatorChannelHomeViewModel|fetchHome\\(creatorId: Int\\)|ApiResponse<CreatorChannelHomeResponse>|isApiFailedPlaceholderVisible|creatorFollow|creatorUnFollow|selectedTab|hasLoaded" SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeViewModel.swift - 기대 결과: 홈 API 디코딩, API 실패 placeholder 상태, 기존 follow/unfollow API 호출이 확인된다.
- 실행 명령:
- 후속 구조 변경:
- title bar mutation은 기존
UserProfile현재 동작과 동일하게 Task 2.4에서CreatorChannelViewModel의creatorFollow(follow:notify:)기반으로 정리한다.
- title bar mutation은 기존
- 대상 파일:
Phase 2: 라우팅과 기본 화면 shell
-
Task 2.1: 기존 creatorDetail 라우팅을 신규 홈으로 연결
- 대상 파일:
- 수정:
SodaLive/Sources/ContentView.swift - 생성:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 확인:
SodaLive/Sources/App/AppStep.swift
- 수정:
- 작업 내용:
AppStep.creatorDetail(userId:)case는 유지한다.ContentView에서.creatorDetail(let userId)destination을CreatorChannelHomeView(creatorId: userId)로 변경한다.- 기존
UserProfileView를 삭제하거나 수정하지 않는다. - 초기 구현에서는
CreatorChannelHomeView가creatorId: Int를 받아 화면을 구성한다.
- 검증 기준:
- 실행 명령:
rg "case \\.creatorDetail|CreatorChannelHomeView\\(creatorId: userId\\)|UserProfileView\\(userId:" SodaLive/Sources/ContentView.swift SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 기대 결과:
.creatorDetail이 신규CreatorChannelHomeView로 연결되고 기존UserProfileView파일은 유지된다.
- 실행 명령:
- 후속 구조 변경:
- 크리에이터 채널 공통 shell 분리 결정에 따라 Task 2.4에서
.creatorDetaildestination을CreatorChannelView(creatorId:)로 변경한다.
- 크리에이터 채널 공통 shell 분리 결정에 따라 Task 2.4에서
- 대상 파일:
-
Task 2.2: 기본 shell과 로딩/API 실패 placeholder 구성
- 대상 파일:
- 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelPlaceholderTabView.swift
- 수정:
- 작업 내용:
@StateObject private var viewModel = CreatorChannelHomeViewModel()를 사용한다.- 최초
onAppear에서hasLoaded == false일 때fetchHome(creatorId:)를 호출한다. - root background는 black으로 둔다.
response == nil && isApiFailedPlaceholderVisible == true이면 title bar, tab-bar, 선택된 tab placeholder만 표시한다.- 로딩 중에는 기존
LoadingView또는 V2 관례에 맞는 loading view를 사용한다. - 홈 외 tab 선택 시
CreatorChannelPlaceholderTabView(title: selectedTab.title)을 표시한다.
- 검증 기준:
- 실행 명령:
rg "@StateObject private var viewModel|fetchHome\\(creatorId: creatorId\\)|isApiFailedPlaceholderVisible|CreatorChannelPlaceholderTabView|LoadingView|Color.black" SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelPlaceholderTabView.swift - 기대 결과: API 호출, 실패 placeholder, 홈 외 tab placeholder shell이 확인된다.
- 실행 명령:
- 후속 구조 변경:
- 공통 shell과 선택 tab/API 상태는 Task 2.4에서
CreatorChannelView/CreatorChannelViewModel로 이동하고,CreatorChannelHomeView는 홈 탭 콘텐츠만 담당한다.
- 공통 shell과 선택 tab/API 상태는 Task 2.4에서
- 대상 파일:
-
Task 2.3: I18n 문구 추가
- 대상 파일:
- 수정:
SodaLive/Sources/I18n/I18n.swift
- 수정:
- 작업 내용:
I18n.CreatorChannelHomeenum을 추가한다.- 섹션명
currentLive,latestAudio,donation,notice,schedule,audio,series,community,fanTalk,introduce,activity,sns를 추가한다. - 액션 문구
follow,talk,viewAll를 추가한다. - 활동 row 문구
debut,liveCount,liveDurationHours,liveContributorCount,audioContentCount,seriesCount를 추가한다. - ko/en/ja 문구를 모두 제공한다.
- 검증 기준:
- 실행 명령:
rg "enum CreatorChannelHome|currentLive|latestAudio|fanTalk|introduce|activity|viewAll|liveDurationHours|seriesCount" SodaLive/Sources/I18n/I18n.swift - 기대 결과: 신규 사용자 노출 문구가
I18n에 존재한다.
- 실행 명령:
- 대상 파일:
-
Task 2.4: 공통 CreatorChannel shell로 구조 정리
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 생성:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelViewModel.swift - 생성/이동:
SodaLive/Sources/V2/CreatorChannel/Models/CreatorChannelTab.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 수정/정리:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeViewModel.swift - 수정:
SodaLive/Sources/ContentView.swift - 확인:
SodaLive/Sources/App/AppStep.swift
- 생성:
- 작업 내용:
ContentView의.creatorDetail(let userId)destination을CreatorChannelView(creatorId: userId)로 연결한다.CreatorChannelView는@StateObject private var viewModel = CreatorChannelViewModel()을 사용한다.CreatorChannelViewModel은isLoading,response,hasLoaded,selectedTab,isApiFailedPlaceholderVisible, follow/notify mutation을 소유한다.- 기존
CreatorChannelHomeViewModel의 홈 API 호출/공통 상태 책임은CreatorChannelViewModel로 이동하고, 남는 책임이 없으면 파일을 제거한다. - title bar의 팔로우/팔로우 취소/알림 설정/알림 설정 취소는 기존
UserProfile현재 UI 흐름과 동일하게UserRepository.creatorFollow(creatorId:follow:notify:)를 사용한다. - 팔로우는
creatorFollow(follow: true, notify: true), 팔로우 취소는creatorFollow(follow: false, notify: false)로 호출한다. ic_bar_bell터치 시creatorFollow(follow: true, notify: true),ic_bar_bell_colored터치 시creatorFollow(follow: true, notify: false)로 호출한다.CreatorChannelHomeTab은CreatorChannelTab으로 이름을 바꾸고 공통 shell 경로로 이동한다.CreatorChannelHomeView는CreatorChannelHomeResponse와 tab 전환 closure를 주입받아 tab-bar 아래 홈 탭 콘텐츠만 렌더링하고, 대화하기 action은CreatorChannelHeaderSection에 유지한다.- API 실패 placeholder 상태에서는
CreatorChannelView가 서버 데이터 없이 가능한 title bar, tab-bar, 선택된 tab placeholder를 유지한다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelView|final class CreatorChannelViewModel|enum CreatorChannelTab|CreatorChannelView\\(creatorId: userId\\)|CreatorChannelHomeView\\(|selectedTab|fetchHome\\(creatorId:|creatorFollow\\(.*follow: true, notify: true|creatorFollow\\(.*follow: false, notify: false|creatorFollow\\(.*follow: true, notify: false" SodaLive/Sources/V2/CreatorChannel SodaLive/Sources/ContentView.swift - 기대 결과: 라우팅 진입점과 선택 tab/API 상태가
CreatorChannelView/CreatorChannelViewModel로 이동했고, title bar follow/notify mutation이 기존UserProfile의creatorFollow(follow:notify:)기준으로 연결되어 있으며,CreatorChannelHomeView는 홈 탭 콘텐츠 렌더링만 담당한다.
- 실행 명령:
- 대상 파일:
Phase 3: Header / Title Bar / Tab Bar / Sticky
-
Task 3.1: title bar 컴포넌트 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTitleBar.swift - 확인:
SodaLive/Sources/Common/FollowButtonImageAsset.swift
- 생성:
- 작업 내용:
- back 버튼, 팔로우/팔로잉 상태 버튼, 알림 상태 아이콘, 더보기 버튼을 표시한다.
- back 버튼은
ic_new_bar_backasset을 사용한다. - 더보기 버튼은
ic_new_moreasset을 사용한다. isFollow == false이면팔로우capsule을 표시한다.isFollow == false상태의 follow capsule에는ic_new_followasset을 사용한다.isFollow == true상태의 following capsule에는ic_new_followingasset을 사용한다.isFollow == true && isNotify == true이면 팔로잉 상태 capsule과 알림 설정 아이콘ic_bar_bell_colored를 표시한다.isFollow == true && isNotify == false이면 팔로잉 상태 capsule과 알림 해제 아이콘ic_bar_bell을 표시한다.ic_new_follow터치 시 부모의 팔로우 action으로creatorFollow(follow: true, notify: true)가 호출되도록 연결한다.ic_new_following터치 시 부모의 팔로우 취소 action으로creatorFollow(follow: false, notify: false)가 호출되도록 연결한다.ic_bar_bell터치 시 부모의 알림 설정 action으로creatorFollow(follow: true, notify: true)가 호출되도록 연결한다.ic_bar_bell_colored터치 시 부모의 알림 설정 취소 action으로creatorFollow(follow: true, notify: false)가 호출되도록 연결한다.- 더보기 버튼은 항상 표시한다.
- 배경 opacity는 외부에서 전달받는
backgroundProgress로 제어한다. - 구현 기준은 Figma
296:14287,296:14288,296:142893개 title bar 상태를 따른다. - title bar 아이콘은
ic_new_bar_back,ic_new_follow,ic_new_following,ic_new_more,ic_bar_bell,ic_bar_bell_colored외 다른 asset으로 대체하지 않는다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelTitleBar|isFollow|isNotify|backgroundProgress|onTapBack|onTapFollow|onTapUnfollow|onTapNotify|onTapUnnotify|onTapMore|ic_new_bar_back|ic_new_follow|ic_new_following|ic_new_more|ic_bar_bell|ic_bar_bell_colored|팔로우" SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTitleBar.swift - 기대 결과: Figma 3개 title bar 상태를 표현하는 조건 분기, 지정된 6개 icon asset 사용, 팔로우/팔로우 취소/알림 설정/알림 설정 취소 tap closure가 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 3.2: 크리에이터 이미지/프로필 헤더 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelHeaderSection.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
- 생성:
- 작업 내용:
- HeaderView의 표시 내용은
CreatorChannelHomeResponse.creator를 사용해 채운다. - 별도 원형/소형 프로필 이미지는 표시하지 않는다.
creator.profileImageUrl은 큰 배경 이미지에만 사용한다.- 큰 배경 이미지 영역은 OS status bar까지 확장되도록 top safe area를 무시한다.
creator.nickname,creator.followerCount를 표시한다.- 이미지 로드 실패 시 기존
DownsampledKFImage또는KFImageplaceholder 관례를 따른다.
- HeaderView의 표시 내용은
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelHeaderSection|CreatorChannelCreatorResponse|profileImageUrl|ignoresSafeArea\\(.*top|nickname|followerCount|DownsampledKFImage|KFImage" SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelHeaderSection.swift SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 기대 결과:
CreatorChannelHomeResponse.creator기반 데이터 표시, 큰 배경 이미지의 top safe area 확장, 별도 프로필 이미지 미표시가 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 3.3: horizontal tab-bar 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTabBar.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 확인:
SodaLive/Sources/V2/Component/TextTabBar.swift
- 생성:
- 작업 내용:
CreatorChannelTab.allCases를 horizontal scroll로 표시한다.- 선택된 tab은 white text와 soda color bottom indicator로 표시한다.
- 비선택 tab은 gray text로 표시한다.
화보tab은 표시하지 않는다.- sticky 상태일 때도 같은 컴포넌트를 사용한다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelTabBar|ScrollView\\(\\.horizontal|CreatorChannelTab.allCases|selectedTab|soda|indicator|화보" SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTabBar.swift SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 기대 결과: 7개 tab만 표시되고 선택 상태 UI가 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 3.4: scroll progress와 sticky 계산 연결
- 대상 파일:
- 수정:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTitleBar.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTabBar.swift
- 수정:
- 작업 내용:
GeometryReader와PreferenceKey기반 scroll offset 또는 geometry preference로 tab-bar와 title bar의 거리를 계산한다.- 거리에 따라 title bar background progress를 0...1로 clamp한다.
- title bar는 header view 위에
ZStack또는overlay형태로 띄운다. - title bar 뒤로 큰 배경 이미지가 보이도록 기본
backgroundProgress는 0, 기본 배경은 투명으로 둔다. - tab-bar가 title bar에 닿으면 tab-bar를 sticky 상태로 고정한다.
- sticky 기준은 디바이스 최상단
y=0이 아니라 title bar 하단이며, sticky 이후 tab-bar는 title bar 하단까지만 스크롤된 뒤 멈춘다. - sticky 이후 OS status bar 영역이 title bar와 동일한 black 배경으로 보이게 상단 overlay를 둔다.
- 검증 기준:
- 실행 명령:
rg "PreferenceKey|GeometryReader|ZStack|overlay|backgroundProgress|Color\\.clear|opacity|isTabBarSticky|clamp|safeAreaInsets|CreatorChannelTitleBar|CreatorChannelTabBar" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTitleBar.swift SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTabBar.swift - 기대 결과: geometry preference 기반 계산, 기본 투명 title bar overlay, scroll 기반 title bar opacity, sticky tab-bar 상태 계산이 확인되고, tab-bar sticky 기준이 디바이스 최상단이 아니라 title bar 하단임이 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 3.5: title bar 닉네임 표시 연결
- 대상 파일:
- 수정:
SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTitleBar.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
- 수정:
- 작업 내용:
CreatorChannelTitleBar에 크리에이터 닉네임을 주입받는 값을 추가한다.- title bar의 back 버튼 우측 Text에는 크리에이터 닉네임을 표시한다.
- 닉네임은 한 줄로 표시하고, 영역을 넘으면 말줄임 처리한다.
- 닉네임이 길어도 우측 팔로우/알림/더보기 영역은 항상 먼저 보이도록 layout priority 또는 고정 영역 우선순위를 적용한다.
- 닉네임은 title bar background opacity가 1일 때만 표시한다.
CreatorChannelView는viewModel.response?.creator.nickname을CreatorChannelTitleBar에 전달한다.
- 검증 기준:
- 실행 명령:
rg "nickname|lineLimit\\(1\\)|truncationMode|layoutPriority|backgroundProgress|opacity|CreatorChannelTitleBar\\(" SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTitleBar.swift SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 기대 결과: title bar에 크리에이터 닉네임이 전달되고, 한 줄 말줄임, 우측 action 영역 우선 노출,
backgroundProgress가 1일 때만 닉네임 표시 조건이 확인된다.
- 실행 명령:
- 대상 파일:
Phase 4: 홈 외 placeholder
- Task 4.1: 홈 외 tab placeholder 연결
- 대상 파일:
- 수정:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 생성:
SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelPlaceholderTabView.swift
- 수정:
- 작업 내용:
selectedTab != .home이면 실제 목록 대신CreatorChannelPlaceholderTabView(title: selectedTab.title)을 표시한다.- 홈 섹션의 전체보기 action 중 별도 기존 route가 없는 경우 대응 tab을 선택하도록 연결한다.
- 팬Talk 전체보기는
selectedTab = .fanTalk로 이동한다.
- 검증 기준:
- 실행 명령:
rg "selectedTab != \\.home|CreatorChannelPlaceholderTabView\\(title: selectedTab.title\\)|selectedTab = \\.fanTalk|selectedTab = \\.audio|selectedTab = \\.series|selectedTab = \\.community|selectedTab = \\.donation" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 기대 결과: 홈 외 tab과 전체보기 placeholder 전환이 확인된다.
- 실행 명령:
- 대상 파일:
Phase 5: 현재 라이브 섹션
- Task 5.1: 현재 라이브 섹션 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelCurrentLiveSection.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift
- 생성:
- 작업 내용:
currentLive == nil이면 섹션을 표시하지 않는다.liveId,title,coverImageUrl,beginDateTimeUtc,price,isAdult를 표시한다.coverImageUrl이 없으면 기존 이미지 placeholder 패턴을 사용한다.isAdult == true이면 기존 성인 콘텐츠 표시 asset/pattern을 사용한다.- card tap은 기존 live detail/live room 진입 흐름이 확인되면 연결하고, 없으면 action closure만 둔다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelCurrentLiveSection|CreatorChannelLiveResponse|currentLive|liveId|coverImageUrl|isAdult|onTapLive" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelCurrentLiveSection.swift SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 기대 결과:
currentLiveoptional 기반 숨김과 live item 표시가 확인된다.
- 실행 명령:
- 대상 파일:
Phase 6: 최신 오디오 콘텐츠 섹션
- Task 6.1: 최신 오디오 콘텐츠 섹션 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelLatestAudioSection.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 확인:
SodaLive/Sources/V2/Component/AudioContentCard.swift
- 생성:
- 작업 내용:
latestAudioContent == nil이면 섹션을 표시하지 않는다.AudioContentCard재사용이 맞으면 사용하고, 태그/잠금 표시가 부족하면 채널 홈 전용 thumbnail wrapper를 만든다.isAdult,isPointAvailable,isFirstContent,seriesName,isOriginalSeries표시를 기존 태그 관례에 맞춘다.- card tap은 기존
AppStep.contentDetail(contentId:)흐름이 맞으면 연결한다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelLatestAudioSection|latestAudioContent|AudioContentCard|isPointAvailable|isFirstContent|isOriginalSeries|contentDetail" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelLatestAudioSection.swift SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 기대 결과: 최신 오디오 optional 기반 숨김, 태그 표시, 상세 진입이 확인된다.
- 실행 명령:
- 대상 파일:
Phase 7: 채널 후원 섹션
- Task 7.1: 채널 후원 섹션 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelDonationSection.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 확인:
SodaLive/Sources/App/AppStep.swift - 확인:
SodaLive/Sources/ContentView.swift
- 생성:
- 디자인 기준:
- Figma 후원 아이템:
567:17927,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=567-17927&m=dev
- Figma 후원 아이템:
- 작업 내용:
channelDonations.isEmpty여도 섹션을 숨기지 않고 Figma290:8820기준의 빈 후원 UI를 표시한다.- 각 item은 Figma 후원 아이템처럼 외곽 card 배경을
#202020, corner radius 14, 내부 vertical spacing 14 기준으로 구성한다. - item 상단의 팬 정보/후원 금액 영역은
profileImageUrl,nickname,createdAtUtc,can을 표시한다. profileImageUrl은 42x42 원형 이미지로 표시하고, 이미지가 없거나 로드 실패 시 기존 프로필 placeholder 패턴을 따른다.nickname은 14pt medium,createdAtUtc상대 시간은 14pt regular로 표시한다.- 후원 금액은 우측 pill에 기존 can icon과
{can}캔형식으로 표시한다. - 팬 이름과 후원 금액을 포함하는 상단 영역의 배경색은 후원 금액
can에 따라 다르게 적용한다.1...50:#E2E2E251...100:#73EE01101...500:#00EAFF501...:#FF4C3C
- 상단 영역 배경이 밝은 색상인
1...500구간에서는nickname은 black,createdAtUtc는 기존 gray 700 계열로 표시한다.501...구간은 red 배경 대비를 위해nickname을 white,createdAtUtc를gray100으로 표시한다. 금액 pill은 모든 구간에서#202020배경과 white text를 유지한다. message는 상단 영역 아래에 16pt regular, white text로 표시하고, 긴 문장은 화면 폭 안에서 줄바꿈한다.- 전체보기는 기존
AppStep.channelDonationAll(creatorId:)로 이동하지 않고, 부모에서 주입받은onSelectTab(.donation)closure로 현재 크리에이터 채널의 후원 tab을 선택한다. - 빈 후원 UI는 section title 아래
#202020card,처음으로 크리에이터를\n후원해 보세요!문구, white capsule후원하기버튼, blackic_new_donationicon/text를 표시한다. - 후원하기 버튼은 기존
UserProfileView에서 사용하던LiveRoomDonationDialogView를 그대로 표시한다. - Dialog 설정은 기존 채널 후원과 동일하게
isAudioContentDonation: false,messageLimit: 100,I18n.MemberChannel.secretDonationLabel,I18n.MemberChannel.secretDonationMinimumCanMessage,shouldPrefixSecretInMessagePlaceholder: false를 사용한다. - 후원 전송은 기존
ChannelDonationViewModel.postChannelDonation을 재사용하고, 성공 시 현재 채널 홈 API를 다시 호출해 후원 섹션에 즉시 반영한다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelDonationSection|CreatorChannelDonationEmptyCard|처음으로 크리에이터를|ic_new_donation|LiveRoomDonationDialogView|ChannelDonationViewModel|postChannelDonation|fetchHome\(creatorId: creatorId\)|createdAtUtc|can|#E2E2E2|#73EE01|#00EAFF|#FF4C3C|onSelectTab|\\.donation|channelDonationAll" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelDonationSection.swift - 기대 결과: 빈 후원 UI, 후원 금액별 상단 영역 컬러, 기존 후원 Dialog 재사용, 후원 성공 후 홈 API 재조회, 후원 tab 전체보기 연결이 확인되고 신규 구현 경로에서
channelDonationAllroute를 사용하지 않는다.
- 실행 명령:
- 대상 파일:
Phase 8: 공지 섹션
- Task 8.1: 공지 섹션 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelNoticeSection.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 확인:
SodaLive/Sources/V2/Component/Card/CommunityPostCard.swift
- 생성:
- 작업 내용:
notices.isEmpty이면 섹션을 표시하지 않는다.CreatorChannelCommunityPostResponse를 사용한다.- 공지 섹션은 커뮤니티와 별도 component로 둔다.
imageUrl,audioUrl,price,existOrdered,likeCount,commentCount를 기존 커뮤니티 카드 패턴으로 표시한다.- item tap/댓글/구매 action은 기존 route가 확인되는 범위에서만 연결하고, 불명확한 action은 빈 closure로 둔다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelNoticeSection|notices|CreatorChannelCommunityPostResponse|CommunityPostCard|existOrdered|commentCount" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelNoticeSection.swift SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 기대 결과: 공지 섹션이 커뮤니티 섹션과 분리되어 있고 빈 배열 숨김이 확인된다.
- 실행 명령:
- 대상 파일:
Phase 9: 스케줄 섹션
- Task 9.1: 스케줄 섹션 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelScheduleSection.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 확인:
SodaLive/Sources/V2/Main/MainView.swift
- 생성:
- 작업 내용:
schedules.isEmpty이면 섹션을 표시하지 않는다.- 각 item의
scheduledAtUtc,title,type,targetId를 표시한다. - tap action은 closure로 분리하고,
.live는 라이브 상세,.liveReplay와.audio는 동일한 오디오 콘텐츠 상세,.community는 커뮤니티 화면으로 분기한다. .unknown은 crash 없이 무시한다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelScheduleSection|schedules|scheduledAtUtc|CreatorActivityType|targetId|unknown|onTapSchedule" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelScheduleSection.swift SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 기대 결과: 스케줄 표시와 type별 tap closure가 확인된다.
- 실행 명령:
- 대상 파일:
Phase 10: 오디오 섹션
- Task 10.1: 오디오 목록 섹션 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelAudioSection.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 확인:
SodaLive/Sources/V2/Component/AudioContentCard.swift
- 생성:
- 작업 내용:
audioContents.isEmpty이면 섹션을 표시하지 않는다.- Figma 홈 노출 개수만 표시한다.
AudioContentCard와 채널 홈 전용 thumbnail wrapper를 재사용한다.- 전체보기는 부모에서 주입받은
onSelectTab(.audio)closure로 연결한다. - item tap은 기존
AppStep.contentDetail(contentId:)흐름으로 연결한다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelAudioSection|audioContents|AudioContentCard|prefix|onSelectTab|\\.audio|contentDetail" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelAudioSection.swift SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 기대 결과: 빈 배열 숨김, 홈 노출 개수 제한, 오디오 tab 전체보기 연결이 확인된다.
- 실행 명령:
- 대상 파일:
Phase 11: 시리즈 섹션
- Task 11.1: 시리즈 섹션 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelSeriesSection.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift
- 생성:
- 작업 내용:
series.isEmpty이면 섹션을 표시하지 않는다.- 각 item의
seriesId,coverImageUrl,isNew,isOriginal을 사용한다. - 카드에는 시리즈 제목과 콘텐츠 수를 표시하지 않는다.
- 전체보기는 부모에서 주입받은
onSelectTab(.series)closure로 연결한다. - item tap은 기존
AppStep.seriesDetail(seriesId:)흐름으로 연결한다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelSeriesSection|seriesId|coverImageUrl|isNew|isOriginal|onSelectTab|\\.series|seriesDetail" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelSeriesSection.swift SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 기대 결과: 시리즈 카드, 전체보기, 상세 진입이 확인된다.
- 실행 명령:
- 대상 파일:
Phase 12: 커뮤니티 섹션
- Task 12.1: 커뮤니티 섹션 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelCommunitySection.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 확인:
SodaLive/Sources/V2/Component/Card/CommunityPostCard.swift
- 생성:
- 작업 내용:
communities.isEmpty이면 섹션을 표시하지 않는다.CommunityPostCard가 요구사항과 맞으면 재사용한다.- 유료/잠금 게시물은 기존
price,existOrdered처리 패턴을 따른다. - 전체보기는 부모에서 주입받은
onSelectTab(.community)closure로 연결한다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelCommunitySection|communities|CommunityPostCard|existOrdered|onTapPurchase|onSelectTab|\\.community" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelCommunitySection.swift SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 기대 결과: 커뮤니티 섹션과 전체보기 tab 전환이 확인된다.
- 실행 명령:
- 대상 파일:
Phase 13: 팬Talk 섹션
- Task 13.1: 팬Talk 섹션 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelFanTalkSection.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift
- 생성:
- 작업 내용:
fanTalk.latestFanTalk == nil이면 섹션을 표시하지 않는다.totalCount,nickname,profileImageUrl,content,languageCode,createdAtUtc를 표시한다.- 전체보기는 부모에서 주입받은
onSelectTab(.fanTalk)closure로 연결한다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelFanTalkSection|latestFanTalk|totalCount|languageCode|createdAtUtc|onSelectTab|\\.fanTalk" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelFanTalkSection.swift SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 기대 결과: 최신 팬Talk가 있을 때만 표시되고 전체보기는 팬Talk tab으로 이동한다.
- 실행 명령:
- 대상 파일:
Phase 14: 소개 섹션
- Task 14.1: 소개 섹션 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelIntroduceSection.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift
- 생성:
- 작업 내용:
introduce가 빈 문자열이면 섹션을 표시하지 않는다.- 긴 텍스트는 화면 폭을 넘지 않게 줄바꿈한다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelIntroduceSection|introduce|trimmingCharacters|fixedSize|lineLimit" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelIntroduceSection.swift SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 기대 결과: 빈 소개 숨김과 긴 텍스트 줄바꿈 처리가 확인된다.
- 실행 명령:
- 대상 파일:
Phase 15: 활동 섹션
- Task 15.1: 활동 섹션 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelActivitySection.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift
- 생성:
- 작업 내용:
debutDateUtc와dDay를2026.06.11(D+1)형식으로 표시한다.liveCount,liveDurationHours,liveContributorCount,audioContentCount,seriesCount를 표시한다.화보row는 만들지 않는다.- 숫자는 기존
.comma()등 프로젝트 formatting 패턴을 따른다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelActivitySection|debutDateUtc|dDay|liveCount|liveDurationHours|liveContributorCount|audioContentCount|seriesCount|화보|comma" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelActivitySection.swift - 기대 결과: 활동 6개 항목만 표시되고 화보 row가 없다.
- 실행 명령:
- 대상 파일:
Phase 16: SNS 섹션
- Task 16.1: SNS 섹션 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelSnsSection.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 확인:
SodaLive/Sources/Explorer/Profile/Detail/CreatorDetailDialogView.swift
- 생성:
- 작업 내용:
instagramUrl,youtubeUrl,xUrl,kakaoOpenChatUrl,fancimmUrl중 유효한 URL만 표시한다.- 표시 순서는
Instagram,YouTube,X,KakaoTalk,Fancimm(팬심M)이다. - 아이콘은 각각
ic_sns_instagram,ic_sns_youtube,ic_sns_x,ic_sns_kakao,ic_sns_fancimm을 사용한다. - tap 시
openURL또는 기존 in-app web 흐름을 따른다. - 유효한 SNS URL이 하나도 없으면 섹션을 표시하지 않는다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelSnsSection|ic_sns_instagram|ic_sns_youtube|ic_sns_x|ic_sns_kakao|ic_sns_fancimm|openURL|fancimmUrl" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelSnsSection.swift - 기대 결과: SNS asset과 URL 필터링, tap 처리 방식이 확인된다.
- 실행 명령:
- 대상 파일:
Phase 17: 대화하기 액션 영역
-
Task 17.1: 대화하기 액션 섹션 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelTalkActionSection.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift
- 생성:
- 작업 내용:
isAiChatAvailable == true일 때만 대화하기 버튼을 표시한다.- 버튼 아이콘은
ic_new_talk를 사용한다. - 버튼은 영역 중앙에 배치한다.
- 버튼이 없어도 영역 높이와 vertical spacing을 유지한다.
isDmAvailable과ic_new_dm은 이번 UI에 사용하지 않는다.- 버튼 tap은
CreatorChannelHeaderSection이 부모에서 주입받은onTapTalkclosure로 전달한다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelTalkActionSection|isAiChatAvailable|ic_new_talk|ic_new_dm|frame\\(height|onTapTalk" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelTalkActionSection.swift - 기대 결과: 대화하기만 조건부 표시되고 DM 버튼 구현이 없다.
- 실행 명령:
- 대상 파일:
-
Task 17.2: 기존 AI 채팅방 진입 guard 연결
- 대상 파일:
- 수정:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelViewModel.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/Repository/CreatorChannelHomeRepository.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelHeaderSection.swift - 확인:
SodaLive/Sources/Chat/Character/Detail/CharacterDetailView.swift - 확인:
SodaLive/Sources/Chat/Character/Detail/CharacterDetailViewModel.swift - 확인:
SodaLive/Sources/Chat/ChatTabView.swift - 확인:
SodaLive/Sources/App/AppStep.swift
- 수정:
- 작업 내용:
CreatorChannelView가CreatorChannelHeaderSection에onTapTalkclosure를 주입한다.- token이 없으면
.login으로 이동한다. - 국가 코드를 trim/uppercase 처리하고, 비어 있거나
KR이면 한국으로 취급한다. - 한국 사용자는
auth == false일 때 기존 본인인증 confirm/fullScreenCover 흐름을 재사용하거나 같은 조건으로 연결한다. - 비한국 사용자는 기존
ChatTabView의 비한국 분기와 동일하게auth조건 비교를 적용한다. - 본인인증과 콘텐츠 보기 설정 guard를 통과하면
creator.characterId로TalkApi.createChatRoom을 호출하고, 성공 응답의chatRoomId로.chatRoom(id:)에 바로 진입한다. - 본인인증 완료 후 실행되는
pendingAction도.characterDetail(characterId:)가 아니라 같은 채팅방 생성 후.chatRoom(id:)진입 helper를 사용한다.
- 검증 기준:
- 실행 명령:
rg "onTapTalk|countryCode|uppercased\\(\\)|isKoreanCountry|auth == false|isShowAuthConfirmView|createChatRoom|chatRoom\\(id:|setAppStep\\(step: \\.login\\)" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift SodaLive/Sources/V2/CreatorChannel/CreatorChannelViewModel.swift SodaLive/Sources/V2/CreatorChannel/Home/Repository/CreatorChannelHomeRepository.swift SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelHeaderSection.swift - 기대 결과: 기존 AI 채팅 guard와 동일한 국가/본인인증 분기가 유지되고, guard 통과 후 캐릭터 상세가 아닌 채팅방으로 직접 이동한다.
- 실행 명령:
rg "characterDetail\\(characterId: characterId\\)" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 기대 결과: 검색 결과가 없다.
- 실행 명령:
- 대상 파일:
Phase 18: 최종 조립과 검증
-
Task 18.1: 홈 섹션 순서 조립
- 대상 파일:
- 수정:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift
- 수정:
- 작업 내용:
CreatorChannelView에서 공통 shell 순서를 PRD와 동일하게 조립한다.- 공통 shell 배치: 크리에이터 이미지 header를 먼저 배치하고, title bar는 header 위에 overlay로 띄우며, 그 아래 tab-bar와 선택된 tab content를 배치한다.
- title bar 기본 배경은 투명이고 scroll progress에 따라 black으로 전환된다.
- 대화하기 액션은 최신 코드 기준처럼
CreatorChannelHeaderSection내부에 유지한다. CreatorChannelHomeView에서 홈 탭 콘텐츠 순서를 최신 코드 기준과 동일하게 조립한다.- 홈 탭 콘텐츠 순서: 현재 라이브, 최신 오디오, 채널 후원, 공지, 스케줄, 오디오, 시리즈, 커뮤니티, 팬Talk, 소개, 활동, SNS.
- 각 섹션은 자신의 데이터가 없으면 숨긴다.
- API 실패 placeholder 상태에서는 데이터 기반 섹션을 표시하지 않는다.
- 검증 기준:
- 실행 명령:
rg -n "ZStack|overlay|Color\\.clear|backgroundProgress|CreatorChannelTitleBar|CreatorChannelHeaderSection|CreatorChannelTabBar|CreatorChannelHomeView|CreatorChannelTalkActionSection|CreatorChannelCurrentLiveSection|CreatorChannelLatestAudioSection|CreatorChannelDonationSection|CreatorChannelNoticeSection|CreatorChannelScheduleSection|CreatorChannelAudioSection|CreatorChannelSeriesSection|CreatorChannelCommunitySection|CreatorChannelFanTalkSection|CreatorChannelIntroduceSection|CreatorChannelActivitySection|CreatorChannelSnsSection" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - 기대 결과: 최신 코드 기준의 공통 shell, header 대화하기 액션, 홈 탭 콘텐츠 순서대로 조립되어 있다.
- 실행 명령:
- 대상 파일:
-
Task 18.2: 프로젝트 파일 포함 여부 확인
- 대상 파일:
- 확인/필요 시 수정:
SodaLive.xcodeproj/project.pbxproj
- 확인/필요 시 수정:
- 작업 내용:
- 신규 Swift 파일이 Xcode target에 포함되는지 확인한다.
- 자동 포함되지 않는 프로젝트 구조이면
project.pbxproj에 신규 파일을 추가한다. - 기존 사용자 변경이 있는 경우 해당 변경을 되돌리지 않는다.
- 검증 기준:
- 실행 명령:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build - 기대 결과: 신규 파일 누락으로 인한 compile error가 없다.
- 실행 명령:
- 대상 파일:
-
Task 18.3: PRD 성공 기준 회귀 점검
- 대상 파일:
- 확인:
docs/20260701_크리에이터_채널_홈/prd.md - 확인:
SodaLive/Sources/V2/CreatorChannel/** - 확인:
SodaLive/Sources/V2/CreatorChannel/Home/**
- 확인:
- 작업 내용:
- PRD
Success Criteria를 한 줄씩 대조한다. 화보, DM 버튼, API 실패 전체 error state가 구현에 들어가지 않았는지 검색한다.ic_sns_*,ic_new_talk, title bar icon asset, 기존UserProfile기준 follow/notify mutation, title bar/header overlay, AI 채팅 guard가 구현에 포함됐는지 검색한다.
- PRD
- 검증 기준:
- 실행 명령:
rg -n "화보|photo|ic_new_dm|DM|ic_new_talk|ic_sns_|ic_new_bar_back|ic_new_follow|ic_new_following|ic_new_more|ic_bar_bell|ic_bar_bell_colored|creatorFollow|follow: true, notify: true|follow: false, notify: false|follow: true, notify: false|onTapNotify|onTapUnnotify|ZStack|overlay|Color\\.clear|isApiFailedPlaceholderVisible|countryCode|auth == false" SodaLive/Sources/V2/CreatorChannel SodaLive/Sources/ContentView.swift - 기대 결과: 제외 범위는 UI 구현에 없고, 필수 요구사항 키워드는 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 18.4: 빌드 검증
- 대상 파일:
- 확인:
docs/agent-guides/build-test-verification.md
- 확인:
- 작업 내용:
- 공식 검증 명령으로 Debug build를 실행한다.
- 실패 시 에러 로그를 기준으로 최소 수정하고 같은 명령을 다시 실행한다.
- 검증 기준:
- 실행 명령:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build - 기대 결과: exit code 0으로 빌드가 완료된다.
- 실행 명령:
- 대상 파일:
Phase 19: 스케줄 라우팅 및 라이브 상세 전역 표시 계층 보정
-
Task 19.1: 스케줄 라우팅과 라이브 상세 표시 흐름 조사
- 대상 파일:
- 확인:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelScheduleSection.swift - 확인:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 확인:
SodaLive/Sources/App/AppState.swift - 확인:
SodaLive/Sources/ContentView.swift - 비교:
SodaLive/Sources/V2/Main/MainView.swift - 비교:
docs/20260714_라이브룸_전역_표시와_키보드_레이아웃_수정/prd.md
- 확인:
- 작업 내용:
.live와.liveReplay가 두 스케줄 handler에서 같은 라이브 분기로 처리되는지 확인한다..live의targetId는 room ID,.liveReplay와.audio의targetId는 콘텐츠 ID라는 타입 의미를 대조한다.liveDetailSheet상태 갱신 지점과LiveDetailView렌더 위치를 분리해 추적한다.- 메인 화면에서는 보이고 navigation destination에서는 가려지는 계층 차이를 기존 전역 라이브룸 표시 방식과 비교한다.
- 검증 기준:
- 실행 명령:
rg -n -A14 "func handle(Following)?ScheduleTap" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift SodaLive/Sources/V2/Main/MainView.swift - 기대 결과:
.liveReplay가.live와 묶여 잘못된 라이브 경로로 전달되는 라우팅 문제를 확인한다. - 실행 명령:
rg -n "liveDetailSheet|LiveDetailView\\(|\\.overlay" SodaLive/Sources/App/AppState.swift SodaLive/Sources/ContentView.swift - 기대 결과:
.live상태 갱신은 정상이며LiveDetailView렌더 위치가NavigationStack루트 콘텐츠 내부인 표시 계층 문제를 확인한다.
- 실행 명령:
- 대상 파일:
-
Task 19.2: 스케줄 type별 라우팅 보정
- 대상 파일:
- 수정:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 수정:
SodaLive/Sources/V2/Main/MainView.swift
- 수정:
- 작업 내용:
CreatorChannelView.handleScheduleTap에서.live만showLiveDetail(targetId)로 전달한다.CreatorChannelView.handleScheduleTap에서.liveReplay와.audio는 동일한 오디오 콘텐츠 상세 화면을 여는showContentDetail(targetId)로 전달한다.MainView.handleFollowingScheduleTap에서.live는 기존handleRecommendationLiveTap(roomId:)흐름을 유지한다.MainView.handleFollowingScheduleTap에서.liveReplay와.audio는 동일한 오디오 콘텐츠 상세 화면을 여는handleRecommendationContentTap(contentId:)로 전달한다.- 신규 route나 helper를 추가하지 않고 기존 상세 진입 함수를 재사용한다.
- 검증 기준:
- 실행 명령:
rg -n -A14 "func handle(Following)?ScheduleTap" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift SodaLive/Sources/V2/Main/MainView.swift - 기대 결과: 두 handler 모두
.live는 라이브 경로,.liveReplay와.audio는 동일한 오디오 콘텐츠 상세 경로로 분리되어 있다. - 실행 명령:
rg -n "case \\.live, \\.liveReplay" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift SodaLive/Sources/V2/Main/MainView.swift - 기대 결과: 검색 결과가 없다.
- 실행 명령:
- 대상 파일:
-
Task 19.3: 라이브 상세 렌더 호스트를 앱 전역 overlay로 이동
- 대상 파일:
- 수정:
SodaLive/Sources/ContentView.swift
- 수정:
- 작업 내용:
NavigationStack내부 루트ZStack의 기존liveDetailSheet렌더 분기를 복제하지 않고NavigationStack.overlay의ZStack첫 번째 계층으로 이동한다.- 외부 overlay에서 동일 상태를 처리한 뒤 불필요해진 기존 위치의 렌더 분기는 제거한다.
roomId, 네 개의 action callback,onClickClose의hideLiveDetailSheet()호출과 animation은 변경하지 않는다.- 전역 라이브룸과 외부 이동 확인 다이얼로그는 라이브 상세 뒤에 배치해 기존 우선순위를 유지한다.
- 검증 기준:
- 실행 명령:
rg -n "NavigationStack|if let liveDetailSheet|LiveDetailView\\(|LiveRoomViewV2\\(|leaveLiveNavigationDialog|\\.overlay" SodaLive/Sources/ContentView.swift - 기대 결과:
if let liveDetailSheet상태 기반 렌더 분기는NavigationStack바깥 overlay에 하나만 존재하고 기존 루트ZStack에는 남지 않으며, 표시 순서가 라이브 상세 → 라이브룸 → 외부 이동 확인 다이얼로그다.
- 실행 명령:
- 대상 파일:
-
Task 19.4: 정적 검사와 Debug 빌드 검증
- 대상 파일:
- 확인:
SodaLive/Sources/ContentView.swift - 확인:
SodaLive/Sources/App/AppState.swift - 확인:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 확인:
SodaLive/Sources/V2/Main/MainView.swift
- 확인:
- 작업 내용:
- 전역
LiveDetailView호스트 수와 기존.liveDetail호출부를 검색한다. .liveReplay가 라이브 분기로 남아 있지 않은지 검색한다.- whitespace 오류를 확인하고 공식
SodaLive-devDebug 빌드를 실행한다.
- 전역
- 검증 기준:
- 실행 명령:
git diff --check - 기대 결과: 출력 없이 exit code 0이다.
- 실행 명령:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build - 기대 결과:
** BUILD SUCCEEDED **.
- 실행 명령:
- 대상 파일:
-
Task 19.5: 진입점별 수동 동작 검증
- 대상 화면:
- 크리에이터 채널 홈의
.live예약 스케줄 - 크리에이터 채널 홈의
.liveReplay스케줄 - 메인 팔로잉 화면의
.liveReplay스케줄 - 크리에이터 채널 라이브 탭
- 메인 화면의 기존 라이브 상세 진입점
- 크리에이터 채널 홈의
- 작업 내용:
- 크리에이터 채널의
.live항목 tap 직후 현재 화면 위에 라이브 상세가 보이는지 확인한다. - 크리에이터 채널과 메인의
.liveReplay항목 tap 시.audio와 동일한 오디오 콘텐츠 상세로 이동하고 라이브 상세나 라이브룸이 표시되지 않는지 확인한다. - dim 영역 또는 닫기 버튼으로 상세를 닫았을 때 진입 전 화면과 navigation path가 유지되는지 확인한다.
- 라이브 상세에서 라이브룸에 입장할 수 있는 기존 경로는 라이브룸이 상세 위에 표시되는지 확인한다.
- 크리에이터 채널의
- 검증 기준:
- 기대 결과:
.live만 라이브 상세를 표시하고.liveReplay와.audio는 동일한 오디오 콘텐츠 상세로 이동하며, 닫기와 라이브룸 표시 우선순위에 회귀가 없다.
- 기대 결과:
- 대상 화면:
검증 기록
- 2026-07-01:
docs/20260701_크리에이터_채널_홈/prd.md를 기준으로 API 선구현, Figma 섹션별 phase, placeholder tab, API 실패 placeholder, DM/화보 제외 범위를 계획에 반영했다. - 2026-07-01:
docs/agent-guides/documentation-policy.md를 확인해plan-task.md경로와 phase/task/checklist 형식을 검증했다. - 2026-07-01:
docs/agent-guides/build-test-verification.md를 확인해 최종 빌드 검증 명령을xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build로 반영했다. - 2026-07-01: 기존 V2 홈 API/Repository/ViewModel, AI 채팅 guard, follow/unfollow API, SNS asset 사용처를 확인해 대상 파일과 검증 기준에 반영했다.
- 2026-07-01: 사용자 요청에 따라 기존 Phase 4
대화하기 액션 영역을 Phase 17로 이동하고, 기존 Phase 517을 Phase 416으로 한 칸씩 당겼다. - 2026-07-01: Header, TitleBar, TabBar만으로 sticky 동작을 먼저 확인할 수 있도록 Phase 3에
CreatorChannelHomeView_Previews기반 debug-only sticky scaffold 검증 task를 추가했다. 2026-07-02 구조 변경으로 실제 검증 대상은CreatorChannelView_Previews로 갱신했다. - 2026-07-01: Phase 1~2 구현을 완료하고
rg체크리스트 및xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build성공으로 신규 API/상태 모델, 라우팅, 기본 shell, I18n, 프로젝트 파일 포함을 검증했다. - 2026-07-02: 사용자 확인 사항과 최신 코드 기준을 반영해 title bar, 크리에이터 프로필 header, tab-bar를
CreatorChannelView공통 shell로 분리하고,CreatorChannelHomeView는 tab-bar 아래 홈 탭 콘텐츠만 담당하며 대화하기 action은CreatorChannelHeaderSection내부에 유지하도록 PRD와 계획을 갱신했다. - 2026-07-02: 이미 완료된 Phase 1~2 기록은 보존하고, 후속 구조 정리를 위해 Task 2.4
공통 CreatorChannel shell로 구조 정리를 추가했다. - 2026-07-02: 사용자 확인 사항과 최신 코드 기준을 반영해 title bar Figma URL 3종과 사용할 아이콘 asset(
ic_new_bar_back,ic_new_follow,ic_new_following,ic_new_more,ic_bar_bell,ic_bar_bell_colored)을 Task 3.1 및 최종 회귀 검색 기준에 추가했다. - 2026-07-03: Phase 5 현재 라이브 섹션을 구현했다. Figma
290:8950기준으로 LIVE pill, 시작 시간, 제목, 커버 이미지/placeholder, 유료 캔 배지, 성인 표시를 반영하고CreatorChannelHomeView에currentLiveoptional 기반으로 연결했다. - 2026-07-03: Phase 7 채널 후원 섹션을 구현했다. Figma
296:14908, 후원 아이템567:17927기준으로 후원 금액별 상단 컬러(1...50#E2E2E2,51...100#73EE01,101...500#00EAFF,501...#FF4C3C),ic_new_donation후원하기 버튼,.donationtab 전체보기 전환, Preview 금액 구간별 샘플을 반영했다.xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build성공으로 신규 파일 target 포함과 컴파일을 검증했다. - 2026-07-03: 사용자 요청에 따라 Phase 7 후원하기 버튼을 기존
LiveRoomDonationDialogView/ChannelDonationViewModel.postChannelDonation흐름으로 연결하고, 성공 시CreatorChannelViewModel.fetchHome(creatorId:)로 현재 채널 홈 데이터를 다시 불러와 후원 섹션에 즉시 반영하도록 계획을 갱신했다. 후원 내역이 없는 경우 Figma290:8820기준의 빈 후원 UI를 표시하도록 Task 7.1에 반영했다. - 2026-07-03: Phase 6 최신 오디오 콘텐츠 섹션을 구현했다. Figma
296:14898, tag567:18272,567:18274기준으로 88px 썸네일, 상단/하단 tag overlay,Newlabel, 제목, 재생시간을 반영하고latestAudioContentoptional 기반 숨김 및AppStep.contentDetail(contentId:)상세 진입을 연결했다.rg체크리스트와xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build성공으로 검증했다. - 2026-07-03: Phase 4를 완료해
CreatorChannelView에서 홈 탭은CreatorChannelHomeView, 홈 외 탭은CreatorChannelPlaceholderTabView(title: selectedTab.title)로 분기하고, 홈 섹션 전체보기용 tab 선택 closure가.audio,.series,.community,.fanTalk,.donation으로 전환되도록 연결했다. - 2026-07-02: 기존
UserProfile구현과 최신 코드 기준을 확인해 title bar 팔로우/팔로우 취소/알림 설정/알림 설정 취소를UserRepository.creatorFollow(creatorId:follow:notify:)로 처리하고,ic_bar_bell/ic_bar_bell_colored터치 시 각각notify: true/notify: false호출이 일어나도록 계획에 반영했다. - 2026-07-03: Task 3.4 구현을 완료했다.
CreatorChannelView에서 geometry preference로 tab-bar 위치를 추적하고, sticky 기준을 디바이스 최상단이 아닌 title bar 하단(safeAreaInsets.top + 56)으로 계산하도록 변경했다.rg "PreferenceKey|GeometryReader|ZStack|overlay|backgroundProgress|Color\\.clear|opacity|isTabBarSticky|clamp|safeAreaInsets|CreatorChannelTitleBar|CreatorChannelTabBar" ...기준 키워드를 확인했고,xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build가BUILD SUCCEEDED로 완료됐다. - 2026-07-03: Task 3.5 구현을 완료했다.
CreatorChannelTitleBar에 크리에이터 닉네임 주입값을 추가하고,backgroundProgress가 1일 때만 한 줄 말줄임으로 표시되도록 연결했다. 우측 팔로우/알림/더보기 영역은layoutPriority로 우선 노출되도록 처리했다.rg "nickname|lineLimit\\(1\\)|truncationMode|layoutPriority|backgroundProgress|opacity|CreatorChannelTitleBar\\(" ...기준 키워드를 확인했고,xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build가BUILD SUCCEEDED로 완료됐다. - 2026-07-02: Task 3.2 구현을 완료하고
CreatorChannelHeaderSection을 공통 shell에 연결했다.rg "struct CreatorChannelHeaderSection|CreatorChannelCreatorResponse|profileImageUrl|ignoresSafeArea\\(.*top|nickname|followerCount|DownsampledKFImage|KFImage" SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelHeaderSection.swift SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift와xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build성공으로 검증했다. - 2026-07-02: Task 3.1 title bar 컴포넌트를
SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTitleBar.swift로 생성하고CreatorChannelView의 inline title bar를 교체했다.rg "struct CreatorChannelTitleBar|isFollow|isNotify|backgroundProgress|onTapBack|onTapFollow|onTapUnfollow|onTapNotify|onTapUnnotify|onTapMore|ic_new_bar_back|ic_new_follow|ic_new_following|ic_new_more|ic_bar_bell|ic_bar_bell_colored|팔로우" SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTitleBar.swift와xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build성공으로 검증했다. - 2026-07-02: 사용자 확인 사항을 반영해 HeaderView는
CreatorChannelHomeResponse.creator데이터로 채우고, 별도 프로필 이미지 없이 큰 배경 이미지만 표시하며, title bar는 기본 투명 배경으로 header 위에 overlay되도록 Task 3.2/3.4/3.5와 최종 검증 기준을 갱신했다. - 2026-07-03: 사용자 요청에 따라 Task 17.2의 대화하기 액션을 캐릭터 상세 이동이 아니라 기존 Character Detail 하단
대화하기와 동일한TalkApi.createChatRoom호출 후.chatRoom(id:)직접 진입으로 변경했다.CreatorChannelView의 로그인/한국 본인인증/content settings guard는 유지했고, 본인인증 완료 후pendingAction도 같은startChat(characterId:)helper를 사용하도록 연결했다.rg -n "characterDetail\\(characterId: characterId\\)|startChat\\(characterId:|createChatRoom\\(characterId:|chatRoom\\(id:" "SodaLive/Sources/V2/CreatorChannel"와 ast-grepAppState.shared.setAppStep(step: .characterDetail(characterId: $ID))검색으로 CreatorChannel 대화하기 경로에 캐릭터 상세 이동이 남지 않았음을 확인했다. 테스트는xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" test실행 결과Scheme SodaLive-dev is not currently configured for the test action.으로 RED/GREEN 자동화가 불가했다. 빌드는xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build가BUILD SUCCEEDED로 완료됐다. - 2026-07-03: Phase 18 최종 조립과 검증을 완료했다. 최신 코드 기준에 맞춰 대화하기 액션은
CreatorChannelHeaderSection내부에 유지하고,CreatorChannelHomeView홈 콘텐츠 순서는 현재 라이브, 최신 오디오, 채널 후원, 공지, 스케줄, 오디오, 시리즈, 커뮤니티, 팬Talk, 소개, 활동, SNS 순서로 확인했다. title bar 알림 설정 asset은 최신 코드 기준인ic_bar_bell_colored를 유지했다.rg -n "ZStack|overlay|Color\\.clear|backgroundProgress|CreatorChannelTitleBar|CreatorChannelHeaderSection|CreatorChannelTabBar|CreatorChannelHomeView|CreatorChannelTalkActionSection|CreatorChannelCurrentLiveSection|CreatorChannelLatestAudioSection|CreatorChannelDonationSection|CreatorChannelNoticeSection|CreatorChannelScheduleSection|CreatorChannelAudioSection|CreatorChannelSeriesSection|CreatorChannelCommunitySection|CreatorChannelFanTalkSection|CreatorChannelIntroduceSection|CreatorChannelActivitySection|CreatorChannelSnsSection" ...와rg -n "화보|photo|ic_new_dm|DM|ic_new_talk|ic_sns_|ic_new_bar_back|ic_new_follow|ic_new_following|ic_new_more|ic_bar_bell|ic_bar_bell_colored|creatorFollow|follow: true, notify: true|follow: false, notify: false|follow: true, notify: false|onTapNotify|onTapUnnotify|ZStack|overlay|Color\\.clear|isApiFailedPlaceholderVisible|countryCode|auth == false" ...로 성공 기준을 회귀 점검했고, 신규 CreatorChannel Swift 파일은project.pbxproj의 Sources phase에 포함되어 있음을 확인했다.xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build는BUILD SUCCEEDED로 완료됐다. - 2026-07-20: 크리에이터 채널 홈 스케줄 item에서
CreatorChannelScheduleSection→CreatorChannelView.handleScheduleTap→showLiveDetail→AppState.setAppStep(.liveDetail)까지 이벤트와 상태 갱신이 정상임을 확인했다.liveDetailSheet의 렌더 호스트가NavigationStack루트ZStack안에 있어 destination인CreatorChannelView뒤에 가려지는 것이 근본 원인이다. 기존AppState상태나 채널 callback을 복제하지 않고SodaLive/Sources/ContentView.swift에서 해당 렌더 분기만 기존 외부 overlay로 옮기는 최소 수정안을 계획했다. 구현과 빌드·수동 검증은 아직 수행하지 않았다. - 2026-07-20: 사용자 확인에 따라 Task 19.3에 기존
liveDetailSheet렌더 분기를 복제하지 않고 외부 overlay로 이동하며, 이동 후 기존 루트ZStack의 분기를 제거하고 상태 기반 호스트가 하나만 남는지 검증하도록 명시했다. - 2026-07-20: 사용자 확인에 따라
LiveDetailView표시 대상을.live로 한정하고,.liveReplay는 다시 듣기 콘텐츠의contentId로.audio와 동일한 오디오 콘텐츠 상세에 진입하도록 요구사항을 수정했다. 현재CreatorChannelView.handleScheduleTap과MainView.handleFollowingScheduleTap이 모두.liveReplay를.live와 묶고 있어 두 파일의 분기를 수정하는 Task 19.2를 추가하고 기존 후속 task를 19.3~19.5로 재번호화했다. - 2026-07-20: Task 19.2~19.4 구현을 완료했다.
CreatorChannelView.handleScheduleTap과MainView.handleFollowingScheduleTap에서.live만 라이브 경로로 두고.audio, .liveReplay를 콘텐츠 상세 경로로 분리했다.ContentView의liveDetailSheet상태 기반LiveDetailView렌더 호스트는 기존 루트ZStack에서 제거하고NavigationStack.overlay의 첫 번째 계층으로 이동해 라이브 상세 → 전역 라이브룸 → 외부 이동 확인 다이얼로그 순서를 맞췄다.rg -n -A14 "func handle(Following)?ScheduleTap|if let liveDetailSheet|LiveDetailView\\(|LiveRoomViewV2\\(|leaveLiveNavigationDialog|\\.overlay|case \\.live, \\.liveReplay" ...로.liveReplay묶음 제거와 overlay 위치를 확인했고,git diff --check는 출력 없이 통과했다.sourcekit-lsp는 active 상태였으나 변경 파일별lsp_diagnostics가 3초 내 fresh diagnostics를 반환하지 않았다. 공식xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build는** BUILD SUCCEEDED **로 완료됐다. Task 19.5의 실제 진입점별 기기/시뮬레이터 수동 검증은 아직 수행하지 않았다.
Phase 20: 종료된 라이브 상세 DIM 잔류 보정
-
Task 20.1: 종료된 라이브 상세 실패 흐름 문서화와 원인 확인
- 대상 파일:
- 확인:
SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift - 확인:
SodaLive/Sources/Live/Room/Detail/LiveDetailViewModel.swift - 확인:
SodaLive/Sources/ContentView.swift
- 확인:
- 작업 내용:
LiveDetailViewModel.getDetail실패 시 로컬isShowPopup만 켜지고LiveDetailView표시 상태가 해제되지 않는 흐름을 확인한다.LiveDetailView가 닫히지 않으면Color.black.opacity(0.7)DIM 배경이 계속 남는 것을 수정 대상으로 기록한다.
- 검증 기준:
- 실행 명령:
rg -n "getDetail\(roomId:|isShowPopup = true|hideView\(|onClickClose|liveDetailSheet" SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift SodaLive/Sources/Live/Room/Detail/LiveDetailViewModel.swift SodaLive/Sources/ContentView.swift - 기대 결과: 상세 조회 실패와 overlay 닫기 경로가 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 20.2: 종료된 라이브 상세 실패 시 DIM 해제
- 대상 파일:
- 수정:
SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift
- 수정:
- 작업 내용:
LiveDetailView가 room 데이터 없이 상세 조회 실패 토스트를 표시해야 하는 경우 전역 토스트로 메시지를 전달한다.- 같은 실패 흐름에서 기존
onClickClose/AppState.back()기반 close 경로를 호출해LiveDetailView와 DIM overlay를 닫는다. - 정상적으로 room 데이터를 받은 라이브 상세 표시와 기존 닫기 버튼 동작은 변경하지 않는다.
- 검증 기준:
- 실행 명령:
rg -n "handleDetailLoadFailure|AppState.shared.errorMessage|AppState.shared.isShowErrorPopup|hideView\(" SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift - 기대 결과: 상세 조회 실패 시 전역 토스트와 close 경로 호출이 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 20.3: 정적 검사와 Debug 빌드 검증
- 대상 파일:
- 확인:
SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift - 확인:
SodaLive/Sources/ContentView.swift
- 확인:
- 작업 내용:
- 종료 라이브 실패 흐름과 기존 overlay 순서를 정적 검색으로 확인한다.
git diff --check와 공식 Debug 빌드를 실행한다.
- 검증 기준:
- 실행 명령:
git diff --check - 기대 결과: 출력 없이 exit code 0이다.
- 실행 명령:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build - 기대 결과:
** BUILD SUCCEEDED **.
- 실행 명령:
- 대상 파일:
-
2026-07-20: Phase 20 구현을 완료했다.
LiveDetailViewModel.getDetail실패 시viewModel.isShowPopup = true만 설정되고LiveDetailView자체 표시 상태는 해제되지 않아Color.black.opacity(0.7)DIM 배경이 남는 원인을 확인했다.LiveDetailView에서viewModel.isShowPopup변경을 감지하되viewModel.room == nil인 상세 조회 실패에만handleDetailLoadFailure()를 호출하도록 했고, 해당 helper는 기존 메시지를AppState.shared.errorMessage/isShowErrorPopup으로 넘긴 뒤hideView()로 기존onClickClose또는AppState.back()닫기 경로를 실행한다.rg -n "handleDetailLoadFailure|AppState.shared.errorMessage|AppState.shared.isShowErrorPopup|viewModel.room == nil|hideView\\(|Phase 20|이미 종료된 라이브 상세 조회 실패" ...와git diff --check를 통과했다.lsp_diagnostics는Kingfisher모듈 해석 문제로 실패했으나, 공식xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build는** BUILD SUCCEEDED **로 완료됐다. 실제 종료된 라이브 API 응답을 사용하는 기기/시뮬레이터 수동 검증은 수행하지 않았다. -
2026-07-20: Phase 20 후속 보정을 적용했다. 종료된 라이브 상세 실패 처리에서 전역 토스트 상태를 먼저 켠 뒤
LiveDetailView를 닫으면 overlay 해제와 함께 토스트 표시가 누락될 수 있어, 실패 메시지를 지역 변수로 보존하고viewModel.isShowPopup = false및hideView()로 DIM overlay를 먼저 해제한 다음 다음 main runloop에서AppState.shared.errorMessage/isShowErrorPopup을 설정하도록 순서를 조정했다. -
2026-07-20: Phase 20 토스트 계층 보정을 적용했다.
sodaToast는 적용된 content 위에 overlay를 붙이는 modifier인데, 기존 전역 토스트 host가NavigationStack내부 루트ZStack에 붙어 있어 navigation destination 및 전역LiveDetailViewoverlay보다 아래 계층에 남을 수 있었다.ContentView의 전역.sodaToast(isPresented: $appState.isShowErrorPopup, ...)를NavigationStack.overlay뒤의 최상위 modifier로 이동해 DIM overlay 해제 후에도 토스트가 최상위에서 표시되도록 했다. -
2026-07-20: Phase 20 추가 보정을 적용했다. 전역
AppState.isShowErrorPopup이 이미true인 상태에서 같은 값을 다시 설정하면SodaToastModifier.onChange(of: isPresented)가 재실행되지 않을 수 있고,LiveDetailViewclose animation과 같은 runloop에서 토스트를 켜면 표시 타이밍이 겹칠 수 있어 종료 상세 실패 처리에서AppState.shared.isShowErrorPopup = false로 먼저 reset한 뒤hideView()를 호출하고, 0.25초 후AppState.shared.errorMessage/isShowErrorPopup을 설정하도록 조정했다.lsp_diagnostics는 기존 SourceKit 환경의No such module 'Kingfisher'로 실패했으나,git diff --check는 통과했고xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build는** BUILD SUCCEEDED **로 완료됐다.
Phase 21: 채널 홈 후원 카드 반응형 너비 보정
-
Task 21.1: 후원 카드 너비 계산 보정
- 대상 파일:
- 수정:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelDonationSection.swift
- 수정:
- 작업 내용:
- 기준 디바이스 너비
402pt와 최대 카드 너비374pt를 사용한다. - 디바이스 너비가
402pt이상이면 기존374pt를 유지한다. - 디바이스 너비가
402pt미만이면374 × deviceWidth / 402비율로 카드 너비만 축소한다. - 카드 높이, 내부 구성, 패딩, 카드 간격과 후원 탭 세로 목록은 변경하지 않는다.
- 기준 디바이스 너비
- 검증 기준:
- 실행 명령:
swift -e 'import Foundation; let widths = [320.0, 375.0, 402.0, 430.0]; print(widths.map { 374.0 * min($0 / 402.0, 1.0) })' - 기대 결과:
320pt,375pt에서는 비례 축소되고402pt,430pt에서는 모두374pt다. - 실행 명령:
rg -n "baseDeviceWidth|maxCardWidth|cardWidth|frame\\(width:" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelDonationSection.swift - 기대 결과: 후원 섹션 카드에만 반응형 너비 계산이 적용되어 있다.
- 실행 명령:
- 대상 파일:
-
Task 21.2: 정적 검사와 Debug 빌드 검증
- 대상 파일:
- 확인:
docs/20260701_크리에이터_채널_홈/prd.md - 확인:
docs/20260701_크리에이터_채널_홈/plan-task.md - 확인:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelDonationSection.swift
- 확인:
- 작업 내용:
- 문서 요구사항과 구현 계산식이 일치하는지 확인한다.
- whitespace 오류를 확인하고 공식
SodaLive-devDebug 빌드를 실행한다.
- 검증 기준:
- 실행 명령:
git diff --check - 기대 결과: 출력 없이 exit code 0이다.
- 실행 명령:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build - 기대 결과:
** BUILD SUCCEEDED **.
- 실행 명령:
- 대상 파일:
-
2026-07-20: Phase 21 구현을 완료했다.
CreatorChannelDonationSection의 기존 고정374pt카드 너비를374 × min(deviceWidth / 402, 1)계산값으로 교체해402pt이상에서는 기존 너비를 유지하고 작은 디바이스에서만 비례 축소되도록 했다.swift -module-cache-path /tmp/sodalive-swift-module-cache -e 'import Foundation; let widths = [320.0, 375.0, 402.0, 430.0]; print(widths.map { 374.0 * min($0 / 402.0, 1.0) })'실행 결과는[297.71144278606965, 348.8805970149254, 374.0, 374.0]이었다.rg로 계산식 적용 위치를 확인했고git diff --check를 통과했다.xcodebuild -workspace SodaLive.xcworkspace -scheme SodaLive-dev -configuration Debug -destination 'platform=iOS Simulator,id=224FBAAE-B5C7-4A10-9143-3944A3280E48' -derivedDataPath /tmp/sodalive-shell-derived-escalated build는** BUILD SUCCEEDED **로 완료됐다. 프로젝트에 테스트 번들 타깃이 없어 별도 단위 테스트는 실행하지 않았다.