45 KiB
크리에이터 채널 커뮤니티 아이템 통일 구현 계획
For agentic workers: REQUIRED SUB-SKILL: Use
superpowers:executing-plansto implement this plan task-by-task. 프로젝트 보수적 실행 모드에 따라 multi-agent는 사용하지 않는다.
Goal: 홈과 커뮤니티 탭의 커뮤니티 아이템 외형·상세 진입·더보기를 통일하고 구매는 상세에서만 처리하며, 표시할 reaction이 없을 때 빈 공간을 제거한다.
Architecture: 홈 API 게시글을 private 로컬 변환으로 CreatorChannelCommunityPostItem에 연결해 기존 CreatorChannelCommunityListItem을 재사용한다. 목록 구매 상태·dialog는 상세 ViewModel·View로 옮기고 기존 구매 API를 재사용하며, 변경 성공 후 홈·커뮤니티 목록을 동기화한다. 목록·홈 공용 아이템과 상세는 유료 잠금 상태에서 reaction bar 전체를 조건부로 제외한다.
Tech Stack: Swift, SwiftUI, Combine, Moya, Kingfisher, SDWebImageSwiftUI, Xcode workspace SodaLive.xcworkspace.
Global Constraints
- 기능 변경은
SodaLive/Sources/V2/CreatorChannel/**에서 해결하고 신규 dependency를 추가하지 않는다. - 기존
CommunityPostCard와 메인 홈 팔로잉·추천 사용처는 수정하지 않는다. - 백엔드는 홈 API의
notices·communities아이템에 non-optionalisCommentAvailable: Bool·isPinned: Bool을 제공한다. - 홈 API의
dateUtc는 유지하고 iOS에서 값 변환 없이createdAtUtc로 연결한다. - 목록의 리스트형·썸네일형 구매 호출은 제거하고 기존 구매 dialog·API 호출을 상세로 옮긴다.
- 유료 미구매 영역은 홈·리스트형·썸네일형·상세 모두
Color.gray800을 사용한다. - 하트·댓글을 모두 숨기는 유료 미구매 상태에서는 reaction bar의 고정 높이와 부모 spacing을 남기지 않는다.
- 현재 실행 가능한 단일 test bundle이 없으므로 신규 test 타겟을 만들지 않고 정적 contract check·Preview·Debug build·시뮬레이터로 검증한다.
- 사용자가 직접 요청하지 않았으므로
git commit은 실행하지 않는다.
| 문서 항목 | 내용 |
|---|---|
| 상태 | reaction bar 회귀 수정·빌드 완료·외부 통합 검증 대기 |
| 작성일 | 2026-08-10 |
| 요구사항 기준 | docs/20260810_크리에이터_채널_커뮤니티_아이템_통일/prd.md |
| API 기준 | GET /api/v2/creator-channels/{creatorId}/home 필드 확장·기존 커뮤니티 목록/상세 API |
| 현재 Phase | Phase 3 Gate |
| 현재 활성 Goal | P3-T1·P3-GATE—EXT-001·부팅된 Simulator 대기 |
목표
홈 요약·커뮤니티 리스트·썸네일에서 게시글 터치 결과와 잠금 스타일을 통일하고, 더보기 권한 메뉴와 상세 구매 흐름을 정확하게 유지한다.
현재 상태
| Phase | 상태 | 완료 Task | 활성/다음 Goal | 차단 또는 남은 조건 |
|---|---|---|---|---|
| 1 | 완료 | 3/3 |
P1-GATE 완료 |
없음 |
| 2 | 완료 | 3/3 |
P2-GATE 완료 |
없음 |
| 3 | 진행 | 0/1 |
P3-T1, P3-GATE |
EXT-001 반영·Simulator 부팅 |
범위
포함
- 홈 커뮤니티 응답 필드·Preview fixture 반영
- 리스트형·썸네일형 목록 구매 제거와 상세 진입 통일
- 홈 섹션의
CreatorChannelCommunityListItem재사용 - 홈의 고정·수정·삭제·신고 메뉴 연결과 성공 후 목록 동기화
- 홈·커뮤니티 리스트와 상세에서 표시할 reaction이 없을 때 빈 공간 제거
- 정적 검사·Preview·Debug build·시뮬레이터 검증·문서 누적
제외
CommunityPostCard와 메인 홈 팔로잉·추천 섹션 변경- 구매 endpoint와
CommunityPostPurchaseDialog내부 UI 변경 - 커뮤니티 작성·상세·댓글의 범위 밖 리팩터링
- 신규 공용 모델·protocol·factory·dependency·test target 추가
- 백엔드 구현과 배포
기술적 제약
- 홈 응답·탭 응답 모델은 통합하지 않고
CreatorChannelCommunitySectionprivate 변환으로 연결한다. - 목록 구매 제거로 새로 미사용된 상태·메서드·dialog 분기만 제거한다.
- 홈·커뮤니티 변경 성공 후 갱신은
CreatorChannelView의 한 helper에서 두 ViewModel 재조회를 호출한다. - 사용자 노출 오류는 기존
errorMessage·isShowPopup·toast 흐름을 유지한다. - 홈 응답에 추가 필드가 없으면 decoding 실패를 기존 홈 API 실패로 처리하고 fallback 값을 만들지 않는다.
Task 검증 규칙
- 현재 프로젝트에 실행 가능한 unit test bundle이 없어 SwiftUI View·Decodable 변경에 대한 신규 unit test를 추가하지 않는다.
- 각 구현 Task는 변경 전 구조를 재현하는 실행 가능한
rgcontract check를 RED로 실행한다. - 최소 구현 후 같은 contract check의 기대 결과가 반전되는지 확인하고, 영향 범위
xcodebuild로 GREEN을 판정한다. - Preview·시뮬레이터 검증은 시각·gesture 동작이 unit test target 없이 자동화되지 않는 부분의 대체 완료 증거로 사용한다.
Phase 1: 홈 계약과 목록 상호작용
Phase 결과: 홈 응답이 필요한 고정·댓글 상태를 디코딩하고, 커뮤니티 리스트형·썸네일형은 상세로 이동하며 구매 dialog·API는 상세에서 동작한다.
선행조건: PRD CCCI-004, CCCI-005, CCCI-007, CCCI-008과 EXT-001 계약 확정.
Phase 완료 조건: P1-T1, P1-T2, P1-T3, P1-GATE 완료.
Task 1.1 홈 커뮤니티 응답 계약 반영
Goal 실행 P1-T1: 홈 커뮤니티·공지 아이템이 isCommentAvailable·isPinned을 non-optional Bool로 디코딩한다.
- 시작 조건:
EXT-001필드명·타입 확정. - 완료 증거: 모델·Preview fixture 반영, RED/GREEN contract check,
SodaLive-devDebug build. - 범위 밖: 백엔드 구현, 모델 통합, fallback 기본값.
Files:
- Modify:
SodaLive/Sources/V2/CreatorChannel/Home/Models/CreatorChannelHomeResponse.swift - Modify:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelCommunitySection.swift - Modify:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelNoticeSection.swift - Test: 신규 test 파일 없음—기존 Preview fixture·contract check·Debug build 사용
Interfaces:
-
Consumes: 홈 API
communities·notices아이템의isCommentAvailable: Bool·isPinned: Bool. -
Produces:
CreatorChannelCommunityPostResponse.isCommentAvailable: Bool,CreatorChannelCommunityPostResponse.isPinned: Bool. -
RED: 홈 응답 모델에 두 필드가 없음을 확인한다.
rg -n "let (isCommentAvailable|isPinned): Bool" SodaLive/Sources/V2/CreatorChannel/Home/Models/CreatorChannelHomeResponse.swift
Expected: match 0건, exit code 1.
- RED 확인: 현재 Preview fixture가 두 필드 인자를 전달하지 않음을 확인한다.
rg -n "isCommentAvailable:|isPinned:" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelCommunitySection.swift SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelNoticeSection.swift
Expected: match 0건, exit code 1.
- GREEN:
CreatorChannelCommunityPostResponse마지막에 두 필드를 추가하고 세 개 Preview fixture에 명시적 샘플 값을 전달한다.
let commentCount: Int
let isLiked: Bool
let isCommentAvailable: Bool
let isPinned: Bool
Preview 규칙:
isCommentAvailable: index != 3,
isPinned: index == 1
CreatorChannelNoticeSection fixture는 각 아이템에 isCommentAvailable: true·isPinned: true/false를 명시한다.
- GREEN 확인: 두 필드·세 fixture가 있고 Debug build가 성공함을 확인한다.
rg -n "let (isCommentAvailable|isPinned): Bool" SodaLive/Sources/V2/CreatorChannel/Home/Models/CreatorChannelHomeResponse.swift
rg -n "isCommentAvailable:|isPinned:" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelCommunitySection.swift SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelNoticeSection.swift
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build
Expected: 모델 2건·fixture 6건 이상 match, ** BUILD SUCCEEDED **.
- REFACTOR: 추가 변환 타입·optional fallback·주석을 만들지 않고
git diff --check결과를 누적한다.
Task 1.2 목록 구매 제거와 잠금 배경 통일
Goal 실행 P1-T2: 커뮤니티 리스트형·썸네일형의 유료 미구매 영역이 Color.gray800으로 보이고 터치 시 상세로 이동한다.
- 시작 조건:
P1-T1완료. - 완료 증거: 목록 구매 심볼 0건,
Color.gray400잠금 배경 0건, 썸네일 유료 Preview, Debug build. - 범위 밖: 상세 구매 연결은
P1-T3에서 처리하고, 구매 endpoint·dialog 내부 UI는 변경하지 않는다.
Files:
- Modify:
SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift - Modify:
SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityGridItem.swift - Modify:
SodaLive/Sources/V2/CreatorChannel/Community/CreatorChannelCommunityTabView.swift - Modify:
SodaLive/Sources/V2/CreatorChannel/Community/CreatorChannelCommunityViewModel.swift - Modify:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - Test:
CreatorChannelCommunityGridItem_Previewsin the grid item file·contract check·Debug build
Interfaces:
-
Consumes: 기존
onTapDetail,CreatorChannelCommunityPostDetailView구매 흐름. -
Produces:
CreatorChannelCommunityListIteminit withoutonTapPurchase,CreatorChannelCommunityGridIteminit withoutonTapPurchase. -
RED: 목록 구매 상태·callback·dialog가 남아 있음을 확인한다.
rg -n "onTapPurchase|openPurchaseDialog|isShowPostPurchaseView|selectedPostPrice|purchaseCommunityPost" SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityGridItem.swift SodaLive/Sources/V2/CreatorChannel/Community/CreatorChannelCommunityTabView.swift SodaLive/Sources/V2/CreatorChannel/Community/CreatorChannelCommunityViewModel.swift SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
Expected: 기존 호출처·상태·메서드 match, exit code 0.
- RED 확인: 리스트형·썸네일형 잠금 배경이
Color.gray400인 것을 확인한다.
rg -n "\.fill\(Color\.gray400\)|^[[:space:]]*Color\.gray400[[:space:]]*$" SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityGridItem.swift
Expected: 잠금 배경 2건 match, exit code 0.
- GREEN: 두 아이템의
onTapPurchase를 제거하고 잠금 영역을 상세 진입 gesture에 포함한다.
private var paidLockedImage: some View {
RoundedRectangle(cornerRadius: SodaSpacing.s14, style: .continuous)
.fill(Color.gray800)
.frame(maxWidth: .infinity)
.frame(height: 236)
.overlay(paidPriceOverlay)
}
Grid ZStack은 잠금/접근 가능 분기 밖에 하나의 gesture를 둔다.
.contentShape(Rectangle())
.onTapGesture(perform: onTapDetail)
썸네일 유료 잠금 상태를 고정된 fixture로 확인할 Preview를 추가한다.
struct CreatorChannelCommunityGridItem_Previews: PreviewProvider {
static var previews: some View {
CreatorChannelCommunityGridItem(
post: CreatorChannelCommunityPostItem(
postId: 1,
creatorId: 10,
creatorNickname: "크리에이터 이름",
creatorProfileUrl: "https://picsum.photos/600",
createdAtUtc: "2026-08-10T00:00:00Z",
content: "유료 커뮤니티 게시글",
imageUrl: nil,
audioUrl: nil,
price: 30,
isCommentAvailable: true,
likeCount: 5,
commentCount: 2,
isPinned: true,
existOrdered: false,
isLiked: false
),
isOwnPost: false,
onTapDetail: {}
)
.frame(width: 134, height: 134)
.background(Color.black)
.previewLayout(.sizeThatFits)
}
}
CreatorChannelCommunityViewModel에서 isShowPostPurchaseView, selectedPostPrice, openPurchaseDialog, purchaseCommunityPost를 제거하고 CreatorChannelView.communityOverlay의 목록 구매 dialog 분기를 제거한다.
- GREEN 확인: 목록 구매 심볼·
Color.gray400이 사라지고 두 아이템에Color.gray800이 있음을 확인한다.
rg -n "onTapPurchase|openPurchaseDialog|isShowPostPurchaseView|selectedPostPrice|purchaseCommunityPost" SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityGridItem.swift SodaLive/Sources/V2/CreatorChannel/Community/CreatorChannelCommunityTabView.swift SodaLive/Sources/V2/CreatorChannel/Community/CreatorChannelCommunityViewModel.swift SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
rg -n "\.fill\(Color\.gray400\)|^[[:space:]]*Color\.gray400[[:space:]]*$" SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityGridItem.swift
rg -n "Color\.gray800" SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityGridItem.swift
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build
Expected: 첫 rg와 잠금 배경 rg 각각 match 0건·exit code 1, 세 번째 rg 두 파일 match, ** BUILD SUCCEEDED **.
- REFACTOR: 목록 구매 제거로 새로 미사용된 import·state만 정리하고 상세 구매 연결은
P1-T3에 남긴다.
Task 1.3 기존 구매 흐름을 상세로 이동
Goal 실행 P1-T3: 상세의 유료 미구매 잠금 영역에서 기존 구매 다이얼로그·API가 동작하고 성공 후 상세·홈·커뮤니티 목록을 갱신한다.
- 시작 조건:
P1-T2완료. - 완료 증거:
showPurchaseError0건, 상세 구매 dialog·API 연결, Debug build. - 범위 밖: 구매 endpoint,
CommunityPostPurchaseDialog내부 UI, 결제 정책 변경.
Files:
- Modify:
SodaLive/Sources/V2/CreatorChannel/Community/Detail/CreatorChannelCommunityPostDetailView.swift - Modify:
SodaLive/Sources/V2/CreatorChannel/Community/Detail/CreatorChannelCommunityPostDetailViewModel.swift - Test: contract check·Debug build·시뮬레이터 상세 구매 확인
Interfaces:
-
Consumes:
CreatorCommunityRepository.purchaseCommunityPost(postId:),CommunityPostPurchaseDialog,onCommunityRefresh. -
Produces:
isShowPurchaseDialog,presentPurchaseDialog(),purchaseCommunityPost(). -
RED: 상세 잠금 영역이 구매 대신 공통 오류만 표시하고 상세 구매 상태·메서드가 없음을 확인한다.
rg -n "showPurchaseError|onTapPurchase: showPurchaseError" SodaLive/Sources/V2/CreatorChannel/Community/Detail/CreatorChannelCommunityPostDetailView.swift
rg -n "isShowPurchaseDialog|CommunityPostPurchaseDialog|func (presentPurchaseDialog|purchaseCommunityPost)" SodaLive/Sources/V2/CreatorChannel/Community/Detail/CreatorChannelCommunityPostDetailView.swift SodaLive/Sources/V2/CreatorChannel/Community/Detail/CreatorChannelCommunityPostDetailViewModel.swift
Expected: 첫 명령 match, 둘째 명령 match 0건·exit code 1.
- GREEN: 상세 View에 기존 dialog를 표시하고 상세 ViewModel에 기존 구매 API 호출을 연결한다.
@Published var isShowPurchaseDialog = false
func presentPurchaseDialog() {
guard let detail, detail.price > 0, detail.existOrdered == false, isOwnPost == false else { return }
isShowPurchaseDialog = true
}
func purchaseCommunityPost()
구매 성공 분기는 fetchDetail(postId:)과 onCommunityRefresh?()를 호출한다. 상세 View는 onTapPurchase: viewModel.presentPurchaseDialog와 아래 기존 dialog를 연결한다.
CommunityPostPurchaseDialog(
isShowing: $viewModel.isShowPurchaseDialog,
can: detail.price,
confirmAction: viewModel.purchaseCommunityPost
)
- GREEN 확인: 오류 placeholder가 제거되고 상세 구매 연결·Debug build가 통과함을 확인한다.
rg -n "showPurchaseError" SodaLive/Sources/V2/CreatorChannel/Community/Detail/CreatorChannelCommunityPostDetailView.swift
rg -n "isShowPurchaseDialog|CommunityPostPurchaseDialog|func (presentPurchaseDialog|purchaseCommunityPost)|purchaseCommunityPost\(postId:" SodaLive/Sources/V2/CreatorChannel/Community/Detail/CreatorChannelCommunityPostDetailView.swift SodaLive/Sources/V2/CreatorChannel/Community/Detail/CreatorChannelCommunityPostDetailViewModel.swift
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build
Expected: 첫 rg match 0건·exit code 1, 둘째 rg 필수 연결 match, ** BUILD SUCCEEDED **.
- REFACTOR: 목록 ViewModel에 구매 상태를 되돌리지 않고 상세의 기존 error/toast·refresh 흐름을 재사용한다.
Phase 1 Gate
Goal 실행 P1-GATE: 홈 계약과 목록 상호작용 변경의 컴파일·정적 계약을 판정한다.
git diff --check
rg -n "let (isCommentAvailable|isPinned): Bool" SodaLive/Sources/V2/CreatorChannel/Home/Models/CreatorChannelHomeResponse.swift
rg -n "Color\.gray800" SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityGridItem.swift SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift
rg -n "CommunityPostPurchaseDialog|func purchaseCommunityPost|purchaseCommunityPost\(postId:" SodaLive/Sources/V2/CreatorChannel/Community/Detail/CreatorChannelCommunityPostDetailView.swift SodaLive/Sources/V2/CreatorChannel/Community/Detail/CreatorChannelCommunityPostDetailViewModel.swift
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build
Expected: whitespace 오류 0건, 필드 2건, 세 UI의 Color.gray800·상세 구매 연결 match, ** BUILD SUCCEEDED **.
Phase 2: 홈 아이템 재사용과 메뉴 연결
Phase 결과: 홈이 기존 커뮤니티 리스트 아이템·상세 route·권한 메뉴를 재사용하고 변경 성공 후 홈·커뮤니티 목록을 동기화한다.
선행조건: P1-GATE 완료.
Phase 완료 조건: P2-T1, P2-T2, P2-R1, P2-GATE 완료.
Task 2.1 홈 섹션에 기존 리스트 아이템·상세·더보기 연결
Goal 실행 P2-T1: 홈 섹션이 최대 3개의 CreatorChannelCommunityListItem을 표시하고 본체는 상세로, 더보기는 기존 권한 메뉴로 연결한다.
- 시작 조건:
P1-GATE완료. - 완료 증거:
CommunityPostCard사용 0건, 로컬 변환·postIdroute·홈 overlay 연결, Preview, Debug build. - 범위 밖: 신규 표시 모델, 메뉴 UI 복제, 메인 홈
CommunityPostCard수정.
Files:
- Modify:
SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelCommunitySection.swift - Modify:
SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift - Modify:
SodaLive/Sources/V2/CreatorChannel/Community/CreatorChannelCommunityTabView.swift - Modify:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - Test:
CreatorChannelCommunitySection_Previews·contract check·Debug build
Interfaces:
-
Consumes:
CreatorChannelCommunityPostResponse,CreatorChannelCommunityPostItem,CreatorChannelCommunityViewModel.openReportMenu(post:),AppStep.creatorChannelCommunityPostDetail. -
Produces:
CreatorChannelCommunitySection(isOwnCreatorChannel:onTapMore:onTapDetail:),CreatorChannelHomeView(isOwnCreatorChannel:onTapCommunityMore:onTapCommunityDetail:),showCommunityPostDetail(_ postId: Int). -
RED: 홈 섹션이 아직
CommunityPostCard를 사용하고 홈 상세·더보기 callback이 없음을 확인한다.
rg -n "CommunityPostCard\(" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelCommunitySection.swift
rg -n "onTapCommunity(More|Detail)|communityPostItem" SodaLive/Sources/V2/CreatorChannel/Home SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
Expected: 첫 명령 match 1건·exit code 0, 둘째 명령 match 0건·exit code 1.
- RED 확인:
communityOverlay노출이.community에만 한정됨을 확인한다.
rg -n "if viewModel\.selectedTab == \.community" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
Expected: communityOverlay 함수 내 match 포함, exit code 0.
- GREEN: 홈 게시글을 커뮤니티 탭 아이템으로 연결하는 private property를 추가한다.
private extension CreatorChannelCommunityPostResponse {
var communityPostItem: CreatorChannelCommunityPostItem {
CreatorChannelCommunityPostItem(
postId: postId,
creatorId: creatorId,
creatorNickname: creatorNickname,
creatorProfileUrl: creatorProfileUrl,
createdAtUtc: dateUtc,
content: content,
imageUrl: imageUrl,
audioUrl: audioUrl,
price: price,
isCommentAvailable: isCommentAvailable,
likeCount: likeCount,
commentCount: commentCount,
isPinned: isPinned,
existOrdered: existOrdered,
isLiked: isLiked
)
}
}
CreatorChannelCommunitySection은 isOwnCreatorChannel: Bool, onTapMore: (CreatorChannelCommunityPostItem) -> Void, onTapDetail: (Int) -> Void를 받고 CreatorChannelCommunityListItem에 연결한다. CreatorChannelHomeView는 동일 상태·callback을 전달한다.
홈 섹션 Preview도 변경된 입력 계약을 명시한다.
CreatorChannelCommunitySection(
communities: previewCommunities,
isOwnCreatorChannel: true,
onSelectTab: { _ in },
onTapMore: { _ in },
onTapDetail: { _ in }
)
- GREEN: 홈·커뮤니티 탭이
postId기반 상세 helper를 공통 사용하고 홈에서도 기존 overlay를 보여준다.
private func showCommunityPostDetail(_ postId: Int) {
AppState.shared.setAppStep(
step: .creatorChannelCommunityPostDetail(
postId: postId,
onCommunityRefresh: {
viewModel.fetchHome(creatorId: creatorId)
communityViewModel.fetchFirstPage(creatorId: creatorId)
}
)
)
}
CreatorChannelCommunityTabView.onTapDetail도 (Int) -> Void로 줄이고 post.postId를 전달한다. communityOverlay 조건은 .home || .community로 확장한다.
- GREEN 확인: 기존 카드·탭 전용 상세 모델 callback이 제거되고 새 연결과 Debug build가 통과함을 확인한다.
rg -n "CommunityPostCard\(" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelCommunitySection.swift
rg -n "communityPostItem|CreatorChannelCommunityListItem\(|onTapCommunityMore|onTapCommunityDetail|showCommunityPostDetail\(_ postId: Int\)" SodaLive/Sources/V2/CreatorChannel/Home SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build
Expected: 첫 명령 match 0건·exit code 1, 둘째 명령 필수 연결 match, ** BUILD SUCCEEDED **.
- REFACTOR:
CreatorChannelCommunitySection.relativeTimeText같은 카드 제거로 미사용된 헬퍼만 제거하고,CommunityPostCard의 다른 사용처는 건드리지 않는다.
Task 2.2 관리 동작 성공 후 홈·커뮤니티 동기화
Goal 실행 P2-T2: 홈 더보기에서 고정·수정·삭제한 결과가 홈과 커뮤니티 탭 목록에 모두 반영된다.
- 시작 조건:
P2-T1완료. - 완료 증거: 한 개의
refreshCommunityFeeds()helper, 변경 성공 callback, Debug build. - 범위 밖: 좋아요 optimistic state, 신고 성공 후 목록 재조회, 메뉴 UI 변경.
Files:
- Modify:
SodaLive/Sources/V2/CreatorChannel/Community/CreatorChannelCommunityViewModel.swift - Modify:
SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift - Test: contract check·Debug build·시뮬레이터 관리 액션 확인
Interfaces:
-
Consumes:
deleteCommunityPost,updateCommunityPostFixed,showCommunityModify, 두 ViewModel의 재조회 메서드. -
Produces:
deleteCommunityPost(onSuccess:),updateCommunityPostFixed(onSuccess:),refreshCommunityFeeds(). -
RED: 삭제·고정·수정 성공 후 커뮤니티 탭만 재조회하는 현재 구조를 확인한다.
rg -n "fetchFirstPage\(creatorId: creatorId\)|fetchHome\(creatorId: creatorId\)|deleteCommunityPost\(creatorId:|updateCommunityPostFixed\(creatorId:" SodaLive/Sources/V2/CreatorChannel/Community/CreatorChannelCommunityViewModel.swift SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
Expected: ViewModel 내 재조회와 creatorId 기반 mutation, 수정 callback의 커뮤니티 탭 재조회 match.
- RED 확인:
refreshCommunityFeedshelper가 없음을 확인한다.
rg -n "refreshCommunityFeeds" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
Expected: match 0건, exit code 1.
- GREEN: ViewModel mutation은 성공 시 주입된 callback을 호출하고 재조회 소유권을
CreatorChannelView로 옮긴다.
func deleteCommunityPost(onSuccess: @escaping () -> Void)
func updateCommunityPostFixed(onSuccess: @escaping () -> Void)
private func refreshCommunityFeeds() {
viewModel.fetchHome(creatorId: creatorId)
communityViewModel.fetchFirstPage(creatorId: creatorId)
}
두 mutation의 기존 성공 분기에서 ViewModel 자체 재조회 대신 callback을 실행한다.
if decoded.success {
self.errorMessage = I18n.Explorer.deleted
self.isShowPopup = true
onSuccess()
}
if decoded.success {
onSuccess()
}
fixedAction, 삭제 확인 action, showCommunityModify 성공 callback이 refreshCommunityFeeds 하나를 사용하도록 연결한다.
- GREEN 확인: helper가 두 재조회를 포함하고 mutation의 기존
creatorId인자·ViewModel 내 재조회가 제거됨을 확인한다.
rg -n "refreshCommunityFeeds|fetchHome\(creatorId: creatorId\)|fetchFirstPage\(creatorId: creatorId\)" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
rg -n "deleteCommunityPost\(creatorId:|updateCommunityPostFixed\(creatorId:|fetchFirstPage\(creatorId: creatorId\)" SodaLive/Sources/V2/CreatorChannel/Community/CreatorChannelCommunityViewModel.swift
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build
Expected: 첫 명령은 helper·두 재조회·세 action 연결 match, 둘째 명령 match 0건·exit code 1, ** BUILD SUCCEEDED **.
- REFACTOR: 기존 글 작성 성공 callback은 요청 범위가 아니므로 별도 정리하지 않고 이번 변경의 중복만 제거한다.
Regression Task 2.3 표시할 reaction이 없을 때 빈 공간 제거
Goal 실행 P2-R1: 홈·커뮤니티 리스트와 상세의 유료 미구매 상태에서 하트·댓글과 reaction bar의 고정 높이를 함께 제거한다.
- 리뷰 근거:
REV-P3-003—reviews/phase3-community-item-unification.md - 시작 조건: 사용자 회귀 제보와 코드 근거 확인, PRD
CCCI-009·DEC-013반영. - 완료 증거: 두 View의 무조건
reactionBar삽입 0건,if !isPaidLocked조건부 삽입 2건,git diff --check, Debug build. - 범위 밖: reaction icon·count 스타일 변경, 썸네일 레이아웃 변경, 신규 helper·test target 추가.
Files:
- Modify:
SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift - Modify:
SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift - Test: 신규 test 파일 없음—focused contract check·Debug build 사용
Interfaces:
-
Consumes: 각 View의 기존
isPaidLocked,reactionBar. -
Produces: 유료 잠금 상태에서
reactionBar가 View 계층에 없는 레이아웃. -
RED: 두 View body가
reactionBar를 무조건 삽입하고, 내부의 빈HStack이.frame(height: 24)를 유지함을 확인한다.
rg -n '^[[:space:]]{12}reactionBar$' SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift
rg -n 'frame\(height: 24\)' SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift
Expected: 첫 명령 match 2건, 둘째 명령 match 2건.
-
GREEN: 두 body에서
reactionBar를if !isPaidLocked일 때만 삽입하고, 내부의 중복 잠금 조건만 제거한다. -
GREEN 확인: 무조건 삽입이 사라지고 조건부 삽입·Debug build가 통과함을 확인한다.
rg -n '^[[:space:]]{12}reactionBar$' SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift
rg -n -U 'if !isPaidLocked \{\n[[:space:]]+reactionBar' SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift
git diff --check
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build
Expected: 첫 명령 match 0건·exit code 1, 둘째 명령 match 2건, whitespace 오류 0건, ** BUILD SUCCEEDED **.
- REFACTOR: 신규 상태·helper를 추가하지 않고 기존
isPaidLocked만 재사용한다.
Phase 2 Gate
Goal 실행 P2-GATE: 홈 재사용·상세·더보기·목록 동기화 구조를 판정한다.
git diff --check
rg -n "communityPostItem|CreatorChannelCommunityListItem\(|onTapCommunityMore|onTapCommunityDetail|refreshCommunityFeeds" SodaLive/Sources/V2/CreatorChannel/Home SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
rg -n "CommunityPostCard\(" SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelCommunitySection.swift
rg -n -U 'if !isPaidLocked \{\n[[:space:]]+reactionBar' SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build
Expected: whitespace 오류 0건, 필수 연결 match, 홈 CommunityPostCard match 0건·exit code 1, ** BUILD SUCCEEDED **.
Phase 3: 리뷰·통합 검증·문서 종결
Phase 결과: 정적 계약·Debug build·Preview·시뮬레이터 흐름을 확인하고 PRD·계획·리뷰 기록을 동기화한다.
선행조건: P2-GATE 완료. 시뮬레이터 통합 판정은 EXT-001 반영 후 실행.
Phase 완료 조건: P3-T1, P3-GATE 완료·검증 기록 누적.
Task 3.1 영향 범위 리뷰와 완료 증거 누적
Goal 실행 P3-T1: 확정 요구사항 전체의 자동·수동 증거와 잔여 위험을 문서화한다.
- 시작 조건:
P2-GATE완료. - 완료 증거: 리뷰 리포트, 정적 검사, Debug build, Preview/시뮬레이터 결과, PRD·계획 Progress.
- 범위 밖: 실패와 무관한 리팩터링, test target 추가, 백엔드 수정.
- TDD 예외 사유: production 동작을 추가하지 않는 리뷰·검증·문서 Task다.
- 대체 검증 방법: 아래 정적 검사·Debug build·Preview·시뮬레이터 대조표를 사용한다.
Files:
- Create:
docs/20260810_크리에이터_채널_커뮤니티_아이템_통일/reviews/phase3-community-item-unification.md - Modify:
docs/20260810_크리에이터_채널_커뮤니티_아이템_통일/prd.md - Modify:
docs/20260810_크리에이터_채널_커뮤니티_아이템_통일/plan-task.md - Test: 정적 검사·Debug build·Preview·시뮬레이터 대체 검증
Interfaces:
-
Consumes:
CCCI-001~008,EXT-001, Phase 1·2 산출물. -
Produces: Phase 3 리뷰 판정, 최종 Progress, 남은 외부 조건.
-
정적 검사로 필수 연결과 금지 호출처를 확인한다.
rg -n "let (isCommentAvailable|isPinned): Bool" SodaLive/Sources/V2/CreatorChannel/Home/Models/CreatorChannelHomeResponse.swift
rg -n "communityPostItem|CreatorChannelCommunityListItem\(|showCommunityPostDetail\(_ postId: Int\)|refreshCommunityFeeds" SodaLive/Sources/V2/CreatorChannel/Home SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
rg -n "onTapPurchase|openPurchaseDialog|isShowPostPurchaseView|selectedPostPrice|purchaseCommunityPost" SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityGridItem.swift SodaLive/Sources/V2/CreatorChannel/Community/CreatorChannelCommunityTabView.swift SodaLive/Sources/V2/CreatorChannel/Community/CreatorChannelCommunityViewModel.swift SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
rg -n "Color\.gray800" SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityGridItem.swift SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift
git diff --check
Expected: 필드·홈 연결·세 UI의 Color.gray800 match, 목록 구매 심볼 0건·exit code 1, whitespace 오류 0건.
SodaLive-devDebug build를 실행한다.
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build
Expected: exit code 0, ** BUILD SUCCEEDED **.
- Preview에서 홈 유료 잠금·고정·댓글 비활성 상태와 썸네일 유료 잠금 상태를 확인한다.
EXT-001반영 후 시뮬레이터에서 홈·리스트형·썸네일형 본체 터치가 상세로 이동하고 목록 구매 dialog가 나오지 않음을 확인한다.- 본인 채널의 고정·수정·삭제, 타인 채널의 신고, 상세 구매, 더보기·좋아요 터치 중복 없음을 수동 확인한다.
docs/sample/sample-review.md를 읽고phase3-community-item-unification.md에 검토 범위·근거·명령·발견 사항을 기록한다.- 확정 수정 항목이 있으면 코드 수정 전 해당 Phase에 회귀 Task를 추가한다.
- PRD 상태·요구사항 추적표와 이 문서의 체크박스·Progress를 실제 결과로 갱신한다.
Phase 3 Gate
Goal 실행 P3-GATE: 확정 요구사항·자동 검증·수동 검증·문서 추적성을 최종 판정한다.
P3-T1리뷰에 확정 수정 항목이 없거나 추가 회귀 Task가 완료됐다.git diff --check·정적 contract check·SodaLive-devDebug build가 통과했다.- Preview 검증이 통과했다.
EXT-001반영 후 시뮬레이터 통합 검증이 통과했다. 미반영이면 Phase를 완료 표시하지 않고 재개 조건을 Progress에 남긴다.- PRD·
plan-task.md·review 리포트의 판정과 검증 기록이 일치한다.
실행 순서와 의존성
| 순서 | Goal | 선행조건 | 병행 가능 | 차단 시 다음 행동 |
|---|---|---|---|---|
| 1 | P1-T1 |
PRD·EXT-001 계약 확정 |
아니요 | 백엔드 필드명·타입 확인 |
| 2 | P1-T2 |
P1-T1 완료 |
아니요 | 목록 호출처·상세 구매 경계 재확인 |
| 3 | P1-T3 |
P1-T2 완료 |
아니요 | 기존 상세 잠금·구매 API 경계 재확인 |
| 4 | P1-GATE |
Phase 1 Task 전체 | 아니요 | 실패 소유 Task 수정 |
| 5 | P2-T1 |
P1-GATE |
아니요 | 홈·탭 모델 매핑 재확인 |
| 6 | P2-T2 |
P2-T1 |
아니요 | mutation 성공 callback 호출처 재확인 |
| 7 | P2-R1 |
사용자 회귀 제보·PRD 반영 | 아니요 | reaction bar 삽입 조건 재확인 |
| 8 | P2-GATE |
Phase 2 Task 전체 | 아니요 | 실패 소유 Task 수정 |
| 9 | P3-T1 |
P2-GATE |
아니요 | 리뷰 수정 Task 추가 |
| 10 | P3-GATE |
P3-T1·EXT-001 |
아니요 | 백엔드 반영 후 통합 검증 재개 |
P1-T1 → P1-T2 → P1-T3 → P1-GATE → P2-T1 → P2-T2 → P2-R1 → P2-GATE → P3-T1 → P3-GATE
변경 금지 항목
CommunityPostCard와 메인 홈 팔로잉·추천 사용처를 수정하지 않는다.- 구매 endpoint와
CommunityPostPurchaseDialog내부 UI를 변경하지 않는다. - 홈 API의
dateUtc를 임의로 rename·parse·timezone 변환하지 않는다. - 백엔드 미반영 필드에 optional·fallback 값을 만들어 통합 실패를 숨기지 않는다.
- 신규 protocol·factory·display model·dependency·test target을 추가하지 않는다.
- 요청 범위 밖의 기존 dead code·format·naming을 정리하지 않는다.
의사결정 및 중단 규칙
- PRD·현재 API 응답·구현이 충돌하면 PRD의
EXT-001을 우선하고 추정 구현하지 않는다. - iOS 컴파일과 Preview 작업은 백엔드 반영 전에 진행할 수 있지만, 시뮬레이터 통합 판정은
EXT-001반영 후에만 완료한다. - 구현 범위가 바뀌면 PRD Decision Log·요구사항·이 문서 체크박스를 코드 수정 전에 갱신한다.
- 같은 차단 사유가 최초 시도와 자동 후속을 포함해 3회 연속 반복되고 독립 작업도 불가능할 때만 차단으로 판정한다.
- 체크박스·검증·Progress가 모두 충족되기 전에 Goal·Phase를 완료 표시하지 않는다.
Progress
기존 기록을 삭제하지 않고 실제 실행 결과를 누적한다.
계획 작성 — 2026-08-10
- 상태: 계획 검토 대기
- 무엇을: 인터뷰·설계 승인 결과를 Phase 1~3·Task 6개·Gate 3개로 변환했고, 기준선 확인에서 누락된 상세 구매 이동 Task를 추가했다.
- 왜: 코드 수정 전 파일 범위·인터페이스·검증·외부 의존을 확정하기 위해서다.
- 어떻게:
rg로 현재 모델·callback·구매 상태·색상·Preview fixture 호출처를 확인했다.docs/agent-guides/documentation-policy.md,build-test-verification.md,code-style.md,agent-execution-policy.md와 현재 PRD·샘플을 대조했다.
- 남은 항목: 사용자 계획 검토,
P1-T1시작. - 다음 행동: 계획 승인 후
superpowers:executing-plans로P1-T1을 실행한다.
Phase 1~2 구현 — 2026-08-10
- 상태: 코드·정적 계약·Debug build 완료
- 무엇을:
- 홈 응답에
isCommentAvailable·isPinned을 추가했다. - 목록 구매를 제거하고 잠금 배경을
Color.gray800으로 통일했다. - 기준선에서 발견한 상세 구매 누락을
P1-T3로 추가한 뒤 기존 dialog·API를 상세로 이동했다. - 홈을
CreatorChannelCommunityListItem으로 교체하고 상세·더보기·두 목록 refresh를 연결했다.
- 홈 응답에
- 왜:
CCCI-001~008의 iOS 코드 범위를 충족하기 위해서다. - 어떻게:
- 각 Task의 RED/GREEN
rgcontract check를 실행했다. - iPhone 17 Pro iOS 26.0 대상
SodaLive-devDebug build를 실행해 exit code 0을 확인했다.
- 각 Task의 RED/GREEN
- 남은 항목: Preview·Simulator 통합 검증.
- 다음 행동: Phase 3 리뷰와 외부 조건 확인.
Phase 3 리뷰 — 2026-08-10
- 상태: 코드 리뷰 완료·통합 검증 대기
- 무엇을: 전체 diff를 PRD·계획과 대조하고
reviews/phase3-community-item-unification.md를 작성했다. - 왜: 완료 주장을 코드·빌드·수동 증거로 분리하기 위해서다.
- 어떻게:
- 정적 계약·
git diff --check·Debug build는 통과했다. xcrun simctl list devices결과 사용 가능한 Simulator가 모두Shutdown임을 확인했다.
- 정적 계약·
- 남은 항목:
EXT-001반영, Preview, 본체 상세 이동·권한별 더보기·목록 dialog 미노출·상세 구매 수동 확인. - 다음 행동: 사용자가 Simulator를 부팅하고 백엔드 필드 반영을 알리면
P3-T1·P3-GATE를 재개한다.
Reaction bar 회귀 수정 — 2026-08-10
- 상태:
P2-R1구현 전 - 무엇을: 홈·커뮤니티 리스트와 상세의 하트·댓글이 모두 숨겨질 때 남는 빈 공간을 회귀 Task로 추가했다.
- 왜: 두 View가 빈 reaction
HStack의 고정 24pt 높이를 계속 배치하는 근본 원인을 확인했다. - 어떻게: 공용 리스트 아이템과 상세 content View의 body·
reactionBar를 추적하고REV-P3-003,CCCI-009,DEC-013을 연결했다. - 남은 항목: RED 확인, 최소 코드 수정, 정적 검사·Debug build, 문서 결과 누적.
- 다음 행동:
P2-R1을 실행한다.
Reaction bar 회귀 수정 완료 — 2026-08-10
- 상태:
P2-R1·P2-GATE완료 - 무엇을: 공용 리스트 아이템과 상세에서 유료 잠금 상태일 때
reactionBar전체를 View 계층에서 제외했다. - 왜: 하트·댓글 자식만 숨기면 빈
HStack의 24pt 높이와 부모 spacing이 남기 때문이다. - 어떻게:
- RED: body의 무조건
reactionBar삽입 2건,.frame(height: 24)2건을 확인했다. - GREEN: 무조건 삽입 0건,
if !isPaidLocked조건부 삽입 2건을 확인했다. git diff --check오류 0건, iPhone 17 Pro 대상SodaLive-devDebug build exit code 0을 확인했다.
- RED: body의 무조건
- 남은 항목: 기존
EXT-001·부팅된 Simulator 기반 Preview/통합 검증. - 다음 행동: 외부 조건 충족 후
P3-GATE를 재개한다.
Decision Log
| 날짜 | ID | 상태 | 결정 | 근거 | 영향 Goal/문서 |
|---|---|---|---|---|---|
| 2026-08-10 | PLAN-DEC-001 |
확정 | 로컬 변환·기존 컴포넌트·기존 메뉴 상태를 재사용한다. | PRD DEC-008~011 |
P2-T1, P2-T2 |
| 2026-08-10 | PLAN-DEC-002 |
확정 | 목록 구매를 홈·리스트형·썸네일형에서 모두 제거한다. | PRD DEC-003, DEC-007 |
P1-T2 |
| 2026-08-10 | PLAN-DEC-003 |
확정 | 백엔드 필드는 non-optional로 디코딩하고 미반영 응답을 fallback으로 숨기지 않는다. | PRD DEC-006, EXT-001 |
P1-T1, P3-GATE |
| 2026-08-10 | PLAN-DEC-004 |
확정 | 신규 test target 대신 contract check·Preview·Debug build·시뮬레이터를 완료 증거로 사용한다. | 현재 프로젝트에 unit test bundle 없음 | 전체 Task·Gate |
| 2026-08-10 | PLAN-DEC-005 |
확정 | 목록의 기존 구매 상태·API 호출을 상세 View·ViewModel로 옮긴다. | 상세의 현재 showPurchaseError()만으로는 사용자 요구인 상세 구매가 불가능함 |
P1-T2, P1-T3 |
| 2026-08-10 | PLAN-DEC-006 |
확정 | 하트·댓글이 모두 숨겨지는 경우 높이 보정 대신 reaction bar 전체를 조건부로 제외한다. | 공용 리스트·상세의 빈 고정 높이를 같은 기존 상태로 제거하는 최소 변경 | P2-R1, CCCI-009 |
발견된 문제
| ID | 심각도 | 상태 | 발견 내용 | 영향 Goal | 처리 계획 |
|---|---|---|---|---|---|
ISSUE-001 |
High | 외부 조건 대기 | 백엔드 홈 API 응답에 isCommentAvailable·isPinned이 없으면 신규 iOS 모델 디코딩에 실패한다. |
P1-T1, P3-GATE |
iOS 구현·빌드는 완료했고 EXT-001 반영 후 통합 검증한다. |
ISSUE-002 |
High | 환경 대기 | 사용 가능한 Simulator가 모두 Shutdown이라 실제 터치·메뉴·구매 검증을 실행하지 못했다. |
P3-T1, P3-GATE |
Simulator 부팅 후 수동 검증을 재개한다. |
ISSUE-003 |
Medium | 수정 완료 | 유료 잠금 상태에서 하트·댓글은 숨겨지지만 빈 reaction bar의 고정 24pt 높이가 홈·목록·상세에 남는다. | P2-R1, P3-GATE |
조건부 삽입 contract check·Debug build 통과. |
최종 보고 형식
구현 결과: 홈·커뮤니티 아이템 통일과 상세 구매 일원화
- 변경: 홈 아이템 재사용, 목록 구매 제거, 더보기·상세·잠금 색상 통일
- 결정: `DEC-001~012`, `PLAN-DEC-001~005`
- 검증:
- 정적 contract check·`git diff --check` — 실제 결과
- `SodaLive-dev` Debug build — 실제 결과
- Preview·시뮬레이터 — 실제 결과 또는 외부 조건
- 남은 항목: `EXT-001` 반영 여부 또는 없음
- 문서: PRD·`plan-task.md`·Phase 3 review 리포트