18 KiB
18 KiB
크리에이터 채널 팬Talk 탭 구현 계획
기준 문서
- PRD:
docs/20260704_크리에이터_채널_팬Talk_탭/prd.md - 기존 크리에이터 채널 홈 PRD:
docs/20260701_크리에이터_채널_홈/prd.md - 기존 크리에이터 채널 후원 탭 구현 계획:
docs/20260704_크리에이터_채널_후원_탭/plan-task.md - 코드 스타일:
docs/agent-guides/code-style.md - 빌드/검증:
docs/agent-guides/build-test-verification.md - Figma 전체 화면:
290:9139,https://www.figma.com/design/HmN1yNdJ3EIpqknFL0Hkab/-%EA%B3%B5%EC%9C%A0%EC%9A%A9-%EB%B3%B4%EC%9D%B4%EC%8A%A4%EC%98%A8-UI-UX-%EA%B8%B0%ED%9A%8D%EB%AC%B8%EC%84%9C?node-id=290-9139&m=dev - Figma 아이템 뷰(답글 없음):
290:9145,https://www.figma.com/design/HmN1yNdJ3EIpqknFL0Hkab/-%EA%B3%B5%EC%9C%A0%EC%9A%A9-%EB%B3%B4%EC%9D%B4%EC%8A%A4%EC%98%A8-UI-UX-%EA%B8%B0%ED%9A%8D%EB%AC%B8%EC%84%9C?node-id=290-9145&m=dev - Figma 아이템 뷰(답글 있음):
290:9147,https://www.figma.com/design/HmN1yNdJ3EIpqknFL0Hkab/-%EA%B3%B5%EC%9C%A0%EC%9A%A9-%EB%B3%B4%EC%9D%B4%EC%8A%A4%EC%98%A8-UI-UX-%EA%B8%B0%ED%9A%8D%EB%AC%B8%EC%84%9C?node-id=290-9147&m=dev - Figma 더보기 anchored context popup:
666:36114,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=666-36114&m=dev - Figma Empty:
290:9001,https://www.figma.com/design/HmN1yNdJ3EIpqknFL0Hkab/-%EA%B3%B5%EC%9C%A0%EC%9A%A9-%EB%B3%B4%EC%9D%B4%EC%8A%A4%EC%98%A8-UI-UX-%EA%B8%B0%ED%9A%8D%EB%AC%B8%EC%84%9C?node-id=290-9001&m=dev
구현 원칙
- 기존
CreatorChannelView의 공통 shell, header, sticky tab-bar, title bar 동작은 유지한다. CreatorChannelTab.fanTalk콘텐츠만 신규CreatorChannelFanTalkTabView로 교체한다.- 팬Talk API 모델은 홈 탭 모델과 타입명 충돌이 나지 않도록 분리한다.
- sort-bar는 정렬 없이
전체 {fanTalkCount}만 표시한다. - 신고는 기존
CheersReportDialogView와ReportRepository.report의ReportType.CHEERS흐름을 재사용한다. - 삭제는 기존
ExplorerRepository.modifyCheers(cheersId:content:isActive:)에isActive=false를 전달하는 흐름을 재사용한다. - 더보기 버튼은
ic_new_more를 사용한다. - 내가 쓴 글이면
수정하기,삭제하기를 표시하고, 내가 쓴 글이 아니지만 내 채널이면삭제하기만 표시한다. - 글쓰기와 수정하기 action은 신규 글쓰기 페이지 구현 전까지 no-op placeholder로 둔다.
- 내 채널인 경우 우측하단 글쓰기 floating button과 empty view 내부
응원 남기기버튼을 모두 표시하지 않는다. - 우측하단 plus button은
CreatorChannelFloatingActionMenu의 privatefloatingButton과 동일한 UI이므로, 팬Talk 전용으로 별도 구현하지 않고CreatorChannel/Components하위 공용 icon floating button으로 추출해 재사용한다.
주요 대상 파일
생성
SodaLive/Sources/V2/CreatorChannel/FanTalk/Models/CreatorChannelFanTalkTabResponse.swiftSodaLive/Sources/V2/CreatorChannel/FanTalk/Repository/CreatorChannelFanTalkApi.swiftSodaLive/Sources/V2/CreatorChannel/FanTalk/Repository/CreatorChannelFanTalkRepository.swiftSodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkViewModel.swiftSodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swiftSodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkCountBar.swiftSodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkListItem.swiftSodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkActionPopup.swiftSodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkEmptyView.swiftSodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelFloatingIconButton.swift
수정
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swiftSodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelFloatingActionMenu.swiftSodaLive/Sources/V2/CreatorChannel/Home/Models/CreatorChannelHomeResponse.swiftSodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelFanTalkSection.swiftSodaLive/Sources/I18n/I18n.swift- 필요 시
SodaLive.xcodeproj/project.pbxproj
TASK 체크리스트
Phase 1: 문서와 API 모델
-
Task 1.1: PRD와 계획 문서 생성
- 대상 파일:
- 생성:
docs/20260704_크리에이터_채널_팬Talk_탭/prd.md - 생성:
docs/20260704_크리에이터_채널_팬Talk_탭/plan-task.md
- 생성:
- 검증 기준:
- 실행 명령:
rg "290:9139|290:9145|290:9147|666:36114|290:9001|CreatorChannelFanTalkTabResponse|/api/v2/creator-channels/.*/fan-talks|ic_new_more" docs/20260704_크리에이터_채널_팬Talk_탭 - 기대 결과: Figma URL, 응답 모델, API path, 액션 요구사항이 문서에 기록된다.
- 실행 명령:
- 대상 파일:
-
Task 1.2: 팬Talk 탭 Response model 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/FanTalk/Models/CreatorChannelFanTalkTabResponse.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/Models/CreatorChannelHomeResponse.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelFanTalkSection.swift
- 생성:
- 작업 내용:
CreatorChannelFanTalkTabResponse,CreatorChannelFanTalkItemResponse,CreatorChannelFanTalkReplyResponse를Decodable로 생성한다.- 홈 탭 기존
CreatorChannelFanTalkResponse와 충돌하지 않도록 홈 탭 타입명을 변경하거나 신규 타입명을 다르게 둔다. Identifiable은fanTalkId를id로 사용한다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelFanTalkTabResponse|fanTalkCount|fanTalks|hasNext|struct CreatorChannelFanTalkItemResponse|writerId|creatorReplies|struct CreatorChannelFanTalkReplyResponse" SodaLive/Sources/V2/CreatorChannel/FanTalk/Models/CreatorChannelFanTalkTabResponse.swift
- 실행 명령:
- 대상 파일:
Phase 2: API, Repository, ViewModel
-
Task 2.1: 팬Talk 탭 API endpoint 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/FanTalk/Repository/CreatorChannelFanTalkApi.swift
- 생성:
- 작업 내용:
CreatorChannelFanTalkApi.getFanTalks(creatorId:page:size:)를 만든다.- path는
/api/v2/creator-channels/{creatorId}/fan-talks로 구성한다. - query parameter는
page,size만 보낸다.
- 검증 기준:
- 실행 명령:
rg "CreatorChannelFanTalkApi|getFanTalks|/api/v2/creator-channels/|/fan-talks|page|size|URLEncoding.queryString" SodaLive/Sources/V2/CreatorChannel/FanTalk/Repository/CreatorChannelFanTalkApi.swift
- 실행 명령:
- 대상 파일:
-
Task 2.2: 팬Talk 탭 Repository 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/FanTalk/Repository/CreatorChannelFanTalkRepository.swift
- 생성:
- 작업 내용:
MoyaProvider<CreatorChannelFanTalkApi>를 사용하는getFanTalks(...)publisher를 제공한다.
- 검증 기준:
- 실행 명령:
rg "CreatorChannelFanTalkRepository|MoyaProvider<CreatorChannelFanTalkApi>|AnyPublisher<Response, MoyaError>|getFanTalks" SodaLive/Sources/V2/CreatorChannel/FanTalk/Repository/CreatorChannelFanTalkRepository.swift
- 실행 명령:
- 대상 파일:
-
Task 2.3: 팬Talk 탭 ViewModel 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkViewModel.swift
- 생성:
- 작업 내용:
- 상태는 loading, loadingNextPage, response, fanTalks, page, size, hasNext, hasLoaded, error toast, 신고/삭제 dialog 상태를 둔다.
fetchFirstPage(creatorId:)는page=0,size=20으로 조회한다.fetchNextPageIfNeeded(creatorId:currentItem:)는 마지막 item 기준으로 다음 페이지를 조회한다.- 첫 페이지는 목록 교체, 다음 페이지는 append한다.
report(reason:)는ReportRequest(type: .CHEERS, cheersId: selectedFanTalkId, reason: reason)를 호출한다.deleteSelectedFanTalk(creatorId:)는ExplorerRepository.modifyCheers(..., isActive: false)를 호출하고 성공 후 첫 페이지를 다시 조회한다.- 최신 요청만 반영하도록
latestRequestId패턴을 사용한다.
- 검증 기준:
- 실행 명령:
rg "CreatorChannelFanTalkViewModel|fetchFirstPage|fetchNextPageIfNeeded|isLoadingNextPage|latestRequestId|report\\(|deleteSelectedFanTalk|ReportType\\.CHEERS|modifyCheers|hasNext" SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkViewModel.swift
- 실행 명령:
- 대상 파일:
Phase 3: Figma 섹션별 UI
-
Task 3.1: 팬Talk count bar 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkCountBar.swift
- 생성:
- 작업 내용:
- Figma sort-bar 기준으로 높이 52pt, 좌측
전체 {fanTalkCount}만 표시한다. - 정렬 버튼/아이콘/action은 포함하지 않는다.
- Figma sort-bar 기준으로 높이 52pt, 좌측
- 검증 기준:
- 실행 명령:
rg "CreatorChannelFanTalkCountBar|fanTalkCount|전체|frame\\(height: 52\\)|ic_new_sort|selectedSort" SodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkCountBar.swift - 기대 결과: count bar 구현이 확인되고 정렬 관련 문자열은 없어야 한다.
- 실행 명령:
- 대상 파일:
-
Task 3.2: 팬Talk item 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkListItem.swift
- 생성:
- 작업 내용:
- 작성자 프로필 42pt, 닉네임/상대 시간, 본문 50pt inset, 하단 separator를 구현한다.
- 답글이 있으면 좌측 라인과 답글 카드를 표시한다.
isMine || isOwnCreatorChannel이면ic_new_more버튼을 표시한다.- 그 외에는
신고텍스트 버튼을 표시한다. - 프로필 이미지와 답글 프로필 이미지는 Kingfisher 기반 기존 컴포넌트를 사용한다.
- 검증 기준:
- 실행 명령:
rg "CreatorChannelFanTalkListItem|writerProfileImageUrl|writerNickname|createdAtUtc|creatorReplies|ic_new_more|신고|Color\\.gray800|Color\\.gray900|42|20" SodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkListItem.swift
- 실행 명령:
- 대상 파일:
-
Task 3.3: 더보기 anchored context popup 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkActionPopup.swift
- 생성:
- 작업 내용:
- Figma
666:36114기준으로 borderColor.gray700, backgroundColor.gray900, radius 14pt를 사용한다. - 내가 쓴 글이면
수정하기,삭제하기를 표시한다. - 내가 쓴 글이 아니지만 내 채널이면
삭제하기만 표시한다. - tap action은 부모에서 주입한다.
- Figma
- 검증 기준:
- 실행 명령:
rg "CreatorChannelFanTalkActionPopup|수정하기|삭제하기|Color\\.gray700|Color\\.gray900|cornerRadius\\(14\\)|onTapEdit|onTapDelete" SodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkActionPopup.swift
- 실행 명령:
- 대상 파일:
-
Task 3.4: Empty view 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkEmptyView.swift
- 생성:
- 작업 내용:
- Figma
290:9001기준으로아직 응원이 없습니다.\n처음으로 크리에이터를 응원해 보세요!문구를 표시한다. - plus 아이콘과
응원 남기기텍스트가 있는 capsule button을 표시한다. - 내 채널이면 button을 숨긴다.
- tap action은 부모에서 주입한다.
- Figma
- 검증 기준:
- 실행 명령:
rg "CreatorChannelFanTalkEmptyView|아직 응원이 없습니다|처음으로 크리에이터를 응원해 보세요|응원 남기기|showsWriteButton|onTapWrite" SodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkEmptyView.swift
- 실행 명령:
- 대상 파일:
-
Task 3.5: 공용 icon floating button 추출
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelFloatingIconButton.swift - 수정:
SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelFloatingActionMenu.swift
- 생성:
- 작업 내용:
CreatorChannelFloatingActionMenu내부 privatefloatingButton과 같은 66pt 원형 버튼, 38pt 아이콘, background color, plain button style을 공용 컴포넌트로 분리한다.- 공용 컴포넌트는
imageName,backgroundColor,accessibilityLabel,action을 받는다. - 기존
CreatorChannelFloatingActionMenu는 privatefloatingButton구현 대신 공용 컴포넌트를 사용하도록 변경한다. - 팬Talk 우측하단 글쓰기 plus button은 이 공용 컴포넌트에
imageName: "ic_plus_no_bg",backgroundColor: Color.soda400를 전달해 사용한다. - 글쓰기 plus button은 텍스트를 표시하지 않는다.
- 검증 기준:
- 실행 명령:
rg "struct CreatorChannelFloatingIconButton|imageName|backgroundColor|accessibilityLabel|frame\\(width: 38, height: 38\\)|frame\\(width: 66, height: 66\\)|clipShape\\(Circle\\(\\)\\)" SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelFloatingIconButton.swift - 실행 명령:
rg "CreatorChannelFloatingIconButton|ic_plus_no_bg|ic_new_upload_community_post|ic_new_upload_audio|ic_new_create_live|ic_new_x_black" SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelFloatingActionMenu.swift SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - 실행 명령:
rg "Text\\(" SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelFloatingIconButton.swift - 기대 결과: 공용 icon-only floating button과 기존 floating action menu 재사용이 확인되고, 공용 컴포넌트에는 텍스트가 없어야 한다.
- 실행 명령:
- 대상 파일:
-
Task 3.6: 팬Talk 탭 본문 구현
- 대상 파일:
- 생성:
SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swift
- 생성:
- 작업 내용:
- count bar, empty view, fanTalk list를 배치한다.
- 첫 진입 시
fetchFirstPage(creatorId:)를 호출한다. - 마지막 fanTalk item 노출 시
fetchNextPageIfNeeded를 호출한다. fanTalkCount == 0이면CreatorChannelFanTalkEmptyView를 표시한다.- 내 채널인 경우 empty view 내부 글쓰기 버튼을 숨긴다.
CheersReportDialogView와 삭제 confirm dialog를 표시한다.
- 검증 기준:
- 실행 명령:
rg "CreatorChannelFanTalkTabView|CreatorChannelFanTalkCountBar|CreatorChannelFanTalkEmptyView|CreatorChannelFanTalkListItem|fetchFirstPage|fetchNextPageIfNeeded|CheersReportDialogView|SodaDialog|onTapWrite" SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swift
- 실행 명령:
- 대상 파일:
Phase 4: CreatorChannelView 연결
- Task 4.1: 팬Talk 탭 콘텐츠 연결
- 대상 파일:
- 수정:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
- 수정:
- 작업 내용:
@StateObject로 팬Talk 탭 ViewModel을 보유한다.selectedTabContent에서.fanTalk일 때CreatorChannelFanTalkTabView를 표시한다.- 우측하단 글쓰기 floating button은
selectedTab == .fanTalk, 내 채널이 아니고fanTalkCount > 0일 때만CreatorChannelFloatingIconButton으로 표시한다. - 글쓰기 action은 신규 글쓰기 페이지 구현 전까지 no-op placeholder로 둔다.
- 검증 기준:
- 실행 명령:
rg "CreatorChannelFanTalkViewModel|CreatorChannelFanTalkTabView|viewModel\\.selectedTab == \\.fanTalk|CreatorChannelFloatingIconButton|showFanTalkWrite|fanTalkCount|ic_plus_no_bg" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
- 실행 명령:
- 대상 파일:
Phase 5: 프로젝트 등록과 검증
-
Task 5.1: 프로젝트 파일 등록과 정적 검증
- 대상 파일:
- 확인/수정:
SodaLive.xcodeproj/project.pbxproj
- 확인/수정:
- 검증 기준:
- 실행 명령:
git diff --check -- docs/20260704_크리에이터_채널_팬Talk_탭 SodaLive/Sources/V2/CreatorChannel SodaLive/Sources/I18n/I18n.swift SodaLive.xcodeproj/project.pbxproj - 기대 결과: 공백 오류 없이 성공한다.
- 실행 명령:
plutil -lint SodaLive.xcodeproj/project.pbxproj - 기대 결과:
OK출력.
- 실행 명령:
- 대상 파일:
-
Task 5.2: 빌드 검증
- 대상 파일:
- 확인:
SodaLive.xcworkspace - 확인:
SodaLive.xcodeproj
- 확인:
- 검증 기준:
- 실행 명령:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build - 기대 결과:
BUILD SUCCEEDED. - workspace 인식 실패 등 환경 문제가 있으면
xcodebuild -project "SodaLive.xcodeproj" -scheme "SodaLive-dev" -configuration Debug build를 대체 검증으로 실행하고 실패 원인을 검증 기록에 남긴다.
- 실행 명령:
- 대상 파일:
검증 기록
- 2026-07-04: Figma
get_design_context와get_screenshot으로290:9139,290:9145,290:9147,666:36114,290:9001을 확인했다. - 2026-07-04:
rg와sed로 기존CreatorChannelView, 후원 탭 구현,UserProfileFanTalkViewModel,UserProfileFanTalkCheersItemView,UserProfileView신고/삭제 흐름을 확인했다. - 2026-07-04: 사용자 피드백에 따라 우측하단 plus button은
CreatorChannelFloatingActionMenu의 privatefloatingButton과 동일 UI로 판단했다. 중복 컴포넌트를 만들지 않고CreatorChannelFloatingIconButton공용 컴포넌트로 추출해CreatorChannelFloatingActionMenu와 팬Talk 글쓰기 floating button에서 재사용하는 방향으로 계획을 보완했다. - 2026-07-04:
xcodebuild -workspace "SodaLive.xcworkspace" -list로SodaLive,SodaLive-dev앱 스킴은 확인했지만 테스트 action 구성은 확인되지 않았다. - 2026-07-04:
rg검증으로 팬Talk 탭 response model, API endpoint, Repository, ViewModel, count bar, list item, action popup, empty view, tab view,CreatorChannelView연결 문자열을 확인했다. - 2026-07-04:
plutil -lint SodaLive.xcodeproj/project.pbxproj결과OK를 확인했다. - 2026-07-04:
git diff --check -- docs/20260704_크리에이터_채널_팬Talk_탭 SodaLive/Sources/V2/CreatorChannel SodaLive/Sources/I18n/I18n.swift SodaLive.xcodeproj/project.pbxproj를 실행해 공백 오류가 없음을 확인했다. - 2026-07-04:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build결과BUILD SUCCEEDED를 확인했다. - 2026-07-04:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" test는Scheme SodaLive-dev is not currently configured for the test action.으로 실패했다. 현재 범위에서는 새 테스트 타깃을 추가하지 않고 빌드/정적 검증으로 대체했다.