docs(home): 홈 추천 Phase 7 산출물을 정리한다

This commit is contained in:
2026-06-01 17:57:42 +09:00
parent 85591c2a8b
commit 9f27d70910
2 changed files with 82 additions and 5 deletions

View File

@@ -429,21 +429,24 @@
### Phase 7: 통합 검증과 문서 갱신
- [ ] **Task 7.1: repository 조건 회귀 테스트 보강**
- [x] **Task 7.1: repository 조건 회귀 테스트 보강**
- Files:
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/HomeRecommendationQueryServiceTest.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommend/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt`
- RED: 차단 관계 양방향 제외, 커뮤니티 성인 노출 조건, 본인인증 여부 조건이 필요한 추천 필터, 팔로우 크리에이터 제외, 비활성 회원 제외 테스트를 추가한다.
- 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommend.application.HomeRecommendationQueryServiceTest`
- GREEN: 누락 조건을 QueryDSL where 조건 또는 service 필터에 추가한다.
- REFACTOR: 같은 차단/성인 조건이 여러 쿼리에 반복되면 repository private 함수로만 정리한다.
- 기대 결과: PRD Edge Case와 회원 조건이 테스트 이름으로 추적된다.
- [ ] **Task 7.2: 운영 지표 기록 지점 확인**
- [x] **Task 7.2: 운영 지표 기록 지점 확인**
- Files:
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt`
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/application/HomeRecommendationFacade.kt`
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/CreatorContentViewHistoryService.kt`
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/RecommendedCreatorFollowService.kt`
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/RecommendationSnapshotRefreshService.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/content/AudioContentServiceTest.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/api/home/HomeRecommendationControllerTest.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/CreatorContentViewHistoryServiceTest.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/RecommendedCreatorFollowServiceTest.kt`
@@ -454,7 +457,7 @@
- REFACTOR: 지표 기록 때문에 공개 응답 스키마나 비즈니스 분기가 바뀌지 않도록 application 경계에서만 정리한다.
- 기대 결과: PRD Metrics 항목이 구현 코드의 로그/metric 지점으로 추적되고 테스트에서 호출 여부를 확인할 수 있다. 특히 콘텐츠 상세 조회의 이력 저장 실패가 사용자 응답을 깨지 않으면서도 운영자가 감지 가능한 신호로 남는다.
- [ ] **Task 7.3: 전체 테스트/린트 검증**
- [x] **Task 7.3: 전체 테스트/린트 검증**
- Files:
- Modify: `docs/20260529_메인_홈_추천_API/plan-task.md`
- TDD 예외 사유: 검증 명령 실행과 문서 기록 task라 제품 코드 테스트를 새로 작성하지 않는다.
@@ -464,7 +467,7 @@
- `./gradlew tasks --all`
- 기대 결과: 세 명령이 모두 성공하고, 이 문서 하단 검증 기록에 실행 일시/명령/결과를 누적한다.
- [ ] **Task 7.4: 신규 엔티티 테이블 생성 SQL 문서화**
- [x] **Task 7.4: 신규 엔티티 테이블 생성 SQL 문서화**
- Files:
- Create: `docs/20260529_메인_홈_추천_API/create-new-entity-tables.sql`
- Modify: `docs/20260529_메인_홈_추천_API/plan-task.md`
@@ -476,13 +479,52 @@
- REFACTOR: SQL 문서에는 이번 작업에서 새로 추가된 테이블만 포함한다. 기존 테이블 변경이나 데이터 마이그레이션은 별도 배포 절차 항목으로 분리하며, Phase 5의 `creator_following` 유니크 제약은 `docs/20260529_메인_홈_추천_API/alter-existing-tables.sql`에 기록한다.
- 기대 결과: Phase 7 완료 시점의 최종 엔티티 구조와 일치하는 신규 테이블 생성 SQL이 문서로 남아 운영 DB 반영 범위를 검토할 수 있다.
- [x] **Task 7.5: 공통 차단 필터 전체 추천 섹션 적용 보완**
- Files:
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/application/HomeRecommendationFacade.kt`
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/HomeRecommendationQueryService.kt`
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommend/port/out/HomeRecommendationQueryPort.kt`
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommend/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommend/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/HomeRecommendationQueryServiceTest.kt`
- RED: 라이브, 최근 활동, 최근 데뷔, 첫 오디오, 최근 응원 상세, 인기 커뮤니티 상세가 회원과 크리에이터의 양방향 활성 차단 관계를 제외하는 테스트를 추가한다. 커뮤니티 성인 노출, 본인인증 기반 성인 노출 조건, 팔로우 제외, 비활성 회원 제외 회귀 테스트 이름을 명시적으로 유지한다.
- 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommend.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest`
- GREEN: facade/service/port/repository에 `memberId` 조회 컨텍스트를 전파하고, QueryDSL/native SQL 조회에 양방향 `block_member` 제외 조건을 적용한다.
- 기대 결과: 장르 추천뿐 아니라 요청된 모든 홈 추천 섹션에서 내가 차단했거나 나를 차단한 크리에이터의 데이터가 제외된다.
- [x] **Task 7.6: 운영 성공 로그 after-commit 기록 보완**
- Files:
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/CreatorContentViewHistoryService.kt`
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/RecommendedCreatorFollowService.kt`
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/RecommendationSnapshotRefreshService.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/CreatorContentViewHistoryServiceTest.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/RecommendedCreatorFollowServiceTest.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/RecommendationSnapshotRefreshServiceTest.kt`
- RED: 조회 이력 저장, 추천 크리에이터 동시 팔로우, 일 스냅샷 갱신 성공 로그가 트랜잭션 커밋 전에는 기록되지 않고 커밋 후 기록되는 테스트를 추가한다.
- 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommend.application.CreatorContentViewHistoryServiceTest --tests kr.co.vividnext.sodalive.v2.recommend.application.RecommendedCreatorFollowServiceTest --tests kr.co.vividnext.sodalive.v2.recommend.application.RecommendationSnapshotRefreshServiceTest`
- GREEN: 성공 로그는 `TransactionSynchronizationManager``afterCommit`으로 등록하고, 트랜잭션 동기화가 없는 단위 실행에서는 기존처럼 즉시 기록한다. 실패 로그와 skip 로그는 기존 동작을 유지한다.
- 기대 결과: 트랜잭션이 커밋되기 전 성공 로그가 먼저 남아 운영 지표를 오염시키지 않는다.
- [x] **Task 7.7: 홈 배너 차단 필터 누락 보완**
- Files:
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/application/HomeRecommendationFacade.kt`
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/HomeRecommendationQueryService.kt`
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommend/port/out/HomeRecommendationQueryPort.kt`
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommend/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommend/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/HomeRecommendationQueryServiceTest.kt`
- RED: 홈 배너 `CREATOR` 대상 크리에이터와 `SERIES` 대상 시리즈 소유자가 회원과 양방향 활성 차단 관계인 경우 제외되는 테스트를 추가한다. `EVENT``LINK` 배너는 기존 활성 조건 기준으로 유지한다.
- 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommend.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest.shouldExcludeBidirectionalBlockedCreatorsFromHomeBanners`
- GREEN: 홈 통합 조회에서 배너 조회에도 `memberId`를 전달하고, 배너 조회 포트/서비스/repository가 `CREATOR``bannerCreator.id`, `SERIES``seriesOwner.id` 기준으로 양방향 `block_member` 제외 조건을 적용한다.
- 기대 결과: 홈 배너 섹션에서도 차단 관계 크리에이터 또는 시리즈 소유자의 추천 데이터가 노출되지 않는다.
---
## PRD Coverage Check
- Feature A: Phase 3, Phase 6, Phase 7에서 통합 조회, limit, 인증/비회원, 팔로우 제외, 콘텐츠 조회 이력, 본인인증 여부, 차단 필터, 스냅샷 빈 배열 처리를 검증한다.
- Feature B: Task 3.1, Task 6.3에서 라이브 최신순/전체보기/비활성 회원 제외와 크리에이터 닉네임/프로필 이미지/라이브 번호 노출 필드를 검증한다.
- Feature C: Task 3.1에서 기존 콘텐츠 홈 배너 재활용, orders 정렬, 동일 orders 랜덤 정렬, 활성 배너/콘텐츠 조건, `EVENT`/`CREATOR`/`SERIES` 대상 비활성 제외, `LINK` 배너의 자체 활성 상태 기준 노출, 앱 이동 필드 유지를 검증한다.
- Feature C: Task 3.1과 Task 7.7에서 기존 콘텐츠 홈 배너 재활용, orders 정렬, 동일 orders 랜덤 정렬, 활성 배너/콘텐츠 조건, `EVENT`/`CREATOR`/`SERIES` 대상 비활성 제외, `CREATOR`/`SERIES` 대상 양방향 차단 제외, `LINK` 배너의 자체 활성 상태 기준 노출, 앱 이동 필드 유지를 검증한다.
- Feature D: Task 1.3, Task 3.1에서 활동 타입 영문 enum, 최신 활동 1개, 크리에이터 프로필 이미지/닉네임, UTC 시간, 이동 대상 id nullable을 검증한다.
- Feature E: Task 1.1, Task 1.2, Task 3.2, Task 6.3에서 데뷔일/점수/동점 랜덤 정렬/프로필 이미지와 닉네임 노출/전체보기를 검증한다.
- Feature F: Task 1.1, Task 3.2, Task 6.3에서 첫 오디오 콘텐츠 판정, 최신성 점수 구간, 예약 공개 제외를 검증한다.
@@ -539,3 +581,11 @@
- 2026-05-31: Phase 4 구현 중 `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommend.application.CreatorContentViewHistoryServiceTest`, `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommend.application.HomeRecommendationQueryServiceTest`, `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommend.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest`, `./gradlew test --tests kr.co.vividnext.sodalive.content.AudioContentServiceTest`를 실행해 모두 `BUILD SUCCESSFUL`을 확인했다.
- 2026-06-01: Phase 6 Task 6.1~6.3을 진행했다. `HomeRecommendationResponse`/`HomeRecommendationPageResponse` API DTO와 `HomeRecommendationFacade`(섹션별 기본 limit 20/20/10/10/10/10/5x8/8/10 전달, 회원의 성인 노출 여부=`member.auth != null``memberId`를 장르/커뮤니티 조회 조건으로 전달, KST→UTC ISO 변환, cloud-front host 이미지 URL 조립)를 추가했다. `HomeRecommendationController`에 통합 조회 `GET /api/v2/home/recommendations`와 전체보기 5개(`/lives`, `/debut-creators`, `/first-audio-contents`, `/ai-characters`, `/communities`)를 추가했고 size 기본값 20/최대 50으로 정규화했다. `SecurityConfig`에 해당 GET endpoint 6개 `permitAll`을 추가해 비회원 접근을 허용했다. `HomeRecommendationControllerTest`에 통합 조회(비회원/회원), 페이징 응답 형식, size 상한 테스트를 추가했고 `./gradlew test --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest`가 12/12 통과했다. ktlint는 이 환경 셸 PATH에 Java가 없어 직접 실행하지 못했고 IDE 인스펙션으로 신규 파일 무경고를 확인했다(컨트롤러의 `@AuthenticationPrincipal` SpEL 문자열 경고는 기존 팔로우 endpoint와 동일한 false positive).
- 2026-06-01: Phase 6 Task 6.4 리뷰 보완을 진행했다. RED에서 `HomeRecommendationControllerTest`에 세부 전체보기 비회원 거부와 음수 `page` 보정 테스트를 추가했고 기존 구현은 `shouldRejectAnonymousSectionPages`, `shouldNormalizeNegativePageToZero` 2건 실패로 확인했다. GREEN에서 `SecurityConfig`는 통합 조회 `GET /api/v2/home/recommendations``permitAll`로 유지하고 전체보기 5개는 회원 인증 대상으로 변경했다. `HomeRecommendationController`는 전체보기 요청에서 인증 회원을 요구하고 `page < 0`을 0으로 보정하며, `HomeRecommendationFacade`는 성인 노출 여부를 `MemberContentPreferenceService.initializeDefaultPreference(member).isAdultContentVisible`와 기존 `isAdultVisibleByPolicy(...)`로 계산하도록 수정했다. 검증으로 `./gradlew test --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest`를 실행해 `BUILD SUCCESSFUL`을 확인했다.
- 2026-06-01: Phase 7 Task 7.1 RED/GREEN을 진행했다. RED에서 `DefaultHomeRecommendationQueryRepositoryTest.shouldExcludeBidirectionalBlockedCreatorsFromGenreCreatorRecommendations`가 양방향 차단 크리에이터를 제외하지 못해 실패했고, GREEN에서 장르 추천 테마 후보/크리에이터 조회 native SQL에 `block_member` 양방향 활성 차단 제외 조건을 추가했다. 검증으로 `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommend.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest.shouldExcludeBidirectionalBlockedCreatorsFromGenreCreatorRecommendations``BUILD SUCCESSFUL`로 통과했다.
- 2026-06-01: Phase 7 Task 7.2 RED/GREEN을 진행했다. RED에서 홈 통합/전체보기 성공, 콘텐츠 조회 이력 저장/스킵, 추천 크리에이터 동시 팔로우 성공/실패, 일 스냅샷 갱신 성공, 콘텐츠 상세 조회 이력 기록 실패 관측 로그 테스트 9건이 로그 이벤트 키 미존재로 실패했다. GREEN에서 기존 프로젝트 관례대로 신규 metric dependency 없이 `LoggerFactory` 구조화 로그를 추가했고, 콘텐츠 상세 조회의 `CreatorContentViewHistoryService.recordView(...)` 실패는 응답 실패로 전파하지 않고 `memberId`, `contentId`, 원인을 로그로 남기도록 했다. 검증으로 Phase 7 대상 테스트 묶음 `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommend.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest --tests kr.co.vividnext.sodalive.v2.recommend.application.CreatorContentViewHistoryServiceTest --tests kr.co.vividnext.sodalive.v2.recommend.application.RecommendedCreatorFollowServiceTest --tests kr.co.vividnext.sodalive.v2.recommend.application.RecommendationSnapshotRefreshServiceTest --tests kr.co.vividnext.sodalive.content.AudioContentServiceTest``BUILD SUCCESSFUL`로 통과했다. 추천 섹션별 클릭률은 별도 클릭 ingress가 없어 이번 범위에서는 응답/impression 관측 로그만 추가했다.
- 2026-06-01: Phase 7 리뷰 지적에 따라 홈 통합 조회와 라이브 전체보기 조회 실패 로그 테스트를 추가하고, `HomeRecommendationFacade`에서 실패 시 `home_recommendations_query_failure`, `home_recommendations_page_query_failure` 로그를 남긴 뒤 예외를 재전파하도록 보강했다. 검증으로 `./gradlew test --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest.shouldLogHomeRecommendationFailure --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest.shouldLogHomeRecommendationPageFailure``BUILD SUCCESSFUL`로 통과했다.
- 2026-06-01: Phase 7 재리뷰 지적에 따라 최근 데뷔/첫 오디오/AI 캐릭터 전체보기 실패도 `home_recommendations_page_query_failure` 로그를 남긴 뒤 예외를 재전파하도록 보강했다. 검증으로 `./gradlew test --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest.shouldLogOtherHomeRecommendationPageFailures``BUILD SUCCESSFUL`로 통과했고, 이후 `./gradlew ktlintCheck``BUILD SUCCESSFUL in 16s`, `./gradlew test``BUILD SUCCESSFUL in 54s`로 통과했다.
- 2026-06-01: Phase 7 Task 7.4로 신규 엔티티 테이블 생성 SQL `docs/20260529_메인_홈_추천_API/create-new-entity-tables.sql`을 작성했다. 최종 JPA 엔티티 기준으로 `recommendation_snapshot`, `creator_content_view_history` 두 신규 테이블만 포함했고, 기존 테이블 변경은 `alter-existing-tables.sql` 범위로 유지했다. 검증으로 `rg -n "CREATE TABLE|create table|recommendation_snapshot|creator_content_view_history" docs/20260529_메인_홈_추천_API/create-new-entity-tables.sql``./gradlew tasks --all`이 모두 성공했다.
- 2026-06-01: Phase 7 Task 7.3 전체 검증을 순차 실행했다. `./gradlew ktlintCheck`는 처음에 신규 로그 호출의 긴 라인과 리뷰 보완 후 테스트 import 순서로 실패했고 줄바꿈/import 정리 후 통과했다. 최종 재리뷰 보완 후 `./gradlew ktlintCheck``BUILD SUCCESSFUL in 16s`, `./gradlew test``BUILD SUCCESSFUL in 54s`로 통과했고, `./gradlew tasks --all`은 앞선 Task 7.4 검증에서 `BUILD SUCCESSFUL in 1s`로 통과했다.
- 2026-06-01: Phase 7 Task 7.5~7.6 보완을 진행했다. 라이브/최근 활동/최근 데뷔/첫 오디오/최근 응원/인기 커뮤니티에 회원 `memberId` 조회 컨텍스트를 전달하고 양방향 활성 차단 관계를 제외하도록 수정했다. 커뮤니티 성인 노출, 본인인증 기반 성인 노출 조건, 팔로우 제외, 비활성 회원 제외 회귀 테스트 이름을 명시적으로 유지하고, 조회 이력/동시 팔로우/스냅샷 성공 로그는 트랜잭션 커밋 후 기록되도록 보완했다. 검증으로 Phase 7 대상 테스트 묶음, `./gradlew ktlintCheck`, `./gradlew test`가 모두 `BUILD SUCCESSFUL`로 통과했다.
- 2026-06-01: 리뷰 게이트 Context Mining에서 홈 배너 `CREATOR`/`SERIES` 대상의 차단 필터 누락을 발견해 Phase 7 Task 7.7로 보완했다. 홈 통합 조회의 배너 조회에도 `memberId`를 전달하고, 배너 repository 조회에서 `CREATOR`는 대상 크리에이터, `SERIES`는 시리즈 소유자 기준 양방향 활성 `block_member` 제외 조건을 적용했다. 회귀 테스트 `DefaultHomeRecommendationQueryRepositoryTest.shouldExcludeBidirectionalBlockedCreatorsFromHomeBanners``HomeRecommendationQueryServiceTest`를 추가/보강했고, `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommend.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest.shouldExcludeBidirectionalBlockedCreatorsFromHomeBanners --tests kr.co.vividnext.sodalive.v2.recommend.application.HomeRecommendationQueryServiceTest``BUILD SUCCESSFUL`로 통과했다.