docs(main): 로그인 가드 후속 진행을 기록한다

This commit is contained in:
2026-06-27 03:55:36 +09:00
parent 4a45f9699c
commit 1e073e85a1
2 changed files with 120 additions and 10 deletions

View File

@@ -10,10 +10,13 @@
- 한국 접속자는 `SharedPreferenceManager.isAuth``true`일 때 본인인증 완료로 판단한다. - 한국 접속자는 `SharedPreferenceManager.isAuth``true`일 때 본인인증 완료로 판단한다.
- 한국 외 접속자는 본인인증 여부와 무관하게 성인 콘텐츠 설정 확인 단계로 진행한다. - 한국 외 접속자는 본인인증 여부와 무관하게 성인 콘텐츠 설정 확인 단계로 진행한다.
- 성인 콘텐츠 표시 설정은 `SharedPreferenceManager.isAdultContentVisible` 기준으로 판단한다. - 성인 콘텐츠 표시 설정은 `SharedPreferenceManager.isAdultContentVisible` 기준으로 판단한다.
- `HomeMainFragment`의 팔로잉 탭 선택은 화면 내부 탭 전환이지만, 로그인 사용자 전용 콘텐츠 진입으로 보아 로그인 가드 대상에 포함한다.
## Success Criteria ## Success Criteria
- v2 메인 전용 이동 guard helper가 추가된다. - v2 메인 전용 이동 guard helper가 추가된다.
- `HomeMainFragment`의 모든 실제 화면 이동이 helper를 통과한다. - `HomeMainFragment`의 모든 실제 화면 이동이 helper를 통과한다.
- `HomeMainFragment`의 팔로잉 탭 선택은 팔로잉 화면 전환 및 팔로잉 데이터 로드 전에 helper를 통과한다.
- `HomeMainFragment`의 팔로잉 탭 선택이 미로그인으로 차단되면, 탭 선택 상태와 화면은 팔로잉 탭 선택 전 상태로 복구된다.
- `ContentMainFragment`의 모든 실제 화면 이동이 helper를 통과한다. - `ContentMainFragment`의 모든 실제 화면 이동이 helper를 통과한다.
- 성인 콘텐츠로 판별 가능한 이동은 login -> country/auth -> adult setting 순서로 helper를 통과한다. - 성인 콘텐츠로 판별 가능한 이동은 login -> country/auth -> adult setting 순서로 helper를 통과한다.
- helper는 `SharedPreferenceManager.countryCode`, `SharedPreferenceManager.isAuth`, `SharedPreferenceManager.isAdultContentVisible`, `ContentSettingsActivity` 이동을 포함한다. - helper는 `SharedPreferenceManager.countryCode`, `SharedPreferenceManager.isAuth`, `SharedPreferenceManager.isAdultContentVisible`, `ContentSettingsActivity` 이동을 포함한다.
@@ -142,7 +145,7 @@
- 2026-06-27: 사용자 결정에 따라 한국 접속 미인증 사용자 본인인증 안내 흐름은 v2 helper에서 직접 재사용하는 것으로 확정했다. - 2026-06-27: 사용자 결정에 따라 한국 접속 미인증 사용자 본인인증 안내 흐름은 v2 helper에서 직접 재사용하는 것으로 확정했다.
### Phase 3: HomeMainFragment 이동 지점에 로그인 가드 적용 ### Phase 3: HomeMainFragment 이동 지점에 로그인 가드 적용
- [ ] **Task 3.1: HomeMainFragment source test 추가** - [x] **Task 3.1: HomeMainFragment source test 추가**
- 파일: `app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragmentLoginGuardSourceTest.kt` - 파일: `app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragmentLoginGuardSourceTest.kt`
- 검증 기준: - 검증 기준:
- `HomeMainFragment`가 `ensureMainV2NavigationAllowed`를 import/use 한다. - `HomeMainFragment`가 `ensureMainV2NavigationAllowed`를 import/use 한다.
@@ -154,8 +157,10 @@
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLoginGuardSourceTest" ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLoginGuardSourceTest"
``` ```
- 기대 결과: 구현 전에는 helper 사용 부재로 실패한다. - 기대 결과: 구현 전에는 helper 사용 부재로 실패한다.
- 검증 기록:
- 2026-06-27: `HomeMainFragmentLoginGuardSourceTest`를 추가했다. 구현 전 실행 결과 helper import/guard 부재로 실패해 RED 상태를 확인했다.
- [ ] **Task 3.2: HomeMainFragment 적용** - [x] **Task 3.2: HomeMainFragment 적용**
- 파일: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt` - 파일: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt`
- 구현 방향: - 구현 방향:
- `ensureMainV2NavigationAllowed { startActivity(...) }` 형태로 감싼다. - `ensureMainV2NavigationAllowed { startActivity(...) }` 형태로 감싼다.
@@ -164,9 +169,61 @@
- 성인 콘텐츠 여부를 판단할 수 없는 이동에는 임의 adult 판정을 추가하지 않는다. - 성인 콘텐츠 여부를 판단할 수 없는 이동에는 임의 adult 판정을 추가하지 않는다.
- `BaseFragment`, legacy `MainActivity`, legacy `HomeFragment`는 수정하지 않는다. - `BaseFragment`, legacy `MainActivity`, legacy `HomeFragment`는 수정하지 않는다.
- 검증 기준: Task 3.1 source test가 통과한다. - 검증 기준: Task 3.1 source test가 통과한다.
- 검증 기록:
- 2026-06-27: `HomeMainFragment`의 실제 화면 이동 지점에 `ensureMainV2NavigationAllowed`를 적용했다. invalid route/id return은 guard보다 먼저 유지했고, 홈 모델에서 성인 콘텐츠 여부를 판단할 수 없어 기본 로그인 가드만 적용했다.
- 2026-06-27: 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLoginGuardSourceTest"`가 통과했다.
- [x] **Task 3.3: HomeMainFragment 팔로잉 탭 로그인 가드 source test 추가**
- 파일: `app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragmentLoginGuardSourceTest.kt`
- 검증 기준:
- `binding.textTabBarHome.root.setOnTabSelectedListener`가 팔로잉 탭 선택 시 즉시 `showHomeTab(HOME_TAB_FOLLOWING)`을 호출하지 않는다.
- 팔로잉 탭 선택은 `ensureMainV2NavigationAllowed`를 통과한 뒤 `showHomeTab(HOME_TAB_FOLLOWING)` 또는 팔로잉 탭 전환 helper를 실행한다.
- 추천 탭과 랭킹 탭 선택은 기존처럼 로그인 가드 없이 탭 전환을 유지한다.
- 팔로잉 탭 전환 전 `homeFollowingViewModel.loadFollowing()`이 실행되지 않도록, 팔로잉 탭 화면 전환과 데이터 로드는 guard 허용 callback 내부 또는 guard 이후 함수에만 위치한다.
- 실행 명령:
```bash
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLoginGuardSourceTest"
```
- 기대 결과: 구현 전에는 팔로잉 탭 선택 경로의 guard 부재로 실패한다.
- 검증 기록:
- 2026-06-27: 사용자 추가 요청에 따라 문서에 신규 source test Task만 추가했다. 구현 및 검증은 아직 수행하지 않는다.
- 2026-06-27: `HomeMainFragmentLoginGuardSourceTest`에 팔로잉 탭 선택이 `ensureMainV2NavigationAllowed` 통과 후 `showHomeTab(HOME_TAB_FOLLOWING)`을 실행하는지 검증하는 source test를 추가했다. 구현 전 실행 결과 팔로잉 탭 선택 경로의 guard 부재로 실패해 RED 상태를 확인했다.
- [x] **Task 3.4: HomeMainFragment 팔로잉 탭 전환 로그인 가드 적용**
- 파일: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt`
- 구현 방향:
- `setOnTabSelectedListener` 또는 `showHomeTab(index)` 흐름에서 `HOME_TAB_FOLLOWING` 선택만 `ensureMainV2NavigationAllowed { ... }`로 감싼다.
- 미로그인 상태에서는 `MainV2Activity.showLoginActivity()`만 실행되고 `binding.nsvHomeFollowingContent.visibility = View.VISIBLE`, `hasLoadedFollowing = true`, `homeFollowingViewModel.loadFollowing()`이 실행되지 않게 한다.
- 로그인 상태에서는 기존 팔로잉 탭 전환 동작과 최초 1회 `homeFollowingViewModel.loadFollowing()` 흐름을 유지한다.
- `HOME_TAB_RECOMMENDATION`, `HOME_TAB_RANKING` 전환은 로그인 가드 없이 기존 동작을 유지한다.
- 레거시 `HomeFragment`, `MainActivity`, `BaseFragment`는 수정하지 않는다.
- 검증 기준: Task 3.3 source test가 통과한다.
- 검증 기록:
- 2026-06-27: 사용자 추가 요청에 따라 문서에 신규 구현 Task만 추가했다. 구현 및 검증은 아직 수행하지 않는다.
- 2026-06-27: `HomeMainFragment`의 tab listener에서 `HOME_TAB_FOLLOWING` 선택만 `ensureMainV2NavigationAllowed`로 감싸고, 추천/랭킹 탭은 기존처럼 `showHomeTab(index)`로 즉시 전환되도록 유지했다. 미로그인 상태에서는 guard callback 내부의 `showHomeTab(HOME_TAB_FOLLOWING)`이 실행되지 않아 팔로잉 화면 전환과 `homeFollowingViewModel.loadFollowing()`이 실행되지 않는다.
- 2026-06-27: 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLoginGuardSourceTest"`가 통과했다.
- [x] **Task 3.5: 팔로잉 탭 미로그인 차단 시 이전 탭 상태 복구**
- 파일:
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt`
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragmentLoginGuardSourceTest.kt`
- 구현 방향:
- 현재 선택된 홈 탭 index를 `HomeMainFragment` 내부 상태로 보관한다.
- 추천/랭킹/팔로잉 탭 전환이 실제로 허용되어 `showHomeTab(index)`가 실행될 때 현재 탭 index를 갱신한다.
- 팔로잉 탭 선택이 미로그인 상태로 차단되면 `TextTabBarView.selectTab(currentHomeTabIndex)`로 탭 선택 UI를 이전 탭으로 복구한 뒤 기존 로그인 가드를 실행한다.
- 로그인 상태에서는 기존처럼 팔로잉 탭으로 전환하고 최초 1회 `homeFollowingViewModel.loadFollowing()` 흐름을 유지한다.
- 레거시 `HomeFragment`, `MainActivity`, `BaseFragment`는 수정하지 않는다.
- 검증 기준:
- `HomeMainFragmentLoginGuardSourceTest`가 팔로잉 탭 미로그인 차단 시 이전 탭 선택 복구 흐름을 검증한다.
- Phase 5 통합 검증이 통과한다.
- 검증 기록:
- 2026-06-27: 사용자 후속 요청에 따라 문서에 신규 Task만 추가했다. 구현 및 검증은 이어서 수행한다.
- 2026-06-27: `HomeMainFragmentLoginGuardSourceTest`에 팔로잉 탭 미로그인 차단 시 이전 탭 선택 상태 복구 source test를 추가했고, 구현 전 실행 결과 실패해 RED 상태를 확인했다.
- 2026-06-27: `HomeMainFragment`에서 현재 홈 탭 index를 보관하고, 팔로잉 탭 선택이 미로그인 상태이면 `TextTabBarView.selectTab(currentHomeTabIndex)`로 이전 탭 선택 상태를 복구한 뒤 기존 로그인 가드를 호출하도록 구현했다.
- 2026-06-27: 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLoginGuardSourceTest"`가 통과했다.
### Phase 4: ContentMainFragment 이동 지점에 로그인 가드 적용 ### Phase 4: ContentMainFragment 이동 지점에 로그인 가드 적용
- [ ] **Task 4.1: ContentMainFragment source test 추가** - [x] **Task 4.1: ContentMainFragment source test 추가**
- 파일: `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragmentLoginGuardSourceTest.kt` - 파일: `app/src/test/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragmentLoginGuardSourceTest.kt`
- 검증 기준: - 검증 기준:
- `ContentMainFragment`가 `ensureMainV2NavigationAllowed`를 import/use 한다. - `ContentMainFragment`가 `ensureMainV2NavigationAllowed`를 import/use 한다.
@@ -178,44 +235,75 @@
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentLoginGuardSourceTest" ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentLoginGuardSourceTest"
``` ```
- 기대 결과: 구현 전에는 helper 사용 부재로 실패한다. - 기대 결과: 구현 전에는 helper 사용 부재로 실패한다.
- 검증 기록:
- 2026-06-27: `ContentMainFragmentLoginGuardSourceTest`를 추가했다. 구현 전 실행 결과 helper import/guard 및 성인 콘텐츠 여부 전달 부재로 실패해 RED 상태를 확인했다.
- [ ] **Task 4.2: ContentMainFragment 적용** - [x] **Task 4.2: ContentMainFragment 적용**
- 파일: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt` - 파일: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/ContentMainFragment.kt`
- 구현 방향: - 구현 방향:
- 최종 이동 함수인 `onBannerClick`, `openAudioContentDetail`, `openSeriesDetail`에서 `ensureMainV2NavigationAllowed { startActivity(...) }`를 사용한다. - 최종 이동 함수인 `onBannerClick`, `openAudioContentDetail`, `openSeriesDetail`에서 `ensureMainV2NavigationAllowed { startActivity(...) }`를 사용한다.
- `ContentAudioCardUiModel.showAdultBadge`, `ContentCommentedAudioUiModel.showAdultBadge`, 전체 탭 audio/series item의 `showAdultBadge`를 성인 콘텐츠 가드 입력으로 전달한다. - `ContentAudioCardUiModel.showAdultBadge`, 전체 탭 audio/series item의 `showAdultBadge`를 성인 콘텐츠 가드 입력으로 전달한다.
- 현재 `ContentCommentedAudioUiModel`과 추천 `ContentOriginalSeriesUiModel`에는 성인 콘텐츠 여부 필드가 없어 모델/어댑터 범위를 확장하지 않는다.
- 랭킹 아이템이나 배너처럼 성인 콘텐츠 여부를 판단할 수 없는 이동은 로그인 가드만 적용한다. - 랭킹 아이템이나 배너처럼 성인 콘텐츠 여부를 판단할 수 없는 이동은 로그인 가드만 적용한다.
- 랭킹/카드 클릭 위임 구조는 유지한다. - 랭킹/카드 클릭 위임 구조는 유지한다.
- 검증 기준: Task 4.1 source test가 통과한다. - 검증 기준: Task 4.1 source test가 통과한다.
- 검증 기록:
- 2026-06-27: `ContentMainFragment`의 `onBannerClick`, `openAudioContentDetail`, `openSeriesDetail` 최종 이동 지점에 `ensureMainV2NavigationAllowed`를 적용했다. `ContentAudioCardUiModel.showAdultBadge`와 전체 탭 audio/series item의 `showAdultBadge`는 `requiresAdultContentAccess`로 전달했다.
- 2026-06-27: 현재 `ContentCommentedAudioUiModel`과 추천 `ContentOriginalSeriesUiModel`에는 성인 콘텐츠 여부 필드가 없어, 모델/어댑터 범위를 확장하지 않고 로그인 가드만 적용했다.
- 2026-06-27: 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentLoginGuardSourceTest"`가 통과했다.
### Phase 5: 통합 검증 ### Phase 5: 통합 검증
- [ ] **Task 5.1: v2 main source test 실행** - 추가 범위인 Task 3.3/3.4 구현이 완료되었으므로 Phase 5 체크리스트는 재검증 필요 상태로 유지한다.
- [x] **Task 5.1: v2 main source test 실행**
- 실행 명령: - 실행 명령:
```bash ```bash
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.*" ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.*"
``` ```
- 기대 결과: v2 main 관련 source/unit test 통과. - 기대 결과: v2 main 관련 source/unit test 통과.
- 검증 기록:
- 2026-06-27: Phase 3/4 코드 리뷰 및 검증 요청에 따라 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.*"`를 재실행했고 통과했다.
- 2026-06-27: Phase 3/4 코드 리뷰 및 검증 요청에 따라 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.*"`를 재실행했으나 실패했다. 실패 테스트는 `HomeFollowingFragmentSourceTest.following tab branch shows following content and hides other home surfaces`, `HomeFollowingViewModelTest.token이 있으면 repository에 Bearer auth header를 전달한다`이다. `HomeFollowingFragmentSourceTest` 실패는 단독 실행에서도 재현되며, 팔로잉 탭 guard 추가로 `HOME_TAB_FOLLOWING ->` 문자열이 listener와 `showHomeTab` 양쪽에 존재하게 되어 기존 source test가 listener 분기를 잘못 잘라 읽는 것이 원인이다. `HomeFollowingViewModelTest.token이 있으면 repository에 Bearer auth header를 전달한다`는 단독 실행 시 통과해 전체 패턴 실행 중 전역 상태/테스트 순서 영향을 추가 확인해야 한다.
- 2026-06-27: `HomeFollowingFragmentSourceTest`가 `showHomeTab(index)` 내부 팔로잉 분기를 검증하도록 source test 범위를 보정하고, `HomeFollowingViewModelTest`가 전역 `SharedPreferenceManager` 대신 테스트-local token provider를 사용하도록 격리했다. 이후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.*"`를 재실행했고 통과했다.
- 2026-06-27: 사용자 후속 요청으로 Task 3.5가 추가되어 Phase 5.1은 재검증 필요 상태로 되돌렸다.
- 2026-06-27: Task 3.5 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.*"`를 재실행했고 통과했다.
- 2026-06-27: Phase 3/4 코드 리뷰 및 검증 요청에 따라 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLoginGuardSourceTest" --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentLoginGuardSourceTest"`와 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.*"`를 재실행했고 통과했다.
- [ ] **Task 5.2: 컴파일 검증** - [x] **Task 5.2: 컴파일 검증**
- 실행 명령: - 실행 명령:
```bash ```bash
./gradlew :app:compileDebugKotlin ./gradlew :app:compileDebugKotlin
``` ```
- 기대 결과: Kotlin debug compile 통과. - 기대 결과: Kotlin debug compile 통과.
- 검증 기록:
- 2026-06-27: Phase 3/4 코드 리뷰 및 검증 요청에 따라 `./gradlew :app:compileDebugKotlin`을 재실행했고 통과했다.
- 2026-06-27: Phase 3/4 코드 리뷰 및 검증 요청에 따라 `./gradlew :app:compileDebugKotlin`을 재실행했고 통과했다.
- 2026-06-27: Task 3.5 구현 후 `./gradlew :app:compileDebugKotlin`을 재실행했고 통과했다.
- 2026-06-27: Phase 3/4 코드 리뷰 및 검증 요청에 따라 `./gradlew :app:compileDebugKotlin`을 재실행했고 통과했다.
- [ ] **Task 5.3: ktlint 검증** - [x] **Task 5.3: ktlint 검증**
- 실행 명령: - 실행 명령:
```bash ```bash
./gradlew :app:ktlintCheck ./gradlew :app:ktlintCheck
``` ```
- 기대 결과: ktlint 통과. - 기대 결과: ktlint 통과.
- 검증 기록:
- 2026-06-27: Phase 3/4 코드 리뷰 및 검증 요청에 따라 `./gradlew :app:ktlintCheck`를 재실행했고 통과했다.
- 2026-06-27: Phase 3/4 코드 리뷰 및 검증 요청에 따라 `./gradlew :app:ktlintCheck`를 재실행했고 통과했다.
- 2026-06-27: Task 3.5 구현 후 `./gradlew :app:ktlintCheck`를 재실행했고 통과했다.
- 2026-06-27: Phase 3/4 코드 리뷰 및 검증 요청에 따라 `./gradlew :app:ktlintCheck`를 재실행했고 통과했다.
- [ ] **Task 5.4: diff whitespace 검증** - [x] **Task 5.4: diff whitespace 검증**
- 실행 명령: - 실행 명령:
```bash ```bash
git diff --check git diff --check
``` ```
- 기대 결과: whitespace error 없음. - 기대 결과: whitespace error 없음.
- 검증 기록:
- 2026-06-27: Phase 3/4 코드 리뷰 및 검증 요청에 따라 `git diff --check`를 재실행했고 whitespace error가 없음을 확인했다.
- 2026-06-27: Phase 3/4 코드 리뷰 및 검증 요청에 따라 `git diff --check`를 재실행했고 whitespace error가 없음을 확인했다.
- 2026-06-27: Task 3.5 구현 후 `git diff --check`를 재실행했고 whitespace error가 없음을 확인했다.
- 2026-06-27: Phase 3/4 코드 리뷰 및 검증 요청에 따라 `git diff --check`를 재실행했고 whitespace error가 없음을 확인했다.
## Verification Log ## Verification Log
- 2026-06-27: 사용자 요청에 따라 이번 작업은 문서 생성만 수행한다. source/test/helper 구현 및 Gradle 검증은 아직 실행하지 않는다. - 2026-06-27: 사용자 요청에 따라 이번 작업은 문서 생성만 수행한다. source/test/helper 구현 및 Gradle 검증은 아직 실행하지 않는다.
@@ -224,3 +312,13 @@
- 2026-06-27: Phase 1/2 진행 결과 `MainV2LoginGuardSourceTest`와 `MainV2LoginGuard`를 추가했다. 구현 전 단일 source test는 helper 파일 부재로 실패했고, 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.MainV2LoginGuardSourceTest"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 통과했다. - 2026-06-27: Phase 1/2 진행 결과 `MainV2LoginGuardSourceTest`와 `MainV2LoginGuard`를 추가했다. 구현 전 단일 source test는 helper 파일 부재로 실패했고, 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.MainV2LoginGuardSourceTest"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 통과했다.
- 2026-06-27: 리뷰 지적에 따라 빈 `Auth.auth` 콜백을 금지하는 source test를 추가한 뒤 RED를 확인했고, 서버 검증/상태 갱신 후처리 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.MainV2LoginGuardSourceTest"`와 `./gradlew :app:compileDebugKotlin`이 통과했다. - 2026-06-27: 리뷰 지적에 따라 빈 `Auth.auth` 콜백을 금지하는 source test를 추가한 뒤 RED를 확인했고, 서버 검증/상태 갱신 후처리 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.MainV2LoginGuardSourceTest"`와 `./gradlew :app:compileDebugKotlin`이 통과했다.
- 2026-06-27: Phase 1/2 코드 리뷰 지적을 반영한 뒤 검증을 재수행했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.MainV2LoginGuardSourceTest"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`는 모두 통과했다. - 2026-06-27: Phase 1/2 코드 리뷰 지적을 반영한 뒤 검증을 재수행했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.MainV2LoginGuardSourceTest"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`는 모두 통과했다.
- 2026-06-27: Phase 3/4 진행 결과 `HomeMainFragmentLoginGuardSourceTest`, `ContentMainFragmentLoginGuardSourceTest`를 추가하고 `HomeMainFragment`, `ContentMainFragment`의 실제 화면 이동 지점에 v2 main guard helper를 적용했다. 각 source test는 구현 전 RED, 구현 후 GREEN을 확인했다.
- 2026-06-27: Phase 3/4 최종 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeMainFragmentLoginGuardSourceTest" --tests "kr.co.vividnext.sodalive.v2.main.content.ContentMainFragmentLoginGuardSourceTest"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 통과했다. 리뷰 게이트에서 문서 범위 불일치와 `ContentOriginalSeriesUiModel` 비확장 검증 누락을 지적받아 보완했고, 재검토 PASS를 확인했다.
- 2026-06-27: 사용자 요청에 따라 Phase 3의 Task 3.3/3.4를 진행했다. 팔로잉 탭 선택 경로 source test는 구현 전 RED, 구현 후 GREEN을 확인했다.
- 2026-06-27: Phase 3/4 코드 리뷰 및 검증 요청에 따라 변경 범위를 재검토했다. `HomeMainFragment`와 `ContentMainFragment`의 실제 `startActivity` 이동은 v2 main guard helper를 통과하며, invalid route/id return은 guard보다 먼저 유지된다. 판단 가능한 성인 콘텐츠 여부는 `ContentAudioCardUiModel.showAdultBadge`와 전체 탭 audio/series `showAdultBadge`에서 `requiresAdultContentAccess`로 전달된다. 차단 이슈는 발견하지 못했다.
- 2026-06-27: 사용자 추가 요청에 따라 `HomeMainFragment` 팔로잉 탭 선택 전 로그인 가드 요구사항을 PRD와 Plan/Task에 추가했다. 추가 범위가 생겼으므로 Phase 5 검증 체크리스트는 미완료 상태로 되돌렸고, 이후 Task 3.3/3.4 구현 및 검증을 진행했다.
- 2026-06-27: Phase 3/4 코드 리뷰 및 검증 요청에 따라 재검토했다. `TextTabBarView.selectTab()`은 선택 상태를 먼저 적용한 뒤 listener를 호출하므로, 현재 `HomeMainFragment`의 listener guard는 팔로잉 콘텐츠 전환과 데이터 로드는 막지만 비로그인 상태에서 팔로잉 탭 선택 표시가 먼저 바뀔 수 있다. 또한 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.*"`는 실패했으므로 Phase 5.1은 미완료로 유지한다. `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`는 통과했다.
- 2026-06-27: Phase 3/4 코드 리뷰 후속으로 `HomeFollowingFragmentSourceTest`의 팔로잉 분기 추출 범위를 `showHomeTab(index)` 내부로 좁혔고, `HomeFollowingViewModelTest`의 token 검증은 테스트-local token provider로 격리했다. 이후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeFollowingFragmentSourceTest.following tab branch shows following content and hides other home surfaces"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.HomeFollowingViewModelTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 통과했다.
- 2026-06-27: 사용자 후속 요청에 따라 팔로잉 탭 미로그인 차단 시 이전 탭 상태 복구 요구사항을 PRD와 Task 3.5에 추가했다. 구현 전 Phase 5.1은 재검증 필요 상태로 되돌렸다.
- 2026-06-27: Task 3.5 구현 결과 `HomeMainFragment`가 현재 홈 탭 index를 보관하고, 미로그인 팔로잉 탭 선택 시 이전 탭 선택 상태로 복구한 뒤 로그인 가드를 호출하도록 변경했다. `HomeMainFragmentLoginGuardSourceTest`는 구현 전 RED, 구현 후 GREEN을 확인했다. 최종 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 통과했다.
- 2026-06-27: Phase 3/4 코드 리뷰 및 검증 요청에 따라 변경 범위를 재검토했다. `HomeMainFragment`는 실제 이동과 팔로잉 탭 전환이 v2 main guard helper를 통과하며, 미로그인 팔로잉 탭 선택 시 이전 탭 선택 상태로 복구된다. `ContentMainFragment`는 실제 이동이 helper를 통과하고 판단 가능한 성인 콘텐츠 여부를 `requiresAdultContentAccess`로 전달한다. 차단 이슈는 발견하지 못했다. Fresh verification으로 Phase 3/4 전용 source test, `v2.main.*` 전체 test, compile, ktlint, diff whitespace 검증이 통과했다.

