diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt index 9341253d..71425817 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt @@ -37,6 +37,7 @@ import kr.co.vividnext.sodalive.explorer.profile.creator_community.modify.Creato import kr.co.vividnext.sodalive.explorer.profile.creator_community.modify.ModifyCommunityPostRequest import kr.co.vividnext.sodalive.explorer.profile.creator_community.write.CreatorCommunityWriteActivity import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAllViewActivity +import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListActivity import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.loadUrl import kr.co.vividnext.sodalive.extensions.moneyFormat @@ -224,6 +225,7 @@ class CreatorChannelActivity : private fun setupClickListeners() { binding.ivBack.setOnClickListener { finish() } binding.ivMore.setOnClickListener { onMoreClicked() } + binding.tvFollowerCount.setOnClickListener { onFollowerCountClicked() } binding.layoutFollowCapsule.setOnClickListener { onFollowCapsuleClicked() } binding.ivBell.setOnClickListener { onBellClicked() } binding.ownerFabButton.setOnClickListener { expandOwnerFab() } @@ -251,6 +253,14 @@ class CreatorChannelActivity : } } + private fun onFollowerCountClicked() { + if (currentHeader?.isOwner != true) return + startActivity( + Intent(this, UserFollowerListActivity::class.java) + .putExtra(Constants.EXTRA_USER_ID, creatorId) + ) + } + private fun bindHeader(header: CreatorChannelHeaderUiModel) { binding.tvNickname.text = header.nickname binding.tvTitleNickname.text = header.nickname diff --git a/app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt b/app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt index 7dacbb69..30c37fb5 100644 --- a/app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt +++ b/app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt @@ -372,6 +372,26 @@ class CreatorChannelActivitySourceTest { assertFalse(layout.contains("@+id/tv_follow\"")) } + @Test + fun `내 채널 팔로워 수 클릭 source는 레거시 팔로워 목록으로 이동한다`() { + val source = projectFile( + "app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt" + ).readText() + val clickSource = sourceSection( + source = source, + startMarker = "private fun onFollowerCountClicked()", + endMarker = "private fun bindHeader" + ) + + assertTrue(source.contains("import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListActivity")) + assertTrue(source.contains("binding.tvFollowerCount.setOnClickListener")) + assertTrue(clickSource.contains("if (currentHeader?.isOwner != true) return")) + assertTrue(clickSource.contains("Intent(this, UserFollowerListActivity::class.java)")) + assertTrue(clickSource.contains("putExtra(Constants.EXTRA_USER_ID, creatorId)")) + assertFalse(clickSource.contains("followerCount > 0")) + assertFalse(source.contains("FollowingCreatorActivity::class.java")) + } + @Test fun `creator channel home은 status bar 뒤까지 header를 그리고 자체 inset을 처리한다`() { val baseActivity = projectFile("app/src/main/java/kr/co/vividnext/sodalive/base/BaseActivity.kt").readText() diff --git a/docs/20260803_내_채널_팔로워_목록_연결/plan-task.md b/docs/20260803_내_채널_팔로워_목록_연결/plan-task.md new file mode 100644 index 00000000..c0d7eeb6 --- /dev/null +++ b/docs/20260803_내_채널_팔로워_목록_연결/plan-task.md @@ -0,0 +1,213 @@ +# 내 채널 팔로워 목록 연결 Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:test-driven-development to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 내 채널 상단 `팔로워 n명` 터치 시 기존 레거시 팔로워 목록 화면으로 이동한다. + +**Architecture:** `CreatorChannelActivity`가 이미 헤더와 현재 `creatorId`를 소유하므로 Activity 내부에서 클릭 리스너를 추가한다. 목적지는 레거시 `UserFollowerListActivity`이며 기존 호출 방식처럼 `Constants.EXTRA_USER_ID`만 전달한다. + +**Tech Stack:** Android Kotlin, ViewBinding, JUnit source test, Gradle `:app:testDebugUnitTest`, `:app:assembleDebug`. + +--- + +| 문서 항목 | 내용 | +|---|---| +| 상태 | 구현 완료 | +| 작성일 | `2026-08-03` | +| 요구사항 기준 | `docs/20260803_내_채널_팔로워_목록_연결/prd.md` | +| API 기준 | 기존 레거시 `UserFollowerListActivity` / `ExplorerApi.getFollowerList` | +| 현재 Phase | Phase 1 | +| 현재 활성 Goal | 없음 | + +## 목표 + +내 채널 소유자가 v2 크리에이터 채널의 `팔로워 n명`을 눌러 기존 레거시 팔로워 목록을 확인한다. + +## 현재 상태 + +| Phase | 상태 | 완료 Task | 활성/다음 Goal | 차단 또는 남은 조건 | +|---:|---|---:|---|---| +| 1 | 완료 | `1/1` | 없음 | 직접 Activity 기동은 `not exported` 보안 정책상 adb에서 차단됨 | + +## 범위 + +### 포함 + +- `CreatorChannelActivity`의 `tvFollowerCount` 클릭 연결. +- 기존 `UserFollowerListActivity`에 `Constants.EXTRA_USER_ID = creatorId` 전달. +- owner 전용 동작과 0명 허용 계약을 source test로 고정. + +### 제외 + +- 신규 v2 팔로워/팔로잉 목록 화면. +- 레거시 `UserFollowerListActivity` 및 API 수정. +- 타인 채널의 팔로워 수 클릭 동작. +- 팔로워/팔로잉 문구 변경. + +## 기술적 제약 + +- 레거시 코드는 직접 수정하지 않는다. +- 새 dependency, router, helper abstraction을 추가하지 않는다. +- 기존 `CreatorChannelActivitySourceTest`의 source-test 패턴을 따른다. +- production 구현은 RED 확인 후 진행한다. + +## Phase 1 + +**Phase 결과:** 내 채널 헤더의 `팔로워 n명`이 레거시 팔로워 목록으로 이동한다. + +**선행조건:** PRD 승인 완료. + +**Phase 완료 조건:** `P1-T1`과 `P1-GATE` 완료, 검증 기록 누적. + +### 구현 항목 + +#### Task 1.1 내 채널 팔로워 수 클릭 연결 + +**Goal 실행 `P1-T1`:** `CreatorChannelActivity`에서 owner의 `tvFollowerCount` 클릭을 `UserFollowerListActivity`로 연결한다. + +- **시작 조건:** `FOLLOWER-LINK-001~003` 확정. +- **완료 증거:** RED/GREEN source test, debug build, 수동 검증 기록. +- **범위 밖:** 레거시 화면 수정, 신규 v2 화면 작성, 타인 채널 동작 추가. + +**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/CreatorChannelActivity.kt` + +**Interfaces:** + +- Consumes: `creatorId: Long`, `currentHeader?.isOwner`, `Constants.EXTRA_USER_ID`. +- Produces: `Intent(this, UserFollowerListActivity::class.java).putExtra(Constants.EXTRA_USER_ID, creatorId)` 실행 경로. + +- [x] **RED:** `CreatorChannelActivitySourceTest`에 `내 채널 팔로워 수 클릭 source는 레거시 팔로워 목록으로 이동한다` 테스트를 추가한다. + +```kotlin +@Test +fun `내 채널 팔로워 수 클릭 source는 레거시 팔로워 목록으로 이동한다`() { + val source = projectFile( + "app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt" + ).readText() + val clickSource = sourceSection( + source = source, + startMarker = "private fun onFollowerCountClicked()", + endMarker = "private fun bindHeader" + ) + + assertTrue(source.contains("import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListActivity")) + assertTrue(source.contains("binding.tvFollowerCount.setOnClickListener")) + assertTrue(clickSource.contains("if (currentHeader?.isOwner != true) return")) + assertTrue(clickSource.contains("Intent(this, UserFollowerListActivity::class.java)")) + assertTrue(clickSource.contains("putExtra(Constants.EXTRA_USER_ID, creatorId)")) + assertFalse(clickSource.contains("followerCount > 0")) + assertFalse(source.contains("FollowingCreatorActivity::class.java")) +} +``` + +- [x] **RED 확인:** focused test를 실행해 `start marker not found: private fun onFollowerCountClicked()` 실패를 확인한다. + +```bash +./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest.내 채널 팔로워 수 클릭 source는 레거시 팔로워 목록으로 이동한다" +``` + +- [x] **GREEN:** `CreatorChannelActivity`에 import, click listener, 최소 handler를 추가한다. + +```kotlin +import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListActivity + +binding.tvFollowerCount.setOnClickListener { onFollowerCountClicked() } + +private fun onFollowerCountClicked() { + if (currentHeader?.isOwner != true) return + startActivity( + Intent(this, UserFollowerListActivity::class.java) + .putExtra(Constants.EXTRA_USER_ID, creatorId) + ) +} +``` + +- [x] **GREEN 확인:** 같은 focused test가 성공하는지 확인한다. + +```bash +./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest.내 채널 팔로워 수 클릭 source는 레거시 팔로워 목록으로 이동한다" +``` + +- [x] **REFACTOR:** 불필요한 변경이 없는지 확인하고 아래 직접 영향 회귀를 실행한다. + +```bash +./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" +./gradlew :app:assembleDebug +``` + +### 검증 방법 + +#### Phase 1 Gate + +**Goal 실행 `P1-GATE`:** 문서와 코드가 요구사항을 충족하는지 최종 판정한다. + +```bash +./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest" +./gradlew :app:assembleDebug +``` + +**Expected:** test/build 모두 exit code 0. `CreatorChannelActivity`는 `UserFollowerListActivity`만 참조하고 `FollowingCreatorActivity`를 참조하지 않는다. + +수동 검증: + +- [ ] Android 실행 환경에서 내 채널 진입 후 `팔로워 n명` 터치 시 `UserFollowerListActivity`가 열리는지 확인한다. +- [x] 실행 환경이 없으면 사용 가능한 명령과 부재 사유를 Progress에 기록한다. + +## 실행 순서와 의존성 + +| 순서 | Goal | 선행조건 | 병행 가능 | 차단 시 다음 행동 | +|---:|---|---|---|---| +| 1 | `P1-T1` | PRD 승인 | 아니요 | 테스트 실패 원인을 해당 Task에서 수정 | +| 2 | `P1-GATE` | `P1-T1` 완료 | 아니요 | 실패 소유 Task에 회귀 수정 기록 추가 | + +```text +P1-T1 -> P1-GATE +``` + +## 변경 금지 항목 + +- 레거시 `UserFollowerListActivity`를 수정하지 않는다. +- 새 화면, dependency, router abstraction을 만들지 않는다. +- test를 삭제, skip, 완화하지 않는다. +- 민감정보를 로그, Toast, 문서에 기록하지 않는다. + +## Progress + +기존 기록을 삭제하거나 덮어쓰지 않고 실제 실행 결과를 누적한다. + +### P1-T1 1차 실행 — 2026-08-03 + +- 상태: 완료 +- 무엇을: `CreatorChannelActivity`의 `tvFollowerCount` 클릭을 owner 전용 `UserFollowerListActivity` 진입으로 연결하고 source test를 추가했다. +- 왜: `FOLLOWER-LINK-001~003` 구현 기준 충족. +- 어떻게: + - `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest.내 채널 팔로워 수 클릭 source는 레거시 팔로워 목록으로 이동한다"` — RED 실패, `CreatorChannelActivitySourceTest.kt:2378`에서 `onFollowerCountClicked()` source marker 부재로 실패. + - 같은 focused 명령 재실행 — GREEN 성공, exit code 0. + - `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"` — 성공, exit code 0. + - `./gradlew :app:testDebugUnitTest` — 성공, exit code 0. + - `./gradlew :app:assembleDebug` — 성공, exit code 0. + - `adb install -r "app/build/outputs/apk/debug/app-debug.apk"` — 성공. + - `adb shell am start -W -n kr.co.vividnext.sodalive.debug/kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListActivity --el extra_user_id 1` — `not exported` 보안 정책으로 직접 Activity 기동 차단. + - `adb shell monkey -p kr.co.vividnext.sodalive.debug 1` — debug 앱 실행 이벤트 주입 성공. +- 남은 항목: 로그인된 내 채널 실제 클릭 검증은 인증 상태가 있는 수동 QA 환경에서 확인 필요. +- 다음 행동: 없음. + +## Decision Log + +| 날짜 | ID | 상태 | 결정 | 근거 | 영향 Goal/문서 | +|---|---|---|---|---|---| +| `2026-08-03` | `DEC-001` | 확정 | `UserFollowerListActivity`를 목적지로 사용한다. | 내 채널을 팔로우하는 사용자 목록 요구. | `P1-T1`, `prd.md#15-decision-log` | + +## 발견된 문제 + +| ID | 심각도 | 상태 | 발견 내용 | 영향 Goal | 처리 계획 | +|---|---|---|---|---|---| +| 없음 | Low | 보류 | 현재 발견된 범위 내 문제 없음 | 없음 | 없음 | + +## Verification Log + +- `2026-08-03`: RED/GREEN source test, 직접 영향 source test, 전체 debug unit test, debug build가 모두 성공했다. 연결된 Android 기기에는 APK 설치와 앱 실행 이벤트 주입까지 확인했으나, 레거시 Activity 직접 기동은 `not exported` 보안 정책으로 차단되어 로그인된 내 채널에서의 실제 클릭은 별도 QA 환경에서 확인해야 한다. +- `2026-08-03`: 리뷰 게이트를 수행했고 `reviews/phase1-follower-list-link-review.md`에 확정 발견 사항 없음으로 기록했다. diff --git a/docs/20260803_내_채널_팔로워_목록_연결/prd.md b/docs/20260803_내_채널_팔로워_목록_연결/prd.md new file mode 100644 index 00000000..67b6128c --- /dev/null +++ b/docs/20260803_내_채널_팔로워_목록_연결/prd.md @@ -0,0 +1,119 @@ +# 내 채널 팔로워 목록 연결 PRD + +## 문서 정보 + +| 항목 | 내용 | +|---|---| +| 문서 상태 | 구현 완료 | +| 작성일 | `2026-08-03` | +| 최종 수정일 | `2026-08-03` | +| 대상 제품 | v2 크리에이터 채널 내 채널 팔로워 목록 연결 | +| 작성자·결정권자 | 사용자, Sisyphus | +| 관련 API Contract | 기존 레거시 `UserFollowerListActivity` / `ExplorerApi.getFollowerList` 재사용 | +| 관련 구현 계획 | `docs/20260803_내_채널_팔로워_목록_연결/plan-task.md` | +| 관련 review | `docs/20260803_내_채널_팔로워_목록_연결/reviews/phase1-follower-list-link-review.md` | + +## 1. Overview + +내 채널 소유자는 v2 크리에이터 채널 상단의 `팔로워 n명` 영역을 눌러 자신을 팔로우하는 사용자 목록을 확인할 수 있어야 한다. 신규 v2 화면을 만들지 않고 기존 레거시 `UserFollowerListActivity`를 그대로 연결한다. + +## 2. Problem Statement + +현재 v2 크리에이터 채널은 `팔로워 n명`을 표시하지만 클릭 동작이 없다. 사용자는 내 채널을 팔로우하는 사용자 목록으로 이동하려면 레거시 프로필 경로를 우회해야 한다. + +문제를 해결했다는 판단은 내 채널에서 `팔로워 n명`을 터치했을 때 `Constants.EXTRA_USER_ID`에 현재 `creatorId`가 담긴 `UserFollowerListActivity`가 실행되는 것으로 한다. + +## 3. Goals + +### 3.1 제품 목표 + +- 내 채널 소유자는 채널 상단 `팔로워 n명`에서 팔로워 목록 화면으로 이동할 수 있다. +- 기존 레거시 팔로워 목록 화면과 API 계약을 재사용한다. +- 타인 채널에서는 이번 연결을 노출하지 않는다. + +### 3.2 UX 목표 + +- 기존 문구, 배치, 수치 표시를 변경하지 않는다. +- 팔로워 수가 0명이어도 같은 목록 화면으로 진입한다. +- 별도 안내, 다이얼로그, 신규 화면을 추가하지 않는다. + +## 4. Non-Goals + +- `FollowingCreatorActivity` 연결은 구현하지 않는다. 이 화면은 현재 사용자가 팔로잉한 크리에이터 목록이다. +- 신규 v2 팔로워 목록 화면을 만들지 않는다. +- 레거시 `UserFollowerListActivity`, 레거시 API, 레거시 레이아웃은 수정하지 않는다. +- `팔로워 n명` 문구를 `팔로잉 n명`으로 변경하지 않는다. +- 타인 채널의 팔로워 수 클릭 동작은 추가하지 않는다. + +## 5. Target Users and Permissions + +| 사용자 | 목표 | 주요 작업 | 사용 환경 | +|---|---|---|---| +| 내 채널 소유자 | 내 채널을 팔로우하는 사용자 확인 | `팔로워 n명` 터치 후 목록 조회 | Android 앱 | + +권한 기준은 기존 `CreatorChannelActivity` 진입의 로그인 가드와 `UserFollowerListActivity`의 기존 API 인증을 따른다. + +## 6. 핵심 사용자 흐름 + +1. 사용자가 본인 크리에이터 채널에 진입한다. +2. 채널 상단 헤더의 `팔로워 n명`을 터치한다. +3. 앱은 기존 `UserFollowerListActivity`를 실행하며 `Constants.EXTRA_USER_ID`에 현재 `creatorId`를 전달한다. +4. 레거시 화면이 기존 방식대로 팔로워 목록을 조회하고 표시한다. + +## 7. 정보 구조와 라우팅 + +```text +CreatorChannelActivity + tvFollowerCount click + -> UserFollowerListActivity + extra: Constants.EXTRA_USER_ID = creatorId +``` + +## 8. 기능 요구사항 + +| ID | 상태 | 요구사항 | 수용 기준 | 계약/Goal 연결 | +|---|---|---|---|---| +| `FOLLOWER-LINK-001` | 확정 | 내 채널 소유자가 `팔로워 n명`을 누르면 레거시 팔로워 목록으로 이동한다. | `UserFollowerListActivity` Intent가 생성되고 `Constants.EXTRA_USER_ID`에 현재 `creatorId`가 전달된다. | `P1-T1` | +| `FOLLOWER-LINK-002` | 확정 | 타인 채널에서는 이번 클릭 연결이 동작하지 않는다. | `currentHeader.isOwner != true`이면 목록 Activity를 시작하지 않는다. | `P1-T1` | +| `FOLLOWER-LINK-003` | 확정 | 팔로워 수 0명도 동일하게 목록 화면으로 진입한다. | 클릭 조건에 `followerCount > 0` 제한이 없다. | `P1-T1` | + +## 9. UI/UX Expectations + +- 기존 `tv_follower_count` 표시를 그대로 사용한다. +- 레이아웃, 색상, 문구, 접근성 리소스는 변경하지 않는다. +- 클릭 가능성 외 시각적 embellishment는 추가하지 않는다. + +## 10. API 계약 + +신규 API 계약은 없다. `UserFollowerListActivity`가 기존 `ExplorerApi.getFollowerList(userId, page, size, Authorization)` 흐름을 재사용한다. + +## 11. 보안과 데이터 취급 + +- 전달 값은 기존 내부 식별자 `creatorId`뿐이다. +- 토큰, API URL, 민감정보를 로그나 Toast에 추가로 노출하지 않는다. + +## 12. 성공 기준 + +- [x] `CreatorChannelActivitySourceTest`가 클릭 연결, owner 제한, extra 전달 계약을 검증한다. +- [x] focused unit test가 RED 후 GREEN으로 통과한다. +- [x] `:app:assembleDebug`가 성공한다. +- [x] 실제 Android 표면 검증 또는 실행 환경 부재 사유가 계획 문서에 기록된다. + +## 13. Open Questions + +| ID | 상태 | 결정 필요 사항 | 현재 권고 | 결정 주체 | 결정 기한/시점 | 영향 Goal | +|---|---|---|---|---|---|---| +| 없음 | 확정 | 추가 결정 없음 | 권장 설계 승인됨 | 사용자 | 완료 | `P1-T1` | + +## 14. 요구사항 추적표 + +| 요구사항 범위 | API Contract | 계획 Phase | Goal | 자동 검증 | 수동 검증 | +|---|---|---:|---|---|---| +| `FOLLOWER-LINK-001~003` | 기존 레거시 API 재사용 | 1 | `P1-T1`, `P1-GATE` | `CreatorChannelActivitySourceTest` | 내 채널 `팔로워 n명` 터치 | + +## 15. Decision Log + +| 날짜 | ID | 상태 | 결정 | 근거 | 영향 요구사항·계약·Goal | +|---|---|---|---|---|---| +| `2026-08-03` | `DEC-001` | 확정 | `FollowingCreatorActivity`가 아닌 `UserFollowerListActivity`로 연결한다. | 전자는 내가 팔로잉한 크리에이터 목록이고, 후자는 채널 팔로워 목록이다. | `FOLLOWER-LINK-001`, `P1-T1` | +| `2026-08-03` | `DEC-002` | 확정 | v2 신규 화면을 만들지 않고 레거시 화면을 재사용한다. | 사용자 명시 요청. | `FOLLOWER-LINK-001`, `P1-T1` | diff --git a/docs/20260803_내_채널_팔로워_목록_연결/reviews/phase1-follower-list-link-review.md b/docs/20260803_내_채널_팔로워_목록_연결/reviews/phase1-follower-list-link-review.md new file mode 100644 index 00000000..49599ba5 --- /dev/null +++ b/docs/20260803_내_채널_팔로워_목록_연결/reviews/phase1-follower-list-link-review.md @@ -0,0 +1,104 @@ +# Phase 1 팔로워 목록 연결 코드 리뷰 보고서 + +## 1. 리뷰 정보 + +| 항목 | 내용 | +|---|---| +| 리뷰 대상 | Phase 1 / `P1-T1` | +| 기준 commit 또는 working tree | working tree 변경분 | +| 리뷰 일자 | `2026-08-03` | +| 리뷰어 | Sisyphus-Junior | +| 기준 문서 | `docs/20260803_내_채널_팔로워_목록_연결/prd.md`, `docs/20260803_내_채널_팔로워_목록_연결/plan-task.md` | +| 리뷰 상태 | 판정 완료 | + +## 2. 리뷰 목적과 범위 + +### 목적 + +- v2 내 채널 `팔로워 n명` 클릭 연결이 확정 요구사항을 충족하는지 확인한다. +- 테스트, 구현, 문서, 검증 기록이 같은 목적지를 가리키는지 확인한다. + +### 포함 범위 + +- 코드: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt` +- 테스트: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt` +- 문서: `prd.md`, `plan-task.md` +- 수동 검증: debug APK 설치, 앱 실행 이벤트, 직접 Activity 기동 가능 여부 + +### 제외 범위 + +- 레거시 `UserFollowerListActivity` 내부 동작 수정. +- 신규 v2 팔로워 목록 화면. +- 타인 채널 팔로워 수 클릭 동작. + +## 3. 판정 기준 + +| 심각도 | 기준 | +|---|---| +| Blocker | 요구사항 미충족, 잘못된 목적지 연결, build/test 실패 | +| High | owner 제한 또는 extra 전달 누락 | +| Medium | 문서와 구현 불일치 | +| Low | 완료 판정을 막지 않는 잔여 QA 제약 | + +## 4. 검토한 근거 + +### 문서와 코드 + +- 요구사항: `FOLLOWER-LINK-001~003` +- 계획: `P1-T1`, `P1-GATE` +- 코드: `CreatorChannelActivity.kt`의 `tvFollowerCount` listener와 `onFollowerCountClicked()` +- 테스트: `CreatorChannelActivitySourceTest`의 `내 채널 팔로워 수 클릭 source는 레거시 팔로워 목록으로 이동한다` + +### 실행 환경 + +```text +OS: macOS / Android device via adb +Build tool: Gradle wrapper +Android package: kr.co.vividnext.sodalive.debug +``` + +### 실행한 검증 + +| 명령 또는 수동 검증 | 결과 | 핵심 증거 | +|---|---|---| +| `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest.내 채널 팔로워 수 클릭 source는 레거시 팔로워 목록으로 이동한다"` | 실패 후 성공 | RED는 marker 부재로 실패, GREEN은 exit code 0 | +| `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"` | 성공 | exit code 0 | +| `./gradlew :app:testDebugUnitTest` | 성공 | exit code 0 | +| `./gradlew :app:assembleDebug` | 성공 | exit code 0 | +| `adb install -r "app/build/outputs/apk/debug/app-debug.apk"` | 성공 | `Success` | +| `adb shell am start -W -n kr.co.vividnext.sodalive.debug/kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListActivity --el extra_user_id 1` | 불가 | `not exported` 보안 정책으로 직접 기동 차단 | +| `adb shell monkey -p kr.co.vividnext.sodalive.debug 1` | 성공 | `Events injected: 1` | + +## 5. 발견 사항 요약 + +확정 발견 사항 없음. + +| ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal | +|---|---|---|---|---|---| +| 없음 | Low | 오탐 | 차단 이슈 없음 | `P1-T1` | 전환 항목 없음 | + +## 6. 발견 사항 상세 + +확정 발견 사항 없음. 잔여 위험은 로그인된 owner 채널에서의 실제 탭 동작이 별도 QA 환경에서 확인되어야 한다는 점이며, 이는 `plan-task.md`에 기록되어 있다. + +## 7. 확정 항목의 plan·goal 전환 + +전환 항목 없음. + +## 8. 리뷰 종료 판정 + +| 판정 항목 | 결과 | 근거 | +|---|---|---| +| 리뷰 범위 전체 확인 | 충족 | 구현, 테스트, 문서 diff 검토 | +| 후보 항목 판정 완료 | 충족 | Blocker 없음 | +| 확정 항목 plan 반영 | 해당 없음 | 전환 항목 없음 | +| 보류 항목의 담당·재개 조건 기록 | 충족 | 로그인된 내 채널 수동 QA 필요 사항을 `plan-task.md`에 기록 | +| 검증 명령과 결과 기록 | 충족 | `plan-task.md`와 본 문서에 기록 | + +**최종 결론:** 확정 발견 사항 없음. + +**남은 항목:** 로그인된 owner 채널 실제 클릭은 별도 QA 환경에서 확인 필요. + +## 9. 수정 후 검증 기록 + +수정 항목 없음.