From 075ca88f01a88a36389c10d055a1dbc4ae1be817 Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 22 Jul 2026 21:25:04 +0900 Subject: [PATCH] =?UTF-8?q?fix(home):=20=EC=A2=85=EB=A3=8C=EB=90=9C=20?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=20=EB=8D=B0=EB=B7=94=20=ED=8C=90?= =?UTF-8?q?=EC=A0=95=EC=9D=84=20=EB=B3=B4=EA=B0=95=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/20260529_메인_홈_추천_API/plan-task.md | 4 ++- docs/20260529_메인_홈_추천_API/prd.md | 1 + ...efaultHomeRecommendationQueryRepository.kt | 3 +-- ...ltHomeRecommendationQueryRepositoryTest.kt | 26 +++++++++++++++++++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/docs/20260529_메인_홈_추천_API/plan-task.md b/docs/20260529_메인_홈_추천_API/plan-task.md index d0bfa4cb..07412812 100644 --- a/docs/20260529_메인_홈_추천_API/plan-task.md +++ b/docs/20260529_메인_홈_추천_API/plan-task.md @@ -259,9 +259,11 @@ - Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/application/HomeRecommendationQueryServiceTest.kt` - RED: 데뷔 후 30일 이내 추천 점수순, 최근 데뷔 크리에이터 노출 정보의 프로필 이미지/닉네임, 첫 오디오 콘텐츠 3번째 이내 활성 콘텐츠만 인정, 최신성 점수 구간별 정렬, 예약 공개 콘텐츠 제외 테스트를 작성한다. - 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.application.HomeRecommendationQueryServiceTest` - - GREEN: 데뷔일 계산, 최근 7일/30일 집계, `release_date` 기준 최신성 점수, 동점 랜덤 정렬을 구현한다. + - GREEN: 데뷔일 계산, 최근 7일/30일 집계, `release_date` 기준 최신성 점수, 동점 랜덤 정렬을 구현한다. 최근 데뷔 크리에이터의 라이브 기준 데뷔 판정은 종료된 라이브도 유지되는 `live_room.channel_name` 존재 여부를 기준으로 하며, 종료 시 `false`가 되는 `live_room.is_active`는 조건으로 사용하지 않는다. - REFACTOR: 데뷔일 계산은 `CreatorDebutPolicy`, 산식은 `RecommendationScorePolicy`만 호출하도록 중복 제거한다. - 기대 결과: 앞선 비활성 콘텐츠가 3개 이상이면 이후 활성 콘텐츠가 제외된다. + - 검증 기록: + - 2026-07-22: 종료된 라이브도 `channel_name`이 있으면 최근 데뷔 크리에이터의 라이브 데뷔로 인정하도록 `DefaultHomeRecommendationQueryRepositoryTest.shouldIncludeEndedLiveWithChannelNameInRecentDebutCreators`를 추가했다. RED에서 기존 SQL의 `lr.is_active = true` 조건 때문에 실패했고, GREEN에서 `findRecentDebutCreators`의 live 데뷔 branch가 `channel_name` 기준만 사용하도록 수정해 focused test가 `BUILD SUCCESSFUL`로 통과했다. - [x] **Task 3.3: AI 캐릭터/응원/인기 커뮤니티 스냅샷 조회 구현** - Files: diff --git a/docs/20260529_메인_홈_추천_API/prd.md b/docs/20260529_메인_홈_추천_API/prd.md index a578bc53..6ea62a31 100644 --- a/docs/20260529_메인_홈_추천_API/prd.md +++ b/docs/20260529_메인_홈_추천_API/prd.md @@ -132,6 +132,7 @@ - 전체 리스트 API는 페이징으로 조회할 수 있어야 한다. - 데뷔일은 콘텐츠를 처음 공개한 날과 라이브를 한 날 중 빠른 날짜로 계산한다. - 데뷔일 계산 로직은 기존 `ExplorerService.getCreatorDetail`의 `debutDateTime` 계산 방식과 동일하게 맞춘다. +- 라이브 기준 데뷔 판정은 `live_room.channel_name`이 존재하고 빈 값이 아닌 라이브를 사용한다. 종료된 라이브는 `live_room.is_active = false`가 되므로 최근 데뷔 판정에서 `is_active`는 조건으로 사용하지 않는다. - 데뷔 후 30일 이내 크리에이터만 대상으로 한다. - 추천 점수는 `((팔로우 증가량 * 0.35) + (콘텐츠 활동 점수 * 0.3) + (소통 점수 * 0.2)) * 신규 부스트`로 계산한다. - 팔로우 증가량은 최근 7일간 신규 팔로우한 유저 수로 계산한다. diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt index 942dc8ce..0b5bdf43 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt @@ -228,8 +228,7 @@ class DefaultHomeRecommendationQueryRepository( union all select lr.member_id as creator_id, lr.begin_date_time as debut_at from live_room lr - where lr.is_active = true - and lr.channel_name is not null + where lr.channel_name is not null and lr.channel_name <> '' and lr.begin_date_time <= :now and (:includeAdultContents = true or lr.is_adult = false) diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt index ea202b9b..5ea19c98 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt @@ -1245,6 +1245,32 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor( assertEquals(listOf(newHighScoreCreator.id, newLowScoreCreator.id), creators.map { it.creatorId }) } + @Test + @DisplayName("최근 데뷔 크리에이터는 종료된 라이브도 채널명이 있으면 라이브 데뷔로 인정한다") + fun shouldIncludeEndedLiveWithChannelNameInRecentDebutCreators() { + val now = LocalDateTime.of(2026, 5, 31, 10, 0) + val endedLiveCreator = saveMember("ended-live-debut", MemberRole.CREATOR) + val blankChannelCreator = saveMember("blank-ended-live-debut", MemberRole.CREATOR) + + saveLiveRoom( + endedLiveCreator, + now.minusDays(5), + channelName = "ended-live-channel", + isActive = false + ) + saveLiveRoom( + blankChannelCreator, + now.minusDays(4), + channelName = "", + isActive = false + ) + flushAndClear() + + val creators = repository.findRecentDebutCreators(now, limit = 10) + + assertEquals(listOf(endedLiveCreator.id), creators.map { it.creatorId }) + } + @Test @DisplayName("최근 데뷔 크리에이터는 인기 커뮤니티 전용 부스트가 아니라 기존 신규 부스트를 유지한다") fun shouldKeepOriginalNewBoostForRecentDebutCreators() {