Files
sodalive-android/docs/20260814_크리에이터_채널_차단_후_이탈/plan-task.md
T

17 KiB

크리에이터 채널 차단 후 이탈 구현 계획/TASK

For agentic workers: 각 단계는 체크박스(- [ ])로 추적하고, 완료 즉시 - [x]로 갱신한다. 구현 범위 변경이 생기면 이 문서를 먼저 수정한 뒤 코드에 반영한다.

Goal: 차단 성공 후 사용자가 현재 크리에이터 채널에 머물지 않고 이전 화면 또는 MainV2Activity 홈 fallback으로 이동한다.

Architecture: CreatorChannelHomeViewModel은 기존 차단 API 성공 흐름에서 one-shot 성공 이벤트를 추가로 emit한다. CreatorChannelHomeFragment는 이벤트를 consume해 Host callback으로 넘기고, CreatorChannelActivityisTaskRoot 여부에 따라 finish() 또는 MainV2Activity fallback 후 finish()를 수행한다.

Tech Stack: Kotlin, AndroidX LiveData, RxJava3, JUnit4 local unit test, source contract test.


전제와 성공 기준

  • PRD: docs/20260814_크리에이터_채널_차단_후_이탈/prd.md
  • 구현은 차단 API 성공 후에만 화면 이탈을 수행한다.
  • 기존 차단 확인 모달과 성공/실패 toast는 유지한다.
  • 홈 fallback Activity는 kr.co.vividnext.sodalive.v2.main.MainV2Activity다.
  • 테스트 범위는 app/src/test local unit/source contract test로 한정한다.
  • 사용자가 명시적으로 요청하지 않았으므로 app/src/androidTest, connectedDebugAndroidTest, 기기·에뮬레이터 조작, 스크린샷 검증은 포함하지 않는다.

파일 구조

  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModel.kt
    • 차단 성공 one-shot event를 제공한다.
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeFragment.kt
    • 차단 성공 event를 observe/consume하고 host callback으로 전달한다.
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt
    • host callback을 구현하고 isTaskRoot fallback을 처리한다.
  • Modify: app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModelTest.kt
    • 차단 성공/실패 event contract를 검증한다.
  • Modify: app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt
    • Fragment/Activity wiring과 MainV2Activity fallback source contract를 검증한다.

Phase 1: 차단 성공 후 채널 이탈

Phase 결과: 사용자가 크리에이터 채널에서 현재 크리에이터 차단에 성공하면 현재 채널에서 빠져나가고, 이전 화면이 없으면 MainV2Activity로 이동한다.

선행조건: docs/20260814_크리에이터_채널_차단_후_이탈/prd.md 확정.

Phase 완료 조건: P1-T1, P1-T2, P1-GATE 완료와 검증 기록 누적.

구현 항목

Task 1.1 차단 성공 이벤트 추가

Goal 실행 P1-T1: CreatorChannelHomeViewModel.blockUser()가 API 성공 시 기존 성공 toast와 함께 차단 성공 event를 emit한다.

  • 시작 조건: CCB-001, CCB-005 확정.
  • 완료 증거: RED/GREEN 체크박스 전체 완료, focused CreatorChannelHomeViewModelTest 통과.
  • 범위 밖: Fragment/Activity navigation wiring은 P1-T2에서 처리한다.

Files:

  • Modify: app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModelTest.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModel.kt

Interfaces:

  • Consumes: 기존 CreatorChannelHomeUiState.Content, CreatorChannelRepository.blockUser(userId, token), CreatorChannelEvent<T>.

  • Produces: blockSuccessLiveData: LiveData<CreatorChannelEvent<Unit>>.

  • RED: 기존 차단 성공은 block API를 호출하고 차단 완료 토스트를 emit한다 test에 blockSuccessLiveData event 검증을 추가한다. 실패 케이스 test에는 ApiResponse.success == false일 때 blockSuccessLiveData.value == null을 검증한다.

  • RED 확인: 아래 focused test를 실행해 blockSuccessLiveData 미정의 또는 event 미발행 assertion 실패를 확인한다.

./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest" --no-parallel --no-daemon -Pkotlin.incremental=false
  • GREEN: CreatorChannelHomeViewModelMutableLiveData<CreatorChannelEvent<Unit>> 기반 blockSuccessLiveData를 추가하고, blockUser() 성공 분기에서 기존 creator_channel_block_success toast emit 후 CreatorChannelEvent(Unit)을 emit한다. 실패·예외 분기에서는 emit하지 않는다.
  • GREEN 확인: 같은 focused test를 다시 실행해 성공을 확인한다.
  • REFACTOR: event naming과 observe 순서를 기존 toastLiveData, chatRoomIdLiveData 스타일과 맞추고 focused test를 재실행해 결과를 이 Task 아래 검증 기록에 남긴다.

