From ef9ddae94b37b1e0ec099edd08fe6a96c3c633a5 Mon Sep 17 00:00:00 2001 From: Klaus Date: Sat, 27 Jun 2026 06:40:55 +0900 Subject: [PATCH] =?UTF-8?q?feat(recommendation):=20=EC=B2=AB=20=EC=98=A4?= =?UTF-8?q?=EB=94=94=EC=98=A4=20=EC=BD=98=ED=85=90=EC=B8=A0=20=ED=94=8C?= =?UTF-8?q?=EB=9E=98=EA=B7=B8=EB=A5=BC=20=ED=99=95=EC=9E=A5=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...efaultHomeRecommendationQueryRepository.kt | 16 ++++++++++++++-- .../port/out/HomeRecommendationQueryPort.kt | 4 +++- .../dto/ContentOverviewPageResponseTest.kt | 4 +++- ...ltHomeRecommendationQueryRepositoryTest.kt | 19 +++++++++++++++++++ .../HomeRecommendationQueryServiceTest.kt | 4 +++- 5 files changed, 42 insertions(+), 5 deletions(-) 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 5c377153..02ffd7e4 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 @@ -390,6 +390,14 @@ class DefaultHomeRecommendationQueryRepository( ac.release_date as release_date, ac.is_active as is_active, ac.is_point_available as is_point_available, + ac.is_adult as is_adult, + exists ( + select 1 + from series_content csc + join series cs on cs.id = csc.series_id + where csc.content_id = ac.id + and cs.is_original = true + ) as is_original_series, row_number() over ( partition by ac.member_id order by ac.created_at asc, ac.release_date asc, ac.id asc @@ -416,7 +424,9 @@ class DefaultHomeRecommendationQueryRepository( ec.title as title, ec.price as price, ec.cover_image as cover_image, - ec.is_point_available as is_point_available + ec.is_point_available as is_point_available, + ec.is_adult as is_adult, + ec.is_original_series as is_original_series from eligible_contents ec join member m on m.id = ec.creator_id join creator_debut cd on cd.creator_id = ec.creator_id @@ -465,7 +475,9 @@ class DefaultHomeRecommendationQueryRepository( title = row[4] as String, price = (row[5] as Number).toInt(), coverImage = row[6] as String?, - isPointAvailable = row[7] as Boolean + isPointAvailable = row[7] as Boolean, + isAdult = row[8] as Boolean, + isOriginalSeries = row[9] as Boolean ) } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/port/out/HomeRecommendationQueryPort.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/port/out/HomeRecommendationQueryPort.kt index b6c3e220..735ad379 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/port/out/HomeRecommendationQueryPort.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/port/out/HomeRecommendationQueryPort.kt @@ -119,7 +119,9 @@ data class HomeFirstAudioContentRecord( val title: String, val price: Int, val coverImage: String?, - val isPointAvailable: Boolean + val isPointAvailable: Boolean, + val isAdult: Boolean, + val isOriginalSeries: Boolean ) data class HomeAiCharacterRecommendationRecord( diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/content/overview/dto/ContentOverviewPageResponseTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/content/overview/dto/ContentOverviewPageResponseTest.kt index 4ee45cd2..14c2ec0c 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/content/overview/dto/ContentOverviewPageResponseTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/content/overview/dto/ContentOverviewPageResponseTest.kt @@ -65,7 +65,9 @@ class ContentOverviewPageResponseTest { title = "first audio", price = 100, coverImage = "cover/audio.png", - isPointAvailable = true + isPointAvailable = true, + isAdult = true, + isOriginalSeries = true ), coverImage = "https://cdn.test/cover/audio.png", isAdult = true, 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 0fccae42..095f900f 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 @@ -1164,6 +1164,25 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor( assertEquals(listOf(oldest.id), page1.map { it.contentId }) } + @Test + @DisplayName("첫 오디오 콘텐츠는 성인 여부와 오리지널 시리즈 여부를 함께 조회한다") + fun shouldMapFirstAudioContentAdultAndOriginalSeriesFlags() { + val now = LocalDateTime.of(2026, 5, 31, 10, 0) + val creator = saveMember("first-audio-flags", MemberRole.CREATOR) + val content = saveAudioContent(creator, now.minusDays(1), isActive = true, isAdult = false) + val series = saveSeries("first-audio-original-series", creator, isActive = true).apply { + isOriginal = true + } + saveSeriesContent(series, content) + updateCreatedAt("AudioContent", content.id!!, now.minusDays(1)) + flushAndClear() + + val contents = repository.findFirstAudioContents(now, limit = 10) + + assertEquals(false, contents.single().isAdult) + assertEquals(true, contents.single().isOriginalSeries) + } + @Test @DisplayName("첫 오디오 콘텐츠는 회원과 크리에이터의 양방향 차단 관계를 제외한다") fun shouldExcludeBidirectionalBlockedCreatorsFromFirstAudioContents() { diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/application/HomeRecommendationQueryServiceTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/application/HomeRecommendationQueryServiceTest.kt index 7b3434dc..49b2d2ac 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/application/HomeRecommendationQueryServiceTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/application/HomeRecommendationQueryServiceTest.kt @@ -688,7 +688,9 @@ class HomeRecommendationQueryServiceTest { title = "first-audio", price = 10, coverImage = "first-audio.png", - isPointAvailable = true + isPointAvailable = true, + isAdult = false, + isOriginalSeries = false ) ) var aiCharacterDetails: List = emptyList()