View File

@@ -9,6 +9,7 @@ v2 메인 홈/콘텐츠 페이지에서 상세 화면, 외부 링크, 채팅방
비로그인 상태 또는 성인 콘텐츠 접근 조건을 만족하지 않은 상태에서도 `HomeMainFragment``ContentMainFragment`의 일부 화면 이동이 바로 진행될 수 있다. 비로그인 상태 또는 성인 콘텐츠 접근 조건을 만족하지 않은 상태에서도 `HomeMainFragment``ContentMainFragment`의 일부 화면 이동이 바로 진행될 수 있다.
- 홈 추천/팔로잉/랭킹 영역에서 크리에이터 프로필, 오디오 상세, 커뮤니티 글, 채팅방, 라이브 목록 등으로 이동하기 전에 로그인 확인이 일관되게 적용되지 않는다. - 홈 추천/팔로잉/랭킹 영역에서 크리에이터 프로필, 오디오 상세, 커뮤니티 글, 채팅방, 라이브 목록 등으로 이동하기 전에 로그인 확인이 일관되게 적용되지 않는다.
- 홈 팔로잉 탭은 로그인 사용자 전용 콘텐츠 영역이지만, 탭 전환 전에 로그인 가드가 적용되지 않아 비로그인 상태에서도 팔로잉 탭 화면으로 먼저 전환될 수 있다.
- 콘텐츠 추천/랭킹/전체 영역에서 배너, 오디오 상세, 시리즈 상세 이동 전에 로그인 확인이 일관되게 적용되지 않는다. - 콘텐츠 추천/랭킹/전체 영역에서 배너, 오디오 상세, 시리즈 상세 이동 전에 로그인 확인이 일관되게 적용되지 않는다.
- 성인 콘텐츠로 판별 가능한 콘텐츠 이동에서 접속 국가와 본인인증 여부, 성인 콘텐츠 표시 설정이 일관되게 확인되지 않는다. - 성인 콘텐츠로 판별 가능한 콘텐츠 이동에서 접속 국가와 본인인증 여부, 성인 콘텐츠 표시 설정이 일관되게 확인되지 않는다.
- v2 메인 화면에서는 기존 `MainV2Activity.showLoginActivity()` 진입점이 있으나 Fragment 이동 지점에서 공통으로 사용되지 않는다. - v2 메인 화면에서는 기존 `MainV2Activity.showLoginActivity()` 진입점이 있으나 Fragment 이동 지점에서 공통으로 사용되지 않는다.
@@ -17,6 +18,7 @@ v2 메인 홈/콘텐츠 페이지에서 상세 화면, 외부 링크, 채팅방
## 3. Goals ## 3. Goals
- `HomeMainFragment`에서 발생하는 모든 실제 화면 이동 전에 로그인 여부를 확인한다. - `HomeMainFragment`에서 발생하는 모든 실제 화면 이동 전에 로그인 여부를 확인한다.
- `HomeMainFragment`에서 팔로잉 탭을 터치하면 팔로잉 탭 화면으로 전환하기 전에 로그인 여부를 확인한다.
- `ContentMainFragment`에서 발생하는 모든 실제 화면 이동 전에 로그인 여부를 확인한다. - `ContentMainFragment`에서 발생하는 모든 실제 화면 이동 전에 로그인 여부를 확인한다.
- 미로그인 상태에서는 기존 `MainV2Activity.showLoginActivity()`를 호출하고 원래 이동은 실행하지 않는다. - 미로그인 상태에서는 기존 `MainV2Activity.showLoginActivity()`를 호출하고 원래 이동은 실행하지 않는다.
- 로그인 상태에서는 기존 이동 동작과 Intent extra를 유지한다. - 로그인 상태에서는 기존 이동 동작과 Intent extra를 유지한다.
@@ -44,6 +46,7 @@ v2 메인 홈/콘텐츠 페이지에서 상세 화면, 외부 링크, 채팅방
## 6. User Stories ## 6. User Stories
- 비로그인 사용자는 홈/콘텐츠 페이지에서 상세 화면으로 이동하려 할 때 로그인 화면으로 안내받고 싶다. - 비로그인 사용자는 홈/콘텐츠 페이지에서 상세 화면으로 이동하려 할 때 로그인 화면으로 안내받고 싶다.
- 비로그인 사용자는 홈 팔로잉 탭을 터치할 때 팔로잉 탭으로 전환되기 전에 로그인 화면으로 안내받고 싶다.
- 한국 접속 미인증 사용자는 성인 콘텐츠로 이동하려 할 때 본인인증이 필요하다는 안내를 받고 싶다. - 한국 접속 미인증 사용자는 성인 콘텐츠로 이동하려 할 때 본인인증이 필요하다는 안내를 받고 싶다.
- 성인 콘텐츠 표시 설정이 꺼진 사용자는 성인 콘텐츠로 이동하려 할 때 설정 화면으로 안내받고 싶다. - 성인 콘텐츠 표시 설정이 꺼진 사용자는 성인 콘텐츠로 이동하려 할 때 설정 화면으로 안내받고 싶다.
- 로그인 사용자는 기존처럼 탭, 카드, 배너, 랭킹 아이템을 눌렀을 때 해당 화면으로 이동하고 싶다. - 로그인 사용자는 기존처럼 탭, 카드, 배너, 랭킹 아이템을 눌렀을 때 해당 화면으로 이동하고 싶다.
@@ -87,6 +90,10 @@ v2 메인 홈/콘텐츠 페이지에서 상세 화면, 외부 링크, 채팅방
- `openAudioContentDetail` - `openAudioContentDetail`
- `openPopularCommunityPost` - `openPopularCommunityPost`
- 위 이동 지점에 로그인 가드를 적용한다. - 위 이동 지점에 로그인 가드를 적용한다.
- 팔로잉 탭 선택 시 실제 팔로잉 화면으로 전환하기 전에 로그인 가드를 적용한다.
- 팔로잉 탭 선택 시 로그인되어 있으면 기존처럼 팔로잉 탭 화면으로 전환하고, 필요한 경우 기존 `homeFollowingViewModel.loadFollowing()` 흐름을 실행한다.
- 팔로잉 탭 선택 시 미로그인 상태이면 기존 `MainV2Activity.showLoginActivity()`를 호출하고, 팔로잉 탭 화면 전환 및 팔로잉 데이터 로드는 실행하지 않는다.
- 팔로잉 탭 선택 시 미로그인 상태이면 로그인 화면 진입 전후로 홈 탭 선택 상태와 화면은 팔로잉 탭 선택 전 상태를 유지한다.
- 성인 콘텐츠 여부를 판단할 수 있는 홈 이동 지점이 있으면 성인 콘텐츠 가드도 함께 적용한다. - 성인 콘텐츠 여부를 판단할 수 있는 홈 이동 지점이 있으면 성인 콘텐츠 가드도 함께 적용한다.
- 현재 `Unit`으로 남아 있는 클릭 handler는 화면 이동이 아니므로 신규 이동을 만들지 않는다. - 현재 `Unit`으로 남아 있는 클릭 handler는 화면 이동이 아니므로 신규 이동을 만들지 않는다.
@@ -94,6 +101,8 @@ v2 메인 홈/콘텐츠 페이지에서 상세 화면, 외부 링크, 채팅방
- route 또는 id가 유효하지 않아 기존에 return하던 경우에는 로그인 가드 호출 전에 그대로 return한다. - route 또는 id가 유효하지 않아 기존에 return하던 경우에는 로그인 가드 호출 전에 그대로 return한다.
- `ChatRoomType.AI`, `ChatRoomType.DM` 분기별 기존 Intent 생성을 유지한다. - `ChatRoomType.AI`, `ChatRoomType.DM` 분기별 기존 Intent 생성을 유지한다.
- 현재 홈 v2 모델에 성인 콘텐츠 여부 필드가 없는 이동은 로그인 가드만 적용하고, 임의로 adult 판정을 만들지 않는다. - 현재 홈 v2 모델에 성인 콘텐츠 여부 필드가 없는 이동은 로그인 가드만 적용하고, 임의로 adult 판정을 만들지 않는다.
- 추천 탭과 랭킹 탭 전환은 로그인 가드 대상이 아니며 기존 동작을 유지한다.
- 미로그인 사용자가 팔로잉 탭을 터치한 뒤 로그인하지 않고 돌아와도 추천/랭킹 등 이전 홈 탭 상태가 유지된다.
### Feature C: ContentMainFragment 이동 가드 적용 ### Feature C: ContentMainFragment 이동 가드 적용
`ContentMainFragment`의 실제 `startActivity` 이동 지점을 helper로 감싼다. `ContentMainFragment`의 실제 `startActivity` 이동 지점을 helper로 감싼다.
@@ -118,7 +127,9 @@ v2 메인 홈/콘텐츠 페이지에서 상세 화면, 외부 링크, 채팅방
- 한국 접속 미인증 사용자는 성인 콘텐츠 이동 시 기존 앱 패턴과 동일한 본인인증 안내를 받는다. - 한국 접속 미인증 사용자는 성인 콘텐츠 이동 시 기존 앱 패턴과 동일한 본인인증 안내를 받는다.
- 성인 콘텐츠 표시 설정이 꺼진 사용자는 `ContentSettingsActivity`로 이동하며 민감 콘텐츠 안내 Toast가 표시될 수 있다. - 성인 콘텐츠 표시 설정이 꺼진 사용자는 `ContentSettingsActivity`로 이동하며 민감 콘텐츠 안내 Toast가 표시될 수 있다.
- 로그인 사용자의 화면 이동 UX는 기존과 동일하다. - 로그인 사용자의 화면 이동 UX는 기존과 동일하다.
- 탭 전환, 리스트 렌더링, 정렬 팝업, pagination 등 화면 이동이 아닌 동작은 로그인 가드 대상이 아니다. - 홈 팔로잉 탭 전환은 로그인 사용자 전용 콘텐츠 진입으로 간주해 로그인 가드 대상이다.
- 홈 팔로잉 탭 로그인 가드에서 미로그인으로 차단되면, 팔로잉 탭이 선택된 것처럼 표시되지 않고 이전 탭 상태가 유지된다.
- 그 외 탭 전환, 리스트 렌더링, 정렬 팝업, pagination 등 화면 이동이 아닌 동작은 로그인 가드 대상이 아니다.
--- ---
@@ -137,6 +148,7 @@ v2 메인 홈/콘텐츠 페이지에서 상세 화면, 외부 링크, 채팅방
## 10. Metrics ## 10. Metrics
- 구현 후 `HomeMainFragment``ContentMainFragment`의 모든 실제 `startActivity` 이동 지점이 v2 메인 이동 guard helper를 통과한다. - 구현 후 `HomeMainFragment``ContentMainFragment`의 모든 실제 `startActivity` 이동 지점이 v2 메인 이동 guard helper를 통과한다.
- 구현 후 `HomeMainFragment`의 팔로잉 탭 선택은 팔로잉 탭 화면 전환 전에 v2 메인 이동 guard helper를 통과한다.
- 성인 콘텐츠로 판별 가능한 이동은 login -> country/auth -> adult setting 순서로 guard를 통과한다. - 성인 콘텐츠로 판별 가능한 이동은 login -> country/auth -> adult setting 순서로 guard를 통과한다.
- source test가 helper 사용, token 기준, `MainV2Activity.showLoginActivity()` 호출, `countryCode`/`isAuth`/`isAdultContentVisible` 기준, `ContentSettingsActivity` 이동을 검증한다. - source test가 helper 사용, token 기준, `MainV2Activity.showLoginActivity()` 호출, `countryCode`/`isAuth`/`isAdultContentVisible` 기준, `ContentSettingsActivity` 이동을 검증한다.