검증 기록:

  • 2026-08-14 RED: CreatorChannelHomeViewModelTest 실행 시 blockSuccessLiveData 미정의로 compileDebugUnitTestKotlin이 실패했다.
  • 2026-08-14 GREEN: blockSuccessLiveData와 성공 분기 emit을 최소 추가한 뒤 같은 focused test가 BUILD SUCCESSFUL로 통과했다. 성공 event는 한 번만 consume되고, API 실패·예외에서는 emit되지 않음을 확인했다.

Task 1.2 Fragment/Activity 이탈 연결

Goal 실행 P1-T2: 차단 성공 event를 CreatorChannelActivity까지 전달하고, 이전 화면 또는 MainV2Activity fallback으로 이동한다.

  • 시작 조건: P1-T1 완료.
  • 완료 증거: RED/GREEN 체크박스 전체 완료, focused CreatorChannelActivitySourceTest 통과.
  • 범위 밖: 차단 API 호출 방식, 기존 modal UI, MainV2Activity 내부 동작 변경.

Files:

  • Modify: app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeFragment.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt

Interfaces:

  • Consumes: CreatorChannelHomeViewModel.blockSuccessLiveData.

  • Produces: CreatorChannelHomeFragment.Host.onCreatorChannelBlockSucceeded().

  • RED: CreatorChannelActivitySourceTest에 source contract test를 추가한다. 검증 조건은 CreatorChannelHomeFragmentblockSuccessLiveData.observeevent.consume()?.let { host.onCreatorChannelBlockSucceeded() } 흐름을 갖는지, CreatorChannelActivityonCreatorChannelBlockSucceeded()를 구현하는지, 구현 내부에서 isTaskRoot, MainV2Activity::class.java, finish()를 사용하는지 확인한다. 또한 showUserBlockDialog() 구간에는 homeActionDelegate?.blockUser()만 있고 직접 finish()MainV2Activity 이동이 없음을 확인한다.

  • RED 확인: 아래 focused test를 실행해 observer, host callback, fallback 구현 부재로 인한 assertion 실패를 확인한다.

./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" --no-parallel --no-daemon -Pkotlin.incremental=false
  • GREEN: CreatorChannelHomeFragment.observeViewModel()에서 blockSuccessLiveData를 observe하고 consume 후 host callback을 호출한다. CreatorChannelHomeFragment.HostonCreatorChannelBlockSucceeded()를 추가한다. CreatorChannelActivityMainV2Activity import를 추가하고, onCreatorChannelBlockSucceeded()에서 isTaskRoot이면 Intent(this, MainV2Activity::class.java)startActivity한 뒤 finish()를 호출한다. isTaskRoot가 아니면 finish()만 호출한다.
  • GREEN 확인: 같은 focused source test를 다시 실행해 성공을 확인한다.
  • REFACTOR: 추가한 source contract가 과도하게 넓지 않은지 확인하고, 기존 CreatorChannelActivitySourceTest.sourceSection() helper를 재사용한다. focused test를 재실행해 결과를 이 Task 아래 검증 기록에 남긴다.

검증 기록:

  • 2026-08-14 RED: CreatorChannelActivitySourceTest 100개 중 신규 차단 이탈 contract만 observer 부재 assertion으로 실패했다.
  • 2026-08-14 GREEN: Fragment observer/Host callback과 Activity isTaskRoot 분기를 최소 추가한 뒤 같은 source test 100개가 모두 통과했다.

완료 조건

  • P1-T1, P1-T2의 체크박스와 완료 증거가 모두 충족됐다.
  • CCB-001~005가 구현 또는 명시 검증으로 추적된다.
  • API 성공 전 navigation이 발생하지 않는다는 source contract가 남아 있다.
  • task root fallback 대상이 MainV2Activity임을 source contract가 검증한다.

검증 방법

Phase 1 Gate

Goal 실행 P1-GATE: 차단 성공 후 채널 이탈과 홈 fallback 동작을 최종 판정한다.

  • 시작 조건: P1-T1, P1-T2 완료.
  • 완료 증거: 아래 자동 검증 통과와 Progress 기록.
  • 범위 밖: Gate 통과를 위한 test 삭제·완화, unrelated refactor, instrumentation test 추가.
./gradlew :app:testDebugUnitTest \
  --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest" \
  --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" \
  --no-parallel --no-daemon -Pkotlin.incremental=false

