docs(home): 메인 홈 추천 Phase 4 진행 상황을 정리한다

This commit is contained in:
2026-05-31 18:21:45 +09:00
parent 5bea7cfb64
commit 82b2eb75d4

View File

@@ -266,7 +266,7 @@
### Phase 4: 콘텐츠 조회 이력 기록
- [ ] **Task 4.1: 콘텐츠 조회 이력 엔티티/서비스 작성**
- [x] **Task 4.1: 콘텐츠 조회 이력 엔티티/서비스 작성**
- Files:
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommend/port/out/CreatorContentViewHistoryPort.kt`
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommend/adapter/out/persistence/CreatorContentViewHistory.kt`
@@ -279,19 +279,19 @@
- REFACTOR: 동일 회원/콘텐츠의 연속 중복 저장 허용 여부는 추천 이력으로 보존하며, 집계 시 distinct 장르 기준으로 처리한다.
- 기대 결과: 조회 이력 저장 실패가 콘텐츠 상세 조회 자체를 실패시키지 않도록 호출부에서 예외 전파 범위를 제한한다.
- [ ] **Task 4.2: 장르 기반 크리에이터 추천 조회 구현**
- [x] **Task 4.2: 장르 기반 크리에이터 추천 조회 구현**
- 선행 조건: Task 4.1의 `CreatorContentViewHistory` 엔티티/리포지토리/저장 service가 준비되어 있어야 한다.
- Files:
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommend/application/HomeRecommendationQueryService.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/application/HomeRecommendationQueryServiceTest.kt`
- RED: 조회 이력 장르 랜덤 5개, 부족분 랜덤 보충, 장르별 8명, 한 응답의 5개 장르 안에서 크리에이터 중복 제거, 서로 다른 조회 시점에서는 같은 크리에이터 재노출 허용, 팔로우 크리에이터 제외, 크리에이터 프로필 이미지/닉네임/id 노출 테스트를 작성한다.
- RED: 조회 이력 콘텐츠의 `content_theme` 기준 랜덤 5개, 부족분 랜덤 보충, 테마별 8명, 한 응답의 5개 테마 안에서 크리에이터 중복 제거, 서로 다른 조회 시점에서는 같은 크리에이터 재노출 허용, 팔로우 크리에이터 제외, 활성 크리에이터/활성 콘텐츠가 없어 빈 그룹이 되는 테마 제외, 크리에이터 프로필 이미지/닉네임/id 노출 테스트를 작성한다.
- 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommend.application.HomeRecommendationQueryServiceTest`
- GREEN: `CreatorContentViewHistory`와 콘텐츠 장르 매핑을 기반으로 후보 장르/크리에이터를 조회한다.
- REFACTOR: 성인 장르`MemberContentPreference.isAdultContentVisible == true` 회원에게만 포함되도록 조건을 공통화한다.
- 기대 결과: 비회원 또는 조회 이력 없는 회원도 조회 가능한 장르 중 랜덤 5개를 받다.
- GREEN: `CreatorContentViewHistory.contentId``content.theme_id` 매핑을 기반으로 후보 테마/크리에이터를 조회한다. 기존 응답 필드명은 공개 스키마 호환을 위해 `genreId`, `genreName`을 유지하되 값은 `content_theme.id`, `content_theme.theme`을 담는다.
- REFACTOR: 성인 콘텐츠 테마`MemberContentPreference.isAdultContentVisible == true` 회원에게만 포함되도록 조건을 공통화한다.
- 기대 결과: 비회원 또는 조회 이력 없는 회원도 조회 가능한 테마 중 랜덤 5개를 받고, 활성 크리에이터/활성 콘텐츠가 없는 빈 그룹은 제외한 뒤 다른 테마로 보충된다.
- [ ] **Task 4.3: 기존 콘텐츠 상세 조회 흐름에 이력 기록 연결**
- [x] **Task 4.3: 기존 콘텐츠 상세 조회 흐름에 이력 기록 연결**
- Files:
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/content/AudioContentServiceTest.kt`
@@ -381,11 +381,11 @@
- 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: 메인 홈 API 성공/실패와 응답 시간, 섹션별 빈 응답 여부, 전체보기 조회 수, 추천 섹션별 클릭률 기록 지점, 동시 팔로우 요청/성공 수, 콘텐츠 조회 이력 기록 성공/실패, 일 배치 집계 성공/실패와 소요 시간을 관측할 수 있는 로그 또는 metric 호출 테스트를 작성한다.
- RED: 메인 홈 API 성공/실패와 응답 시간, 섹션별 빈 응답 여부, 전체보기 조회 수, 추천 섹션별 클릭률 기록 지점, 동시 팔로우 요청/성공 수, 콘텐츠 조회 이력 기록 성공/실패, 콘텐츠 상세 조회 흐름에서 `CreatorContentViewHistoryService.recordView(...)` 실패가 `runCatching`으로 삼켜지더라도 구조화 로그 또는 metric으로 관측되는지, 일 배치 집계 성공/실패와 소요 시간을 관측할 수 있는 로그 또는 metric 호출 테스트를 작성한다.
- 실패 확인: `./gradlew test --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`
- GREEN: 프로젝트에 이미 사용하는 metric 클라이언트가 있으면 해당 클라이언트를 사용하고, 없으면 구조화 로그로 PRD Metrics 항목을 관측 가능하게 남긴다.
- GREEN: 프로젝트에 이미 사용하는 metric 클라이언트가 있으면 해당 클라이언트를 사용하고, 없으면 구조화 로그로 PRD Metrics 항목을 관측 가능하게 남긴다. 콘텐츠 조회 이력 저장 실패는 상세 조회 응답 실패로 전파하지 않되, 실패 원인과 `memberId`, `contentId`를 추적 가능한 형태로 남긴다.
- REFACTOR: 지표 기록 때문에 공개 응답 스키마나 비즈니스 분기가 바뀌지 않도록 application 경계에서만 정리한다.
- 기대 결과: PRD Metrics 항목이 구현 코드의 로그/metric 지점으로 추적되고 테스트에서 호출 여부를 확인할 수 있다.
- 기대 결과: PRD Metrics 항목이 구현 코드의 로그/metric 지점으로 추적되고 테스트에서 호출 여부를 확인할 수 있다. 특히 콘텐츠 상세 조회의 이력 저장 실패가 사용자 응답을 깨지 않으면서도 운영자가 감지 가능한 신호로 남는다.
- [ ] **Task 7.3: 전체 테스트/린트 검증**
- Files:
@@ -465,7 +465,7 @@
- 2026-05-31: Phase 3에는 `CreatorContentViewHistory` 엔티티/리포지토리/저장 서비스가 아직 구현되어 있지 않아 장르 기반 크리에이터 추천 조회를 포함하지 않았다. 해당 산출물은 Phase 4 Task 4.1 범위이므로, 장르 기반 크리에이터 추천 조회는 조회 이력 저장 모델이 준비된 뒤 Phase 4 Task 4.2에서 별도 RED/GREEN으로 진행한다.
- 2026-05-31: Phase 3 리뷰 후속으로 인기 커뮤니티 추천이 상위 10개 스냅샷을 먼저 자른 뒤 크리에이터 중복을 제거해 10개 미만으로 내려갈 수 있는 문제를 보완했다. RED에서 상위 스냅샷 중복 제거 후 뒤 후보로 기본 10개를 채우는 테스트가 실패했고, GREEN에서 인기 커뮤니티만 최신 스냅샷 후보 20개를 읽은 뒤 상세 조립/크리에이터 중복 제거 후 최종 10개를 반환하도록 수정했다. 후속 검증으로 `./gradlew test --rerun-tasks --tests kr.co.vividnext.sodalive.v2.recommend.application.HomeRecommendationQueryServiceTest --tests kr.co.vividnext.sodalive.v2.recommend.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest --tests kr.co.vividnext.sodalive.v2.recommend.application.RecommendationSnapshotRefreshServiceTest`, `./gradlew test --tests 'kr.co.vividnext.sodalive.v2.recommend.*'`, `./gradlew ktlintCheck`, `./gradlew test`를 순차 실행했고 모두 `BUILD SUCCESSFUL`로 통과했다.
- 2026-05-31: 사용자 피드백에 따라 신규 엔티티 테이블 생성 SQL은 Phase 7 완료 후 최종 엔티티 구조 기준으로 작성하도록 계획을 보강했다. `RecommendationSnapshot`, `CreatorContentViewHistory` 등 이번 작업에서 새로 생성된 엔티티의 운영 DB DDL을 `docs/20260529_메인_홈_추천_API/create-new-entity-tables.sql` 산출물로 남기는 Task 7.4를 추가했다.
- 2026-05-31: PRD와 plan-task를 재대조해 큰 기능 흐름은 반영되어 있었으나 일부 PRD 세부 항목의 task 추적성이 약한 점을 확인했다. 라이브/활동/최근 데뷔/최근 응원/인기 커뮤니티/장르 크리에이터 노출 필드, `LINK` 배너 자체 활성 상태 기준, 활동 enum 영문 code 안정성, 한 응답 내 장르 크리에이터 중복 제거와 조회 시점별 재노출 허용, 추천 섹션별 클릭률 metric, Non-Goals 범위를 관련 task와 Coverage Check에 보강했다.
- 2026-05-31: Phase 2/3 재점검 후속으로 배너 대상 활성 조건과 스냅샷 데뷔일 계산의 빈 `channel_name` 라이브 제외 누락을 확인했다. RED에서 `DefaultHomeRecommendationQueryRepositoryTest`에 회귀 테스트를 추가했고 `shouldExcludeHomeBannersWithInactiveTargetsExceptLink`, `shouldExcludeBlankChannelNameLiveFromSnapshotDebutAt`가 실패했다. GREEN에서 `findHomeBanners``EVENT`/`CREATOR`/`SERIES` 대상 활성 조건을 추가하고, 최근 응원/인기 커뮤니티 데뷔일 CTE에 `lr.channel_name <> ''` 조건을 추가했다. 리뷰 중 PRD의 인기 커뮤니티 성인 노출 조건은 항상 제외가 아니라 `MemberContentPreference.isAdultContentVisible == true` 회원에게 노출 허용임을 재확인해, 스냅샷 산정은 성인 게시글도 후보로 유지하고 상세 조회에서 `includeAdultCommunities`로 필터링하도록 수정했다. 추가 코드 리뷰에서 기존 홈 배너가 `tabId = 1`일 때 `tab is null`만 조회하는 계약을 확인해, `findHomeBanners``cb.tab_id is null` 조건과 탭 전용 배너 제외 회귀 테스트를 보강했다. 후속 검증으로 `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommend.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest`, `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommend.application.HomeRecommendationQueryServiceTest --tests kr.co.vividnext.sodalive.v2.recommend.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest --tests kr.co.vividnext.sodalive.v2.recommend.application.RecommendationSnapshotRefreshServiceTest`, `./gradlew test --tests 'kr.co.vividnext.sodalive.v2.recommend.*'`, `./gradlew ktlintCheck`가 모두 `BUILD SUCCESSFUL`로 통과했다. 병렬 Gradle test 실행 중 XML 결과 파일 쓰기 충돌로 한 번 실패했으나, 동일 명령 단독 재실행 시 성공해 테스트 assertion 실패가 아님을 확인했다.
- 2026-05-31: 사용자 피드백에 따라 여러 크리에이터 동시 팔로우에서 본인 크리에이터 id는 전체 실패 조건에서 제외하고, 이미 팔로우 중인 id와 동일하게 `skippedCreatorIds`로 반환하도록 PRD와 plan-task를 수정했다.
- 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`을 확인했다.