Files
sodalive-android/docs/20260708_커뮤니티_게시물_상세_댓글_답글/plan-task.md

34 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.md
    • docs/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:ktlintCheck
    • git 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=20CreatorChannelCommunityCommentsResponse
      • 필드: 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=20CreatorChannelCommunityRepliesResponse
  • 쓰기/수정/삭제/좋아요(기존 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.
  • 수정: 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-ja strings(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
    • 검증: CreatorChannelCommunityDetailViewModelTest PASS.
    • 검증 기록(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): CreatorChannelCommunityFragmentLayoutTestCreatorChannelActivitySourceTest에 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 테스트로 검증했다.
  • 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): CreatorChannelCommunityPostDetailResponsecomments를 추가하고, CreatorChannelCommunityCommentsResponse.commentCount, 댓글/답글의 writerId, writerProfileImageUrl, writerNickname, content 계약을 반영했다. 상세 최초 댓글 목록은 상세 응답의 embedded comments에서 사용하고, 답글 수정/삭제 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_hint toast 이벤트를 노출하고 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로 매핑할 때 Content state가 아직 없어 isCreatorOwner가 false로 고정되는 문제를 수정한다.
    • 검증: 채널 크리에이터가 타인 댓글/최신 답글에 대해 삭제 메뉴 권한을 갖는 ViewModel 회귀 테스트 PASS.
    • 검증 기록(2026-07-08): CreatorChannelCommunityDetailViewModelTest에 채널 작성자가 상세 embedded 타인 댓글의 삭제 메뉴 권한을 갖는 회귀 테스트를 추가하고, 수정 전 AssertionError RED 실패를 확인했다. 이후 embedded 댓글은 상세 응답의 creatorId, 추가 페이지 댓글은 현재 post의 creatorId 기준으로 isCreatorOwner를 명시 전달하도록 수정해 동일 테스트 PASS를 확인했다.

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.xmlitem_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_paywalltv_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로 확인했다.

Verification Log

  • 구현 전 문서 작성 단계에서는 Gradle 검증을 실행하지 않았다.
  • 2026-07-08: 추가 review findings 반영 범위를 확정했다. 상세/답글 변경 결과를 상위 커뮤니티 목록과 상세 댓글/답글 카운트에 반영하고, 좋아요 API의 success=false 응답에서 낙관적 상태를 롤백하며, 댓글/답글 입력창을 3줄까지 자동 확장되도록 고정 높이를 제거하고, 수정 내용이 없을 때 기존 audio_content_comment_no_change toast를 표시하도록 보강한다.
  • 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가 없어 compileDebugUnitTestKotlin RED 실패를 확인했다.
  • 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_change toast 후 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로 재전파되지 않는 차단 이슈가 확인되어 수정했다. CreatorChannelCommunityDetailActivityreplyLauncher에서 답글 화면 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를 중단하도록 보강했다. 댓글/답글 작성·수정·삭제 실패 시 v2 CreatorChannelEvent<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_hint toast 후 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에서 ~/.gradle lock 파일 권한 문제로 실패했으나, 동일 명령을 권한 상승 재실행해 통과했다.
  • 2026-07-08: 코드 리뷰에서 발견된 채널 크리에이터 권한 매핑 문제를 반영했다. 상세 응답 embedded comments를 최초 UI state로 매핑할 때 아직 Content state가 없어 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에서 ~/.gradle lock 파일 권한 문제로 실패했으나, 동일 명령을 권한 상승 재실행해 통과했다.
  • 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에서 ~/.gradle lock 파일 권한 문제로 실패했으나, 동일 명령을 권한 상승 재실행해 통과했다.