./gradlew :app:compileDebugKotlin --no-parallel --no-daemon -Pkotlin.incremental=false

./gradlew :app:ktlintCheck --no-parallel --no-daemon

git diff --check

Expected: focused tests와 compile은 BUILD SUCCESSFUL, git diff --check는 출력 없음. ktlintCheck가 기존 전역 위반으로 실패하면 이번 변경 파일 포함 여부를 확인해 Progress에 구분 기록한다.

  • ViewModel과 Activity source focused test 통합 실행이 통과했다.
  • compileDebugKotlinktlintCheck가 통과했다.
  • git diff --checkgit diff --cached --check 결과 출력이 없었다.
  • 전체 local unit suite의 범위 밖 실패를 분리하고 아래 Progress에 기록했다.

실행 순서와 의존성

순서 Goal 선행조건 병행 가능 차단 시 다음 행동
1 P1-T1 PRD 확정 아니요 ViewModel event contract 재검토
2 P1-T2 P1-T1 아니요 Host callback 또는 Activity fallback contract 재검토
3 P1-GATE P1-T1, P1-T2 아니요 실패 소유 Task의 회귀 수정 Task 추가
P1-T1 -> P1-T2 -> P1-GATE

변경 금지 항목

  • 차단 API request/response 계약을 변경하지 않는다.
  • MainV2Activity 내부 구현을 변경하지 않는다.
  • API 성공 전 CreatorChannelActivity를 종료하거나 홈으로 이동하지 않는다.
  • 기존 modal UI와 string을 변경하지 않는다.
  • app/src/androidTest, 기기·에뮬레이터 UI 조작, 스크린샷 QA를 추가하지 않는다.
  • 관련 없는 creator channel tab, community, fan talk, live routing 코드를 리팩터링하지 않는다.

의사결정 및 중단 규칙

  • 실패 event 또는 예외 event에서도 화면 이탈이 필요하다는 요구가 생기면 PRD Decision Log와 이 문서 범위를 먼저 갱신한다.
  • MainV2Activity fallback에 flag 정책이 필요하다는 증거가 나오면 source/test로 먼저 실패를 고정하고, 기존 홈 진입점의 intent flag 관례를 확인한 뒤 최소 변경한다.
  • 검증 중 기존 전역 test/ktlint 실패가 나오면 이번 변경 파일 포함 여부를 분리해 기록하고, 범위 밖 실패는 임의 수정하지 않는다.

Progress

기존 기록을 삭제하거나 덮어쓰지 않고 실제 실행 결과를 차수별로 누적한다.

문서 작성 — 2026-08-14

  • 상태: 완료
  • 무엇을: PRD와 구현 계획/TASK 문서를 생성했다. production code와 test code는 변경하지 않았다.
  • 왜: 사용자가 “문서만 생성 또는 수정하고 아직 구현은 하지 않는다”고 지시했다.
  • 어떻게:
    • docs/sample/sample-prd.md — 샘플 구조 확인.
    • docs/sample/sample-plan-task.md — TDD Task 구조 확인.
    • docs/agent-guides/work-plan-docs.md — 신규 문서 배치와 검증 기록 규칙 확인.
    • rg -n "차단|block|CreatorChannel|크리에이터 채널|MainV2Activity|뒤로가기" "docs" — 기존 관련 문서 범위 확인.
  • 남은 항목: P1-T1, P1-T2, P1-GATE 구현과 검증.
  • 다음 행동: 사용자가 구현 진행을 승인하면 P1-T1 RED 단계부터 시작한다.

P1-GATE 1차 실행 — 2026-08-14

  • 상태: 완료
  • 무엇을: P1-T1, P1-T2를 RED/GREEN으로 구현하고 focused test, compile, ktlint, diff 검증을 완료했다.
  • 왜: 차단 성공 후 현재 크리에이터 채널에서 이탈하고 task root에서는 MainV2Activity로 fallback해야 한다.
  • 어떻게:
    • ViewModel RED — blockSuccessLiveData 미정의 compile failure 확인.
    • ViewModel GREEN — focused CreatorChannelHomeViewModelTest BUILD SUCCESSFUL.
    • Activity RED — source test 100개 중 신규 차단 이탈 contract 1건 실패 확인.
    • Activity GREEN — source test 100개 전체 통과.
    • focused 통합 test — BUILD SUCCESSFUL.
    • ./gradlew :app:compileDebugKotlin --no-parallel --no-daemon -Pkotlin.incremental=falseBUILD SUCCESSFUL.
    • ./gradlew :app:ktlintCheck --no-parallel --no-daemon — 기존 disabled_rules deprecation warning만 출력하고 BUILD SUCCESSFUL.
    • git diff --check, git diff --cached --check — 출력 없음.
    • 전체 testDebugUnitTest — 1,221개 중 범위 밖 CreatorChannelFanTalkFragmentLayoutTest 1건 실패. 일본어 리소스는 팬레터 문구이나 테스트는 기존 응원 문구를 기대하며, 관련 파일은 현재 diff에 없다.
  • 남은 항목: Phase 1 리뷰 blocker 해소 확인.
  • 다음 행동: 문서 완료 상태를 반영한 diff를 재리뷰한다.

