docs(creator): 채널 공유 검증 기록을 남긴다

This commit is contained in:
2026-09-15 11:46:09 +09:00
parent f891c15eb9
commit 5029332023
2 changed files with 71 additions and 37 deletions
@@ -2,7 +2,7 @@
| 문서 항목 | 내용 |
|---|---|
| 상태 | 구현 대기 |
| 상태 | 구현 완료 |
| 작성일 | `2026-09-14` |
| 요구사항 기준 | `docs/20260914_크리에이터_채널_공유/prd.md` |
| API 기준 | 없음 |
@@ -17,7 +17,7 @@
| Phase | 상태 | 완료 Task | 활성/다음 Goal | 차단 또는 남은 조건 |
|---:|---|---:|---|---|
| 1 | 대기 | `0/4` | `P1-T1` | 없음 |
| 1 | 완료 | `5/5` | 없음 | 실제 앱 수동 테스트는 사용자 확인 대기 |
## 범위
@@ -62,7 +62,7 @@
**선행조건:** `docs/20260914_크리에이터_채널_공유/prd.md` 확정.
**Phase 완료 조건:** `P1-T1`~`P1-T3`과 `P1-GATE` 완료, 검증 기록 누적.
**Phase 완료 조건:** `P1-T1`~`P1-T3`, `P1-R1`, `P1-GATE` 완료, 검증 기록 누적.
### 구현 항목
@@ -85,11 +85,11 @@
- Consumes: `CreatorChannelHeaderUiModel.isOwner`
- Produces: `iv_share` owner 전용 title action
- [ ] **RED:** `CreatorChannelShareSourceTest`에 `activity_creator_channel.xml`이 `@+id/iv_share`와 `@drawable/ic_audio_content_share`를 포함해야 한다는 source test를 추가한다. `CreatorChannelActivity.kt`가 owner 분기에서 `binding.ivShare.visibility = View.VISIBLE`를 포함해야 한다는 source test를 추가한다.
- [ ] **RED 확인:** `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelShareSourceTest"`를 실행해 `iv_share` 또는 owner visibility 계약 미구현 실패를 확인한다.
- [ ] **GREEN:** `activity_creator_channel.xml`의 `title_action_container`에 `ImageView` `@+id/iv_share`를 추가하고 `android:src="@drawable/ic_audio_content_share"`, `android:visibility="gone"`을 지정한다. `CreatorChannelActivity.bindTitleBar()` owner 분기에서 follow, bell, more를 숨기고 share를 보이게 하며, non-owner 분기에서는 share를 숨긴다.
- [ ] **GREEN 확인:** 같은 focused test를 다시 실행해 PASS를 확인한다.
- [ ] **REFACTOR:** 새 동작을 바꾸지 않는 범위에서 이번 Task가 만든 중복만 정리하고 focused test 결과를 Progress에 기록한다.
- [x] **RED:** `CreatorChannelShareSourceTest`에 `activity_creator_channel.xml`이 `@+id/iv_share`와 `@drawable/ic_audio_content_share`를 포함해야 한다는 source test를 추가한다. `CreatorChannelActivity.kt`가 owner 분기에서 `binding.ivShare.visibility = View.VISIBLE`를 포함해야 한다는 source test를 추가한다.
- [x] **RED 확인:** `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelShareSourceTest"`를 실행해 `iv_share` 또는 owner visibility 계약 미구현 실패를 확인한다.
- [x] **GREEN:** `activity_creator_channel.xml`의 `title_action_container`에 `ImageView` `@+id/iv_share`를 추가하고 `android:src="@drawable/ic_audio_content_share"`, `android:visibility="gone"`을 지정한다. `CreatorChannelActivity.bindTitleBar()` owner 분기에서 follow, bell, more를 숨기고 share를 보이게 하며, non-owner 분기에서는 share를 숨긴다.
- [x] **GREEN 확인:** 같은 focused test를 다시 실행해 PASS를 확인한다.
- [x] **REFACTOR:** 새 동작을 바꾸지 않는 범위에서 이번 Task가 만든 중복만 정리하고 focused test 결과를 Progress에 기록한다.
#### Task 1.2 non-owner BottomSheet 공유 항목 추가
@@ -111,11 +111,11 @@
- Consumes: `CreatorChannelMoreBottomSheet.newInstance()`
- Produces: `CreatorChannelMoreBottomSheet.onClickChannelShare`
- [ ] **RED:** source test에 `dialog_creator_channel_more.xml`의 `@+id/tv_channel_share`와 `@string/screen_user_profile_share_channel` 존재를 검증한다. `CreatorChannelMoreBottomSheet.kt`가 `onClickChannelShare` callback과 `tvChannelShare.setOnClickListener`를 포함해야 한다는 source test를 추가한다.
- [ ] **RED 확인:** `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelShareSourceTest"`를 실행해 BottomSheet 공유 항목 미구현 실패를 확인한다.
- [ ] **GREEN:** `dialog_creator_channel_more.xml` 상단 메뉴 영역에 기존 TextView와 같은 style/padding/textColor/textSize로 `tv_channel_share`를 추가한다. `CreatorChannelMoreBottomSheet`에 `var onClickChannelShare: (() -> Unit)? = null`을 추가하고 클릭 시 `dismiss()` 후 callback을 호출한다. `CreatorChannelActivity.onMoreClicked()`에서 `onClickChannelShare = { shareCurrentCreatorChannel() }`를 연결한다.
- [ ] **GREEN 확인:** 같은 focused test를 다시 실행해 PASS를 확인한다.
- [ ] **REFACTOR:** 기존 block/report/profile report callback이 삭제되지 않았는지 source test와 diff로 확인하고 Progress에 기록한다.
- [x] **RED:** source test에 `dialog_creator_channel_more.xml`의 `@+id/tv_channel_share`와 `@string/screen_user_profile_share_channel` 존재를 검증한다. `CreatorChannelMoreBottomSheet.kt`가 `onClickChannelShare` callback과 `tvChannelShare.setOnClickListener`를 포함해야 한다는 source test를 추가한다.
- [x] **RED 확인:** `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelShareSourceTest"`를 실행해 BottomSheet 공유 항목 미구현 실패를 확인한다.
- [x] **GREEN:** `dialog_creator_channel_more.xml` 상단 메뉴 영역에 기존 TextView와 같은 style/padding/textColor/textSize로 `tv_channel_share`를 추가한다. `CreatorChannelMoreBottomSheet`에 `var onClickChannelShare: (() -> Unit)? = null`을 추가하고 클릭 시 `dismiss()` 후 callback을 호출한다. `CreatorChannelActivity.onMoreClicked()`에서 `onClickChannelShare = { shareCurrentCreatorChannel() }`를 연결한다.
- [x] **GREEN 확인:** 같은 focused test를 다시 실행해 PASS를 확인한다.
- [x] **REFACTOR:** 기존 block/report/profile report callback이 삭제되지 않았는지 source test와 diff로 확인하고 Progress에 기록한다.
#### Task 1.3 공유 메시지와 chooser 실행 연결
@@ -135,20 +135,46 @@
- Consumes: `currentHeader.creatorId`, `currentHeader.nickname`, `Utils.createOneLinkUrl`
- Produces: `shareCurrentCreatorChannel()`
- [ ] **RED:** source test에 `CreatorChannelActivity.kt`가 `Intent(Intent.ACTION_SEND)`, `intent.type = "text/plain"`, `Intent.EXTRA_TEXT`, `Intent.createChooser`, `R.string.screen_user_profile_share_channel`, `deep_link_value` = `channel`, `deep_link_sub5`를 포함해야 한다는 계약을 추가한다.
- [ ] **RED 확인:** `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelShareSourceTest"`를 실행해 공유 payload 미구현 실패를 확인한다.
- [ ] **GREEN:** `CreatorChannelActivity`에 `shareCurrentCreatorChannel()` private 함수를 추가한다. `currentHeader`가 없거나 `creatorId <= 0L`이면 return한다. params는 `af_dp=voiceon://`, `deep_link_value=channel`, `deep_link_sub5=$creatorId`를 사용한다. 메시지는 `소다라이브 ${header.nickname}님의 채널입니다.\n$shareUrl`로 만들고 기존 Activity 공유 코드와 같은 chooser를 실행한다. `setupClickListeners()`에서 `binding.ivShare.setOnClickListener { shareCurrentCreatorChannel() }`를 연결한다.
- [ ] **GREEN 확인:** 같은 focused test를 다시 실행해 PASS를 확인한다.
- [ ] **REFACTOR:** `UserProfileActivity`, `UserProfileViewModel`이 수정되지 않았는지 `git diff -- app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/UserProfileActivity.kt app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/UserProfileViewModel.kt`로 확인하고 Progress에 기록한다.
- [x] **RED:** source test에 `CreatorChannelActivity.kt`가 `Intent(Intent.ACTION_SEND)`, `intent.type = "text/plain"`, `Intent.EXTRA_TEXT`, `Intent.createChooser`, `R.string.screen_user_profile_share_channel`, `deep_link_value` = `channel`, `deep_link_sub5`를 포함해야 한다는 계약을 추가한다.
- [x] **RED 확인:** `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelShareSourceTest"`를 실행해 공유 payload 미구현 실패를 확인한다.
- [x] **GREEN:** `CreatorChannelActivity`에 `shareCurrentCreatorChannel()` private 함수를 추가한다. `currentHeader`가 없거나 `creatorId <= 0L`이면 return한다. params는 `af_dp=voiceon://`, `deep_link_value=channel`, `deep_link_sub5=$creatorId`를 사용한다. 메시지는 `소다라이브 ${header.nickname}님의 채널입니다.\n$shareUrl`로 만들고 기존 Activity 공유 코드와 같은 chooser를 실행한다. `setupClickListeners()`에서 `binding.ivShare.setOnClickListener { shareCurrentCreatorChannel() }`를 연결한다.
- [x] **GREEN 확인:** 같은 focused test를 다시 실행해 PASS를 확인한다.
- [x] **REFACTOR:** `UserProfileActivity`, `UserProfileViewModel`이 수정되지 않았는지 `git diff -- app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/UserProfileActivity.kt app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/UserProfileViewModel.kt`로 확인하고 Progress에 기록한다.
### 완료 조건
- [ ] `P1-T1`, `P1-T2`, `P1-T3`의 체크박스와 완료 증거가 모두 충족됐다.
- [ ] `SHARE-001~004`, `REG-001~002`가 구현·검증 기록으로 추적된다.
- [ ] 레거시 프로필 파일 수정이 없다.
- [x] `P1-T1`, `P1-T2`, `P1-T3`의 체크박스와 완료 증거가 모두 충족됐다.
- [x] `SHARE-001~004`, `REG-001~002`가 구현·검증 기록으로 추적된다.
- [x] 레거시 프로필 파일 수정이 없다.
### 검증 방법
#### Task 1.4 후원 테스트 can 격리 회귀 수정
**Goal 실행 `P1-R1`:** `CreatorChannelHomeViewModelTest`와 `CreatorChannelDonationViewModelTest`가 공유 `SharedPreferenceManager.can` 상태에 영향받지 않도록 테스트 격리를 보강한다.
- **시작 조건:** `ISSUE-001` 재현 및 root cause 확인.
- **완료 증거:** `SharedPreferenceManagerTest` PASS, `creator.channel.*` 패키지 테스트 PASS.
- **범위 밖:** 후원 ViewModel production 동작 변경, 전체 DataStore reset, 레거시 파일 수정.
**Files:**
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/common/SharedPreferenceManager.kt`
- Modify: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModelTest.kt`
- Modify: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/donation/CreatorChannelDonationViewModelTest.kt`
- Test: `app/src/test/java/kr/co/vividnext/sodalive/common/SharedPreferenceManagerTest.kt`
**Interfaces:**
- Consumes: `SharedPreferenceManager.can`, `DataStore.edit`
- Produces: `resetCanForTest()`, `setCanForTest(value)` 테스트 전용 동기 helper
- [x] **RED:** `SharedPreferenceManagerTest`에 저장된 `can` 값을 테스트 전용 reset으로 초기화해야 한다는 회귀 테스트를 추가했다.
- [x] **RED 확인:** production helper 미구현 상태에서 focused test가 컴파일 실패하는 것을 확인하려 했으나 Gradle 초기 compile이 timeout됐다. 이후 helper 구현 전 계약 실패 조건은 `resetForTest(clearPersisted = true)` 미존재로 확인했다.
- [x] **GREEN:** 전체 DataStore를 지우지 않고 `PREF_CAN` 키만 동기적으로 제거·설정하는 `resetCanForTest()`, `setCanForTest(value)`를 추가했다. `CreatorChannelHomeViewModelTest`, `CreatorChannelDonationViewModelTest`의 `can` setup/teardown만 해당 helper로 교체했다.
- [x] **GREEN 확인:** `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.common.SharedPreferenceManagerTest" --rerun-tasks` PASS, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"` PASS를 확인했다.
- [x] **REFACTOR:** 전체 DataStore clear 방식은 병렬 테스트의 `token` 상태까지 지워 NPE를 만들었으므로 제거하고, `can` 키 한정 동기 helper로 범위를 줄였다.
#### Phase 1 Gate
**Goal 실행 `P1-GATE`:** 크리에이터 채널 공유 진입점과 기존 더보기 동작 보존을 최종 판정한다.
@@ -167,11 +193,11 @@ git diff --check
수동 검증:
- [ ] 내 채널 진입 시 우측 상단 `ic_audio_content_share` 버튼이 표시되고 더보기는 숨겨진다.
- [ ] 내 채널 공유 버튼 탭 시 Android 공유 chooser 제목이 `채널 공유`로 표시된다.
- [ ] 다른 사람 채널 진입 시 기존 follow, bell, more가 표시되고 공유 버튼은 숨겨진다.
- [ ] 다른 사람 채널 더보기 BottomSheet에서 `채널 공유` 선택 시 같은 Android 공유 chooser가 표시된다.
- [ ] 기존 차단, 유저 신고, 프로필 신고 항목이 계속 동작한다.
- [ ] 내 채널 진입 시 우측 상단 `ic_audio_content_share` 버튼이 표시되고 더보기는 숨겨진다. — 사용자 수동 확인 대기
- [ ] 내 채널 공유 버튼 탭 시 Android 공유 chooser 제목이 `채널 공유`로 표시된다. — 사용자 수동 확인 대기
- [ ] 다른 사람 채널 진입 시 기존 follow, bell, more가 표시되고 공유 버튼은 숨겨진다. — 사용자 수동 확인 대기
- [ ] 다른 사람 채널 더보기 BottomSheet에서 `채널 공유` 선택 시 같은 Android 공유 chooser가 표시된다. — 사용자 수동 확인 대기
- [ ] 기존 차단, 유저 신고, 프로필 신고 항목이 계속 동작한다. — 사용자 수동 확인 대기
## 실행 순서와 의존성
@@ -180,10 +206,11 @@ git diff --check
| 1 | `P1-T1` | PRD 확정 | 아니요 | title bar layout/source 계약 재확인 |
| 2 | `P1-T2` | `P1-T1` | 아니요 | BottomSheet binding 이름 재확인 |
| 3 | `P1-T3` | `P1-T1`, `P1-T2` | 아니요 | 기존 프로필 공유 코드 재대조 |
| 4 | `P1-GATE` | Phase 1 Task 전체 | 아니요 | 실패 소유 Task의 회귀 수정 goal 생성 |
| 4 | `P1-R1` | `ISSUE-001` 재현 | 아니요 | `SharedPreferenceManager.can` 테스트 격리 root cause 재확인 |
| 5 | `P1-GATE` | Phase 1 Task 전체 | 아니요 | 실패 소유 Task의 회귀 수정 goal 생성 |
```text
P1-T1 → P1-T2 → P1-T3 → P1-GATE
P1-T1 → P1-T2 → P1-T3 → P1-R1 → P1-GATE
```
## 변경 금지 항목
@@ -226,11 +253,14 @@ P1-T1 → P1-T2 → P1-T3 → P1-GATE
| `2026-09-14` | `DEC-001` | 확정 | 내 채널은 title bar 직접 공유 버튼, 타인 채널은 더보기 BottomSheet 공유 항목으로 구현한다. | 사용자 요청 | `P1-T1`, `P1-T2` |
| `2026-09-14` | `DEC-002` | 확정 | 기존 프로필 공유의 chooser와 OneLink 형식을 크리에이터 채널 v2 안에서 동일하게 사용한다. | `UserProfileActivity.kt:887~902`, `UserProfileViewModel.kt:351~362` 확인 | `P1-T3` |
| `2026-09-14` | `DEC-003` | 확정 | 시각 QA와 스크린샷 검증은 수행하지 않고 실제 앱 수동 테스트로 확인한다. | 사용자 지시 | `P1-GATE` |
## 발견된 문제
| ID | 심각도 | 상태 | 발견 내용 | 영향 Goal | 처리 계획 |
|---|---|---|---|---|---|
| 없음 | Low | 후보 없음 | 문서 작성 범위에서 차단 이슈 없음 | 없음 | 없음 |
| `ISSUE-001` | Low | 해결 | `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`가 `CreatorChannelHomeViewModelTest`의 `SharedPreferenceManager.can` assertion에서 1건 실패했다. 원인은 `SharedPreferenceManager.can` setter가 비동기 DataStore write를 수행하고, 테스트 간 persisted `PREF_CAN` 값이 재초기화 시점에 다시 읽힐 수 있는 격리성 문제였다. | `P1-R1`, `P1-GATE` | `PREF_CAN`만 동기 초기화·설정하는 테스트 전용 helper를 추가하고 후원 관련 테스트 setup/teardown에 적용했다. |
## 최종 보고 형식
@@ -249,3 +279,5 @@ P1-T1 → P1-T2 → P1-T3 → P1-GATE
## Verification Log
- 2026-09-14: 문서 작성만 수행했다. 코드 구현, Gradle 빌드, 기능 테스트는 실행하지 않았다.
- 2026-09-14: 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelShareSourceTest" --rerun-tasks` PASS, `./gradlew :app:mergeDebugResources` PASS, `./gradlew :app:assembleDebug` PASS, `git diff --check` PASS를 확인했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`는 `CreatorChannelHomeViewModelTest`의 후원 can assertion 1건으로 실패했으나, 실패 후보 테스트 2개는 각각 단독 실행 PASS했다. 사용자가 시각 QA 대신 실제 앱 수동 테스트를 선택했으므로 수동 검증 체크박스는 사용자 확인 대기로 남겼다.
- 2026-09-15: `ISSUE-001` 후속으로 `SharedPreferenceManager.can` 테스트 격리 문제를 수정했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.common.SharedPreferenceManagerTest" --rerun-tasks` PASS, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"` PASS, `git diff --check` PASS를 확인했다. 공유 기능 focused test `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelShareSourceTest"`도 PASS 상태를 재확인했다.
@@ -6,12 +6,12 @@
|---|---|
| 문서 상태 | 구현 기준 확정 |
| 작성일 | `2026-09-14` |
| 최종 수정일 | `2026-09-14` |
| 최종 수정일 | `2026-09-15` |
| 대상 제품 | 크리에이터 채널 공유 |
| 작성자·결정권자 | 사용자 요청 기준 |
| 관련 API Contract | 없음 |
| 관련 구현 계획 | `docs/20260914_크리에이터_채널_공유/plan-task.md` |
| 관련 review | 없음 |
| 관련 review | `docs/20260914_크리에이터_채널_공유/reviews/phase1-creator-channel-share-review.md` |
### 요구사항 상태
@@ -136,16 +136,18 @@ CreatorChannelActivity
### 14.1 기능 수용 기준
- [ ] 내 채널에서 우측 상단 공유 버튼이 표시된다. (`SHARE-001`, `P1-T1`)
- [ ] 내 채널 공유 버튼이 `ic_audio_content_share`를 사용한다. (`SHARE-002`, `P1-T1`)
- [ ] 다른 사람 채널 더보기 BottomSheet에 `채널 공유`가 표시된다. (`SHARE-003`, `P1-T2`)
- [ ] 두 진입점 모두 기존 프로필 공유와 같은 chooser payload를 사용한다. (`SHARE-004`, `P1-T3`)
- [x] 내 채널에서 우측 상단 공유 버튼이 표시된다. (`SHARE-001`, `P1-T1`)
- [x] 내 채널 공유 버튼이 `ic_audio_content_share`를 사용한다. (`SHARE-002`, `P1-T1`)
- [x] 다른 사람 채널 더보기 BottomSheet에 `채널 공유`가 표시된다. (`SHARE-003`, `P1-T2`)
- [x] 두 진입점 모두 기존 프로필 공유와 같은 chooser payload를 사용한다. (`SHARE-004`, `P1-T3`)
### 14.2 회귀 수용 기준
- [ ] non-owner follow, bell, more 표시 정책이 유지된다.
- [ ] 기존 block/report/profile report BottomSheet callback이 유지된다.
- [ ] `UserProfileActivity`, `UserProfileViewModel`은 수정되지 않는다.
- [x] non-owner follow, bell, more 표시 정책이 유지된다.
- [x] 기존 block/report/profile report BottomSheet callback이 유지된다.
- [x] `UserProfileActivity`, `UserProfileViewModel`은 수정되지 않는다.
검증 기록: 2026-09-14 `CreatorChannelShareSourceTest`, `:app:mergeDebugResources`, `:app:assembleDebug`, `git diff --check`, review PASS 기준으로 체크했다. 2026-09-15 `ISSUE-001` 후속으로 `SharedPreferenceManager.can` 테스트 격리를 수정했고 `SharedPreferenceManagerTest`, `creator.channel.*`, `CreatorChannelShareSourceTest`, `git diff --check` PASS를 확인했다. 실제 앱 수동 테스트는 `plan-task.md`의 Phase 1 Gate 수동 검증에 별도 대기 항목으로 남긴다.
## 15. Open Questions