# 크리에이터 채널 차단 후 이탈 구현 계획/TASK > **For agentic workers:** 각 단계는 체크박스(`- [ ]`)로 추적하고, 완료 즉시 `- [x]`로 갱신한다. 구현 범위 변경이 생기면 이 문서를 먼저 수정한 뒤 코드에 반영한다. **Goal:** 차단 성공 후 사용자가 현재 크리에이터 채널에 머물지 않고 이전 화면 또는 `MainV2Activity` 홈 fallback으로 이동한다. **Architecture:** `CreatorChannelHomeViewModel`은 기존 차단 API 성공 흐름에서 one-shot 성공 이벤트를 추가로 emit한다. `CreatorChannelHomeFragment`는 이벤트를 consume해 `Host` callback으로 넘기고, `CreatorChannelActivity`는 `isTaskRoot` 여부에 따라 `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`. - Produces: `blockSuccessLiveData: LiveData>`. - [x] **RED:** 기존 `차단 성공은 block API를 호출하고 차단 완료 토스트를 emit한다` test에 `blockSuccessLiveData` event 검증을 추가한다. 실패 케이스 test에는 `ApiResponse.success == false`일 때 `blockSuccessLiveData.value == null`을 검증한다. - [x] **RED 확인:** 아래 focused test를 실행해 `blockSuccessLiveData` 미정의 또는 event 미발행 assertion 실패를 확인한다. ```bash ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest" --no-parallel --no-daemon -Pkotlin.incremental=false ``` - [x] **GREEN:** `CreatorChannelHomeViewModel`에 `MutableLiveData>` 기반 `blockSuccessLiveData`를 추가하고, `blockUser()` 성공 분기에서 기존 `creator_channel_block_success` toast emit 후 `CreatorChannelEvent(Unit)`을 emit한다. 실패·예외 분기에서는 emit하지 않는다. - [x] **GREEN 확인:** 같은 focused test를 다시 실행해 성공을 확인한다. - [x] **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()`. - [x] **RED:** `CreatorChannelActivitySourceTest`에 source contract test를 추가한다. 검증 조건은 `CreatorChannelHomeFragment`가 `blockSuccessLiveData.observe`와 `event.consume()?.let { host.onCreatorChannelBlockSucceeded() }` 흐름을 갖는지, `CreatorChannelActivity`가 `onCreatorChannelBlockSucceeded()`를 구현하는지, 구현 내부에서 `isTaskRoot`, `MainV2Activity::class.java`, `finish()`를 사용하는지 확인한다. 또한 `showUserBlockDialog()` 구간에는 `homeActionDelegate?.blockUser()`만 있고 직접 `finish()`나 `MainV2Activity` 이동이 없음을 확인한다. - [x] **RED 확인:** 아래 focused test를 실행해 observer, host callback, fallback 구현 부재로 인한 assertion 실패를 확인한다. ```bash ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" --no-parallel --no-daemon -Pkotlin.incremental=false ``` - [x] **GREEN:** `CreatorChannelHomeFragment.observeViewModel()`에서 `blockSuccessLiveData`를 observe하고 consume 후 host callback을 호출한다. `CreatorChannelHomeFragment.Host`에 `onCreatorChannelBlockSucceeded()`를 추가한다. `CreatorChannelActivity`는 `MainV2Activity` import를 추가하고, `onCreatorChannelBlockSucceeded()`에서 `isTaskRoot`이면 `Intent(this, MainV2Activity::class.java)`를 `startActivity`한 뒤 `finish()`를 호출한다. `isTaskRoot`가 아니면 `finish()`만 호출한다. - [x] **GREEN 확인:** 같은 focused source test를 다시 실행해 성공을 확인한다. - [x] **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개가 모두 통과했다. ### 완료 조건 - [x] `P1-T1`, `P1-T2`의 체크박스와 완료 증거가 모두 충족됐다. - [x] `CCB-001~005`가 구현 또는 명시 검증으로 추적된다. - [x] API 성공 전 navigation이 발생하지 않는다는 source contract가 남아 있다. - [x] task root fallback 대상이 `MainV2Activity`임을 source contract가 검증한다. ### 검증 방법 #### Phase 1 Gate **Goal 실행 `P1-GATE`:** 차단 성공 후 채널 이탈과 홈 fallback 동작을 최종 판정한다. - **시작 조건:** `P1-T1`, `P1-T2` 완료. - **완료 증거:** 아래 자동 검증 통과와 Progress 기록. - **범위 밖:** Gate 통과를 위한 test 삭제·완화, unrelated refactor, instrumentation test 추가. ```bash ./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에 구분 기록한다. - [x] ViewModel과 Activity source focused test 통합 실행이 통과했다. - [x] `compileDebugKotlin`과 `ktlintCheck`가 통과했다. - [x] `git diff --check`와 `git diff --cached --check` 결과 출력이 없었다. - [x] 전체 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 추가 | ```text 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=false` — `BUILD 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=false` — `BUILD SUCCESSFUL`. - `./gradlew :app:testDebugUnitTest --no-parallel --no-daemon -Pkotlin.incremental=false` — `BUILD 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가 통과했다.