49 KiB
49 KiB
메인 홈 팔로잉 탭 구현 계획
기준 문서
- PRD:
docs/20260630_메인_홈_팔로잉_탭/prd.md - 코드 스타일:
docs/agent-guides/code-style.md - 빌드/검증:
docs/agent-guides/build-test-verification.md - Figma 전체 화면:
24:5682 - Figma 최근 소식 랭킹 카드:
24:5717 - Figma 최근 소식 오디오 카드:
1229:27212 - Figma 최근 소식 화보 카드:
1229:27213
구현 원칙
MainHomeView는 홈 상단 title bar와추천/랭킹/팔로잉Text tab shell만 담당한다.- 팔로잉 탭의 API, 모델, ViewModel, 세부 UI는
SodaLive/Sources/V2/Main/Home/Following/**아래에 둔다. - 여러 화면에서 재사용할 근거가 생기기 전까지 팔로잉 전용 UI는
SodaLive/Sources/V2/Main/Home/Following/Components/**에 둔다. - 기존 추천/랭킹 탭의
TargetType, Repository, ViewModel,ApiResponse<T>디코딩 패턴을 따른다. - 홈 상단
팔로잉탭 터치 시 로그인 guard를 먼저 적용한다. 비로그인 상태에서는 탭 전환과 API 호출을 하지 않고 로그인 화면으로 이동한다. - 팔로잉 탭 전체 empty 문구는
팔로잉 소식이 아직 없어요.\n관심 있는 크리에이터를 팔로우해 보세요.를 사용한다. - API 실패 문구는
팔로잉 정보를 불러오지 못했습니다.\n잠시 후 다시 시도해 주세요.를 사용한다. - 섹션별 배열이 비어 있으면 해당 섹션은 숨긴다.
- 모든 뷰의 루트 container와 섹션 container에는 불필요한 고정 숫자 width/height를 사용하지 않는다.
- 프로필 이미지, 썸네일, 아이콘, tag, 최소 터치 영역처럼 UI 의미상 크기가 정해진 요소에만 고정 크기를 사용한다.
- 외부 라이브러리는 추가하지 않는다.
- Figma localhost asset URL은 앱 코드에 사용하지 않는다.
구현 제약
FollowingCommunityPostNewsResponse에는creatorId가 없다.- 현재 기존 커뮤니티 게시글 직접 진입 구조는
AppState.setPendingCommunityCommentDeepLink(creatorId:postId:)와.creatorCommunityAll(creatorId:)조합이므로postId만으로는 기존 화면에 정확히 진입할 수 없다. COMMUNITY_POSTtap 액션은 구현 전 서버가creatorId를 추가하거나,postId단독 상세 진입 route/API가 있는지 확인해야 한다. 이 확인 없이 임의로 수정 화면(creatorCommunityModify)이나 잘못된 creator 화면으로 이동하지 않는다.
주요 대상 파일
생성
SodaLive/Sources/V2/Main/Home/Following/Models/HomeFollowingTabResponse.swiftSodaLive/Sources/V2/Main/Home/Following/Repository/MainHomeFollowingApi.swiftSodaLive/Sources/V2/Main/Home/Following/Repository/MainHomeFollowingRepository.swiftSodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingViewModel.swiftSodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingCreatorSection.swiftSodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingLiveSection.swiftSodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingChatSection.swiftSodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingScheduleSection.swiftSodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingNewsSection.swiftSodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingRankingNewsCard.swiftSodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingContentNewsCard.swiftSodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingEmptyStateView.swift
수정
SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingView.swiftSodaLive/Sources/V2/Main/Home/MainHomeView.swiftSodaLive/Sources/V2/Main/MainView.swiftSodaLive/Sources/I18n/I18n.swift- 필요 시
SodaLive.xcodeproj/project.pbxproj
확인
SodaLive/Sources/V2/Component/TextTabBar.swiftSodaLive/Sources/V2/Component/SectionTitle.swiftSodaLive/Sources/V2/Component/Card/CommunityPostCard.swiftSodaLive/Sources/V2/Main/Home/Recommendation/MainHomeRecommendationViewModel.swiftSodaLive/Sources/V2/Main/Home/Ranking/MainHomeRankingViewModel.swiftSodaLive/Sources/App/AppStep.swiftSodaLive/Sources/ContentView.swiftSodaLive/Sources/Follow/FollowCreatorView.swiftSodaLive/Sources/Chat/Talk/TalkView.swiftSodaLive/Sources/Explorer/Profile/CreatorCommunity/All/CreatorCommunityAllView.swift
TASK 체크리스트
Phase 1: 기준점 점검과 탭 guard 설계
-
Task 1.1: PRD와 기존 팔로잉 placeholder 확인
- 대상 파일:
- 확인:
docs/20260630_메인_홈_팔로잉_탭/prd.md - 확인:
SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingView.swift - 확인:
SodaLive/Sources/V2/Main/Home/MainHomeView.swift
- 확인:
- 작업 내용:
- PRD 성공 기준과 제외 범위를 다시 읽고 구현 범위를 확정한다.
MainHomeFollowingView가 placeholder인지 확인한다.MainHomeView가TextTabBarbinding으로 탭을 전환하는 구조인지 확인한다.
- 검증 기준:
- 실행 명령:
sed -n '1,120p' SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingView.swift && sed -n '1,120p' SodaLive/Sources/V2/Main/Home/MainHomeView.swift - 기대 결과: 팔로잉 탭은 placeholder이고,
MainHomeView는 탭 shell 역할만 담당한다.
- 실행 명령:
- 대상 파일:
-
Task 1.2: 팔로잉 탭 선택 로그인 guard 연결
- 대상 파일:
- 수정:
SodaLive/Sources/V2/Main/Home/MainHomeView.swift - 수정:
SodaLive/Sources/V2/Main/MainView.swift - 확인:
SodaLive/Sources/V2/Component/TextTabBar.swift
- 수정:
- 작업 내용:
TextTabBar자체는 수정하지 않는다.MainHomeView에onSelectFollowingTab: () -> Boolcallback을 추가한다.TextTabBar의selectedItem에는 customBinding을 전달한다.- binding setter에서
.following선택 시onSelectFollowingTab()이true일 때만selectedTab = .following을 실행한다. MainView에서onSelectFollowingTab을 구현한다.- 토큰이 비어 있으면
AppState.shared.setAppStep(step: .login)을 호출하고false를 반환한다. - 토큰이 있으면
true를 반환한다.
- 검증 기준:
- 실행 명령:
rg "onSelectFollowingTab|Binding\\(|selectedTab = \\.following|setAppStep\\(step: \\.login\\)|TextTabBar" SodaLive/Sources/V2/Main/Home/MainHomeView.swift SodaLive/Sources/V2/Main/MainView.swift - 기대 결과: 팔로잉 탭 선택 guard가
MainHomeView와MainView에 존재하고,TextTabBar.swift는 변경되지 않는다.
- 실행 명령:
- 대상 파일:
Phase 2: API, Repository, Response model, ViewModel
-
Task 2.1: 팔로잉 응답 모델 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/Main/Home/Following/Models/HomeFollowingTabResponse.swift
- 생성:
- 작업 내용:
- PRD의 Swift 모델 기준대로
HomeFollowingTabResponse,FollowingCreatorResponse,FollowingLiveResponse,ChatRoomListItemResponse,FollowingScheduleResponse,FollowingNewsResponse를 만든다. - nested 최근 소식 모델
FollowingCreatorRankingNewsResponse,FollowingContentNewsResponse,FollowingContentRankingNewsResponse,FollowingCommunityPostNewsResponse를 만든다. CreatorActivityType,FollowingNewsType은 unknown case를 포함한Decodable, Hashableenum으로 만든다.- id가 있는 모델은
Identifiable을 채택한다.
- PRD의 Swift 모델 기준대로
- 검증 기준:
- 실행 명령:
rg "struct HomeFollowingTabResponse|struct ChatRoomListItemResponse|enum CreatorActivityType|struct FollowingNewsResponse|struct FollowingCreatorRankingNewsResponse|struct FollowingContentNewsResponse|struct FollowingContentRankingNewsResponse|struct FollowingCommunityPostNewsResponse|enum FollowingNewsType|unknown\\(" SodaLive/Sources/V2/Main/Home/Following/Models/HomeFollowingTabResponse.swift - 기대 결과: PRD의 응답 모델과 unknown enum 처리가 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 2.2: 팔로잉 API endpoint 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/Main/Home/Following/Repository/MainHomeFollowingApi.swift - 확인:
SodaLive/Sources/V2/Main/Home/Recommendation/Repository/MainHomeRecommendationApi.swift
- 생성:
- 작업 내용:
MainHomeFollowingApi를TargetType으로 만든다.- case는
getFollowing하나만 둔다. - path는
/api/v2/home/following, method는.get, task는.requestPlain로 둔다. - headers는 기존 V2 홈 API와 동일하게
Authorization: Bearer {token}패턴을 사용한다.
- 검증 기준:
- 실행 명령:
rg "enum MainHomeFollowingApi|getFollowing|/api/v2/home/following|Authorization|requestPlain|TargetType" SodaLive/Sources/V2/Main/Home/Following/Repository/MainHomeFollowingApi.swift - 기대 결과: 팔로잉 전용 API endpoint와 인증 헤더가 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 2.3: 팔로잉 Repository 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/Main/Home/Following/Repository/MainHomeFollowingRepository.swift - 확인:
SodaLive/Sources/V2/Main/Home/Ranking/Repository/MainHomeRankingRepository.swift
- 생성:
- 작업 내용:
MainHomeFollowingRepository를 만들고MoyaProvider<MainHomeFollowingApi>를 사용한다.getFollowing() -> AnyPublisher<Response, MoyaError>메서드를 제공한다.
- 검증 기준:
- 실행 명령:
rg "final class MainHomeFollowingRepository|MoyaProvider<MainHomeFollowingApi>|getFollowing\\(\\)|AnyPublisher<Response, MoyaError>" SodaLive/Sources/V2/Main/Home/Following/Repository/MainHomeFollowingRepository.swift - 기대 결과: 기존 V2 홈 Repository와 같은 패턴이 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 2.4: 팔로잉 ViewModel 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingViewModel.swift - 확인:
SodaLive/Sources/V2/Main/Home/Recommendation/MainHomeRecommendationViewModel.swift - 확인:
SodaLive/Sources/V2/Main/Home/Ranking/MainHomeRankingViewModel.swift
- 생성:
- 작업 내용:
MainHomeFollowingViewModel을ObservableObject로 만든다.@Published var isLoading,@Published var response,@Published var isLoginRequired,@Published var message,@Published var hasLoaded를 둔다.fetchFollowing()에서ApiResponse<HomeFollowingTabResponse>를 디코딩한다.- 성공 시
response와isLoginRequired를 갱신한다. isLoginRequired == true이면response는 nil로 두고 로그인 필요 상태를 표시할 수 있게 한다.- 모든 섹션 배열이 비어 있으면
message = I18n.HomeFollowing.emptyStateMessage를 설정한다. - API 실패/디코딩 실패 시
message = I18n.HomeFollowing.loadFailedMessage를 설정한다. - 실패 시 toast 대신 안내 상태를 표시한다.
- 검증 기준:
- 실행 명령:
rg "final class MainHomeFollowingViewModel|fetchFollowing|ApiResponse<HomeFollowingTabResponse>|isLoginRequired|emptyStateMessage|loadFailedMessage|hasLoaded|ERROR_LOG" SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingViewModel.swift - 기대 결과: API 디코딩, 로그인 필요 상태, empty/API 실패 문구 처리가 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 2.5: 팔로잉 I18n 문구 추가
- 대상 파일:
- 수정:
SodaLive/Sources/I18n/I18n.swift
- 수정:
- 작업 내용:
I18n.HomeFollowingenum을 추가한다.emptyStateMessageko는팔로잉 소식이 아직 없어요.\n관심 있는 크리에이터를 팔로우해 보세요.로 둔다.loadFailedMessageko는팔로잉 정보를 불러오지 못했습니다.\n잠시 후 다시 시도해 주세요.로 둔다.loginRequiredMessage,loginButtonTitle,allButtonTitle,onAirTitle,recentChatTitle,monthlyScheduleTitle,recentNewsTitle,audioTag,photoTag를 추가한다.- en/ja는 기능 검증을 막지 않는 자연스러운 대응 문구로 추가한다.
- 검증 기준:
- 실행 명령:
rg "enum HomeFollowing|emptyStateMessage|loadFailedMessage|팔로잉 소식이 아직 없어요|팔로잉 정보를 불러오지 못했습니다|allButtonTitle|recentNewsTitle|audioTag|photoTag" SodaLive/Sources/I18n/I18n.swift - 기대 결과: 팔로잉 탭 사용자 노출 문구가 I18n에 존재한다.
- 실행 명령:
- 대상 파일:
Phase 3: 팔로잉 크리에이터 섹션과 전체 버튼
-
Task 3.1: 팔로잉 크리에이터 섹션 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingCreatorSection.swift - 확인:
SodaLive/Sources/V2/Component/Creator/CreatorProfileItem.swift - 확인:
SodaLive/Sources/Follow/FollowCreatorView.swift
- 생성:
- 작업 내용:
followingCreators를 가로 스크롤 목록으로 표시한다.- 각 creator item은 프로필 이미지와 닉네임을 표시한다.
- creator item 탭 시
onTapCreator(creatorId)를 호출한다. - 목록 마지막에는 항상
전체버튼을 표시한다. 전체버튼은followingCreators가 비어 있어도 표시한다.전체버튼 text는I18n.HomeFollowing.allButtonTitle, 색상은Color.soda400을 사용한다.전체버튼 horizontal padding은 16으로 둔다.전체버튼 높이는 creator item 높이와 동일하게 맞춘다.전체버튼 탭 시onTapAll()을 호출한다.
- 검증 기준:
- 실행 명령:
rg "struct MainHomeFollowingCreatorSection|ScrollView\\(\\.horizontal|followingCreators|onTapCreator|onTapAll|allButtonTitle|Color.soda400|padding\\(\\.horizontal, 16\\)" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingCreatorSection.swift - 기대 결과: 가로 creator 목록과 마지막
전체버튼 요구사항이 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 3.2: 전체 팔로잉 목록 진입 연결
- 대상 파일:
- 수정:
SodaLive/Sources/V2/Main/Home/MainHomeView.swift - 수정:
SodaLive/Sources/V2/Main/MainView.swift - 확인:
SodaLive/Sources/App/AppStep.swift - 확인:
SodaLive/Sources/ContentView.swift
- 수정:
- 작업 내용:
MainHomeView에onTapFollowingAll: () -> Voidcallback을 추가한다.MainHomeFollowingView까지 callback을 전달한다.MainView에서onTapFollowingAll을AppState.shared.setAppStep(step: .followingList)로 구현한다.
- 검증 기준:
- 실행 명령:
rg "onTapFollowingAll|followingList|FollowCreatorView" SodaLive/Sources/V2/Main/Home/MainHomeView.swift SodaLive/Sources/V2/Main/MainView.swift SodaLive/Sources/App/AppStep.swift SodaLive/Sources/ContentView.swift - 기대 결과:
전체버튼이 기존FollowCreatorView라우팅으로 연결된다.
- 실행 명령:
- 대상 파일:
Phase 4: 팔로잉 탭 API 호출 연결과 데이터 상태 세팅
-
Task 4.1: 팔로잉 탭 진입 시 API 호출 연결
- 대상 파일:
- 수정:
SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingView.swift - 확인:
SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingViewModel.swift
- 수정:
- 작업 내용:
MainHomeFollowingView에@StateObject private var viewModel = MainHomeFollowingViewModel()를 추가한다.- 최초
onAppear에서viewModel.hasLoaded == false일 때만viewModel.fetchFollowing()을 호출한다. - 이 단계에서는 새 섹션 UI를 추가하지 않고, 이미 존재하는 팔로잉 크리에이터 섹션에
viewModel.response?.followingCreators ?? []를 연결한다. - API 성공 시
MainHomeFollowingViewModel.response에HomeFollowingTabResponse가 세팅되는 흐름을 먼저 확보한다. isLoginRequired,message,hasLoaded,isLoading상태는 ViewModel의 기존 세팅 흐름을 사용한다.
- 검증 기준:
- 실행 명령:
rg "StateObject private var viewModel = MainHomeFollowingViewModel|onAppear|hasLoaded|fetchFollowing|response\\?\\.followingCreators|isLoading|message|MainPlaceholderTabView" SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingView.swift SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingViewModel.swift - 기대 결과: 팔로잉 탭 진입 시 ViewModel이 생성되고, 최초 진입에서 API 호출 후 응답 데이터가 기존 크리에이터 섹션에 전달되는 흐름이 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 4.2: 팔로잉 API 호출 빌드 검증
- 대상 파일:
- 확인:
SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingView.swift - 확인:
SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingViewModel.swift
- 확인:
- 작업 내용:
- 추가 섹션 UI 구현 전에 API 호출 연결만으로 컴파일이 깨지지 않는지 확인한다.
- 로그인 guard가 유지되어 비로그인 상태에서는 팔로잉 탭 전환과 API 호출이 발생하지 않는지 코드 흐름을 확인한다.
- 검증 기준:
- 실행 명령:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build - 기대 결과: 빌드가 성공하고,
MainHomeView의 팔로잉 탭 로그인 guard가 유지된다.
- 실행 명령:
- 대상 파일:
Phase 5: On Air 섹션
- Task 5.1: On Air 섹션 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingLiveSection.swift
- 생성:
- 작업 내용:
onAirLives가 비어 있으면 parent에서 섹션을 렌더링하지 않는다.- 섹션 타이틀은
I18n.HomeFollowing.onAirTitle을 사용한다. - 각 item은 프로필 이미지, 닉네임, 라이브 제목,
startedAtUtc기준 경과 시간을 표시한다. - 시간 표시는 기존
DateParser.relativeTimeText(fromUTC:fallback:now:)패턴을 우선 사용한다. - item 탭 시
onTapLive(liveId)를 호출한다. - 카드 루트에는 고정 width/height를 강제하지 않는다.
- 검증 기준:
- 실행 명령:
rg "struct MainHomeFollowingLiveSection|onAirTitle|FollowingLiveResponse|startedAtUtc|DateParser|onTapLive|DownsampledKFImage|ScrollView\\(\\.horizontal" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingLiveSection.swift - 기대 결과: On Air 섹션의 데이터 표시와 live tap callback이 확인된다.
- 실행 명령:
- 대상 파일:
Phase 6: 최근 대화 섹션
-
Task 6.1: 최근 대화 섹션 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingChatSection.swift - 확인:
SodaLive/Sources/Chat/Talk/TalkView.swift - 확인:
SodaLive/Sources/Chat/Talk/TalkItemView.swift
- 생성:
- 작업 내용:
recentChats가 비어 있으면 parent에서 섹션을 렌더링하지 않는다.- 섹션 타이틀은
I18n.HomeFollowing.recentChatTitle을 사용한다. - 각 item은
targetImageUrl,targetName,lastMessage,lastMessageAt을 표시한다. chatType == "DM"이면Direct태그를 표시한다.lastMessageAt은 UTC 기준 문자열로 받아 상대 시간 또는 기존 Talk item과 맞는 시간 label로 표시한다.- item 탭 시
onTapChatRoom(roomId)를 호출한다.
- 검증 기준:
- 실행 명령:
rg "struct MainHomeFollowingChatSection|recentChatTitle|ChatRoomListItemResponse|targetImageUrl|targetName|lastMessage|lastMessageAt|chatType == \"DM\"|Direct|onTapChatRoom" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingChatSection.swift - 기대 결과: 최근 대화 item 필드,
Direct태그 조건, 채팅방 tap callback이 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 6.2: 채팅방 진입 연결
- 대상 파일:
- 수정:
SodaLive/Sources/V2/Main/Home/MainHomeView.swift - 수정:
SodaLive/Sources/V2/Main/MainView.swift - 확인:
SodaLive/Sources/App/AppStep.swift - 확인:
SodaLive/Sources/ContentView.swift
- 수정:
- 작업 내용:
MainHomeView에onTapChatRoom: (Int) -> Voidcallback을 추가한다.MainHomeFollowingView까지 callback을 전달한다.MainView에서onTapChatRoom을AppState.shared.setAppStep(step: .chatRoom(id: roomId))로 구현한다.
- 검증 기준:
- 실행 명령:
rg "onTapChatRoom|chatRoom\\(id:|ChatRoomView" SodaLive/Sources/V2/Main/Home/MainHomeView.swift SodaLive/Sources/V2/Main/MainView.swift SodaLive/Sources/App/AppStep.swift SodaLive/Sources/ContentView.swift - 기대 결과: 최근 대화 item tap이 기존 채팅방 화면으로 연결된다.
- 실행 명령:
- 대상 파일:
Phase 7: 이달의 스케줄 섹션
-
Task 7.1: 이달의 스케줄 섹션 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingScheduleSection.swift
- 생성:
- 작업 내용:
monthlySchedules가 비어 있으면 parent에서 섹션을 렌더링하지 않는다.- 섹션 타이틀은
I18n.HomeFollowing.monthlyScheduleTitle을 사용한다. - 각 item은 날짜 영역, 크리에이터 프로필/닉네임, 제목, 활동 타입 tag, 시간 또는
On Air상태를 표시한다. scheduledAtUtc가 오늘이면 날짜 영역에오늘을 표시한다.isOnAir == true이면 우측 상태를On Air로 표시하고Color.soda400을 사용한다.isOnAir == true이면 좌측 accent line을 표시한다.CreatorActivityType.live,.liveReplay,.audio,.community를 tag 문구로 매핑한다.- item 탭 시
onTapSchedule(type, targetId)를 호출한다.
- 검증 기준:
- 실행 명령:
rg "struct MainHomeFollowingScheduleSection|monthlyScheduleTitle|FollowingScheduleResponse|scheduledAtUtc|isOnAir|Color.soda400|CreatorActivityType|onTapSchedule|오늘" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingScheduleSection.swift - 기대 결과: 스케줄 카드 표시, On Air 강조, schedule tap callback이 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 7.2: 스케줄 상세 진입 연결
- 대상 파일:
- 수정:
SodaLive/Sources/V2/Main/Home/MainHomeView.swift - 수정:
SodaLive/Sources/V2/Main/MainView.swift
- 수정:
- 작업 내용:
MainHomeView에onTapFollowingSchedule: (CreatorActivityType, Int) -> Voidcallback을 추가한다..live,.liveReplay은 기존 live 입장 callback으로 연결한다..audio는AppState.shared.setAppStep(step: .contentDetail(contentId: targetId))흐름으로 연결한다..community는 기존 커뮤니티 진입 정책이creatorId기반인지postId기반인지 구현 전 확인한다.targetId가 creator id로 내려오는 경우에만.creatorCommunityAll(creatorId: targetId)로 연결한다.
- 검증 기준:
- 실행 명령:
rg "onTapFollowingSchedule|CreatorActivityType|contentDetail|creatorCommunityAll|enterLiveRoom" SodaLive/Sources/V2/Main/Home/MainHomeView.swift SodaLive/Sources/V2/Main/MainView.swift - 기대 결과: schedule type별 routing 분기가 확인된다.
- 실행 명령:
- 대상 파일:
Phase 8: 최근 소식 랭킹 카드
- Task 8.1: 최근 소식 랭킹 카드 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingRankingNewsCard.swift
- 생성:
- 작업 내용:
- Figma
24:5717기준 카드 형태로 만든다. CREATOR_RANKING은FollowingCreatorRankingNewsResponse를 사용한다.CONTENT_RANKING은FollowingContentRankingNewsResponse를 사용한다.rank값을N위로 표시하고Color.soda400로 강조한다.- 타입과 payload가 맞지 않으면 parent에서 렌더링하지 않는다.
- card tap 시 creator ranking은
onTapCreator(creatorId), content ranking은onTapContent(contentId)를 호출한다.
- Figma
- 검증 기준:
- 실행 명령:
rg "struct MainHomeFollowingRankingNewsCard|FollowingCreatorRankingNewsResponse|FollowingContentRankingNewsResponse|rank|Color.soda400|onTapCreator|onTapContent|24:5717" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingRankingNewsCard.swift - 기대 결과: 랭킹 최근 소식 카드와 타입별 tap callback이 확인된다.
- 실행 명령:
- 대상 파일:
Phase 9: 최근 소식 커뮤니티 카드
-
Task 9.1: 최근 소식 커뮤니티 카드 조립
- 대상 파일:
- 생성 또는 수정:
SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingNewsSection.swift - 확인:
SodaLive/Sources/V2/Component/Card/CommunityPostCard.swift
- 생성 또는 수정:
- 작업 내용:
COMMUNITY_POST는communityPostpayload가 있을 때만 렌더링한다.- 표시 값은
postId,creatorProfileImage,creatorNickname,imageUrl,content,createdAt,likeCount,commentCount를 사용한다. - 기존
CommunityPostCard를 재사용할 경우audioUrl = nil,price = 0,existOrdered = true,isLike = false로 매핑한다. createdAt은 기존CommunityPostCard의createdAt표시 형식에 맞춰 전달한다.
- 검증 기준:
- 실행 명령:
rg "COMMUNITY_POST|communityPost|CommunityPostCard|postId|creatorProfileImage|likeCount|commentCount|audioUrl: nil|price: 0|existOrdered: true" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingNewsSection.swift - 기대 결과: community post payload가 기존 community card 표시값으로 매핑된다.
- 실행 명령:
- 대상 파일:
-
Task 9.2: 커뮤니티 게시글 tap 라우팅 제약 처리
- 대상 파일:
- 확인:
SodaLive/Sources/App/AppState.swift - 확인:
SodaLive/Sources/App/AppStep.swift - 확인:
SodaLive/Sources/ContentView.swift - 확인:
SodaLive/Sources/Explorer/Profile/CreatorCommunity/All/CreatorCommunityAllView.swift
- 확인:
- 작업 내용:
postId단독으로 게시글 상세/댓글 화면에 진입 가능한 기존 route가 있는지 확인한다.- 현재 확인된 기존 route가
creatorId를 요구하는 경우, 잘못된 화면 이동을 구현하지 않는다. - 서버 응답에
creatorId가 추가되거나postId단독 route가 생기기 전까지COMMUNITY_POSTtap은 표시 카드 내부의 좋아요/댓글 표시만 제공하고 상세 진입은 연결하지 않는다. - 이 제약을 구현 결과 보고와 검증 기록에 남긴다.
- 검증 기준:
- 실행 명령:
rg "setPendingCommunityCommentDeepLink|consumePendingCommunityCommentPostId|creatorCommunityAll|case chatRoom|case creatorCommunity" SodaLive/Sources/App/AppState.swift SodaLive/Sources/App/AppStep.swift SodaLive/Sources/ContentView.swift SodaLive/Sources/Explorer/Profile/CreatorCommunity/All/CreatorCommunityAllView.swift - 기대 결과: 기존 커뮤니티 직접 진입 경로가
creatorId를 요구하는지 확인된다.
- 실행 명령:
- 대상 파일:
Phase 10: 최근 소식 오디오/화보 콘텐츠 카드
- Task 10.1: 최근 소식 콘텐츠 카드 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingContentNewsCard.swift
- 생성:
- 작업 내용:
- Figma
1229:27212오디오 카드와1229:27213화보 카드 형태를 하나의 카드 컴포넌트에서 variant로 처리한다. AUDIO_CONTENT는 정사각형 썸네일 비율과I18n.HomeFollowing.audioTag를 사용한다.PHOTO_CONTENT는 세로형 썸네일 비율과I18n.HomeFollowing.photoTag를 사용한다.contentImageUrl,creatorProfileImageUrl,creatorNickname,title,visibleFromAtUtc표시값을 받는다.- card tap 시
onTapContent(contentId)를 호출한다. - 루트 container에는 고정 width를 사용하지 않는다.
- Figma
- 검증 기준:
- 실행 명령:
rg "struct MainHomeFollowingContentNewsCard|audioTag|photoTag|contentImageUrl|creatorProfileImageUrl|creatorNickname|visibleFromAtUtc|onTapContent|aspectRatio" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingContentNewsCard.swift - 기대 결과: 오디오/화보 variant와 콘텐츠 상세 callback이 확인된다.
- 실행 명령:
- 대상 파일:
Phase 11: 화면 조립, empty/error 상태, 상세 진입 callback 연결
-
Task 11.1: 팔로잉 탭 화면 조립
- 대상 파일:
- 수정:
SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingView.swift
- 수정:
- 작업 내용:
- placeholder를 제거한다.
- Phase 4에서 연결한
MainHomeFollowingViewModel과 최초fetchFollowing()호출 흐름은 유지한다. - loading, loginRequired, message, content 상태를 분기한다.
- content 상태에서는 PRD 순서대로 팔로잉 크리에이터, On Air, 최근 대화, 이달의 스케줄, 최근 소식을 조립한다.
- 각 섹션 배열이 비어 있으면 해당 섹션을 렌더링하지 않는다.
- 모든 섹션 배열이 비어 있으면
MainHomeFollowingEmptyStateView(message: I18n.HomeFollowing.emptyStateMessage)를 표시한다. - API 실패 시
MainHomeFollowingEmptyStateView(message: I18n.HomeFollowing.loadFailedMessage)를 표시한다.
- 검증 기준:
- 실행 명령:
rg "MainHomeFollowingViewModel|fetchFollowing|MainHomeFollowingCreatorSection|MainHomeFollowingLiveSection|MainHomeFollowingChatSection|MainHomeFollowingScheduleSection|MainHomeFollowingNewsSection|MainHomeFollowingEmptyStateView|emptyStateMessage|loadFailedMessage|MainPlaceholderTabView" SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingView.swift - 기대 결과:
MainPlaceholderTabView는 검색되지 않고, 팔로잉 화면 상태 분기와 섹션 조립이 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 11.2: empty/login required view 생성
- 대상 파일:
- 생성:
SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingEmptyStateView.swift
- 생성:
- 작업 내용:
- message를 받아 검정 배경 위에 표시한다.
- 로그인 필요 상태에서는 로그인 버튼을 표시할 수 있도록 optional action을 받는다.
- 전체 루트에는 고정 width/height를 사용하지 않는다.
- 검증 기준:
- 실행 명령:
rg "struct MainHomeFollowingEmptyStateView|message|loginButtonTitle|Button|Color.black|frame\\(maxWidth: \\.infinity" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingEmptyStateView.swift - 기대 결과: empty/API 실패/로그인 필요 상태 공용 안내 view가 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 11.3: 최근 소식 섹션 조립
- 대상 파일:
- 생성 또는 수정:
SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingNewsSection.swift
- 생성 또는 수정:
- 작업 내용:
recentNews를 순서대로 렌더링한다.visibleFromAtUtc를 모든 item의 표시 시간 기준으로 사용한다..creatorRanking은creatorRankingpayload가 있을 때만MainHomeFollowingRankingNewsCard를 표시한다..contentRanking은contentRankingpayload가 있을 때만MainHomeFollowingRankingNewsCard를 표시한다..communityPost는communityPostpayload가 있을 때만 community card를 표시한다..audioContent는audioContentpayload가 있을 때만MainHomeFollowingContentNewsCard를 표시한다..photoContent는photoContentpayload가 있을 때만MainHomeFollowingContentNewsCard를 표시한다..unknown은 렌더링하지 않는다.
- 검증 기준:
- 실행 명령:
rg "struct MainHomeFollowingNewsSection|recentNewsTitle|visibleFromAtUtc|creatorRanking|contentRanking|communityPost|audioContent|photoContent|unknown|MainHomeFollowingRankingNewsCard|MainHomeFollowingContentNewsCard|CommunityPostCard" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingNewsSection.swift - 기대 결과: 최근 소식 타입별 payload 분기와 unknown 숨김 정책이 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 11.4: 상세 진입 callback 연결
- 대상 파일:
- 수정:
SodaLive/Sources/V2/Main/Home/MainHomeView.swift - 수정:
SodaLive/Sources/V2/Main/MainView.swift
- 수정:
- 작업 내용:
MainHomeView에 팔로잉 탭용 callback을 추가한다.- live는 기존
handleRecommendationLiveTap또는 같은 login/external navigation guard를 재사용한다. - creator는 기존
handleRecommendationCreatorTap을 재사용한다. - content는 기존
handleRecommendationContentTap을 재사용한다. - chat room은
.chatRoom(id:)로 이동한다. - following all은
.followingList로 이동한다. - community post는 Task 9.2 제약에 따라 postId 단독 route가 없으면 상세 진입을 연결하지 않는다.
- 검증 기준:
- 실행 명령:
rg "onTapFollowingAll|onTapChatRoom|onTapFollowingSchedule|handleRecommendationLiveTap|handleRecommendationCreatorTap|handleRecommendationContentTap|followingList|chatRoom\\(id:" SodaLive/Sources/V2/Main/Home/MainHomeView.swift SodaLive/Sources/V2/Main/MainView.swift - 기대 결과: 팔로잉 탭의 상세 진입 callback이 기존 MainView guard/route에 연결된다.
- 실행 명령:
- 대상 파일:
Phase 12: 프로젝트 등록, 빌드, UI 검증
-
Task 12.1: Xcode 프로젝트 포함 여부 확인
- 대상 파일:
- 확인:
SodaLive.xcodeproj/project.pbxproj - 확인:
SodaLive/Sources/V2/Main/Home/Following/**
- 확인:
- 작업 내용:
- 신규 Swift 파일들이 Xcode target에 포함됐는지 확인한다.
- 파일이 target에 자동 포함되지 않는 프로젝트 구조이면
project.pbxproj에 필요한 file reference/build file을 추가한다.
- 검증 기준:
- 실행 명령:
rg "HomeFollowingTabResponse|MainHomeFollowingApi|MainHomeFollowingRepository|MainHomeFollowingViewModel|MainHomeFollowingCreatorSection|MainHomeFollowingNewsSection|MainHomeFollowingEmptyStateView" SodaLive.xcodeproj/project.pbxproj SodaLive/Sources/V2/Main/Home/Following - 기대 결과: 신규 파일 참조와 소스 파일이 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 12.2: 정적 검색 검증
- 대상 파일:
- 확인:
SodaLive/Sources/V2/Main/Home/Following/** - 확인:
SodaLive/Sources/V2/Main/Home/MainHomeView.swift - 확인:
SodaLive/Sources/V2/Main/MainView.swift - 확인:
SodaLive/Sources/I18n/I18n.swift
- 확인:
- 작업 내용:
- PRD 핵심 키워드가 코드에 반영됐는지 확인한다.
MainPlaceholderTabView(title: "팔로잉")이 남아 있지 않은지 확인한다.- Figma localhost asset URL이 들어가지 않았는지 확인한다.
- 검증 기준:
- 실행 명령:
rg "/api/v2/home/following|HomeFollowingTabResponse|ChatRoomListItemResponse|CreatorActivityType|FollowingNewsType|visibleFromAtUtc|팔로잉 소식이 아직 없어요|팔로잉 정보를 불러오지 못했습니다|Color.soda400|followingList|chatRoom\\(id:" SodaLive/Sources/V2/Main/Home/Following SodaLive/Sources/V2/Main/Home/MainHomeView.swift SodaLive/Sources/V2/Main/MainView.swift SodaLive/Sources/I18n/I18n.swift - 기대 결과: API, 모델, 문구, 라우팅, 색상 요구사항이 확인된다.
- 실행 명령:
- 대상 파일:
-
Task 12.3: 빌드 검증
- 대상 파일:
- 확인:
SodaLive.xcworkspace
- 확인:
- 작업 내용:
- 앱 빌드를 실행해 신규 Swift 파일과 라우팅 변경의 컴파일 오류를 확인한다.
- 검증 기준:
- 실행 명령:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build - 기대 결과: 빌드가 성공한다.
- 실행 명령:
- 대상 파일:
-
Task 12.4: 수동 UI 검증
- 대상 파일:
- 확인:
SodaLive/Sources/V2/Main/Home/Following/** - 확인: Figma
24:5682
- 확인:
- 작업 내용:
- 비로그인 상태에서 홈
팔로잉탭을 탭하면 로그인 화면으로 이동하는지 확인한다. - 로그인 상태에서 홈
팔로잉탭 진입 시 API 호출과 섹션 표시가 동작하는지 확인한다. - 팔로잉 크리에이터 섹션 마지막에
전체버튼이 항상 표시되는지 확인한다. 전체버튼 text color가Color.soda400로 보이는지 확인한다.CREATOR_RANKING,CONTENT_RANKING,COMMUNITY_POST,AUDIO_CONTENT,PHOTO_CONTENT가 타입별 UI로 표시되는지 확인한다.- 루트/섹션 container가 고정 width/height 때문에 작은 화면에서 깨지지 않는지 확인한다.
- 비로그인 상태에서 홈
- 검증 기준:
- 실행 명령: 수동 확인
- 기대 결과: PRD 성공 기준과 Figma 섹션 순서가 충족된다.
- 대상 파일:
검증 기록
- 2026-06-30:
docs/agent-guides/documentation-policy.md,build-test-verification.md,code-style.md를 확인해 계획 문서 경로, Phase/checklist 형식, 검증 명령 기준을 반영했다. - 2026-06-30:
SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingView.swift가 placeholder 상태임을 확인했다. - 2026-06-30:
SodaLive/Sources/V2/Main/Home/MainHomeView.swift의 탭 전환이TextTabBarbinding 기반임을 확인해 custom binding setter 방식으로 로그인 guard 계획을 세웠다. - 2026-06-30:
SodaLive/Sources/ContentView.swift에서.followingList -> FollowCreatorView(),.chatRoom(id:) -> ChatRoomView(roomId:)라우팅을 확인했다. - 2026-06-30:
SodaLive/Sources/Explorer/Profile/CreatorCommunity/All/CreatorCommunityAllView.swift와AppState의 pending community post 구조가creatorId를 요구함을 확인해COMMUNITY_POSTtap 라우팅 제약을 계획에 명시했다. - 2026-06-30: Phase 1-2 구현을 진행해
MainHomeView의 팔로잉 탭 customBindingguard,MainView.handleFollowingTabSelection(), 팔로잉 응답 모델/API/Repository/ViewModel,I18n.HomeFollowing문구를 추가했다. - 2026-06-30:
rg "onSelectFollowingTab|Binding\(|selectedTab = \.following|setAppStep\(step: \.login\)|TextTabBar" SodaLive/Sources/V2/Main/Home/MainHomeView.swift SodaLive/Sources/V2/Main/MainView.swift로 팔로잉 탭 guard 연결을 확인했다. - 2026-06-30:
rg "struct HomeFollowingTabResponse|struct ChatRoomListItemResponse|enum CreatorActivityType|struct FollowingNewsResponse|struct FollowingCreatorRankingNewsResponse|struct FollowingContentNewsResponse|struct FollowingContentRankingNewsResponse|struct FollowingCommunityPostNewsResponse|enum FollowingNewsType|unknown\(" SodaLive/Sources/V2/Main/Home/Following/Models/HomeFollowingTabResponse.swift로 Phase 2 응답 모델과 unknown enum 처리를 확인했다. - 2026-06-30:
rg "enum MainHomeFollowingApi|getFollowing|/api/v2/home/following|Authorization|requestPlain|TargetType|final class MainHomeFollowingRepository|MoyaProvider<MainHomeFollowingApi>|AnyPublisher<Response, MoyaError>" SodaLive/Sources/V2/Main/Home/Following/Repository로 API/Repository 패턴을 확인했다. - 2026-06-30:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build를 실행해 빌드 성공을 확인했다. 기존 프로젝트의 duplicate build file/run script warning은 남아 있으나 Phase 1-2 컴파일 오류는 없었다. - 2026-06-30: Phase 3 구현을 진행해
MainHomeFollowingCreatorSection을 추가하고,MainHomeView -> MainHomeFollowingView -> MainView.handleFollowingAllTap()경로로전체버튼을.followingList라우팅에 연결했다. - 2026-06-30:
rg "struct MainHomeFollowingCreatorSection|ScrollView\(\.horizontal|followingCreators|onTapCreator|onTapAll|allButtonTitle|Color\.soda400|padding\(\.horizontal, 16\)" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingCreatorSection.swift로 팔로잉 크리에이터 섹션 요구사항을 확인했다. - 2026-06-30:
rg "onTapFollowingAll|followingList|FollowCreatorView" SodaLive/Sources/V2/Main/Home/MainHomeView.swift SodaLive/Sources/V2/Main/MainView.swift SodaLive/Sources/App/AppStep.swift SodaLive/Sources/ContentView.swift로전체버튼 라우팅 연결을 확인했다. - 2026-06-30:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build를 재실행해 Phase 3 신규 Swift 파일 target 등록과 컴파일 성공을 확인했다. - 2026-07-01: 완료된 Phase 3은 유지하고, Phase 4를 팔로잉 탭 API 호출 연결과 데이터 상태 세팅 단계로 변경했다. 이후 섹션 UI 작업은 Phase 5부터 순차 진행하도록 Phase/Task 번호를 재정렬했다.
- 2026-07-01: Phase 4 구현을 진행해
MainHomeFollowingView에@StateObject private var viewModel = MainHomeFollowingViewModel()를 추가하고, 최초onAppear에서hasLoaded == false일 때fetchFollowing()을 호출하도록 연결했다. - 2026-07-01:
MainHomeFollowingCreatorSection의followingCreators를viewModel.response?.followingCreators ?? []로 연결해 API 성공 응답 데이터가 기존 크리에이터 섹션으로 전달되는 흐름을 확보했다. - 2026-07-01:
rg "StateObject private var viewModel = MainHomeFollowingViewModel|onAppear|hasLoaded|fetchFollowing|response\?\.followingCreators|isLoading|message|MainPlaceholderTabView" SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingView.swift SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingViewModel.swift로 Phase 4 정적 요구사항을 확인했다. - 2026-07-01:
rg "onSelectFollowingTab|Binding\(|selectedTab = \.following|setAppStep\(step: \.login\)|TextTabBar" SodaLive/Sources/V2/Main/Home/MainHomeView.swift SodaLive/Sources/V2/Main/MainView.swift로 비로그인 팔로잉 탭 guard 흐름이 유지됨을 확인했다. - 2026-07-01:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build를 실행해 Phase 4 API 호출 연결 후 빌드 성공을 확인했다. 기존 AppIntents metadata extraction warning은 남아 있으나 컴파일 오류는 없었다. - 2026-07-01: Phase 5 구현을 진행해
MainHomeFollowingLiveSection을 추가하고,FollowingLiveResponse의 프로필 이미지/닉네임/라이브 제목/startedAtUtc상대 시간 표시와onTapLive(liveId)callback을 연결했다. - 2026-07-01:
rg "struct MainHomeFollowingLiveSection|onAirTitle|FollowingLiveResponse|startedAtUtc|DateParser|onTapLive|DownsampledKFImage|ScrollView\(\.horizontal|!onAirLives\.isEmpty" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingLiveSection.swift로 Phase 5 정적 요구사항을 확인했다. - 2026-07-01:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build를 실행해 Phase 5 신규 Swift 파일 컴파일과 빌드 성공을 확인했다. 기존 Crashlytics dSYM/AppIntents metadata extraction warning은 남아 있으나 컴파일 오류는 없었다. - 2026-07-01: 사용자 요청에 따라 Phase 11까지 기다리지 않고
MainHomeFollowingView에MainHomeFollowingLiveSection을 조기 조립했다.viewModel.response?.onAirLives ?? []를 전달하고,MainHomeView의 기존onTapLivecallback을 팔로잉 On Air 섹션까지 연결했다. - 2026-07-01:
SodaLive.xcodeproj/project.pbxproj에MainHomeFollowingLiveSection.swift파일 참조와 Sources build file을 추가해 Xcode navigator와 target compile sources에서 바로 확인 가능하도록 등록했다. - 2026-07-01:
rg "MainHomeFollowingLiveSection.swift|MainHomeFollowingLiveSection.swift in Sources|MainHomeFollowingLiveSection\(" SodaLive.xcodeproj/project.pbxproj SodaLive/Sources/V2/Main/Home로 Xcode 프로젝트 등록과 화면 조립을 확인했다. - 2026-07-01:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build를 재실행해 프로젝트 등록 후 빌드 성공을 확인했다. 기존 duplicate build file/run script/Crashlytics dSYM/AppIntents warning은 남아 있으나 컴파일 오류는 없었다. - 2026-07-01: Figma
24:5693,24:5696을 확인해 On Air 섹션을 캡슐형 라이브 아이템으로 수정했다.75x75프로필, 검정LIVEpill,#62CFFF2pt 캡슐 테두리,14/18/14pt텍스트 계층, leading 14/item gap 8 간격을 반영했다. - 2026-07-01:
rg "CGSize\(width: 75, height: 75\)|Color\(hex: \"62CFFF\"\)|Text\(\"LIVE\"\)|frame\(height: 18\)|padding\(\.trailing, 22\)|padding\(\.leading, SodaSpacing\.s14\)|spacing: SodaSpacing\.s8|appFont\(size: 18, weight: \.bold\)|appFont\(size: 14, weight: \.regular\)" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingLiveSection.swift로 Figma 핵심 수치 반영을 확인했다. - 2026-07-01:
rg "localhost:3845|img_live|frame\(width: 50, height: 18\)|CGSize\(width: 62, height: 62\)|RoundedRectangle" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingLiveSection.swift결과가 없어 Figma localhost asset 미사용과 기존 배지/카드 형태 제거를 확인했다. - 2026-07-01:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build를 실행해 Figma 반영 후 빌드 성공을 확인했다. 기존 Crashlytics dSYM/AppIntents warning은 남아 있으나 컴파일 오류는 없었다. - 2026-07-01: Phase 6 구현을 진행해
MainHomeFollowingChatSection을 추가하고,recentChats를 Figma24:5698,24:5701기준의 가로 카드 섹션으로 표시하도록 조립했다.chatType == "DM"일 때만Direct태그를 표시하고,lastMessageAt은DateParser.relativeTimeText(fromUTC:fallback:now:)로 표시한다. - 2026-07-01:
MainHomeFollowingView -> MainHomeView -> MainView.handleFollowingChatRoomTap(roomId:)경로로 최근 대화 item tap을.chatRoom(id:)라우팅에 연결했다. - 2026-07-01:
SodaLive.xcodeproj/project.pbxproj에MainHomeFollowingChatSection.swift파일 참조와 Sources build file을 추가해 Xcode navigator와 target compile sources에서 바로 확인 가능하도록 등록했다. - 2026-07-01:
rg "struct MainHomeFollowingChatSection|recentChatTitle|ChatRoomListItemResponse|targetImageUrl|targetName|lastMessage|lastMessageAt|DateParser|onTapChatRoom|ScrollView\(\.horizontal|Color\.gray900|frame\(width: 288|CGSize\(width: 64, height: 64\)|chatType == \"DM\"|Direct" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingChatSection.swift로 최근 대화 섹션 핵심 요구사항과 Direct 태그 표시 조건을 확인했다. - 2026-07-01:
rg "onTapChatRoom|MainHomeFollowingChatSection|response\?\.recentChats|chatRoom\(id:|ChatRoomView" SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingView.swift SodaLive/Sources/V2/Main/Home/MainHomeView.swift SodaLive/Sources/V2/Main/MainView.swift SodaLive/Sources/App/AppStep.swift SodaLive/Sources/ContentView.swift로 최근 대화 섹션 조립과 채팅방 라우팅 연결을 확인했다. - 2026-07-01:
rg "MainHomeFollowingChatSection.swift|MainHomeFollowingChatSection.swift in Sources" SodaLive.xcodeproj/project.pbxproj로 신규 Swift 파일의 Xcode 프로젝트 등록을 확인했다. - 2026-07-01:
if rg "localhost:3845|unread" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingChatSection.swift; then exit 1; else true; fi를 실행해 Figma localhost asset과 별도 unread 표시가 들어가지 않았음을 확인했다. - 2026-07-01:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build를 실행해 Phase 6 구현 후 빌드 성공을 확인했다. 기존 duplicate build file/Crashlytics dSYM/AppIntents warning은 남아 있으나 컴파일 오류는 없었다. - 2026-07-01: Figma
24:5703,24:5706,24:5707을 확인해 Phase 7 이달의 스케줄 섹션을 구현했다. 카드Color.gray900, 14pt radius/padding, 53x53 날짜 영역, 20pt 프로필, 16pt 제목/상태, gray700 활동 tag를 반영했고, 오늘/On Air dot 및 On Air 상태/좌측 accent는Color.soda400, 일반 schedule dot/line/status는 gray 계열로 분리했다. - 2026-07-01:
MainHomeFollowingView -> MainHomeView -> MainView.handleFollowingScheduleTap(type:targetId:)경로로 스케줄 tap callback을 연결했다..live/.liveReplay은 기존 live 입장,.audio는 콘텐츠 상세,.community는 기존 정책에 따라creatorCommunityAll(creatorId:),.unknown은 no-op 처리했다. - 2026-07-01:
SodaLive.xcodeproj/project.pbxproj에MainHomeFollowingScheduleSection.swift파일 참조와 Sources build file을 추가해 Xcode navigator와 target compile sources에서 확인 가능하도록 등록했다. - 2026-07-01:
rg "MainHomeFollowingScheduleSection.swift|MainHomeFollowingScheduleSection.swift in Sources|onTapFollowingSchedule|onTapSchedule|monthlySchedules|CreatorActivityType|contentDetail|creatorCommunityAll|enterLiveRoom|On Air|a hh:mm|오늘|Color.soda400|Color.gray500|localhost:3845" SodaLive/Sources/V2/Main/Home/Following SodaLive/Sources/V2/Main/Home/MainHomeView.swift SodaLive/Sources/V2/Main/MainView.swift SodaLive.xcodeproj/project.pbxproj로 Phase 7 UI, 라우팅, 프로젝트 등록, Figma localhost asset 미사용을 확인했다. - 2026-07-01:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build는 기존 DerivedDatabuild.dblock으로 실패했으나,xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug -derivedDataPath "/var/folders/yh/8xsbvpsj5wg2qnxzxdp11_gm0000gn/T/opencode/SodaLiveDerivedDataPhase7" build로 재실행해 빌드 성공을 확인했다. 기존 duplicate build file/run script/AppIntents/dependency scan warning은 남아 있으나 컴파일 오류는 없었다. - 2026-07-01: 사용자 피드백에 따라 Figma
24:5703의 왼쪽 스케줄 timeline을 재확인했다. 기존 item별TimelineGuideView는 카드 사이 gap에서 line이 끊겨 보이고 dot 위치가 Figma보다 카드에 가까웠으므로, list 전체 overlay의ScheduleTimelineLine과 item별TimelineDotView구조로 변경하고 item gap을 4pt로 맞췄다. - 2026-07-01:
rg "VStack\(alignment: \.leading, spacing: SodaSpacing\.s4\)|ScheduleTimelineLine|TimelineDotView|padding\(\.vertical, 52\)|opacity\(monthlySchedules\.count > 1|HStack\(alignment: \.center, spacing: SodaSpacing\.s14\)|localhost:3845" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingScheduleSection.swift로 연속 line/dot 구조와 Figma localhost asset 미사용을 확인했다. - 2026-07-01:
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug -derivedDataPath "/var/folders/yh/8xsbvpsj5wg2qnxzxdp11_gm0000gn/T/opencode/SodaLiveDerivedDataPhase7" build를 실행해 timeline 수정 후 빌드 성공을 확인했다. 기존 warning은 남아 있으나 컴파일 오류는 없었다.