Files
sodalive-ios/docs/20260701_크리에이터_채널_홈/plan-task.md

60 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 아래 홈 탭 콘텐츠만 렌더링한다.
  • 홈 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는 Swift Int로 통일한다.
  • 빈 섹션은 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_fill asset을 사용한다.
  • SNS 아이콘은 ic_sns_instagram, ic_sns_youtube, ic_sns_x, ic_sns_kakao, ic_sns_fancimm asset을 사용한다.
  • 기존 AppStep.creatorDetail(userId:) 진입은 새 크리에이터 채널 화면으로 연결한다.

주요 대상 파일

생성

  • SodaLive/Sources/V2/CreatorChannel/Home/Models/CreatorChannelHomeResponse.swift
  • SodaLive/Sources/V2/CreatorChannel/Models/CreatorChannelTab.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/Repository/CreatorChannelHomeApi.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/Repository/CreatorChannelHomeRepository.swift
  • SodaLive/Sources/V2/CreatorChannel/CreatorChannelViewModel.swift
  • SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift
  • SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTitleBar.swift
  • SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelHeaderSection.swift
  • SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTabBar.swift
  • SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelPlaceholderTabView.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelTalkActionSection.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelCurrentLiveSection.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelLatestAudioSection.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelDonationSection.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelNoticeSection.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelScheduleSection.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelAudioSection.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelSeriesSection.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelCommunitySection.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelFanTalkSection.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelIntroduceSection.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelActivitySection.swift
  • SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelSnsSection.swift

수정

  • SodaLive/Sources/ContentView.swift
  • SodaLive/Sources/I18n/I18n.swift
  • 필요 시 SodaLive.xcodeproj/project.pbxproj

