feat(creator): 내 채널 팔로워 목록을 연결한다
This commit is contained in:
@@ -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.modify.ModifyCommunityPostRequest
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.write.CreatorCommunityWriteActivity
|
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.donation.UserProfileDonationAllViewActivity
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListActivity
|
||||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||||
@@ -224,6 +225,7 @@ class CreatorChannelActivity :
|
|||||||
private fun setupClickListeners() {
|
private fun setupClickListeners() {
|
||||||
binding.ivBack.setOnClickListener { finish() }
|
binding.ivBack.setOnClickListener { finish() }
|
||||||
binding.ivMore.setOnClickListener { onMoreClicked() }
|
binding.ivMore.setOnClickListener { onMoreClicked() }
|
||||||
|
binding.tvFollowerCount.setOnClickListener { onFollowerCountClicked() }
|
||||||
binding.layoutFollowCapsule.setOnClickListener { onFollowCapsuleClicked() }
|
binding.layoutFollowCapsule.setOnClickListener { onFollowCapsuleClicked() }
|
||||||
binding.ivBell.setOnClickListener { onBellClicked() }
|
binding.ivBell.setOnClickListener { onBellClicked() }
|
||||||
binding.ownerFabButton.setOnClickListener { expandOwnerFab() }
|
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) {
|
private fun bindHeader(header: CreatorChannelHeaderUiModel) {
|
||||||
binding.tvNickname.text = header.nickname
|
binding.tvNickname.text = header.nickname
|
||||||
binding.tvTitleNickname.text = header.nickname
|
binding.tvTitleNickname.text = header.nickname
|
||||||
|
|||||||
@@ -372,6 +372,26 @@ class CreatorChannelActivitySourceTest {
|
|||||||
assertFalse(layout.contains("@+id/tv_follow\""))
|
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
|
@Test
|
||||||
fun `creator channel home은 status bar 뒤까지 header를 그리고 자체 inset을 처리한다`() {
|
fun `creator channel home은 status bar 뒤까지 header를 그리고 자체 inset을 처리한다`() {
|
||||||
val baseActivity = projectFile("app/src/main/java/kr/co/vividnext/sodalive/base/BaseActivity.kt").readText()
|
val baseActivity = projectFile("app/src/main/java/kr/co/vividnext/sodalive/base/BaseActivity.kt").readText()
|
||||||
|
|||||||
213
docs/20260803_내_채널_팔로워_목록_연결/plan-task.md
Normal file
213
docs/20260803_내_채널_팔로워_목록_연결/plan-task.md
Normal file
@@ -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`에 확정 발견 사항 없음으로 기록했다.
|
||||||
119
docs/20260803_내_채널_팔로워_목록_연결/prd.md
Normal file
119
docs/20260803_내_채널_팔로워_목록_연결/prd.md
Normal file
@@ -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` |
|
||||||
@@ -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. 수정 후 검증 기록
|
||||||
|
|
||||||
|
수정 항목 없음.
|
||||||
Reference in New Issue
Block a user