P1-GATE 재리뷰 — 2026-08-14

  • 상태: 완료
  • 무엇을: PRD와 계획 문서의 체크박스·검증 기록을 현재 구현 증거와 재대조했다.
  • 왜: 초기 리뷰의 유일한 blocker였던 문서 완료 상태 누락을 해소하기 위해서다.
  • 어떻게:
    • Oracle 재리뷰 — 이전 blocker 해소 및 코드 신규 blocker 없음, 최종 APPROVE.
    • rg -n -- "- \\[ \\]" prd.md plan-task.md — 실제 미완료 체크박스 없음. 템플릿 안내문에 포함된 리터럴 표기만 검색됨.
    • git diff --check, git diff --cached --check — 출력 없음.
  • 남은 항목: 없음.
  • 다음 행동: 완료 결과를 보고한다.

범위 밖 테스트 정정 — 2026-08-14

  • 상태: 완료
  • 무엇을: CreatorChannelFanTalkFragmentLayoutTest의 일본어 empty message 기대값을 현재 values-ja/strings.xml과 맞췄다.
  • 왜: 전체 unit suite에서 남아 있던 유일한 실패가 테스트 기대값의 오래된 “응원” 문구 때문이었고, 사용자가 테스트 수정 지시를 했다.
  • 어떻게:
    • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.fantalk.CreatorChannelFanTalkFragmentLayoutTest" --no-parallel --no-daemon -Pkotlin.incremental=falseBUILD SUCCESSFUL.
    • ./gradlew :app:testDebugUnitTest --no-parallel --no-daemon -Pkotlin.incremental=falseBUILD SUCCESSFUL.
  • 남은 항목: 없음.
  • 다음 행동: 완료 결과를 보고한다.

Decision Log

날짜 ID 상태 결정 근거 영향 Goal/문서
2026-08-14 DEC-001 확정 차단 성공 후 현재 크리에이터 채널에서 이탈한다. 사용자 요청과 후속 확인 P1-T1, P1-T2, PRD CCB-001~005
2026-08-14 DEC-002 확정 이전 화면이 없으면 홈인 MainV2Activity로 fallback 이동한다. 사용자 명시 P1-T2, PRD CCB-004
2026-08-14 DEC-003 확정 이번 턴에서는 문서만 생성하고 구현하지 않는다. 사용자 명시 이 문서 Progress

발견된 문제

ID 심각도 상태 발견 내용 영향 Goal 처리 계획
ISSUE-001 Medium 확정 현재 차단 성공 흐름은 성공 토스트만 emit하고 채널 화면에 머문다. P1-T1, P1-T2 구현 승인 후 RED test부터 수정한다.

Verification Log

  • 2026-08-14: 문서 작성만 수행했다. 구현 파일과 테스트 파일은 수정하지 않았으므로 Gradle 테스트·compile은 실행하지 않았다. 문서 샘플과 작업 문서 규칙, 기존 관련 문서 검색 결과를 기준으로 새 작업 디렉터리를 생성했다.
  • 2026-08-14: P1-T1, P1-T2를 RED/GREEN으로 완료했다. focused test 통합 실행, compileDebugKotlin, ktlintCheck, diff check는 통과했다. 전체 unit suite는 현재 diff 밖 일본어 팬레터 문구와 기존 테스트 기대값 불일치 1건으로 실패했으며 해당 실패를 범위 밖 blocker로 분리 기록했다.
  • 2026-08-14: 문서 완료 상태를 갱신한 뒤 Oracle 재리뷰에서 최종 APPROVE를 받았다. PRD와 계획 문서에 실제 미완료 체크박스가 없음을 확인했다.
  • 2026-08-14: 후속 테스트 정정으로 Fan Talk 일본어 empty message 기대값을 현재 리소스와 맞췄고, focused Fan Talk test와 전체 local unit suite가 통과했다.