22 KiB
22 KiB
제품 요구사항 문서(PRD): 크리에이터 채널 커뮤니티 아이템 통일
문서 정보
| 항목 | 내용 |
|---|---|
| 문서 상태 | reaction bar 회귀 수정·Debug build 완료·EXT-001/Simulator 통합 검증 대기 |
| 작성일 | 2026-08-10 |
| 최종 수정일 | 2026-08-10 |
| 대상 제품 | SodaLive iOS 크리에이터 채널 홈·커뮤니티 |
| 작성자·결정권자 | 사용자·iOS 구현 에이전트 |
| 관련 API Contract | GET /api/v2/creator-channels/{creatorId}/home 커뮤니티 응답 필드 확장 |
| 관련 구현 계획 | docs/20260810_크리에이터_채널_커뮤니티_아이템_통일/plan-task.md |
| 관련 review | reviews/phase3-community-item-unification.md |
1. Overview
크리에이터 채널 홈 탭의 커뮤니티 요약 아이템을 커뮤니티 탭 리스트와 동일한 CreatorChannelCommunityListItem으로 표시한다. 홈과 커뮤니티 탭의 아이템 터치는 게시글 상세로 이동하고, 유료 게시글 구매는 상세 화면에서만 시작한다. 유료 미구매 이미지 영역은 상세 화면의 Color.gray800과 동일하게 통일하고, 하트·댓글을 모두 표시하지 않는 상태에서는 reaction bar의 빈 높이도 제거한다.
2. Problem Statement
- 홈 탭은
CommunityPostCard, 커뮤니티 탭은CreatorChannelCommunityListItem을 사용해 동일한 게시글의 외형과 상호작용이 다르다. - 홈 아이템에는 우측 상단 더보기가 없고 아이템 터치 상세 이동이 연결되지 않았다.
- 커뮤니티 탭의 유료 미구매 영역은
Color.gray400, 상세 화면은Color.gray800을 사용해 색상이 다르다. - 현재
CreatorChannelCommunityListItem의 유료 미구매 영역은 목록에서 구매 다이얼로그를 여는 별도Button이므로, 전체 아이템을 상세 진입으로 통일하려는 요구와 충돌한다. - 홈·커뮤니티 리스트와 상세는 하트·댓글을 모두 숨기는 유료 잠금 상태에서도 높이 24pt의 빈 reaction bar를 삽입해 불필요한 세로 공간이 남는다.
3. Goals
3.1 제품 목표
- 홈 탭과 커뮤니티 탭의 리스트형 커뮤니티 아이템 외형을 하나의 컴포넌트로 통일한다.
- 홈 탭 커뮤니티 아이템 우측 상단에 더보기를 제공한다.
- 커뮤니티 아이템 터치를 상세 진입으로 통일하고 구매는 상세 화면에서 처리한다.
- 유료 미구매 이미지 영역을
Color.gray800으로 통일한다. - 하트·댓글을 모두 표시하지 않는 상태에서는 reaction bar가 레이아웃 공간을 차지하지 않게 한다.
3.2 UX 목표
- 홈에서 본 커뮤니티 아이템이 전체 커뮤니티 탭에서도 같은 정보 구조와 스타일로 보여야 한다.
- 아이템 본문·이미지·유료 잠금 영역을 터치하면 예상 가능하게 상세 화면으로 이동해야 한다.
- 더보기·좋아요 같은 독립 제어의 터치는 아이템 상세 터치와 중복 실행되지 않아야 한다.
- 표시할 reaction이 없으면 콘텐츠 아래에 빈 여백이 남지 않아야 한다.
4. Non-Goals
- 기존 구매 endpoint와
CommunityPostPurchaseDialog의 내부 UI는 변경하지 않는다. - 썸네일형 커뮤니티 아이템의 레이아웃은 변경하지 않는다.
CommunityPostCard의 다른 사용처인 메인 홈 팔로잉·추천 섹션은 변경하지 않는다.- 신규 endpoint, 앱 dependency, 범위 밖 커뮤니티 리팩터링은 추가하지 않는다.
5. Target Users and Permissions
- 타인 채널 방문자: 더보기에서 신고 동작을 사용할 수 있다.
- 본인 채널의 크리에이터: 기존 커뮤니티 게시글 관리 권한 범위 안에서 더보기 동작을 사용한다.
- 유료 미구매 방문자: 목록에서 구매하지 않고 상세 화면에서 구매를 시작한다.
6. 핵심 사용자 흐름
- 사용자가 크리에이터 채널 홈의 커뮤니티 요약 아이템을 확인한다.
- 아이템 본체를 터치하면 해당
postId의 커뮤니티 게시글 상세로 이동한다. - 유료 미구매 게시글이면 상세 화면에서 기존 구매 다이얼로그와 API를 사용한다.
- 사용자가 우측 상단 더보기를 터치하면 확정된 권한 규칙에 맞는 메뉴가 표시된다.
7. 기능 요구사항
| ID | 상태 | 요구사항 | 수용 기준 | 계획 연결 |
|---|---|---|---|---|
CCCI-001 |
확정 | 홈 탭 커뮤니티 섹션은 CommunityPostCard 대신 CreatorChannelCommunityListItem을 사용한다. |
홈과 커뮤니티 탭 리스트 아이템이 동일한 컴포넌트로 렌더링된다. | P2-T1 |
CCCI-002 |
확정 | 홈 탭 커뮤니티 아이템 우측 상단에 더보기를 표시한다. | 더보기가 보이고 아이템 상세 터치와 독립적으로 작동한다. | P2-T1 |
CCCI-003 |
확정 | 아이템 본체 터치는 creatorChannelCommunityPostDetail로 이동한다. |
선택한 게시글의 postId로 상세 API가 호출된다. |
P2-T1 |
CCCI-004 |
확정 | 목록에서 유료 게시글 구매를 시작하지 않고 상세에서 처리한다. | 유료 미구매 영역 터치는 상세로 이동하고 상세의 잠금 영역에서 구매 다이얼로그·API가 동작한다. | P1-T2, P1-T3 |
CCCI-005 |
확정 | 커뮤니티 탭 리스트형·썸네일형의 유료 미구매 영역을 Color.gray800으로 변경한다. |
홈·커뮤니티 탭 두 표시 모드·상세의 유료 미구매 영역이 Color.gray800을 사용한다. |
P1-T2 |
CCCI-006 |
확정 | 홈 탭 더보기는 커뮤니티 탭과 동일하게 본인 게시글에 고정·수정·삭제, 타인 게시글에 신고를 제공한다. | 권한별 메뉴가 커뮤니티 탭과 동일하고 성공 후 홈·커뮤니티 목록이 갱신된다. | P2-T1, P2-T2 |
CCCI-007 |
확정 | 홈과 커뮤니티 탭의 리스트형·썸네일형 모두 목록 구매를 제거하고 유료 미구매 영역 터치를 상세 이동으로 처리한다. | 모든 목록 표시 모드에서 구매 다이얼로그가 열리지 않고 상세에서만 구매한다. | P1-T2, P1-T3 |
CCCI-008 |
외부 의존 | 백엔드 홈 API의 communities·notices 아이템에 isCommentAvailable: Bool·isPinned: Bool을 커뮤니티 탭과 동일하게 제공한다. |
iOS가 두 필드를 임의 기본값 없이 디코딩해 고정·댓글 상태를 표시한다. | P1-T1, EXT-001 |
CCCI-009 |
확정 | 홈·커뮤니티 리스트와 커뮤니티 상세에서 하트·댓글을 모두 표시하지 않을 때 reaction bar를 삽입하지 않는다. | 유료 미구매 잠금 상태에서 하트·댓글과 고정 24pt 높이가 모두 사라지고, 하나라도 표시되면 기존 reaction bar가 유지된다. | P2-R1 |
8. UI/UX Expectations
- 홈 섹션은 기존처럼 최대 3개 아이템과
전체보기버튼을 유지한다. - 홈 아이템의 typography, spacing, profile image, 본문, media, reaction bar, radius는
CreatorChannelCommunityListItem의 현재 구성을 따른다. - 우측 상단 더보기는 기존
ic_seemore_vertical을 재사용한다. - 리스트형 유료 미구매 영역은 236pt 높이를, 썸네일형은 기존 정사각형 비율을 유지한다. 두 형태 모두 잠금 icon·가격 capsule을 유지하고 배경만
Color.gray800으로 통일한다. - 더보기와 좋아요 제어는 자신의 action만 실행하고 상세 이동을 중복 실행하지 않는다.
- 유료 미구매 잠금 상태처럼 하트·댓글을 모두 숨기는 경우 reaction bar 전체를 조건부로 제외해 고정 높이와
VStack간격을 남기지 않는다.
9. 기술·운영 제약
- 변경은
SodaLive/Sources/V2/CreatorChannel/**와 필요한 공용 V2 컴포넌트의 최소 범위에서 해결한다. CommunityPostCard의 메인 홈 사용처는 수정하지 않는다.- 현재 상세 route와 기존 구매 다이얼로그·구매 API를 재사용한다.
- 백엔드는 홈 API 응답에 커뮤니티 탭과 동일한
isCommentAvailable: Bool·isPinned: Bool을 제공한다. iOS는 두 필드가 없는 응답을 추정 기본값으로 보정하지 않는다. - 홈 응답 모델과 커뮤니티 탭 응답 모델의 차이를 제거하기 위한 투기적 protocol·factory·신규 dependency를 추가하지 않는다.
- 본인 게시글 판정은 기존처럼
creatorId == UserDefaults.int(forKey: .userId)를 사용한다.
10. 성공 기준
- 홈 탭 커뮤니티 섹션이
CreatorChannelCommunityListItem을 사용한다. - 홈 API의 커뮤니티 아이템이
isCommentAvailable·isPinned을 정상 디코딩하고 목록 표시에 반영한다. - 홈 아이템 우측 상단에 더보기가 노출되고 확정된 권한 메뉴로 연결된다.
- 홈 리스트형과 커뮤니티 탭의 리스트형·썸네일형 아이템 본체를 터치하면 선택한 게시글 상세로 이동한다.
- 홈·리스트형·썸네일형 목록에서 구매 다이얼로그가 열리지 않고, 상세 잠금 영역에서 구매 다이얼로그·API가 동작한다.
- 홈·리스트형·썸네일형·상세의 유료 미구매 영역이 모두
Color.gray800을 사용한다. - 더보기·좋아요 터치가 상세 이동을 중복 발생시키지 않는다.
- 홈·커뮤니티 리스트와 상세의 유료 미구매 상태에서 하트·댓글용 빈 공간이 남지 않는다.
SodaLive-dev스킴 Debug 빌드가 성공한다.- 시뮬레이터에서 홈·커뮤니티 탭·상세의 아이템 터치, 더보기, 유료 잠금 색상을 확인한다.
11. Open Questions
| ID | 상태 | 결정 필요 사항 | 현재 권고 | 결정 주체 | 결정 시점 | 영향 요구사항 |
|---|---|---|---|---|---|---|
OQ-001 |
확정 | 홈 아이템 더보기가 커뮤니티 탭과 동일하게 본인에게 고정·수정·삭제, 타인에게 신고를 제공한다. | A안 확정 | 사용자 | 2026-08-10 | CCCI-002, CCCI-006 |
OQ-002 |
확정 | 목록 구매 제거를 홈과 커뮤니티 탭 모두에 적용한다. | A안 확정 | 사용자 | 2026-08-10 | CCCI-004, CCCI-007 |
OQ-003 |
확정 | 백엔드 홈 API 응답에 isCommentAvailable·isPinned을 커뮤니티 탭과 동일하게 추가한다. |
A안 확정 | 사용자·API 담당 | iOS 통합 검증 전 | CCCI-001, CCCI-008, EXT-001 |
OQ-004 |
확정 | 홈 API의 날짜 키 dateUtc를 유지하고 iOS 로컬 변환에서 같은 UTC 문자열을 커뮤니티 탭 모델의 createdAtUtc로 연결한다. |
A안 확정·날짜 값 파싱·시간대·포맷 변환 없음 | 사용자 | 2026-08-10 | DEC-008 |
12. 외부 제공 대기 계약
| ID | 우선순위 | 제공 필요 계약 | 담당 주체 | 구현 영향 | 재개 조건 |
|---|---|---|---|---|---|
EXT-001 |
P0 | GET /api/v2/creator-channels/{creatorId}/home 응답의 communities·notices 아이템에 non-optional isCommentAvailable: Bool·isPinned: Bool 추가 |
백엔드 | 홈 아이템의 고정 표시·댓글 노출·고정/해제 메뉴 정확성 | 개발 서버 응답과 계약에 두 필드 반영 |
13. 요구사항 추적표
| 요구사항 범위 | API Contract | 계획 Phase | 자동 검증 | 수동 검증 |
|---|---|---|---|---|
CCCI-001~003, CCCI-006 |
홈 API 필드 확장·기존 목록·상세 API 재사용 | P2-T1, P2-T2 |
focused 구조 검증·Debug build | 홈/커뮤니티 탭 액션 확인 |
CCCI-004, CCCI-005, CCCI-007 |
기존 목록·상세·구매 API 재사용 | P1-T2, P1-T3 |
목록 구매 제거·상세 구매 연결·Color.gray800 참조 검증·Debug build |
목록/상세 잠금 영역·상세 진입·구매 확인 |
CCCI-008 |
홈 API 필드 확장 | P1-T1, P3-GATE, EXT-001 |
decoding contract·Debug build | 백엔드 반영 후 홈 응답 확인 |
CCCI-009 |
기존 목록·상세 모델 재사용 | P2-R1 |
reaction bar 조건부 삽입 contract check·Debug build | 홈·커뮤니티 리스트·상세 유료 잠금 여백 확인 |
14. Decision Log
| 날짜 | ID | 상태 | 결정 | 근거 | 영향 요구사항 |
|---|---|---|---|---|---|
| 2026-08-10 | DEC-001 |
확정 | 홈 커뮤니티 요약 아이템은 CreatorChannelCommunityListItem을 사용한다. |
사용자 요청: 홈·커뮤니티 탭 외형 통일 | CCCI-001 |
| 2026-08-10 | DEC-002 |
확정 | 커뮤니티 아이템 우측 상단에 더보기를 제공한다. | 사용자 요청 | CCCI-002 |
| 2026-08-10 | DEC-003 |
확정 | 아이템 본체는 상세로 이동하고 구매는 상세에서 처리한다. | 사용자 요청 | CCCI-003, CCCI-004 |
| 2026-08-10 | DEC-004 |
확정 | 목록의 유료 미구매 영역은 상세와 동일한 Color.gray800을 사용한다. |
현재 커뮤니티 탭 Color.gray400, 상세 Color.gray800 차이 확인 |
CCCI-005 |
| 2026-08-10 | DEC-005 |
확정 | 홈 더보기는 커뮤니티 탭과 동일하게 본인 게시글에 고정·수정·삭제, 타인 게시글에 신고를 제공한다. | 사용자 인터뷰 A안 선택 | CCCI-002, CCCI-006, OQ-001 |
| 2026-08-10 | DEC-006 |
확정 | 백엔드 홈 API 응답에 isCommentAvailable·isPinned을 커뮤니티 탭과 동일하게 제공한다. |
사용자 인터뷰 A안 선택·백엔드 동시 반영 예정 | CCCI-008, OQ-003, EXT-001 |
| 2026-08-10 | DEC-007 |
확정 | 홈과 커뮤니티 탭 모두 목록 구매를 제거하고 아이템 본체 터치를 상세 이동으로 통일한다. | 사용자 인터뷰 A안 선택 | CCCI-004, CCCI-007, OQ-002 |
| 2026-08-10 | DEC-008 |
확정 | 홈 API 모델을 커뮤니티 탭 아이템으로 로컬 변환하고 기존 CreatorChannelCommunityListItem·메뉴 상태·상세 route를 재사용한다. |
사용자가 접근법 1 선택·신규 공용 모델 없는 최소 변경 | CCCI-001~008 |
| 2026-08-10 | DEC-009 |
확정 | 홈에서 CreatorChannelCommunityListItem·기존 메뉴 상태·상세 route를 재사용하고, 목록 구매 제거·Color.gray800 통일·변경 성공 후 홈·커뮤니티 목록 갱신 설계를 확정한다. |
사용자 설계 승인·날짜 필드 연결 설명만 추가 확인 | CCCI-001~007 |
| 2026-08-10 | DEC-010 |
확정 | 홈 API의 dateUtc는 유지하고 iOS에서 값 변환 없이 CreatorChannelCommunityPostItem.createdAtUtc로 연결한다. |
사용자 A안 선택·기존 홈 API 계약 영향 최소화 | DEC-008, OQ-004 |
| 2026-08-10 | DEC-011 |
확정 | 승인된 컴포넌트·데이터 흐름과 최종 동작·오류·검증 설계를 구현 기준으로 사용한다. | 사용자 최종 설계 승인 | CCCI-001~008, EXT-001 |
| 2026-08-10 | DEC-012 |
확정 | 목록에 있던 기존 구매 다이얼로그·API 호출 소유권을 상세 화면으로 옮긴다. | 구현 전 기준선에서 상세 잠금 버튼이 구매가 아닌 showPurchaseError()만 호출함을 확인·사용자 직접 요구 충족 |
CCCI-004, CCCI-007 |
| 2026-08-10 | DEC-013 |
확정 | 하트·댓글이 모두 숨겨지는 유료 잠금 상태에서는 고정 높이를 보정하지 않고 reaction bar 전체를 조건부로 삽입하지 않는다. | 목록·상세의 공통 원인은 빈 HStack의 .frame(height: 24) 유지이며, 상위 조건부 삽입이 가장 작은 근본 수정이다. |
CCCI-009, P2-R1 |
15. 구현 설계
15.1 데이터 연결
- 홈 API 모델
CreatorChannelCommunityPostResponse에 non-optionalisCommentAvailable: Bool·isPinned: Bool을 추가한다. - 백엔드는 같은 응답 모델을 사용하는
notices·communities모두에 두 필드를 제공한다. CreatorChannelCommunitySection의 private 로컬 변환에서 홈 게시글을CreatorChannelCommunityPostItem으로 연결한다. 신규 공용 protocol·factory·표시 모델은 만들지 않는다.- 날짜는
createdAtUtc: homePost.dateUtc로 같은 UTC 문자열을 대입한다. 파싱, 시간대, 포맷을 변경하지 않는다.
15.2 컴포넌트와 터치
CreatorChannelCommunitySection은 기존처럼 최대 3개와전체보기를 유지하되 각 아이템을CreatorChannelCommunityListItem으로 렌더링한다.- 홈은
CreatorChannelView의isOwnCreatorChannel과 기존 사용자 id 비교 결과를 아이템에 전달한다. CreatorChannelCommunityListItem과CreatorChannelCommunityGridItem에서onTapPurchase를 제거한다. 유료 미구매 영역은Button이 아닌 표시 View로 렌더링해 아이템의onTapDetail을 사용한다.- 리스트형·썸네일형 유료 미구매 영역 배경은 상세와 동일한
Color.gray800을 사용한다. 기존 잠금 icon·가격 capsule·크기는 유지한다. - 상세 진입 helper는 표시 모델 전체 대신
postId만 받아 홈·리스트형·썸네일형이 같은 route를 사용한다. - 더보기·좋아요
Button은 각자의 action만 실행하고 부모 아이템의 상세 진입을 중복 실행하지 않아야 한다. CreatorChannelCommunityListItem과CreatorChannelCommunityPostDetailContentView는isPaidLocked가true이면reactionBar자체를 View 계층에 삽입하지 않는다. 댓글만 비활성이고 좋아요가 표시되는 상태는 기존 reaction bar를 유지한다.
15.3 더보기와 변경 후 갱신
- 홈 아이템 더보기는 로컬 변환한
CreatorChannelCommunityPostItem을CreatorChannelCommunityViewModel.openReportMenu(post:)에 전달한다. CreatorChannelView.communityOverlay노출 범위를 홈과 커뮤니티 탭으로 확장해 기존 고정·수정·삭제·신고 UI를 재사용한다.- 고정·수정·삭제 성공 후
CreatorChannelViewModel.fetchHome(creatorId:)와CreatorChannelCommunityViewModel.fetchFirstPage(creatorId:)를 모두 호출해 두 표시 위치를 동기화한다. - 목록 구매 호출처를 제거한 후
CreatorChannelCommunityViewModel의 목록 구매 상태·메서드와CreatorChannelView.communityOverlay의 구매 dialog 분기를 이번 변경이 만든 orphan으로서 제거한다. CreatorChannelCommunityPostDetailView의 잠금 영역은 기존CommunityPostPurchaseDialog를 표시하고,CreatorChannelCommunityPostDetailViewModel이 기존CreatorCommunityRepository.purchaseCommunityPost(postId:)를 호출한다.- 상세 구매 성공 후 상세를 다시 조회하고
onCommunityRefresh를 호출해 홈·커뮤니티 목록도 갱신한다. endpoint와 dialog 내부 UI는 변경하지 않는다.
15.4 오류와 외부 의존
- 고정·수정·삭제·신고 실패는 기존
CreatorChannelCommunityViewModel과CreatorChannelViewModel의 toast 흐름을 유지한다. isCommentAvailable·isPinned이 없는 홈 응답을 기본값으로 보정하지 않는다.EXT-001미반영 환경의 디코딩 실패는 기존 홈 API 실패 상태로 처리한다.- iOS 구현·빌드는 백엔드 반영과 독립적으로 진행할 수 있지만, 통합·시뮬레이터 완료는
EXT-001반영 후에만 판정한다.
15.5 검증 설계
- 현재 앱 타겟에 실행 가능한 단일 test bundle이 없으므로 이 변경만을 위한 신규 test 타겟이나 dependency를 추가하지 않는다.
- 대체 검증으로 홈 섹션·리스트형·썸네일형 Preview에서 유료 미구매·고정·댓글 비활성 상태를 구성한다.
- 정적 검증은
rg로 목록onTapPurchase·목록 구매 dialog 호출처 제거, 상세 구매 dialog·API 연결,Color.gray800, 홈·목록·썸네일 상세 route 연결을 확인하고git diff --check를 실행한다. - reaction bar 회귀 검증은 두 대상 View의 body에 무조건 삽입된
reactionBar가 없고if !isPaidLocked내부에만 삽입되는지 focusedrg로 확인한다. - 자동 검증은
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build로 컴파일·링크 성공을 확인한다. EXT-001반영 후 시뮬레이터에서 홈·리스트형·썸네일형의 상세 진입, 더보기 권한 메뉴, 목록 구매 dialog 미노출, 상세 구매,Color.gray800을 수동 확인한다.
16. 검증 기록
- 2026-08-10:
CreatorChannelCommunitySection이CommunityPostCard를 사용하고CreatorChannelCommunityListItem은 커뮤니티 탭의 별도 응답 모델을 사용함을 확인했다. - 2026-08-10: 홈 응답에는
isCommentAvailable·isPinned이 없고, 커뮤니티 탭 응답에는 두 필드가 있음을 확인했다. - 2026-08-10:
CreatorChannelCommunityListItem.paidLockedImage은Color.gray400,CreatorChannelCommunityPostDetailContentView.mediaContent의 유료 미구매 영역은Color.gray800을 사용함을 확인했다. - 2026-08-10: 기존 문서
docs/20260701_크리에이터_채널_홈,docs/20260705_크리에이터_채널_커뮤니티_탭,docs/20260707_커뮤니티_게시글_상세를 확인했고 이번 교차 변경은 신규 문서 하나에서 추적한다. - 2026-08-10: 사용자 인터뷰로 홈 더보기의 동일 권한 메뉴, 백엔드 홈 응답의
isCommentAvailable·isPinned추가, 홈·커뮤니티 탭 모두의 목록 구매 제거를 확정했다. - 2026-08-10: 구현 전 기준 빌드는 성공했고, 상세 잠금 영역이 실제 구매 대신
showPurchaseError()를 호출하는 계획 누락을 발견해DEC-012와 상세 구매 이동 Task를 추가했다. - 2026-08-10: 홈 응답 필드·로컬 변환·기존 리스트 아이템·상세/더보기 route·목록 동기화와 상세 구매 이동을 구현했다.
- 2026-08-10: 목록 구매 심볼·잠금
Color.gray400·showPurchaseError제거와 상세 구매 dialog/API 연결을rg로 확인했고git diff --check가 통과했다. - 2026-08-10: iPhone 17 Pro iOS 26.0 대상
SodaLive-devDebug build가 exit code 0으로 성공했다. - 2026-08-10: 사용 가능한 Simulator가 모두
Shutdown이고EXT-001반영 여부를 확인할 수 없어 실제 터치·메뉴·구매 통합 검증은 대기한다. - 2026-08-10: 사용자 제보를 따라 목록·상세를 추적한 결과, 유료 잠금 상태에서도 빈
reactionBar의.frame(height: 24)가 유지되는 공통 원인을 확인하고CCCI-009,DEC-013,P2-R1로 회귀 수정 범위를 확정했다. - 2026-08-10: 두 body의 무조건
reactionBar삽입을if !isPaidLocked조건부 삽입으로 변경했다. focusedrg에서 무조건 삽입 0건·조건부 삽입 2건,git diff --check오류 0건, 동일 iPhone 17 Pro 대상SodaLive-devDebug build exit code 0을 확인했다.