확인

  • SodaLive/Sources/V2/Main/Home/Ranking/Repository/MainHomeRankingApi.swift
  • SodaLive/Sources/V2/Main/Home/Ranking/MainHomeRankingViewModel.swift
  • SodaLive/Sources/V2/Main/Home/Following/Models/HomeFollowingTabResponse.swift
  • SodaLive/Sources/V2/Main/MainView.swift
  • SodaLive/Sources/Chat/ChatTabView.swift
  • SodaLive/Sources/User/UserApi.swift
  • SodaLive/Sources/Content/Series/Detail/SeriesDetailViewModel.swift
  • SodaLive/Sources/V2/Component/SectionTitle.swift
  • SodaLive/Sources/V2/Component/AudioContentCard.swift
  • SodaLive/Sources/V2/Component/Card/CommunityPostCard.swift
  • SodaLive/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와 하위 응답 모델을 Swift Decodable struct로 작성한다.
      • Kotlin Long 필드는 Swift Int로 선언한다.
      • list item은 필요한 경우 Identifiable을 채택하고 id는 서버 id 필드를 사용한다.
      • CreatorActivityType은 기존 enum을 재사용하거나 공용 위치로 이동한다. 중복 enum을 만들지 않는다.
      • nullable URL 필드는 PRD nullable 여부에 맞춰 optional로 선언한다.
    • 검증 기준:
      • 실행 명령: 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
    • 작업 내용:
      • CreatorChannelHomeTab enum을 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가 있고 화보/photo case가 없다.
    • 후속 구조 변경:
      • tab enum은 홈 탭 전용이 아니라 채널 공통 shell 상태이므로 Task 2.4에서 CreatorChannelTab으로 이름과 위치를 정리한다.
  • Task 1.3: API endpoint 생성

    • 대상 파일:
      • 생성: SodaLive/Sources/V2/CreatorChannel/Home/Repository/CreatorChannelHomeApi.swift
      • 확인: SodaLive/Sources/V2/Main/Home/Ranking/Repository/MainHomeRankingApi.swift
    • 작업 내용:
      • CreatorChannelHomeApiTargetType으로 만든다.
      • 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
    • 작업 내용:
      • CreatorChannelHomeViewModelObservableObject로 만든다.
      • @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에서 CreatorChannelViewModelcreatorFollow(follow:notify:) 기반으로 정리한다.

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를 삭제하거나 수정하지 않는다.
      • 초기 구현에서는 CreatorChannelHomeViewcreatorId: 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에서 .creatorDetail destination을 CreatorChannelView(creatorId:)로 변경한다.
  • 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는 홈 탭 콘텐츠만 담당한다.
  • Task 2.3: I18n 문구 추가

    • 대상 파일:
      • 수정: SodaLive/Sources/I18n/I18n.swift
    • 작업 내용:
      • I18n.CreatorChannelHome enum을 추가한다.
      • 섹션명 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()을 사용한다.
      • CreatorChannelViewModelisLoading, 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_fill 터치 시 creatorFollow(follow: true, notify: false)로 호출한다.
      • CreatorChannelHomeTabCreatorChannelTab으로 이름을 바꾸고 공통 shell 경로로 이동한다.
      • CreatorChannelHomeViewCreatorChannelHomeResponse와 tab 전환 closure를 주입받아 tab-bar 아래 홈 탭 콘텐츠만 렌더링한다.
      • 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이 기존 UserProfilecreatorFollow(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_back asset을 사용한다.
      • 더보기 버튼은 ic_new_more asset을 사용한다.
      • isFollow == false이면 팔로우 capsule을 표시한다.
      • isFollow == false 상태의 follow capsule에는 ic_new_follow asset을 사용한다.
      • isFollow == true 상태의 following capsule에는 ic_new_following asset을 사용한다.
      • isFollow == true && isNotify == true이면 팔로잉 상태 capsule과 알림 설정 아이콘 ic_bar_bell_fill을 표시한다.
      • 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_fill 터치 시 부모의 알림 설정 취소 action으로 creatorFollow(follow: true, notify: false)가 호출되도록 연결한다.
      • 더보기 버튼은 항상 표시한다.
      • 배경 opacity는 외부에서 전달받는 backgroundProgress로 제어한다.
      • 구현 기준은 Figma 296:14287, 296:14288, 296:14289 3개 title bar 상태를 따른다.
      • title bar 아이콘은 ic_new_bar_back, ic_new_follow, ic_new_following, ic_new_more, ic_bar_bell, ic_bar_bell_fill 외 다른 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_fill|팔로우" 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 또는 KFImage placeholder 관례를 따른다.
    • 검증 기준:
      • 실행 명령: 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
    • 작업 내용:
      • GeometryReaderPreferenceKey 기반 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일 때만 표시한다.
      • CreatorChannelViewviewModel.response?.creator.nicknameCreatorChannelTitleBar에 전달한다.
    • 검증 기준:
      • 실행 명령: 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
      • 기대 결과: currentLive optional 기반 숨김과 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
    • 작업 내용:
      • channelDonations.isEmpty여도 섹션을 숨기지 않고 Figma 290: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: #E2E2E2
        • 51...100: #73EE01
        • 101...500: #00EAFF
        • 501...: #FF4C3C
      • 상단 영역 배경이 밝은 색상이므로 nickname은 black, createdAtUtc는 기존 gray 700 계열로 표시하고, 금액 pill은 #202020 배경과 white text를 유지한다.
      • message는 상단 영역 아래에 16pt regular, white text로 표시하고, 긴 문장은 화면 폭 안에서 줄바꿈한다.
      • 전체보기는 기존 AppStep.channelDonationAll(creatorId:)로 이동하지 않고, 부모에서 주입받은 onSelectTab(.donation) closure로 현재 크리에이터 채널의 후원 tab을 선택한다.
      • 빈 후원 UI는 section title 아래 #202020 card, 처음으로 크리에이터를\n후원해 보세요! 문구, white capsule 후원하기 버튼, black ic_new_donation icon/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 전체보기 연결이 확인되고 신규 구현 경로에서 channelDonationAll route를 사용하지 않는다.

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 분기는 기존 MainView.handleFollowingScheduleTap과 같은 기준을 따른다.
      • .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
    • 작업 내용:
      • debutDateUtcdDay2026.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을 유지한다.
      • isDmAvailableic_new_dm은 이번 UI에 사용하지 않는다.
      • 버튼 tap은 부모에서 주입받은 onTapTalk closure로 전달한다.
    • 검증 기준:
      • 실행 명령: 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/Home/CreatorChannelHomeView.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
    • 작업 내용:
      • CreatorChannelViewCreatorChannelHomeViewonTapTalk closure를 주입한다.
      • token이 없으면 .login으로 이동한다.
      • 국가 코드를 trim/uppercase 처리하고, 비어 있거나 KR이면 한국으로 취급한다.
      • 한국 사용자는 auth == false일 때 기존 본인인증 confirm/fullScreenCover 흐름을 재사용하거나 같은 조건으로 연결한다.
      • 비한국 사용자는 기존 ChatTabView의 비한국 분기와 동일하게 auth 조건 비교를 적용한다.
      • 본인인증과 콘텐츠 보기 설정 guard를 통과하면 creator.characterIdTalkApi.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/Home/CreatorChannelHomeView.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으로 전환된다.
      • CreatorChannelHomeView에서 홈 탭 콘텐츠 순서를 PRD와 동일하게 조립한다.
      • 홈 탭 콘텐츠 순서: 대화하기, 현재 라이브, 최신 오디오, 채널 후원, 공지, 스케줄, 오디오, 시리즈, 커뮤니티, 팬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
      • 기대 결과: PRD의 공통 shell과 홈 탭 콘텐츠 순서대로 조립되어 있다.
  • 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가 구현에 포함됐는지 검색한다.
    • 검증 기준:
      • 실행 명령: 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_fill|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으로 빌드가 완료된다.

검증 기록

  • 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 아래 홈 탭 콘텐츠만 담당하도록 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_fill)을 Task 3.1 및 최종 회귀 검색 기준에 추가했다.
  • 2026-07-03: Phase 5 현재 라이브 섹션을 구현했다. Figma 290:8950 기준으로 LIVE pill, 시작 시간, 제목, 커버 이미지/placeholder, 유료 캔 배지, 성인 표시를 반영하고 CreatorChannelHomeViewcurrentLive optional 기반으로 연결했다.
  • 2026-07-03: Phase 7 채널 후원 섹션을 구현했다. Figma 296:14908, 후원 아이템 567:17927 기준으로 후원 금액별 상단 컬러(1...50 #E2E2E2, 51...100 #73EE01, 101...500 #00EAFF, 501... #FF4C3C), ic_new_donation 후원하기 버튼, .donation tab 전체보기 전환, Preview 금액 구간별 샘플을 반영했다. xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build 성공으로 신규 파일 target 포함과 컴파일을 검증했다.
  • 2026-07-03: 사용자 요청에 따라 Phase 7 후원하기 버튼을 기존 LiveRoomDonationDialogView/ChannelDonationViewModel.postChannelDonation 흐름으로 연결하고, 성공 시 CreatorChannelViewModel.fetchHome(creatorId:)로 현재 채널 홈 데이터를 다시 불러와 후원 섹션에 즉시 반영하도록 계획을 갱신했다. 후원 내역이 없는 경우 Figma 290:8820 기준의 빈 후원 UI를 표시하도록 Task 7.1에 반영했다.
  • 2026-07-03: Phase 6 최신 오디오 콘텐츠 섹션을 구현했다. Figma 296:14898, tag 567:18272, 567:18274 기준으로 88px 썸네일, 상단/하단 tag overlay, New label, 제목, 재생시간을 반영하고 latestAudioContent optional 기반 숨김 및 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_fill 터치 시 각각 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 buildBUILD 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 buildBUILD 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.swiftxcodebuild -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_fill|팔로우" SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelTitleBar.swiftxcodebuild -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-grep AppState.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 buildBUILD SUCCEEDED로 완료됐다.