104 KiB
커뮤니티 게시물 상세 / 댓글 / 답글 구현 계획/TASK
For agentic workers: 각 단계는 체크박스(
- [ ])로 추적하고, 완료 즉시- [x]로 갱신한다. 구현 범위 변경이 생기면 이 문서를 먼저 수정한 뒤 코드에 반영한다.
Goal: 크리에이터 채널 커뮤니티 탭에서 게시글 item 터치 시 게시물 상세로 진입해 본문/좋아요/댓글을 조회·작성하고, 댓글의 답글 목록 화면(팬Talk 상세와 동일 UI)에서 답글을 조회·작성하며, 수정/삭제/좋아요는 기존 API를 재사용한다.
Architecture: 조회(상세/댓글/답글)는 신규 v2 endpoint를 v2 API/Repository로 호출한다. 쓰기/수정/삭제/좋아요는 기존 CreatorCommunityRepository를 그대로 호출한다. 화면은 커뮤니티 전용으로 신규 구현하되, 답글 목록 화면의 layout XML과 댓글/답글 item view만 재사용 가능하게 설계한다.
Tech Stack: Kotlin, Android XML Views, ViewBinding, RxJava3, Koin, JUnit4/Robolectric.
전제와 성공 기준
- PRD:
docs/20260708_커뮤니티_게시물_상세_댓글_답글/prd.md - 기존 커뮤니티 탭 문서:
docs/20260621_크리에이터_채널_커뮤니티_탭/prd.mddocs/20260621_크리에이터_채널_커뮤니티_탭/plan-task.md
- 재사용 vs 복사 결정: 커뮤니티 전용 신규 구현. layout XML + 댓글/답글 item view만 데이터/콜백 주입형으로 공용화(데이터 계층은 커뮤니티 전용). 근거는 PRD
11. Open Questions & Decisions참고. - 조회 API는 신규 v2 endpoint를 사용하고 기본값
page=0,size=20을 따른다. - 쓰기/수정/삭제/좋아요/팝업 메뉴는 기존 커뮤니티 코드를 재사용한다.
- 구현 완료 판단 시 Gradle 검증뿐 아니라 Figma 4개 화면의 주요 layout, 하트/전송 버튼 상태, 댓글 불가 처리, 입력 영역 동작이 실제 구현 화면에 반영되었는지 확인한다.
- Figma 대조 결과는 문서 최하단
Verification Log에 한국어로 누적 기록한다. - 구현 완료 후 최소 다음 명령을 실행한다.
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"./gradlew :app:mergeDebugResources./gradlew :app:compileDebugKotlin./gradlew :app:ktlintCheckgit diff --check
Figma 참조
- 게시글 상세(댓글 가능 + 댓글 있음):
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-9243&m=dev - 게시글 상세(댓글 불가능):
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-9266&m=dev - 댓글 답글 목록(답글 없음):
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=669-40462&m=dev - 댓글 답글 목록(답글 있음):
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=669-40468&m=dev
API 계약
- 조회(신규 v2,
ApiResponse<T>):- 상세:
GET /api/v2/creator-channels/community-posts/{postId}→CreatorChannelCommunityPostDetailResponse- 필드:
postId,creatorId,creatorNickname,creatorProfileUrl,createdAtUtc,content,imageUrl,audioUrl,price,isCommentAvailable,existOrdered,likeCount,commentCount,isPinned,isLiked,comments comments는 댓글 첫 페이지(CreatorChannelCommunityCommentsResponse)를 포함한다.
- 필드:
- 댓글:
GET /api/v2/creator-channels/community-posts/{postId}/comments?page=0&size=20→CreatorChannelCommunityCommentsResponse- 필드:
commentCount,comments,page,size,hasNext - 댓글 필드:
commentId,writerId,writerProfileImageUrl,writerNickname,content,isSecret,createdAtUtc,latestReply - 최신 답글 필드:
commentId,writerId,writerProfileImageUrl,writerNickname,content,createdAtUtc
- 필드:
- 답글:
GET /api/v2/creator-channels/community-comments/{commentId}/replies?page=0&size=20→CreatorChannelCommunityRepliesResponse
- 상세:
- 쓰기/수정/삭제/좋아요(기존
CreatorCommunityRepository재사용):- 좋아요:
communityPostLike(postId, token) - 댓글 쓰기:
registerComment(postId, comment, token = token) - 답글 쓰기:
registerComment(postId, comment, parentId = commentId, token = token) - 댓글/답글 수정:
modifyComment(ModifyCommentRequest(commentId, comment = ...), token) - 댓글/답글 삭제:
modifyComment(ModifyCommentRequest(commentId, isActive = false), token)
- 좋아요:
- 팝업 메뉴:
R.menu.content_comment_option_menu(내 댓글/답글: 수정/삭제),R.menu.content_comment_option_menu2(채널 크리에이터가 보는 타인 댓글/답글: 삭제). 일반 타인 댓글/답글은 커뮤니티 댓글 전용 신고 API가 없어 더보기 버튼을 노출하지 않는다.
파일 구조 (예정)
- 생성(응답 모델):
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/detail/data/CreatorChannelCommunityDetailResponse.kt- PRD의
CreatorChannelCommunityPostDetailResponse,CreatorChannelCommunityCommentsResponse,CreatorChannelCommunityCommentResponse,CreatorChannelCommunityReplyResponse,CreatorChannelCommunityRepliesResponse.
- PRD의
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelApi.kt- 상세/댓글/답글 조회 endpoint 3개 추가.
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelRepository.kt- 상세/댓글/답글 조회 method 추가.
- 생성(진입점): 커뮤니티 탭 item 터치 → 상세 화면 이동.
- 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityFragment.kt(item click을 Host callback으로 위임). - 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/ui/CreatorChannelCommunityListAdapter.kt,CreatorChannelCommunityGridAdapter.kt(item click 콜백 추가). - 수정:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt(상세 화면 실행).
- 수정:
- 생성(상세 화면):
.../community/detail/CreatorChannelCommunityDetailActivity.kt,CreatorChannelCommunityDetailViewModel.kt - 생성(답글 화면):
.../community/detail/reply/CreatorChannelCommunityReplyActivity.kt,CreatorChannelCommunityReplyViewModel.kt - 생성(layout):
activity_creator_channel_community_detail.xml,activity_creator_channel_community_reply.xml, 댓글/답글 item layout, 입력 영역 layout, 전송 버튼 배경 drawable(enabled/disabled). - 생성(어댑터/item view): 댓글 목록 adapter, 답글 목록 adapter(재사용 가능한 댓글/답글 item view).
- 수정:
app/src/main/AndroidManifest.xml(신규 Activity 등록),app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt(신규 ViewModel binding). - 수정:
values,values-en,values-jastrings(placeholder 등 신규 문자열 또는 기존 재사용). - 테스트 생성: 상세/답글 ViewModel 테스트, layout/source 테스트.
Phase 1: 조회 API/모델 계약
-
Task 1.1: 응답 데이터 클래스 생성
- 생성:
.../community/detail/data/CreatorChannelCommunityDetailResponse.kt - 작업: PRD 명시 5개 data class를
@Keep/@SerializedName포함해 정의한다. - 검증:
./gradlew :app:compileDebugKotlin - 검증 기록(2026-07-08): TDD RED로
CreatorChannelCommunityDetailContractTest추가 후 DTO 패키지/클래스 미존재로:app:compileDebugUnitTestKotlin실패를 확인했다. 이후CreatorChannelCommunityPostDetailResponse,CreatorChannelCommunityCommentsResponse,CreatorChannelCommunityCommentResponse,CreatorChannelCommunityReplyResponse,CreatorChannelCommunityRepliesResponse를 생성하고./gradlew :app:compileDebugKotlin성공을 확인했다.
- 생성:
-
Task 1.2: v2 API/Repository 조회 method 추가
- 수정:
CreatorChannelApi.kt,CreatorChannelRepository.kt - 작업: 상세/댓글/답글 조회 3개 추가(기본
page=0,size=20, token 포함). - 검증:
./gradlew :app:compileDebugKotlin - 검증 기록(2026-07-08): 구현 전
CreatorChannelApi/CreatorChannelRepository의 상세/댓글/답글 method 미존재로 RED 실패를 확인했다. 구현 후./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"및./gradlew :app:compileDebugKotlin성공을 확인했다.
- 수정:
Phase 2: 상세 ViewModel/화면
-
Task 2.1: 상세 ViewModel RED 테스트 작성
- 생성:
CreatorChannelCommunityDetailViewModelTest.kt - 케이스: 상세 로드, 좋아요 토글(낙관적 업데이트+실패 롤백, 중복 방지), 댓글 pagination(hasNext), 댓글 쓰기 성공 후 새로고침, 댓글 불가 시 댓글 조회/입력 미노출.
- 검증: 해당 테스트 실행(구현 전 실패).
- 검증 기록(2026-07-08):
CreatorChannelCommunityDetailViewModelTest를 먼저 추가하고./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.CreatorChannelCommunityDetailViewModelTest"를 실행해CreatorChannelCommunityDetailViewModel/CreatorChannelCommunityDetailUiState미존재 컴파일 오류로 RED 실패를 확인했다.
- 생성:
-
Task 2.2: 상세 ViewModel 구현
- 생성:
CreatorChannelCommunityDetailViewModel.kt - 검증:
CreatorChannelCommunityDetailViewModelTestPASS. - 검증 기록(2026-07-08):
CreatorChannelCommunityDetailViewModel과 상세/댓글/답글 UI state model을 추가하고 동일한 테스트 명령을 재실행해 PASS를 확인했다. 상세 조회, 댓글 첫 페이지/페이지네이션, 좋아요 낙관적 토글/중복 방지/실패 롤백, 댓글 trim 작성/성공 이벤트/댓글 새로고침, 댓글 불가 시 댓글 API/작성 미호출을 검증했다.
- 생성:
-
Task 2.3: 상세 layout/Activity 구현
- 생성:
activity_creator_channel_community_detail.xml,CreatorChannelCommunityDetailActivity.kt, 댓글 adapter/item, 입력 영역, 전송 버튼 drawable. - 작업: Figma
290:9243(댓글 가능)/290:9266(댓글 불가) 기준. 하트 fill/empty, 전송 버튼 gray_900/soda_400 상태, 3줄 자동확장/4줄 스크롤, 댓글 불가 시 댓글/입력 영역 숨김, 최신 답글 1개 중첩 표시, 더보기 팝업 메뉴 재사용. - 수정:
AndroidManifest.xml,AppDI.kt. - 검증:
./gradlew :app:mergeDebugResources,./gradlew :app:compileDebugKotlin - 검증 기록(2026-07-08):
CreatorChannelCommunityDetailReplyUiContractTest를 먼저 추가하고./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"를 실행해 상세/답글 layout·id·source 미존재 컴파일 오류로 RED 실패를 확인했다. 이후activity_creator_channel_community_detail.xml,CreatorChannelCommunityDetailActivity, 댓글 adapter/item, 입력 bar 배경/전송 icon drawable, 문자열, manifest/AppDI 등록을 추가했다. 상세 화면은newIntent(context, postId)로 진입하고postId <= 0은 toast 후 종료하며, 하트 토글/댓글 입력 trim 활성화/댓글 불가 시 댓글 목록과 하단 입력 숨김/최신 답글 card 클릭 답글 화면 진입/팝업 메뉴 재사용 계약을 반영했다.
- 생성:
Phase 3: 답글 화면
-
Task 3.1: 답글 ViewModel RED 테스트/구현
- 생성:
CreatorChannelCommunityReplyViewModel(.kt/Test.kt) - 케이스: 부모 댓글/답글 로드, 답글 pagination, 답글 쓰기(
parentId = commentId) 후 새로고침, 수정/삭제 후 새로고침. - 검증: 테스트 PASS.
- 검증 기록(2026-07-08):
CreatorChannelCommunityReplyViewModelTest를 먼저 추가하고./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.CreatorChannelCommunityReplyViewModelTest"를 실행해CreatorChannelCommunityReplyViewModel/CreatorChannelCommunityReplyUiState미존재 컴파일 오류로 RED 실패를 확인했다. 이후CreatorChannelCommunityReplyViewModel을 추가하고 동일 명령을 재실행해 PASS를 확인했다. 부모 댓글 보존/답글 첫 페이지 조회,hasNext페이지네이션과 중복loadMore방지, 답글 trim 작성/blank 무시/중복 전송 방지/성공 후 입력·이벤트 정리 및 새로고침, 수정·삭제 후 새로고침,commentId <= 0일 때 답글 API 미호출을 검증했다.
- 생성:
-
Task 3.2: 답글 layout/Activity 구현
- 생성:
activity_creator_channel_community_reply.xml,CreatorChannelCommunityReplyActivity.kt, 재사용 가능한 댓글/답글 item view/adapter. - 작업: Figma
669:40462(답글 없음)/669:40468(답글 있음) 기준. 부모 댓글 상단 표시, 답글 들여쓰기, placeholder답글을 입력하세요, 더보기 팝업 메뉴 재사용. - 수정:
AndroidManifest.xml,AppDI.kt. - 검증:
./gradlew :app:mergeDebugResources,./gradlew :app:compileDebugKotlin - 검증 기록(2026-07-08): 상세 UI 계약 RED 테스트에 답글 layout/source 계약을 함께 추가해 실패를 확인한 뒤
activity_creator_channel_community_reply.xml,CreatorChannelCommunityReplyActivity, 답글 adapter/item을 생성했다. 답글 화면은 primitive extras로 부모 댓글을 재구성하고 상단 부모 댓글 표시, 들여쓰기 답글 card,답글을 입력하세요입력 bar, trim 기반 전송 버튼 상태,updateReplyInput/submitReply, 팝업 메뉴의modifyReply/deleteReply연결을 반영했다.
- 생성:
Phase 4: 진입점 연결
- Task 4.1: 커뮤니티 탭 item 터치 → 상세 진입
- 수정:
CreatorChannelCommunityListAdapter.kt,CreatorChannelCommunityGridAdapter.kt,CreatorChannelCommunityFragment.kt(Host callback 추가),CreatorChannelActivity.kt. - 작업: item 터치 시
postId로 상세 화면 실행. 댓글에서 답글 화면(commentId) 진입 연결. 좋아요/댓글/답글 작성 후 목록 새로고침 정책 연결. - 검증:
./gradlew :app:compileDebugKotlin - 검증 기록(2026-07-08):
CreatorChannelCommunityFragmentLayoutTest와CreatorChannelActivitySourceTest에 RED source 계약을 먼저 추가해 list/grid adapter root click callback, fragment Host 위임, Activity의 상세 화면newIntent진입 계약 실패를 확인했다. 이후 list/grid adapter에onPostClick을 추가하고 play/owner more click은 기존 콜백으로 분리 유지했으며, fragment는postId를 Host로 위임하고 Activity는postId <= 0L을 무시한 뒤CreatorChannelCommunityDetailActivity.newIntent(this, postId)로 상세 화면을 실행하도록 연결했다.
- 수정:
Phase 5: 테스트/회귀 검증
-
Task 5.1: source/layout 테스트 추가
- 작업: 조회 API page/size 기본값, 하트 icon 계약(
ic_feed_community_heart_fill/ic_feed_community_heart), 전송 버튼 상태(ic_new_arrow_up_gray+gray_900 /ic_new_arrow_up_white+soda_400), 댓글 불가 시 댓글/입력 숨김, placeholder 문구를 검증. - 검증:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*" - 검증 기록(2026-07-08): review-work 차단 이슈 회귀를 막기 위해 상세 댓글 수정/삭제 ViewModel 테스트와 상세/답글 source 계약 테스트를 먼저 추가했다. 구현 전 동일 targeted 테스트를 실행해
CreatorChannelCommunityDetailViewModel.modifyComment/deleteComment미구현 컴파일 오류로 RED 실패를 확인했다. 구현 후 동일 명령을 재실행해 PASS를 확인했고, 상세/답글 Activity의 하단 도달 pagination 호출, 내 댓글/답글에만 destructive popup 노출, 수정 입력 dialog, 삭제 확인 dialog, 상세 오디오 매니저 연결/lifecycle 정리, 상세 로드 Error finish 계약을 source 테스트로 검증했다.
- 작업: 조회 API page/size 기본값, 하트 icon 계약(
-
Task 5.2: 전체 검증 실행
- 실행: 위 성공 기준의 Gradle 명령 전체.
- Figma 수동 확인:
290:9243,290:9266,669:40462,669:40468대조. - 검증 기록:
Verification Log에 누적. - 검증 기록(2026-07-08): review-work 차단 이슈 수정 후
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest",./gradlew :app:mergeDebugResources,./gradlew :app:compileDebugKotlin이 PASS했다. 최초./gradlew :app:ktlintCheck는 신규 테스트 source 문자열 길이 초과로 실패했으며, 테스트 문자열 분리 후 재실행해 PASS했다.git diff --check는 출력 없이 PASS했다.
Phase 6: review 재반영 및 서버 계약 수정
-
Task 6.1: 서버 댓글 응답 계약 반영
- 작업: 상세 응답 내부
comments와 댓글/최신 답글의writer*/content필드명을 DTO와 UI mapping에 반영한다. - 검증:
CreatorChannelCommunityDetailContractTest, 상세/답글 ViewModel 테스트 PASS. - 검증 기록(2026-07-08):
CreatorChannelCommunityPostDetailResponse에comments를 추가하고,CreatorChannelCommunityCommentsResponse.commentCount, 댓글/답글의writerId,writerProfileImageUrl,writerNickname,content계약을 반영했다. 상세 최초 댓글 목록은 상세 응답의 embeddedcomments에서 사용하고, 답글 수정/삭제 ID는 응답의commentId를 답글 자체 ID로 매핑했다../gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"PASS로 확인했다.
- 작업: 상세 응답 내부
-
Task 6.2: 댓글/답글 refresh 중 stale pagination 응답 방지
- 작업: 상세 댓글과 답글 pagination 요청에 generation guard를 두고, 새로고침 시 이전 요청이 현재 state를 덮지 않게 한다.
- 검증: stale 응답 회귀 테스트 PASS.
- 검증 기록(2026-07-08): 상세 댓글과 답글 ViewModel에 request generation guard를 추가해 새 상세/답글 로드 후 이전 page 응답이 도착해도 현재 목록을 덮지 않도록 수정했다. stale 응답 회귀 테스트를 추가하고 community targeted test PASS를 확인했다.
-
Task 6.3: 수정 dialog blank 입력 안내 보강
- 작업: 댓글/답글/부모 댓글 수정에서 공백 입력 시 기존 커뮤니티 정책과 동일한 내용 입력 toast를 표시한다.
- 검증: source 또는 Activity 계약 테스트 PASS.
- 검증 기록(2026-07-08): 댓글/답글/부모 댓글 수정 요청이 공백이면
screen_creator_community_write_content_hinttoast 이벤트를 노출하고 legacy modify API를 호출하지 않도록 보강했다. ViewModel 회귀 테스트 PASS를 확인했다.
-
Task 6.4: 레이아웃 속성 직접 검증 테스트 축소
- 작업: UI layout 크기/padding/source 문자열 검증을 제거하고, 로직/상태/리소스 존재 계약 중심으로 테스트를 줄인다.
- 검증: targeted unit test PASS.
- 검증 기록(2026-07-08):
CreatorChannelCommunityDetailReplyUiContractTest에서 layout 높이/padding/drawable 문자열 및 Activity source 문자열 직접 검증을 제거하고, inflate 가능한 layout과 필수 view id/문자열/AppDI/manifest 등록 확인으로 축소했다. community targeted test PASS를 확인했다.
Phase 7: review 결과 반영
- Task 7.1: embedded 댓글의 채널 크리에이터 권한 매핑 수정
- 작업: 상세 응답의 embedded
comments를 최초 UI state로 매핑할 때Contentstate가 아직 없어isCreatorOwner가 false로 고정되는 문제를 수정한다. - 검증: 채널 크리에이터가 타인 댓글/최신 답글에 대해 삭제 메뉴 권한을 갖는 ViewModel 회귀 테스트 PASS.
- 검증 기록(2026-07-08):
CreatorChannelCommunityDetailViewModelTest에 채널 작성자가 상세 embedded 타인 댓글의 삭제 메뉴 권한을 갖는 회귀 테스트를 추가하고, 수정 전AssertionErrorRED 실패를 확인했다. 이후 embedded 댓글은 상세 응답의creatorId, 추가 페이지 댓글은 현재 post의creatorId기준으로isCreatorOwner를 명시 전달하도록 수정해 동일 테스트 PASS를 확인했다.
- 작업: 상세 응답의 embedded
Phase 8: 리뷰 결과 추가 반영
-
Task 8.1: 댓글 불가 화면/댓글·답글 item UI 정리
- 작업: 댓글 불가 화면에서는 댓글 목록/입력 영역만 숨기고 별도 안내 문구를 제거한다. 댓글/답글 item에서 Figma/PRD에 없는 reaction row를 제거한다.
- 검증: layout/source 계약 테스트 및 community targeted test PASS.
- 검증 기록(2026-07-08):
CreatorChannelCommunityDetailReplyUiContractTest에 댓글 불가 안내 view 제거, 댓글/답글 reaction id 제거 계약을 추가했다.item_creator_channel_community_comment.xml과item_creator_channel_community_reply.xml에서 Figma에 없는 reaction row를 제거하고 adapter binding 참조를 정리했다. 상세 댓글 불가 화면은 댓글 header/list/input bar만 숨기도록 유지했다../gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"PASS로 확인했다.
-
Task 8.2: 유료 미구매 paywall 표시 수정
- 작업: 유료 미구매 게시물은 raw media URL을 노출하지 않되 Figma 중앙 lock + 가격 paywall 영역은 표시한다.
- 검증: 상세 ViewModel/Activity/layout 계약 테스트 PASS.
- 검증 기록(2026-07-08):
CreatorChannelCommunityPostDetailUiModel.showPaywall을 추가하고 유료 미구매 타인 게시물에서imageUrl/audioUrl은 계속 제거하되showPaywall을 true로 노출하도록 수정했다. 상세 layout에는layout_creator_channel_community_detail_paywall과tv_creator_channel_community_detail_paywall_price를 추가해 이미지 컨테이너 중앙에 lock+가격 pill을 표시한다. 상세 ViewModel/UI 계약 테스트 PASS로 확인했다.
-
Task 8.3: 댓글/답글 상대시간 보정
- 작업: v2
createdAtUtc파싱을 ISO offset/초 단위 epoch까지 지원하고, 서버·단말 시계 차이로 작성 직후 과거 시간이 표시되지 않도록 최근 시간 보정 규칙을 추가한다. 답글 화면 부모 댓글도 원본createdAtUtc를 전달해 답글 목록과 같은 포맷터 기준으로 표시한다. - 검증: 상대시간 포맷터 회귀 테스트 및 상세/답글 ViewModel 테스트 PASS.
- 검증 기록(2026-07-08): 기존 공통 함수
formatUtcRelativeTimeText를 보강해 epoch millis 기존 동작을 유지하면서 epoch seconds, ISO offset, 6자리 fraction을 파싱하도록 수정했다. ISO 문자열은 서버/단말 시계 오차를 고려해 10분 이내를방금전으로 보정한다. 댓글/답글 UI model에 원본createdAtUtc를 보존하고 답글 화면Intent에 전달해 부모 댓글도 동일한UtcRelativeTimeTextFormatter로 재포맷하도록 수정했다.RelativeTimeFormatterTest, 상세/답글 ViewModel 테스트 PASS로 확인했다.
- 작업: v2
Phase 9: 댓글/답글 수정 UX 후속 반영
-
Task 9.1: 타이틀/메뉴/모달 계약 정리
- 수정:
activity_creator_channel_community_detail.xml,activity_creator_channel_community_reply.xml,content_comment_option_menu.xml,content_comment_option_menu2.xml, 상세/답글 Activity. - 작업: 상세/답글 titlebar의
커뮤니티,답글문구를 제거하고, 댓글/답글 더보기 메뉴 문구를수정하기,삭제하기로 바꾼다. v2 패키지 내부 삭제 확인은V2ModalDialog를 사용한다. - 검증: layout/source 계약 테스트,
./gradlew :app:compileDebugKotlin - 검증 기록(2026-07-09): 상세/답글 layout에서 title
TextView를 제거하고, 댓글 메뉴 리소스는creator_channel_fantalk_edit/creator_channel_fantalk_delete를 사용하도록 수정했다. 상세/답글 Activity의 삭제 확인은V2ModalDialog로 교체하고AlertDialog사용을 제거했다.CreatorChannelCommunityDetailReplyUiContractTest에 title id 제거, 메뉴 문구,V2ModalDialogsource 계약을 추가했으며 targeted community test와./gradlew :app:compileDebugKotlinPASS로 확인했다.
- 수정:
-
Task 9.2: 하단 입력창 기반 수정 모드 구현
- 수정:
CreatorChannelCommunityDetailViewModel.kt,CreatorChannelCommunityReplyViewModel.kt, 상세/답글 Activity/layout, 관련 테스트. - 작업: 수정 선택 시 별도 입력 Dialog 없이 하단 입력창에 기존 내용을 채우고 X 취소 버튼을 표시한다. 수정 모드의 send는 쓰기가 아니라 수정 API를 호출하며, 성공/취소 시 일반 입력 모드로 복귀한다.
- 검증: 상세/답글 ViewModel 회귀 테스트, layout/source 계약 테스트,
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*" - 검증 기록(2026-07-09): 상세 댓글은
editingCommentId/editingOriginalComment, 답글 화면은CreatorChannelCommunityReplyEditTarget으로 수정 모드를 상태화했다. 수정 선택 시 하단 입력창에 기존 내용을 세팅하고 X 버튼을 표시하며, 수정 모드의 send는 댓글/답글/부모 댓글 수정 API를 호출한다. 성공 또는 X 취소 시 입력과 수정 target을 초기화한다. 변경 없음과 공백 입력은 기존 toast 정책을 유지했다. ViewModel 회귀 테스트와 layout/source 계약 테스트를 추가했고 targeted community test PASS로 확인했다.
- 수정:
-
Task 9.3: 후속 검증
- 실행:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck,git diff --check. - 검증 기록:
Verification Log에 누적한다. - 검증 기록(2026-07-09):
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck,git diff --check실행 결과 모두 통과했다.ktlintCheck의.editorconfig disabled_rulesdeprecation 경고는 기존 설정 경고로 남아 있다.
- 실행:
Phase 10: 댓글/답글 더보기 메뉴 폰트 후속 반영
- Task 10.1: 더보기 메뉴 regular font 적용
- 수정/생성:
CreatorChannelCommunityMorePopup.kt,view_creator_channel_community_more_popup.xml, 댓글/답글 adapter, UI 계약 테스트. - 작업: 기본
PopupMenu대신PopupWindow기반 커스텀 메뉴를 사용하고, 메뉴 TextView에android:fontFamily="@font/regular"를 명시한다. - 검증:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck,git diff --check. - 검증 기록(2026-07-09): 댓글/답글 더보기 메뉴를
PopupMenu에서CreatorChannelCommunityMorePopup으로 교체했다. 새view_creator_channel_community_more_popup.xml의수정하기,삭제하기TextView에@font/regular를 명시했고, 내 댓글/답글은 수정+삭제, 채널 작성자가 보는 타인 댓글/답글은 삭제만 노출하는 기존 권한 규칙을 유지했다. UI 계약 테스트에 popup layout font와 adapter source 계약을 추가했다../gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck,git diff --check가 모두 통과했다.
- 수정/생성:
Phase 11: 댓글/답글 입력창 키보드 후속 반영
- Task 11.1: 수정 진입/성공 시 키보드 제어
- 수정:
CreatorChannelCommunityDetailActivity.kt,CreatorChannelCommunityReplyActivity.kt, UI 계약 테스트. - 작업:
수정하기터치 후 하단 입력창 수정 모드로 전환될 때 입력창에 focus를 주고 키보드를 즉시 올린다. 댓글/답글 작성 또는 수정 API 성공 이벤트 수신 시 키보드를 내리고 focus를 해제한다. - 검증:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck,git diff --check. - 검증 기록(2026-07-09): 상세/답글 Activity에
showSoftInput/hideSoftInputFromWindow기반 키보드 제어를 추가했다. 수정 target이 새로 설정되면 입력창 focus 후 키보드를 올리고, 댓글 작성/수정 및 답글 작성/수정/부모 댓글 수정 성공 이벤트에서 키보드를 내리도록 연결했다. UI 계약 테스트에 IME 제어 source 계약을 추가했다../gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck,git diff --check가 모두 통과했다.
- 수정:
Phase 12: 커뮤니티 상세 UI border 후속 반영
- Task 12.1: 상세 상단 게시글 배경과 댓글 경계선 수정
- 수정:
app/src/main/res/layout/activity_creator_channel_community_detail.xml,app/src/main/res/layout/item_creator_channel_community_comment.xml,CreatorChannelCommunityCommentAdapter.kt - 작업: 상세 게시글 컨테이너의
bg_feed_cardrounded 배경을 제거하고, 게시글과 댓글 헤더 사이 1dp border를 추가한다. 댓글 item 사이에는 1dp border를 표시하되 마지막 댓글 하단 border는 숨긴다. - 검증:
./gradlew :app:mergeDebugResources,./gradlew :app:compileDebugKotlin,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.CreatorChannelCommunityDetailReplyUiContractTest",./gradlew :app:ktlintCheck,git diff --check - 검증 기록(2026-07-12): 상세 게시글 컨테이너의
bg_feed_card배경을 제거해 목록형 rounded card 배경이 상세 상단 본문에는 적용되지 않도록 했다. 게시글과 댓글 헤더 사이에는gray_8001dp divider를 추가하고 댓글 가능 상태에서만 노출되도록 Activity binding을 연결했다. 댓글 item 하단 divider에는 id를 부여하고 adapter에서 마지막 댓글의 divider를 숨겨 댓글 사이 border로만 보이게 했다../gradlew :app:mergeDebugResources,./gradlew :app:compileDebugKotlin,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.CreatorChannelCommunityDetailReplyUiContractTest",./gradlew :app:ktlintCheck,git diff --check가 모두 통과했다.ktlintCheck의.editorconfig disabled_rulesdeprecation 경고는 기존 설정 경고로 남아 있다.
- 수정:
Phase 13: 커뮤니티 상세 오디오/구매 후속 반영
-
Task 13.1: 상세 오디오 중앙 버튼과 구매 회귀 테스트 추가
- 수정:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityDetailViewModelTest.kt,CreatorChannelCommunityDetailReplyUiContractTest.kt - 작업: 상세 layout에 이미지 중앙 play/pause 버튼이 있고, Activity가
PurchaseCommunityPostDialog와purchaseCommunityPost를 연결하며, ViewModel이 구매 성공 후 상세를 재조회하는 계약을 RED로 고정한다. - 검증:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.CreatorChannelCommunityDetailViewModelTest",./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.CreatorChannelCommunityDetailReplyUiContractTest" - 검증 기록(2026-07-12): 상세 layout의 중앙 오디오 버튼 id, legacy 구매 dialog 연결, ViewModel 구매 성공 후 상세 재조회 계약을 테스트에 추가했다. 최초 병렬 Gradle 실행은 120초/300초 timeout 및 병렬 resource packaging 충돌성
NoSuchFileException으로 완료 결과를 얻지 못했으나, 구현 후 순차 재실행에서 동일 테스트들이 PASS했다.
- 수정:
-
Task 13.2: 상세 오디오 중앙 버튼과 구매 흐름 구현
- 수정:
app/src/main/res/layout/activity_creator_channel_community_detail.xml,CreatorChannelCommunityDetailActivity.kt,CreatorChannelCommunityDetailViewModel.kt - 작업:
item_creator_community_all.xml의iv_play_or_pause처럼 상세 이미지 중앙 버튼을 추가하고, 재생 상태에 따라 play/pause drawable을 갱신한다. 상세 paywall 가격 클릭 시 기존 구매 dialog를 띄우고 구매 성공 후 상세를 다시 로드한다. - 검증: targeted test PASS,
./gradlew :app:mergeDebugResources,./gradlew :app:compileDebugKotlin - 검증 기록(2026-07-12):
activity_creator_channel_community_detail.xml의 이미지 컨테이너 중앙에iv_creator_channel_community_detail_play_or_pause를 추가하고btn_audio_content_play/btn_audio_content_pause를 사용하도록 연결했다.CreatorChannelCommunityDetailActivity는 이미지+오디오 게시물에서 중앙 버튼을 표시하고, 이미지 없는 오디오 게시물은 기존 텍스트 오디오 버튼을 유지한다. paywall 영역 클릭 시 기존PurchaseCommunityPostDialog를 띄우고 확인 시CreatorChannelCommunityDetailViewModel.purchaseCommunityPost()를 호출한다. ViewModel은 기존CreatorCommunityRepository.purchaseCommunityPost를 호출한 뒤 성공 시 상세를 다시 로드한다../gradlew :app:mergeDebugResources,./gradlew :app:compileDebugKotlinPASS로 확인했다.
- 수정:
-
Task 13.3: 후속 검증
- 실행:
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck,git diff --check - 검증 기록:
Verification Log에 누적한다. - 검증 기록(2026-07-12):
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.CreatorChannelCommunityDetailViewModelTest",./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.CreatorChannelCommunityDetailReplyUiContractTest",./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:mergeDebugResources,./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck,git diff --check가 모두 통과했다.ktlintCheck의.editorconfig disabled_rulesdeprecation 경고와 Gradle deprecated feature 경고는 기존 설정 경고로 남아 있다.
- 실행:
Phase 14: 유료 미구매 상세 반응/댓글 숨김 후속
- Task 14.1: 상세 유료 미구매 게시글 reaction/comment 숨김
- 대상 파일:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/detail/CreatorChannelCommunityDetailViewModel.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/detail/CreatorChannelCommunityDetailActivity.ktapp/src/main/res/layout/activity_creator_channel_community_detail.xmlapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityDetailViewModelTest.kt
- 작업:
price > 0 && !existOrdered && creatorId != SharedPreferenceManager.userId잠금 게시글에서는 상세의 reaction 현황, 댓글 목록, 댓글 헤더, 댓글 입력을 숨긴다. - 검증 기록:
- 2026-07-12: RED로
CreatorChannelCommunityDetailViewModelTest.유료 미구매 게시물은 작성자가 아니면 reaction 현황과 댓글을 숨긴다를 추가했고, production 변경 전showReaction미구현 컴파일 실패를 확인했다. 이후 상세 UI 모델/상태와 Activity binding에 잠금 조건을 반영해 focused 테스트 GREEN을 확인했다.
- 2026-07-12: RED로
- 대상 파일:
Phase 15: 커뮤니티 구매 진입점·표시 상태·상세 메뉴 정리
Phase 결과: 홈과 커뮤니티 탭은 게시글 상태를 동일하게 표시하고 상세 이동만 수행하며, 구매와 권한별 관리/신고는 상세에서 수행한다.
선행조건: PRD F0-20260810 승인, 홈 Response의 isPinned/isCommentAvailable 서버 계약 확정.
Phase 완료 조건: P15-T1~P15-T5와 P15-GATE 완료, Task별 검증 기록 및 문서 최하단 Verification Log 누적.
실행 제약: 2026-08-10 사용자 지시에 따라 이번 계획 작성 단계에서는 구현과 Git 커밋을 수행하지 않는다. 이후 구현도 별도 사용자 요청 전에는 시작하지 않으며, 이 Phase에는 commit 단계를 두지 않는다.
Phase 15 파일 구조
- 홈 계약/표시:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeModels.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItem.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedCommunityView.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.ktapp/src/main/res/layout/view_feed_community.xml
- 커뮤니티 탭:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityFragment.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/model/CreatorChannelCommunityUiModels.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/model/CreatorChannelCommunityMappers.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/ui/CreatorChannelCommunityListAdapter.ktapp/src/main/res/layout/item_creator_channel_community_list.xml- 확인만 수행:
app/src/main/res/layout/item_creator_channel_community_grid.xml
- 상세/결과 전파:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/detail/CreatorChannelCommunityDetailActivity.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/detail/CreatorChannelCommunityDetailViewModel.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelRepository.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.ktapp/src/main/java/kr/co/vividnext/sodalive/v2/community/action/CommunityChange.ktapp/src/main/res/layout/activity_creator_channel_community_detail.xml
- 기존 테스트 수정:
app/src/test/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItemTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeModelsTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityMapperTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityFragmentLayoutTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityDetailViewModelTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityDetailReplyUiContractTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.ktapp/src/test/java/kr/co/vividnext/sodalive/v2/community/action/CommunityChangeTest.kt
Task 15.1 홈 Response와 게시글 표시 정책
Goal 실행 P15-T1: 홈 커뮤니티 Response의 고정/댓글 가능 계약과 잠금·reaction 표시 조건을 순수 로직으로 고정한다.
- 시작 조건: PRD
Home Response Contract,Home Community Requirements승인. - 완료 증거: 신규 DTO 필드 파싱 및
FeedItem.Community표시 정책 focused test PASS. - 범위 밖: View binding, 커뮤니티 탭, 상세 메뉴.
Files:
- Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeModels.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItem.kt - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeModelsTest.kt - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItemTest.kt
Interfaces:
- Consumes: 홈 JSON
isPinned: Boolean,isCommentAvailable: Boolean, 기존price,existOrdered. - Produces:
FeedItem.Community에 추가할 member:
val isPinned: Boolean = false
val isCommentAvailable: Boolean = true
val hideReactionWhenLocked: Boolean = false
val isLocked: Boolean
val showReaction: Boolean
val showComment: Boolean
-
isLocked = price > 0 && !existOrdered -
showReaction = !hideReactionWhenLocked || !isLocked -
showComment = showReaction && isCommentAvailable -
RED:
CreatorChannelHomeModelsTest의 홈 JSON에isPinned=true,isCommentAvailable=false커뮤니티를 넣고 두 필드 보존을 검증한다. -
RED:
FeedItemTest에 잠금 숨김 opt-in 유료 미구매는 reaction/comment 모두 false, 기본값 유료 미구매는 기존 reaction/comment 표시 유지, 댓글 불가 무료 글은 reaction true/comment false, 고정 상태 보존 케이스를 추가한다. -
RED 확인: 아래 명령을 실행해 신규 DTO/property 미존재로 인한 컴파일 또는 assertion 실패를 확인한다.
./gradlew :app:testDebugUnitTest \
--tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeModelsTest" \
--tests "kr.co.vividnext.sodalive.v2.widget.feed.FeedItemTest"
-
GREEN:
CreatorChannelCommunityPostResponse에@SerializedName("isPinned"),@SerializedName("isCommentAvailable")필드를 추가하고FeedItem.Community에 다른 화면의 기존 표시를 유지하는 기본값 및 위 계산 property를 최소 구현한다. -
GREEN 확인: 같은 focused test가 PASS하는지 확인한다.
-
REFACTOR: 신규 별도 presentation class를 만들지 않고
FeedItem.Community계산 property만 유지한다. -
검증 기록(2026-08-10): DTO/property 추가 전 focused test의 미존재 컴파일 RED를 확인했다. 구현 및
P15-R3범위 보정 후 홈 JSON 신규 필드, 잠금 opt-in/default, 댓글 불가, 고정 상태 테스트가 최종 Gate에서 PASS했다.
Task 15.2 홈 커뮤니티 표시 연결
Goal 실행 P15-T2: 홈 커뮤니티 item이 잠금·댓글 가능·고정 상태를 표시하고 card 전체 상세 이동 외의 액션을 제공하지 않는다.
- 시작 조건:
P15-T1완료. - 완료 증거:
P15-T1정책을 실제 bind에 사용하고 resource merge/Kotlin compile PASS. - 범위 밖: 커뮤니티 탭 item과 상세 메뉴.
- TDD 예외 사유: XML view 위치·visibility 자체를 직접 검증하는 테스트는 저장소 규칙상 작성하지 않는다. 표시 분기는
P15-T1순수 로직 test로 검증한다. - 대체 검증 방법: View binding id 생성, resource merge, Kotlin compile, 기존
FeedViewTest회귀를 실행한다.
Files:
- Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedCommunityView.kt - Modify:
app/src/main/res/layout/view_feed_community.xml - Verify:
app/src/test/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedViewTest.kt(수정 없이 기존 회귀만 실행)
Interfaces:
-
Consumes:
FeedItem.Community.isPinned,showReaction,showComment. -
Produces:
FeedCommunityView.bind(item)의 공지/reaction 상태와 기존FeedCommunityViewroot click 계약. -
CreatorChannelCommunityPostResponse.toFeedCommunityItem()이isPinned,isCommentAvailable을 전달하도록 수정한다. -
view_feed_community.xml에 커뮤니티 탭과 같은 공지 row와 reaction row/comment icon 식별 id를 추가한다. -
FeedCommunityView.bind()가 공지 row, reaction row, 댓글 icon/count, 하트 icon/count를FeedItem.Community계산 property로 bind하도록 수정한다. -
CreatorChannelHomeSectionAdapter.bindCommunities()의row.setOnClickListener { onCommunityClick(community.postId) }만 item 액션으로 유지한다. -
아래 명령으로 focused 회귀 및 compile을 확인한다.
./gradlew :app:testDebugUnitTest \
--tests "kr.co.vividnext.sodalive.v2.widget.feed.FeedItemTest" \
--tests "kr.co.vividnext.sodalive.v2.widget.feed.FeedViewTest"
./gradlew :app:mergeDebugResources :app:compileDebugKotlin
- 검증 기록(2026-08-10): 홈 mapper/bind/root click을 정적 대조했고
P15-R2에서 reaction id 위치를 정정했다.FeedItemTest,FeedViewTest, resource merge, Kotlin compile이 PASS했다.
Task 15.3 커뮤니티 탭 상세 이동 전용화와 가격 UI 통일
Goal 실행 P15-T3: 커뮤니티 탭 리스트/그리드 item 액션을 상세 이동 하나로 제한하고 잠금 가격 UI를 홈/상세 구조로 통일한다.
- 시작 조건: 기존 list/grid
onPostClick상세 routing 계약 확인. - 완료 증거: play/owner-more callback 제거, list/grid root 상세 이동 유지, mapper/routing focused test 및 compile PASS.
- 범위 밖: 상세 화면 내부 구매·메뉴 동작.
Files:
- Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityFragment.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/model/CreatorChannelCommunityUiModels.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/model/CreatorChannelCommunityMappers.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/ui/CreatorChannelCommunityListAdapter.kt - Modify:
app/src/main/res/layout/item_creator_channel_community_list.xml - Verify only:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/ui/CreatorChannelCommunityGridAdapter.kt - Verify only:
app/src/main/res/layout/item_creator_channel_community_grid.xml - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityMapperTest.kt - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityFragmentLayoutTest.kt
Interfaces:
-
Consumes:
CreatorChannelCommunityPostUiModel.postId,price,isLocked,showOwnerTopPrice. -
Produces: list/grid adapter constructor의 단일 item callback
onPostClick: (CreatorChannelCommunityPostUiModel) -> Unit. -
RED: routing/source 계약 테스트에 Fragment/list adapter가
onPlayClick,onOwnerMoreClick,toggleCommunityAudio,onCreatorChannelCommunityOwnerMoreClicked를 갖지 않고 list/grid root가onPostClick만 호출한다는 케이스를 추가한다. -
RED 확인: 아래 명령으로 현재 하위 액션이 남아 있어 실패함을 확인한다.
./gradlew :app:testDebugUnitTest \
--tests "kr.co.vividnext.sodalive.v2.creator.channel.community.CreatorChannelCommunityMapperTest" \
--tests "kr.co.vividnext.sodalive.v2.creator.channel.community.CreatorChannelCommunityFragmentLayoutTest"
-
GREEN: Fragment의 media player lifecycle/재생 함수와 Host owner-more callback, list adapter의 play/owner-more callback 및 더보기 view를 제거한다.
-
GREEN: UI model/mapper에서 이번 변경으로 미사용이 된
audioUrl,showPlayButton,showOwnerMore만 제거하고 작성자 상단 가격인showOwnerTopPrice는 유지한다. -
GREEN: 기존 Fragment/layout/source test에서 제거된 play/owner-more의 positive assertion만 삭제하거나 상세 이동 단일 callback의 negative assertion으로 교체한다. View 크기·간격·constraint·visibility 속성 assertion은 새로 추가하지 않는다.
-
GREEN: 리스트 잠금 금액의 compound drawable
TextView를 그리드/상세와 같은 별도ImageView(ic_bar_cash)+ 금액TextViewcapsule 구조로 변경한다. -
GREEN: 그리드는 이미
lock icon + cash icon + 금액 capsule구조와 root 상세 이동만 사용하므로 신규 production 변경 없이 계약 일치만 확인한다. -
GREEN 확인: focused test,
./gradlew :app:mergeDebugResources :app:compileDebugKotlin을 실행한다. -
REFACTOR: play/owner-more 제거로 생긴 import·binding·Host 구현 orphan만 삭제하고 다른 탭 코드는 정리하지 않는다.
-
검증 기록(2026-08-10): 하위 액션 제거 계약의 4개 RED 실패를 확인한 뒤 list/grid root
onPostClick만 유지했다. mapper/layout focused test, resource merge, Kotlin compile과 최종 Gate가 PASS했다.
Task 15.4 상세 더보기 권한과 게시글 mutation
Goal 실행 P15-T4: 상세 작성자 영역 우측 끝에서 권한별 관리/신고 메뉴를 제공하고 성공/실패 상태를 정확히 전파한다.
- 시작 조건: 상세 DTO의
creatorId,price,existOrdered,isPinned계약과 기존 레거시 dialog/API 확인. - 완료 증거: 더보기 노출 4개 권한 케이스, 고정/삭제/신고 API와 event focused test PASS, resource merge/compile PASS.
- 범위 밖: 홈/커뮤니티 탭 새로고침 실행.
Files:
- Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/detail/CreatorChannelCommunityDetailViewModel.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/detail/CreatorChannelCommunityDetailActivity.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelRepository.kt - Modify:
app/src/main/res/layout/activity_creator_channel_community_detail.xml - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityDetailViewModelTest.kt - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityDetailReplyUiContractTest.kt
Interfaces:
- Produces UI model fields:
CreatorChannelCommunityPostDetailUiModel에 추가할 member:
val isOwner: Boolean
val showMore: Boolean
isOwner = creatorId == SharedPreferenceManager.userIdshowMore = isOwner || price == 0 || existOrdered- Produces ViewModel methods/events:
fun updateCommunityPostFixed()
fun deleteCommunityPost()
fun reportCommunityPost(reason: String)
val postDeletedEventLiveData: LiveData<Boolean>
- Produces repository method:
fun reportCommunityPost(postId: Long, reason: String, token: String)
- RED: 상세 ViewModel test에 작성자 유료 미구매=true, 일반 무료=true, 일반 유료 구매=true, 일반 유료 미구매=false인
showMore케이스를 추가한다. - RED: 고정 성공은
isPinned반전 요청 후 상세 재조회와postChangedEventLiveData=true, 삭제 성공은postDeletedEventLiveData=true, 신고는ReportType.COMMUNITY_POSTrepository 호출만 수행하는 케이스를 추가한다. - RED: UI 계약 test에
R.id.btn_creator_channel_community_detail_moreresource와 Activity의 modify launcher/기존 BottomSheet·신고 dialog 연결 계약을 추가한다. 위치·constraint·visibility 값은 test에서 직접 검증하지 않는다. - RED 확인: 아래 명령으로 신규 fields/methods 미존재 실패를 확인한다.
./gradlew :app:testDebugUnitTest --tests \
"kr.co.vividnext.sodalive.v2.creator.channel.community.CreatorChannelCommunityDetailViewModelTest"
-
GREEN:
CreatorChannelRepository.reportCommunityPost()가ReportRequest(ReportType.COMMUNITY_POST, reason, communityPostId = postId)를 기존ReportRepository에 위임하도록 추가한다. -
GREEN: DetailViewModel의 고정은
updateCommunityPostFixed(postId, !content.post.isPinned, authToken()), 삭제는ModifyCommunityPostRequest(creatorCommunityId = postId, isActive = false)를 JSONtext/plainRequestBody로 변환한modifyCommunityPost(postImage = null, ...), 신고는 신규 report method를 호출한다. 각 mutation의 중복 요청을 막고 실패 시 기존 Toast event만 내보낸다. -
GREEN: 신고 성공은 API message 또는 기존
character_comment_report_submitted문구를 Toast event로 전달하고 게시글 변경 event는 내보내지 않는다. -
GREEN: 상세 layout에서
layout_creator_channel_community_detail_price와tv_creator_channel_community_detail_purchased를 제거하고, 작성자 영역 우측 끝에@drawable/ic_seemore_vertical,@string/read_morecontent description을 사용하는btn_creator_channel_community_detail_more를 추가한다. 닉네임/작성 시간의 end constraint는 이 버튼 start에 연결한다. -
GREEN: Activity는
post.showMore로 더보기 버튼 visibility를 bind한다. -
GREEN: Activity에서
CreatorCommunityPostMenuBottomSheetDialog를 열어 작성자는 수정/삭제/고정, 일반 사용자는 신고를 연결한다. 수정은 기존CreatorCommunityModifyActivity, 삭제 확인은V2ModalDialog, 신고 입력은CreatorCommunityReportDialog를 재사용한다. -
GREEN: 상세 paywall의
PurchaseCommunityPostDialog -> purchaseCommunityPost()연결은 유지하고 홈/커뮤니티 탭에는 구매 호출부가 없음을 확인한다. -
GREEN: 수정 Activity
RESULT_OK와 고정 성공 시 상세를 재조회하고 상위RESULT_OK를 설정하며, 삭제 event 수신 시RESULT_OK설정 후 상세를 종료한다. -
GREEN 확인: focused test,
./gradlew :app:mergeDebugResources :app:compileDebugKotlin을 실행한다. -
REFACTOR: 신규 menu abstraction 또는 별도 popup을 만들지 않고 기존 BottomSheet/Dialog를 직접 재사용한다.
-
검증 기록(2026-08-10): 신규 fields/methods/resource 미존재 RED를 확인한 뒤 권한 truth table, 고정·삭제·신고 성공/실패·중복 guard, 기존 dialog 재사용과 결과 전파를 구현했다. 커뮤니티 focused test와 resource/compile Gate가 PASS했다.
Task 15.5 상위 새로고침 전파와 목록 메뉴 orphan 제거
Goal 실행 P15-T5: 상세 변경 결과가 홈·커뮤니티 탭을 함께 갱신하고 목록에 남은 관리 메뉴 코드를 제거한다.
- 시작 조건:
P15-T3,P15-T4완료. - 완료 증거: 상세
RESULT_OK -> CommunityChange.Updated -> 홈+커뮤니티 refreshrouting test PASS, 제거된 callback 관련 compile PASS. - 범위 밖: 신고 후 새로고침, 다른 creator channel 탭.
Files:
- Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/community/action/CommunityChange.kt - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/community/action/CommunityChangeTest.kt
Interfaces:
-
Consumes:
resolveCommunityActivityResult(CommunityActivityResultSource.Detail, RESULT_OK) == CommunityChange.Updated. -
Produces:
CommunityChange.Updated처리 시homeActionDelegate?.refreshHome()과refreshCreatorChannelCommunity()호출. -
RED:
CreatorChannelActivitySourceTest에 상세Updated처리 블록이 홈/커뮤니티 refresh를 모두 호출한다는 routing 계약을 추가한다. -
RED 확인: 아래 명령으로 현재
Updated가 커뮤니티만 refresh하고 목록 전용 change가 남아 있어 실패함을 확인한다.
./gradlew :app:testDebugUnitTest \
--tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" \
--tests "kr.co.vividnext.sodalive.v2.community.action.CommunityChangeTest"
-
GREEN:
handleCommunityChange(Updated)가 홈과 커뮤니티를 함께 갱신하도록 변경한다. -
GREEN: 목록 owner-more 제거로 미사용이 된
communityPostModifyLauncher,onCreatorChannelCommunityOwnerMoreClicked, 목록용 고정/삭제/dialog 함수와 관련 import/repository 의존을CreatorChannelActivity에서 제거한다. -
GREEN: 호출자가 사라진
CommunityChange.Deleted,CommunityChange.PinChanged를 제거하고CommunityChangeTest의 삭제/고정 전용 케이스만 제거한다.Write -> Created,Modify/Detail -> Updated, 취소 ->Ignored회귀는 유지한다. -
GREEN 확인: focused test와
./gradlew :app:compileDebugKotlin을 실행한다. -
REFACTOR: 다른 화면에서 사용 중인
CommunityActionCommand.PostDetail,CommunityChange.Created/Updated는 유지한다. -
검증 기록(2026-08-10): routing RED 2건을 확인한 뒤 상세
RESULT_OK의Updated처리에서 홈·커뮤니티를 함께 갱신하고 목록 메뉴 orphan을 제거했다. Activity/action focused test와 Kotlin compile이 PASS했다.
Task 15.R1 목록 메뉴 제거 후 미사용 import 정리
Goal 실행 P15-R1: 확정 review 항목 REV-P15-001의 미사용 import를 제거해 Phase 15 style Gate를 회복한다.
-
시작 조건:
REV-P15-001확정,P15-T5목록 메뉴/orphan 제거 완료. -
대상 파일:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt -
수정 범위:
SharedPreferenceManager미사용 import 1줄 제거. -
회귀 테스트:
./gradlew :app:ktlintCheck, Phase 15 Gate 전체. -
완료 증거: RED ktlint 정확한 1건 → import 제거 → ktlint/Gate PASS → review 보고서 수정 후 검증 누적.
-
범위 밖: 다른 import 순서, 관련 없는 style 정리,
.editorconfigdeprecation 경고. -
./gradlew :app:ktlintCheck에서CreatorChannelActivity.kt:29:1 Unused import만 확정된 RED를 기록한다. -
SharedPreferenceManagerimport 1줄만 제거한다. -
./gradlew :app:ktlintCheck와 Phase 15 Gate를 재실행한다. -
plan-task.mdVerification Log와phase15-community-purchase-detail-menu-review.md에 완료 증거를 누적한다. -
검증 기록(2026-08-10): 최초 Gate에서
CreatorChannelActivity.kt:29:1 Unused importRED를 확인하고 해당 import 1줄만 제거했다. 최종ktlintCheck와 Phase 15 Gate가 PASS했다.
Task 15.R2 홈 reaction row binding 대상 정정
Goal 실행 P15-R2: 확정 review 항목 REV-P15-002의 잘못된 ll_feed_community_reaction id 위치를 정정해 유료 미구매 홈 item의 reaction UI만 숨긴다.
-
시작 조건:
REV-P15-002확정,P15-T2표시 정책 구현 완료. -
대상 파일:
app/src/main/res/layout/view_feed_community.xml -
수정 범위:
ll_feed_community_reactionid를 작성자 row에서 하트·댓글 reaction row로 이동. -
회귀 검증:
FeedItemTest,FeedViewTest,:app:mergeDebugResources,:app:compileDebugKotlin, Phase 15 Gate, XML tree 정적 재확인. -
완료 증거: 수정 전 XML tree에서 id가 프로필 row를 가리키는 근거 → id 1개 이동 → focused 회귀/Gate PASS → 리뷰 보고서 누적.
-
TDD 예외 사유: 저장소 규칙상 View visibility·layout 속성을 직접 검증하는 신규 테스트를 추가하지 않는다. 표시 분기는 기존
FeedItemTest, binding/resource는 resource merge·compile·정적 XML tree 검토로 대체한다. -
범위 밖: 홈 card 간격·크기·제약, 다른 row 레이아웃.
-
수정 전
ll_feed_community_reactionid가 프로필 row에 있고 실제 reaction row에는 id가 없는 근거를 기록한다. -
id를 실제 reaction row로 이동한다.
-
focused 회귀, resource merge/compile, Phase 15 Gate를 재실행한다.
-
plan-task.mdVerification Log와 review 보고서에 완료 증거를 누적한다. -
검증 기록(2026-08-10): 수정 전 id가 프로필 row에 연결되고 실제 reaction row에는 없음을 XML tree로 확인했다. id 1개를 실제 reaction row로 이동한 뒤 focused test, resource merge, Kotlin compile과 최종 Gate가 PASS했다.
Task 15.R3 공유 FeedItem reaction 정책 범위 정정
Goal 실행 P15-R3: 확정 review 항목 REV-P15-003의 공유 모델 회귀를 제거해 크리에이터 채널 홈에서만 유료 미구매 reaction을 숨기고 다른 FeedItem.Community 호출부는 기존 표시 동작을 유지한다.
-
시작 조건:
REV-P15-003확정,P15-T1~P15-T2표시 정책 구현 완료. -
대상 파일:
app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItem.kt,app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt,app/src/test/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItemTest.kt,app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragmentLayoutTest.kt -
수정 범위:
FeedItem.Community신규 정책은 기본값으로 기존 reaction을 유지하고, 크리에이터 채널 홈 mapper만 잠금 시 숨김을 명시하도록 제한. -
회귀 테스트: 잠금 item의 기본값은 reaction/comment 표시 유지, 크리에이터 채널 홈 opt-in은 reaction/comment 숨김, 기존 댓글 불가·고정 상태 테스트, Phase 15 Gate.
-
완료 증거: 메인 홈 인기 커뮤니티 mapper와 공유
FeedCommunityView호출 경로 확인 → 기본값 회귀 테스트 RED → 최소 opt-in 구현 → focused 회귀/Gate PASS → 리뷰 보고서 누적. -
범위 밖: 메인 홈 인기 커뮤니티의 이미지 잠금/가격 정책, 다른 feed UI 변경.
-
메인 홈 인기 커뮤니티가
price,existOrdered를 전달하고 공유FeedCommunityView.bind()를 사용해 기존 reaction까지 숨겨지는 호출 경로를 기록한다. -
RED: 잠금 유료
FeedItem.Community가 신규 정책 기본값에서는 기존 reaction/comment 표시를 유지하고, opt-in에서는 둘 다 숨기는 회귀 테스트를 추가해 실패를 확인한다. -
GREEN: 신규 정책 기본값은 기존 표시를 유지하고
CreatorChannelHomeSectionAdapter만 잠금 reaction 숨김을 선택하도록 최소 수정한다. -
focused 회귀와 Phase 15 Gate를 재실행한다.
-
plan-task.mdVerification Log와 review 보고서에 완료 증거를 누적한다. -
검증 기록(2026-08-10):
HomeRecommendationMappers -> FeedItem.Community -> HomePopularCommunityAdapter -> FeedCommunityView.bind()호출 경로로 공유 정책 회귀를 확정했다.hideReactionWhenLocked미존재 컴파일 RED 후 기본값 false, 크리에이터 채널 홈 true로 제한했고FeedItemTest, 메인 홈 mapper 회귀 테스트와 최종 Gate가 PASS했다.
Task 15.R4 메인 홈 회귀 테스트 파일 미사용 import 정리
Goal 실행 P15-R4: 확정 review 항목 REV-P15-004의 미사용 import를 제거해 Phase 15 style Gate를 회복한다.
-
시작 조건:
P15-R3메인 홈 회귀 테스트 추가 후ktlintCheck실패 확정. -
대상 파일:
app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragmentLayoutTest.kt -
수정 범위: 실제 사용처가 없는
ColorDrawableimport 1줄 제거. -
회귀 검증:
./gradlew :app:ktlintCheck, Phase 15 Gate,git diff --check. -
완료 증거: ktlint 정확한 unused import 1건 → import 제거 → ktlint/Gate PASS → 리뷰 보고서 누적.
-
범위 밖: 같은 테스트 파일의 기존 구조·deprecated API 정리.
-
ktlintCheck의HomeMainFragmentLayoutTest.kt:6:1 Unused importRED를 기록한다. -
ColorDrawableimport 1줄만 제거한다. -
ktlintCheck와 Phase 15 Gate를 재실행한다. -
plan-task.mdVerification Log와 review 보고서에 완료 증거를 누적한다. -
검증 기록(2026-08-10): 메인 홈 회귀 테스트 추가 후 lint 대상이 된 파일에서 사용처 없는
ColorDrawableimport 1건을 확인해 제거했다. 최종ktlintCheck와 전체 focused test Gate가 PASS했다.
Phase 15 Gate
Goal 실행 P15-GATE: 승인된 홈/탭/상세 사용자 흐름과 회귀 방지를 최종 판정한다.
- 시작 조건:
P15-T1~P15-T5완료. - 완료 증거: 아래 명령을 순차 실행해 모두 exit code 0을 확인하고 각 Task 검증 기록 및
Verification Log에 실제 결과를 누적한다. - 범위 밖:
app/src/androidTest,connectedDebugAndroidTest, 기기·에뮬레이터 조작, 스크린샷·시각 QA, Git commit.
./gradlew :app:testDebugUnitTest \
--tests "kr.co.vividnext.sodalive.v2.widget.feed.FeedItemTest" \
--tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeModelsTest" \
--tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLayoutTest"
./gradlew :app:testDebugUnitTest \
--tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*" \
--tests "kr.co.vividnext.sodalive.v2.community.action.*"
./gradlew :app:testDebugUnitTest --tests \
"kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"
./gradlew :app:mergeDebugResources
./gradlew :app:compileDebugKotlin
./gradlew :app:ktlintCheck
git diff --check
Expected: 홈 Response 신규 필드와 reaction/pin 정책, list/grid 상세 이동 전용화, 상세 더보기 권한·구매/관리/신고, 상세 변경 후 홈+커뮤니티 refresh 관련 focused test PASS. 리소스 병합·Kotlin 컴파일·ktlint·diff whitespace 검증 PASS.
Phase 15 실행 순서
P15-T1 → P15-T2 → P15-T3 → P15-T4 → P15-T5 → P15-R1 → P15-R2 → P15-R3 → P15-R4 → P15-GATE
Phase 15 계획 기록 — 2026-08-10
- 상태: 계획 완료 / 구현 미시작
- 무엇을: 승인된 PRD
F0-20260810을P15-T1~P15-T5,P15-GATE로 분해했다. - 왜: 홈·커뮤니티 탭의 표시/액션 일관성과 상세 구매·메뉴·결과 전파를 구현 전에 검증 가능한 단위로 고정하기 위해서다.
- 어떻게:
git diff --check— 문서 변경 whitespace 검증 PASS../gradlew tasks --all— exit code 0,BUILD SUCCESSFUL.
- 남은 항목: Phase 15 구현 전체. 사용자 지시에 따라 이번 작업에서는 수행하지 않는다.
- 다음 행동: 사용자가 구현을 별도로 요청하면
P15-T1RED부터 순차 실행한다.
Phase 15 구현·검증 기록 — 2026-08-10
- 상태: 구현 및 검증 완료 / Git commit 미수행
- 무엇을:
P15-T1P15-T5를 구현하고 리뷰 확정 항목P15-R1P15-R4를 수정했다. - 왜: 미체크 항목이 구현 누락이었음을 코드·테스트 대조로 확인했고, 구현 후 독립 리뷰와 Gate에서 실제 회귀·style 문제를 확인했기 때문이다.
- 어떻게:
- 홈 Response에
isPinned,isCommentAvailable을 연결하고 크리에이터 채널 홈만 유료 미구매 reaction 숨김을 opt-in했다. - 홈·커뮤니티 탭 item 액션을 상세 이동으로 제한하고 상세에 구매·권한별 더보기·변경 결과 전파를 모았다.
REV-P15-001~REV-P15-004를 각각 회귀 Task로 전환한 뒤 최소 수정했다.- 전체 focused local unit/source contract test, resource merge, Kotlin compile, ktlint를 최종 working tree에서 재실행해
BUILD SUCCESSFUL을 확인했고git diff --check,git diff HEAD --check는 출력 없이 PASS했다.
- 홈 Response에
- 제외: 저장소 규칙과 사용자 지시에 따라
app/src/androidTest, 기기·에뮬레이터 조작, 스크린샷·시각 QA, Git commit은 수행하지 않았다. - 남은 항목: 실제 서버 Response 배포 상태와 기기 수동 UI 확인은 이번 자동 검증 범위 밖이다.
Phase 16 — 홈·커뮤니티 리스트 권한별 더보기 메뉴
Phase 결과: 상세와 동일한 권한별 게시글 더보기 메뉴를 홈 커뮤니티 item과 커뮤니티 탭 리스트형에서 사용할 수 있고, 성공한 관리 작업은 두 목록에 함께 반영된다.
선행조건: 승인된 PRD Home and Community List More Menu Requirements, Phase 15 구현·검증 완료.
Phase 완료 조건: P16-T1~P16-T3, P16-GATE 완료와 Task별 검증 기록 및 Verification Log 누적.
범위
포함
- 홈 커뮤니티 item과 커뮤니티 탭 리스트형 작성자 영역 우측 끝
ic_seemore_vertical버튼. - 상세와 동일한 작성자/무료/구매 완료/유료 미구매 권한 truth table.
- 작성자 수정·삭제·고정/고정 해제, 일반 사용자 신고.
- 성공한 수정·삭제·고정/고정 해제 후 홈+커뮤니티 새로고침.
- card 본문 상세 이동과 더보기 메뉴 click 분리.
제외
- 커뮤니티 탭 썸네일형(그리드형) 더보기 버튼.
- 목록에서 유료 게시글 구매·오디오 재생.
- 상세 메뉴 구조 변경, 레거시 파일 수정, 신규 범용 coordinator/dependency.
app/src/androidTest, 기기·에뮬레이터 조작, 스크린샷·시각 QA, Git commit.
Task 16.1 공용 메뉴 권한 presentation 계약
Goal 실행 P16-T1: 홈과 커뮤니티 리스트가 동일한 메뉴 payload와 권한 계산을 사용하고 다른 공유 feed는 기존 표시를 유지한다.
- 시작 조건: PRD 권한 truth table 승인.
- 완료 증거: 메뉴 권한 4개 케이스와 홈/커뮤니티 mapper focused test PASS.
- 범위 밖: 버튼 layout/click, Activity menu/API 실행.
Files:
- Create:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/model/CreatorChannelCommunityMenuItem.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/model/CreatorChannelCommunityUiModels.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/model/CreatorChannelCommunityMappers.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelHomeUiModels.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelHomeMappers.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItem.kt - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityMapperTest.kt - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeMapperTest.kt - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedItemTest.kt
Interfaces:
data class CreatorChannelCommunityMenuItem(
val postId: Long,
val creatorId: Long,
val currentUserId: Long,
val price: Int,
val existOrdered: Boolean,
val isPinned: Boolean
) {
val isOwner: Boolean
val showMore: Boolean
}
-
isOwner = creatorId == currentUserId -
showMore = isOwner || price == 0 || existOrdered -
CreatorChannelCommunityPostUiModel은menuItem: CreatorChannelCommunityMenuItem을 제공한다. -
CreatorChannelHomeSection.Communities는currentMemberId: Long을 함께 보존해 adapter가 같은 menu item을 만든다. -
FeedItem.Community는showMore: Boolean = false를 추가해 다른 공유 feed 호출부의 기존 동작을 유지한다. -
RED:
CreatorChannelCommunityMapperTest에 작성자 유료 미구매=true, 일반 무료=true, 일반 유료 구매=true, 일반 유료 미구매=false인menuItem.showMore와isPinned보존 케이스를 추가한다. -
RED:
CreatorChannelHomeMapperTest에Communities.currentMemberId보존,FeedItemTest에showMore기본값 false 회귀를 추가한다. -
RED 확인: 아래 명령을 실행해 신규 type/property 미존재 컴파일 실패를 확인한다.
./gradlew :app:testDebugUnitTest \
--tests "kr.co.vividnext.sodalive.v2.creator.channel.community.CreatorChannelCommunityMapperTest" \
--tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeMapperTest" \
--tests "kr.co.vividnext.sodalive.v2.widget.feed.FeedItemTest"
-
GREEN: 위
CreatorChannelCommunityMenuItem계산 property를 추가하고 커뮤니티 mapper/UI model과 홈Communities.currentMemberId를 연결한다. -
GREEN:
FeedItem.Community.showMore를 기본값 false로 추가한다. -
GREEN 확인: 같은 focused test가 PASS하는지 확인한다.
-
REFACTOR: 별도 권한 service/factory를 만들지 않고 menu item 계산 property 하나만 공용 정책으로 유지한다.
-
검증 기록(2026-08-10):
menuItem,currentMemberId,showMore미존재로compileDebugUnitTestKotlinRED 실패를 확인했다.CreatorChannelCommunityMenuItem계산 property와 커뮤니티/홈 mapper 연결,FeedItem.Community.showMore=false기본값을 최소 구현한 뒤 지정된 focused test 26개가 모두 PASS했다. 명세·코드 품질 독립 검토에서도 차단 이슈가 없음을 확인했다.
Task 16.2 홈·커뮤니티 리스트 더보기 버튼과 callback
Goal 실행 P16-T2: 홈 커뮤니티 item과 커뮤니티 리스트형의 더보기 버튼이 card 상세 이동과 분리된 공용 menu callback을 호출한다.
- 시작 조건:
P16-T1완료. - 완료 증거: 홈/리스트 callback routing focused test, resource merge, Kotlin compile PASS와 grid 무변경 확인.
- 범위 밖: BottomSheet 표시와 mutation API.
- TDD 예외 사유: 버튼 위치·constraint·visibility 속성 자체는 저장소 규칙상 자동 테스트에서 직접 검증하지 않는다.
- 대체 검증 방법: 권한 visibility는
P16-T1순수 로직 test, callback은 click/source contract test, UI resource는 id 존재·resource merge·compile·정적 XML tree 대조로 검증한다.
Files:
- Modify:
app/src/main/res/layout/view_feed_community.xml - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedCommunityView.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeFragment.kt - Modify:
app/src/main/res/layout/item_creator_channel_community_list.xml - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/ui/CreatorChannelCommunityListAdapter.kt - Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityFragment.kt - Verify only:
app/src/main/res/layout/item_creator_channel_community_grid.xml - Verify only:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/ui/CreatorChannelCommunityGridAdapter.kt - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedViewTest.kt - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityFragmentLayoutTest.kt - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt
Interfaces:
fun FeedCommunityView.setOnMoreClick(listener: ((FeedItem.Community) -> Unit)?)
CreatorChannelHomeSectionAdapter(
onCommunityClick: (Long) -> Unit,
onCommunityMoreClick: (CreatorChannelCommunityMenuItem) -> Unit
)
CreatorChannelCommunityListAdapter(
onPostClick: (CreatorChannelCommunityPostUiModel) -> Unit,
onMoreClick: (CreatorChannelCommunityMenuItem) -> Unit
)
fun onCreatorChannelCommunityMoreClicked(item: CreatorChannelCommunityMenuItem)
- RED:
FeedViewTest에btn_feed_community_moreresource와setOnMoreClick이 bound item만 전달하는 callback 케이스를 추가한다. - RED:
CreatorChannelCommunityFragmentLayoutTest와CreatorChannelActivitySourceTest에 홈/리스트 adapter → Fragment Host의 동일 menu callback, list root 상세 click 유지, grid menu callback 부재 계약을 추가한다. - RED 확인: 아래 명령으로 신규 resource/API/callback 미존재 실패를 확인한다.
./gradlew :app:testDebugUnitTest \
--tests "kr.co.vividnext.sodalive.v2.widget.feed.FeedViewTest" \
--tests "kr.co.vividnext.sodalive.v2.creator.channel.community.CreatorChannelCommunityFragmentLayoutTest" \
--tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"
-
GREEN:
view_feed_community.xml작성자 row를 전체 폭으로 유지하고 우측 끝에 42dpbtn_feed_community_more(ic_seemore_vertical,read_more)를 추가한다.FeedCommunityView.bind()는item.showMore를 bind하고 별도 more click을 적용한다. -
GREEN: 홈 adapter는
Communities.currentMemberId로 menu item을 만들고FeedItem.showMore,setOnMoreClick,onCommunityMoreClick을 연결한다. HomeFragment Host로 같은 menu item을 전달한다. -
GREEN: 커뮤니티 리스트 layout의 기존 top actions 끝에 42dp more 버튼을 추가하고 wrapper는
showOwnerTopPrice || menuItem.showMore일 때 표시한다. list adapter/Fragment Host에onMoreClick을 연결한다. -
GREEN: root
onCommunityClick/onPostClick은 상세 이동을 유지하고 more 버튼은 메뉴 callback만 호출한다. -
GREEN: grid layout/adapter에는 more id/callback을 추가하지 않는다.
-
GREEN 확인: focused test와
./gradlew :app:mergeDebugResources :app:compileDebugKotlin이 PASS하는지 확인한다. -
REFACTOR: 이번 Task가 만든 listener/import/binding 중복만 정리하고 공유 View의 다른 호출부 동작은 변경하지 않는다.
-
검증 기록(2026-08-10):
btn_feed_community_more,btn_creator_channel_community_list_more,setOnMoreClick미존재로compileDebugUnitTestKotlinRED 실패를 확인했다. 두 42dp 버튼과 홈/리스트의 동일CreatorChannelCommunityMenuItemHost callback을 최소 연결한 뒤 지정된 focused test 119개가 모두 PASS했다.:app:mergeDebugResources :app:compileDebugKotlin도 PASS했으며 grid XML/adapter에는 more id·callback이 없음을 정적 확인했다.
Task 16.3 Activity 공용 메뉴와 mutation 결과 전파
Goal 실행 P16-T3: 홈과 커뮤니티 리스트의 공용 callback이 상세와 같은 BottomSheet/Dialog/API를 실행하고 성공한 관리 작업만 두 목록을 갱신한다.
- 시작 조건:
P16-T2완료, Phase 15 상세 메뉴/API 계약 유지. - 완료 증거: Activity source/routing focused test와 전체 community 회귀, compile PASS.
- 범위 밖: 상세 ViewModel/Activity 메뉴 변경, 신고 후 목록 새로고침.
Files:
- Modify:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt - Reuse:
app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelRepository.kt - Reuse: 레거시
CreatorCommunityPostMenuBottomSheetDialog,CreatorCommunityReportDialog,CreatorCommunityModifyActivity,CreatorCommunityRepository - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt - Test:
app/src/test/java/kr/co/vividnext/sodalive/v2/community/action/CommunityChangeTest.kt
Interfaces:
override fun onCreatorChannelCommunityMoreClicked(item: CreatorChannelCommunityMenuItem)
private fun updateCreatorChannelCommunityPostFixed(item: CreatorChannelCommunityMenuItem)
private fun deleteCreatorChannelCommunityPost(item: CreatorChannelCommunityMenuItem)
private fun reportCreatorChannelCommunityPost(item: CreatorChannelCommunityMenuItem, reason: String)
-
Activity는
CreatorCommunityRepository와 기존CreatorChannelRepository.reportCommunityPost()를 주입해 재사용한다. -
수정 launcher의
RESULT_OK, 삭제·고정 성공은 기존handleCommunityChange(CommunityChange.Updated)로 홈+커뮤니티를 갱신한다. -
신고 성공은 API message 또는
character_comment_report_submittedToast만 표시하고 새로고침하지 않는다. -
isCommunityPostMutating단일 guard로 고정·삭제·신고 중복 요청을 막고 성공/실패 모두 guard를 해제한다. -
RED:
CreatorChannelActivitySourceTest에 HomeFragment.Host와 CommunityFragment.Host의 동일 override 하나, 권한 guard, 기존 BottomSheet/Dialog/modify launcher 연결 계약을 추가한다. -
RED: 같은 test에 고정
!item.isPinned, 삭제ModifyCommunityPostRequest(isActive=false), 신고reportCommunityPost, 성공CommunityChange.Updated, 신고 성공 no-refresh, 중복 guard 계약을 추가한다. -
RED 확인: 아래 명령으로 Activity 공용 메뉴/mutation 연결 미존재 실패를 확인한다.
./gradlew :app:testDebugUnitTest \
--tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" \
--tests "kr.co.vividnext.sodalive.v2.community.action.CommunityChangeTest"
-
GREEN: Activity에 modify launcher와
CreatorCommunityPostMenuBottomSheetDialog를 연결하고item.showMore가 false면 menu를 시작하지 않는다. -
GREEN: 작성자 menu는 수정·삭제·고정/고정 해제, 일반 사용자 menu는
CreatorCommunityReportDialog신고만 연결한다. mutation method는 메뉴 역할과item.isOwner를 다시 확인한다. -
GREEN: 고정은
updateCommunityPostFixed(item.postId, !item.isPinned, authToken()), 삭제는ModifyCommunityPostRequest(creatorCommunityId = item.postId, isActive = false)JSONtext/plain요청, 신고는CreatorChannelRepository.reportCommunityPost(item.postId, reason, authToken())를 호출한다. -
GREEN: 수정 복귀·고정·삭제 성공만
CommunityChange.Updated로 홈+커뮤니티를 갱신하고 실패/신고는 목록 상태를 변경하지 않는다. -
GREEN 확인: focused test,
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:compileDebugKotlin이 PASS하는지 확인한다. -
REFACTOR: 상세 메뉴 코드를 옮기거나 신규 coordinator를 만들지 않고 Activity의 공용 목록 처리만 유지한다.
-
검증 기록(2026-08-10): Activity 공용 메뉴와 mutation source 계약 3개를 먼저 추가한 뒤 focused test에서 기존 100개는 통과하고 신규 3개가
item.showMoreguard 및 mutation method/guard 미존재로 RED 실패함을 확인했다. 기존 BottomSheet/Dialog/modify launcher와 legacy/V2 repository를 Activity에 직접 연결한 뒤 focused test 103개, community wildcard 회귀 86개가 모두 PASS했다.:app:compileDebugKotlin도 PASS했으며 수정·고정·삭제 성공만CommunityChange.Updated를 호출하고 신고 성공/모든 실패 경로에는 refresh가 없음을 source test로 확인했다. -
리뷰 회귀 수정 검증 기록(2026-08-10): 게시물 작성자 권한은 채널 소유자 상태와 독립된
item.isOwner라는 PRD 계약에 맞춰 source test를 먼저 변경했고, 현재isCreatorChannelOwner()추가 조건 때문에 focused test 103개 중 권한 계약 3개가 RED 실패함을 확인했다. 수정·고정·삭제·신고 경로에서 채널 소유자 조건만 제거한 뒤 focused test 103개와 community wildcard 회귀 86개가 모두 PASS했고:app:compileDebugKotlin도 PASS했다.
Task 16.R1 Phase 완료 문서 정합성 복구
Goal 실행 P16-R1: 확정 review 항목 REV-P16-001에 따라 Phase 16 구현·Gate 완료 상태와 검증 증거를 문서에 누적한다.
-
시작 조건:
P16-T1~P16-T3,P16-GATE실행 완료와REV-P16-001확정. -
대상 파일:
docs/20260708_커뮤니티_게시물_상세_댓글_답글/plan-task.md,reviews/phase16-home-community-list-more-menu-review.md. -
수정 범위: 기존 계획 기록은 보존하고 구현·Gate 완료 기록,
Verification Log, 리뷰 판정만 누적한다. -
회귀 검증:
git diff --check, 최종 리뷰 재검토. -
완료 증거: 미시작 상태와 Gate 기록 누락 근거 → 완료 기록 누적 → diff check PASS → 5개 리뷰 lane 최종 판정.
-
범위 밖: production/test 코드 변경, Gate 재실행을 위한 테스트 완화, Git commit.
-
Phase 16 구현·검증 완료 기록을 기존 계획 기록 뒤에 누적한다.
-
Verification Log에 focused test, resource merge, compile, ktlint, diff check 결과와 제외 범위를 누적한다. -
Phase 16 리뷰 보고서에
REV-P16-001수정 및 재검토 결과를 누적한다. -
git diff --check와 최종 리뷰 재검토를 통과한다. -
검증 기록(2026-08-10): Phase 16 완료 기록과
Verification Log를 누적한 뒤git diff --check,git diff HEAD --check가 출력 없이 PASS했다. 최종 재검토에서 목표·실행 QA·코드 품질·보안·맥락 5개 lane이 모두 PASS했으며 추가 차단 이슈가 없음을 확인했다.
Phase 16 Gate
Goal 실행 P16-GATE: 권한별 버튼·메뉴·mutation·새로고침과 grid 제외, 기존 상세/구매 회귀를 최종 판정한다.
- 시작 조건:
P16-T1~P16-T3완료. - 완료 증거: 아래 명령의 exit code 0, 정적 권한/클릭 대조, Task별 검증 기록과
Verification Log누적. - 범위 밖: Gate 통과를 위한 test 완화, 기기 UI 조작, Git commit.
./gradlew :app:testDebugUnitTest \
--tests "kr.co.vividnext.sodalive.v2.widget.feed.FeedItemTest" \
--tests "kr.co.vividnext.sodalive.v2.widget.feed.FeedViewTest" \
--tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeMapperTest" \
--tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"
./gradlew :app:testDebugUnitTest \
--tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*" \
--tests "kr.co.vividnext.sodalive.v2.community.action.*"
./gradlew :app:mergeDebugResources
./gradlew :app:compileDebugKotlin
./gradlew :app:ktlintCheck
git diff --check
git diff HEAD --check
Expected: 홈·커뮤니티 리스트형은 동일 권한 메뉴를 제공하고 card root 상세 이동을 유지한다. grid에는 메뉴가 없고, 미구매 유료 일반 사용자는 버튼이 숨겨진다. 수정·삭제·고정 성공은 홈+커뮤니티를 갱신하며 신고/실패는 갱신하지 않는다. 기존 상세 구매·메뉴 focused 회귀와 resource/compile/style/whitespace Gate가 모두 PASS한다.
Phase 16 실행 순서
P16-T1 → P16-T2 → P16-T3 → P16-GATE
Phase 16 계획 기록 — 2026-08-10
- 상태: 계획 완료 / 구현 미시작
- 무엇을: 승인된 홈·커뮤니티 리스트형 권한별 더보기 후속 요구를
P16-T1~P16-T3,P16-GATE로 분해했다. - 왜: 공용 권한 계산 → UI callback → Activity mutation 순으로 계약을 분리해 grid 제외와 상세 이동 회귀를 검증하기 위해서다.
- 남은 항목: 사용자 계획 검토 승인 후
P16-T1RED부터 순차 실행한다. - Git commit: 사용자 지시에 따라 수행하지 않는다.
Phase 16 구현·검증 기록 — 2026-08-10
- 상태: 구현 및 Gate 완료 / Git commit 미수행
- 무엇을:
P16-T1~P16-T3를 구현하고 리뷰 확정 항목REV-P16-001을P16-R1로 수정했다. - 왜: 홈과 커뮤니티 리스트형에서 상세과 동일한 권한별 메뉴를 제공하고, 성공한 관리 작업만 양쪽 목록에 반영하기 위해서다.
- 어떻게:
- 공용
CreatorChannelCommunityMenuItem으로 작성자/가격/구매 권한과 고정 상태를 전달했다. - 홈·리스트의 더보기 click을 card 상세 click과 분리하고 grid는 기존 상세 이동만 유지했다.
- 기존 BottomSheet/Dialog/repository를 Activity에서 재사용하고 수정·삭제·고정 성공만
CommunityChange.Updated로 전파했다. - 최초 독립 명세 검토에서 채널 소유자 조건이 작성자 권한을 제한하는 문제를 확인해
item.isOwner계약으로 회귀 수정했다. - 최종 Gate의 focused test, resource merge, Kotlin compile, ktlint, 두 diff check가 모두 통과했다.
- 공용
- 제외:
app/src/androidTest, 기기·에뮬레이터 조작, 스크린샷·시각 QA, 실제 서버 mutation, 별도 worktree, Git commit. - 남은 항목: 없음.
Verification Log
-
2026-08-11: 사용자 요청에 따라 Phase 15·16 완료 체크를 PRD, production, test와 다시 역대조했다. 실제 Task 체크박스는 모두 완료 상태였고 체크 누락·미구현 항목은 없었다. Phase 15 홈 Response/공유 feed 회귀 test, Phase 16 홈·Feed·Activity focused test, community/action focused test와 필터 없는 전체
:app:testDebugUnitTest가 모두BUILD SUCCESSFUL로 PASS했다.:app:mergeDebugResources,:app:compileDebugKotlin,:app:ktlintCheck,git diff --check,git diff HEAD --check도 PASS했다. 구매 호출은 상세에만 있고, 홈·리스트 root/more 분리와 grid 제외, 권한별 메뉴, 성공 관리 mutation의 홈+커뮤니티 갱신, 신고·실패 no-refresh, 공유FeedItem.Community기본값 보존을 정적으로 확인했다. 독립 재리뷰도 Critical/Important/Minor 이슈 없음과 승인 가능으로 판정했다. 새 확정 결함이 없어 억지로 회귀 수정 Task나 production/test 변경을 추가하지 않았고 Git commit도 수행하지 않았다. -
2026-08-10: Phase 16
P16-T1~P16-T3와P16-GATE를 완료했다. 최종 working tree에서 홈·Feed·Activity focused test와 community/action 회귀 test가BUILD SUCCESSFUL로 PASS했고,:app:mergeDebugResources,:app:compileDebugKotlin,:app:ktlintCheck도 모두 PASS했다.git diff --check,git diff HEAD --check는 출력 없이 통과했다. 허용된 실행 QA 재검증에서도 P0 시나리오 11/11과 focused 128개, community/action 96개가 PASS했다. 리뷰에서 확인된 작성자 권한 추가 제한은item.isOwner기준으로 회귀 수정했고, 완료 문서 누락REV-P16-001은P16-R1로 누적했다. 저장소 규칙과 사용자 지시에 따라app/src/androidTest, 기기·에뮬레이터 조작, 스크린샷·시각 QA, 실제 서버 mutation, 별도 worktree, Git commit은 수행하지 않았다..editorconfig disabled_rules및 Gradle deprecated feature 경고는 기존 비차단 경고로 유지했다. -
2026-08-10: Phase 15 문서 대조·구현·독립 재리뷰를 완료했다. 미구현 체크리스트는
P15-T1P15-T5로 구현했고, 리뷰에서REV-P15-001미사용 import,REV-P15-002reaction id 오배치,REV-P15-003공유 피드 reaction 정책 범위 회귀,REV-P15-004테스트 파일 미사용 import를 확정해P15-R1P15-R4로 수정했다. 최종 working tree에서 홈/공유 피드·커뮤니티 상세/action·상위 Activity focused test,:app:mergeDebugResources,:app:compileDebugKotlin,:app:ktlintCheck가 모두BUILD SUCCESSFUL로 PASS했고git diff --check,git diff HEAD --check는 출력 없이 PASS했다. 수정 후 독립 재리뷰에서도 새 Critical/Important/Minor 이슈가 없음을 확인했다..editorconfig disabled_rules및 기존 test deprecated API 경고는 실패가 아닌 기존 경고이며 범위 밖으로 유지했다. Git commit은 수행하지 않았다. -
2026-08-10: 승인된 후속 PRD와 Phase 15 구현 계획만 작성했다. placeholder·요구사항 충돌을 자체 검토했고
git diff --check,./gradlew tasks --all이 통과했다. 사용자 지시에 따라 production/test 코드 구현과 Git commit은 수행하지 않았다. -
2026-07-12: Phase 14 유료 미구매 상세 게시글 reaction/comment 숨김 변경을 완료했다. RED는
CreatorChannelCommunityDetailViewModelTest.유료 미구매 게시물은 작성자가 아니면 reaction 현황과 댓글을 숨긴다의showReaction미구현 컴파일 실패로 확인했고, 구현 후 focused 테스트,./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:mergeDebugResources :app:compileDebugKotlin :app:ktlintCheck가 모두BUILD SUCCESSFUL로 PASS했다. 실제 화면 직접 조작은 Activity가 내부 진입 경로와 데이터 계정에 의존해 이번 검증에서는 단위/리소스/컴파일/스타일 검증으로 대체했다. -
구현 전 문서 작성 단계에서는 Gradle 검증을 실행하지 않았다.
-
2026-07-12: 커뮤니티 상세 오디오 중앙 버튼 및 유료 게시글 구매 후속 변경을 반영했다. 상세 ViewModel 구매 회귀 테스트, 상세 UI 계약 테스트, 커뮤니티 targeted 테스트, 리소스 병합, Kotlin 컴파일, ktlint, diff whitespace 검증이 모두 통과했다. 최초 병렬 Gradle 실행 중 resource packaging incremental output 충돌성 오류가 한 번 발생했으나 순차 재실행에서 재현되지 않았다.
-
2026-07-08: 추가 review findings 반영 범위를 확정했다. 상세/답글 변경 결과를 상위 커뮤니티 목록과 상세 댓글/답글 카운트에 반영하고, 좋아요 API의
success=false응답에서 낙관적 상태를 롤백하며, 댓글/답글 입력창을 3줄까지 자동 확장되도록 고정 높이를 제거하고, 수정 내용이 없을 때 기존audio_content_comment_no_changetoast를 표시하도록 보강한다. -
2026-07-08: Phase 2.3/3.2 UI 구현 전
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"를 실행해 신규 activity/layout/item/source가 없어compileDebugUnitTestKotlinRED 실패를 확인했다. -
2026-07-08: Phase 2.3/3.2 UI 구현 후 동일 targeted 테스트를 재실행해 48개 테스트 PASS를 확인했다. Robolectric inflate로 상세/답글 layout의 title back/content/input bar 및 item layout 계약을 확인했고, source 검사로 AppDI/manifest/ViewModel binding/popup menu/comment hidden/newIntent 계약을 확인했다.
-
2026-07-08: review-work 차단 이슈 대응으로 Phase 5 테스트를 보강했다. RED는
CreatorChannelCommunityDetailViewModel.modifyComment/deleteComment미구현 컴파일 오류로 확인했고, GREEN은 community targeted 테스트와 CreatorChannelActivity source 테스트, resources merge, Kotlin compile, ktlint, diff whitespace 검증 PASS로 확인했다. -
2026-07-08: 최종 확인으로
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest",./gradlew :app:mergeDebugResources,./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck를 재실행해 모두BUILD SUCCESSFUL을 확인했다.git diff --check는 출력 없이 통과했다. -
2026-07-08: review-work 재검증에서 발견된 추가 차단 이슈를 반영했다. 상세 댓글 추가 로딩은 실제 스크롤 컨테이너인
NestedScrollView기준으로 감지하도록 수정하고, 유료 미구매 잠금 게시글은 작성자가 아닌 경우 이미지/오디오 URL을 UI model에서 제거해 raw media URL 노출을 막았다. 댓글/답글 더보기는 레거시와 동일하게 작성자 또는 채널 크리에이터에게만 노출하며, 답글 화면 부모 댓글에도 수정/삭제 메뉴를 연결했다. PRD의 상세 응답comments표현은 별도 댓글 endpoint 첫 페이지 조회 계약으로 정리했다. -
2026-07-08: 추가 차단 이슈 수정 후
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest",./gradlew :app:mergeDebugResources,./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck를 재실행해 모두BUILD SUCCESSFUL을 확인했다.git diff --check는 출력 없이 통과했다. -
2026-07-08: 부모 댓글 수정/삭제 후 답글 화면의 부모 댓글 영역과 상세 댓글 목록이 stale 상태로 남을 수 있다는 review-work 지적을 반영했다. 부모 댓글 수정 성공 시 답글 ViewModel의
parentComment상태를 즉시 갱신하고, 부모 댓글 변경/삭제 이벤트를 Activity result로 상세 화면에 전달해 상세를 재조회하도록 수정했다. 삭제 성공 시 답글 화면은RESULT_OK반환 후 종료한다. 회귀 테스트로 부모 댓글 수정 상태 갱신, 삭제 이벤트, ActivityResult source 계약을 추가하고./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"PASS를 확인했다. -
2026-07-08: 추가 review findings 4건을 반영했다. 상세 진입은
ActivityResultLauncher로 변경해 상세의 댓글/좋아요/수정/삭제 및 답글 화면 변경 결과가 상위 커뮤니티 목록 refresh로 전파되도록 했고, 좋아요 API의success=false응답은 낙관적 상태를 이전 좋아요 상태/개수로 롤백하도록 수정했다. 댓글/답글 작성·수정·삭제 후에는 상세/답글을 서버 재조회해 댓글·답글 count를 동기화하고, 댓글/답글 입력창은 고정 높이를 제거해 3줄까지 자동 확장되도록wrap_content/minHeight=40dp/maxLines=3/vertical scrollbar 계약을 맞췄다. 수정 내용이 원문과 같으면audio_content_comment_no_changetoast 후 API 호출을 막도록 상세/답글 수정 dialog를 보강했다. 검증으로./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest",./gradlew :app:mergeDebugResources,./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck가 모두BUILD SUCCESSFUL임을 확인했고,git diff --check는 출력 없이 통과했다. 최초 병렬 Gradle 실행 중 KSP 증분 캐시 손상/동시 접근 오류가 발생했으나app/build/kspCaches/debug생성 캐시 제거 후 순차 재실행으로 통과했다. -
2026-07-08: review-work 재검증에서 답글 화면 변경 결과가 상세 화면 재조회까지만 반영되고 상위
CreatorChannelActivity목록 refresh로 재전파되지 않는 차단 이슈가 확인되어 수정했다.CreatorChannelCommunityDetailActivity의replyLauncher에서 답글 화면RESULT_OK수신 시setResult(Activity.RESULT_OK)를 먼저 호출한 뒤loadDetail(postId)를 수행하도록 변경했고, source contract test가 이 순서를 검증하도록 보강했다. 검증으로./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest",./gradlew :app:mergeDebugResources,./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck가 모두BUILD SUCCESSFUL임을 확인했고,git diff --check는 출력 없이 통과했다. -
2026-07-08: 추가 review findings 3건을 반영했다. 커뮤니티 게시물 상세 진입 전
SharedPreferenceManager.token.isBlank()이면 기존showLoginActivity()로 이동하고 상세 Activity launch를 중단하도록 보강했다. 댓글/답글 작성·수정·삭제 실패 시 v2CreatorChannelEvent<ToastMessage>기반 toast 이벤트를 노출해 API 메시지 또는common_error_unknown을 표시하도록 상세/답글 ViewModel과 Activity를 수정했다. 상세 댓글 목록 상단에는댓글 {commentCount}헤더를 추가하고, 답글 화면 부모 댓글에서는 reply/heart count reaction row와 latest reply block을 숨겨 Figma/PRD 정적 UI와 맞췄다. 회귀 테스트로 로그인 gate source 계약, 실패 toast 이벤트 consume 계약, 댓글 헤더/부모 reaction row source·layout 계약을 추가했으며 targeted unit test는BUILD SUCCESSFUL을 확인했다. -
2026-07-08: 리뷰 결과 3건과 서버 응답 계약 불일치를 반영했다. 상세 응답 내부
comments를 최초 댓글 목록으로 사용하도록 바꾸고, 댓글/최신 답글/답글 응답 DTO를 서버 계약의writer*,content,commentId필드명에 맞췄다. 상세 댓글/답글 pagination에는 generation guard를 추가해 새로고침 후 stale page 응답이 현재 목록을 덮지 않게 했고, 댓글/답글/부모 댓글 수정 blank 입력은screen_creator_community_write_content_hinttoast 후 API를 호출하지 않도록 했다. UI 계약 테스트는 layout 속성/source 문자열 직접 검증을 제거해 필수 view/resource 등록 중심으로 축소했다. 검증으로./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest",./gradlew :app:mergeDebugResources,./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck가 모두BUILD SUCCESSFUL임을 확인했다.git diff --check,git diff HEAD --check는 출력 없이 통과했다.:app:mergeDebugResources는 최초 sandbox에서~/.gradlelock 파일 권한 문제로 실패했으나, 동일 명령을 권한 상승 재실행해 통과했다. -
2026-07-08: 코드 리뷰에서 발견된 채널 크리에이터 권한 매핑 문제를 반영했다. 상세 응답 embedded
comments를 최초 UI state로 매핑할 때 아직Contentstate가 없어isCreatorOwner가 false로 고정되던 문제를, 상세 응답의creatorId또는 현재 post의creatorId를 기준으로 명시 전달하도록 수정했다. 회귀 테스트는 수정 전 RED 실패 후 수정 후 PASS를 확인했다. 최종 검증으로./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest",./gradlew :app:mergeDebugResources,./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck가 모두BUILD SUCCESSFUL임을 확인했다.git diff --check,git diff HEAD --check는 출력 없이 통과했다.:app:mergeDebugResources는 최초 sandbox에서~/.gradlelock 파일 권한 문제로 실패했으나, 동일 명령을 권한 상승 재실행해 통과했다. -
2026-07-08: 리뷰 결과 추가 반영을 완료했다. 댓글 불가 화면은 댓글 목록/header/input bar만 숨기고 별도 안내 문구 view를 제거했다. 댓글/답글 item에서 Figma에 없는 reaction row를 제거했다. 유료 미구매 상세는 raw image/audio URL을 UI model에서 계속 제거하면서
showPaywall로 중앙 lock+가격 paywall을 표시하도록 수정했다. 상대시간은 기존 공통formatUtcRelativeTimeText를 보강해 epoch seconds, ISO offset, 6자리 fraction, 작성 직후 서버/단말 시계 차이를 처리하고, 답글 화면 부모 댓글에는 원본createdAtUtc를 전달해 동일 포맷터 기준으로 표시되게 했다. 검증으로./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.common.RelativeTimeFormatterTest",./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest",./gradlew :app:mergeDebugResources,./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck가 모두BUILD SUCCESSFUL임을 확인했다.git diff --check,git diff HEAD --check는 출력 없이 통과했다.:app:mergeDebugResources는 최초 sandbox에서~/.gradlelock 파일 권한 문제로 실패했으나, 동일 명령을 권한 상승 재실행해 통과했다. -
2026-07-09: 사용자 후속 요청 4건을 반영했다. 상세/답글 titlebar의
커뮤니티,답글문구를 제거했고, 댓글/답글 더보기 메뉴 문구를수정하기,삭제하기로 변경했다. v2 패키지 내부 삭제 확인은V2ModalDialog로 교체했으며, 수정은 Dialog 없이 하단 입력창 수정 모드로 전환되도록 구현했다. 수정 모드에서는 send 버튼으로 수정 API를 호출하고, send 버튼 오른쪽 X 버튼으로 수정 취소가 가능하다. 검증으로./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*",./gradlew :app:compileDebugKotlin,./gradlew :app:ktlintCheck,git diff --check가 모두 통과했다.ktlintCheck의.editorconfig disabled_rulesdeprecation 경고는 기존 설정 경고로 남아 있다. -
2026-07-09: 댓글/답글 더보기 메뉴 font 후속 요청을 반영했다.
PopupMenu는 메뉴 item font를 직접 지정하기 어려워, 댓글/답글 더보기만PopupWindow기반CreatorChannelCommunityMorePopup으로 교체하고 메뉴 TextView에android:fontFamily="@font/regular"를 명시했다. 검증 명령은 Phase 10.1 기록에 누적한다. -
2026-07-09: 수정하기 터치 시 키보드가 바로 올라오고, 입력/수정 API success 후 키보드가 내려가야 한다는 후속 요청을 반영했다. 상세/답글 Activity에서 수정 모드 진입 시 입력창 focus와 IME show를 수행하고, 작성/수정 성공 이벤트에서 IME hide와 focus clear를 수행한다. 검증 명령은 Phase 11.1 기록에 누적한다.
-
2026-07-12: 커뮤니티 상세 상단 게시글 영역의 rounded card 배경 제거와 게시글-댓글/댓글 사이 1dp border 후속 요청을 반영했다. 검증 명령은 Phase 12.1 기록에 누적한다.