feat(recommend): 홈 추천 전체보기 페이징 조회를 추가한다

This commit is contained in:
2026-06-01 13:54:40 +09:00
parent f77bd7b8e2
commit 1f3a38a404
5 changed files with 111 additions and 29 deletions

View File

@@ -13,7 +13,6 @@ import kr.co.vividnext.sodalive.v2.recommend.port.out.HomeRecommendationQueryPor
import kr.co.vividnext.sodalive.v2.recommend.port.out.RecentDebutCreatorRecord
import kr.co.vividnext.sodalive.v2.recommend.port.out.RecentlyActiveCreatorRecord
import kr.co.vividnext.sodalive.v2.recommend.port.out.RecommendationSnapshotPort
import kr.co.vividnext.sodalive.v2.recommend.port.out.RecommendationSnapshotRecord
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.LocalDateTime
@@ -24,36 +23,48 @@ class HomeRecommendationQueryService(
private val queryPort: HomeRecommendationQueryPort,
private val snapshotPort: RecommendationSnapshotPort
) {
fun findLiveRecommendations(limit: Int = DEFAULT_LIVE_LIMIT): List<HomeLiveRecommendationRecord> {
return queryPort.findLiveRecommendations(limit)
fun findLiveRecommendations(
offset: Int = 0,
limit: Int = DEFAULT_LIVE_LIMIT,
includeAdultLives: Boolean = false
): List<HomeLiveRecommendationRecord> {
return queryPort.findLiveRecommendations(offset, limit, includeAdultLives)
}
fun findHomeBanners(limit: Int = DEFAULT_BANNER_LIMIT): List<HomeBannerRecommendationRecord> {
return queryPort.findHomeBanners(limit)
}
fun findRecentlyActiveCreators(limit: Int = DEFAULT_ACTIVE_CREATOR_LIMIT): List<RecentlyActiveCreatorRecord> {
return queryPort.findRecentlyActiveCreators(limit)
fun findRecentlyActiveCreators(
limit: Int = DEFAULT_ACTIVE_CREATOR_LIMIT,
includeAdultActivities: Boolean = false
): List<RecentlyActiveCreatorRecord> {
return queryPort.findRecentlyActiveCreators(limit, includeAdultActivities)
}
fun findRecentDebutCreators(
now: LocalDateTime,
limit: Int = DEFAULT_RECENT_DEBUT_CREATOR_LIMIT
offset: Int = 0,
limit: Int = DEFAULT_RECENT_DEBUT_CREATOR_LIMIT,
includeAdultContents: Boolean = false
): List<RecentDebutCreatorRecord> {
return queryPort.findRecentDebutCreators(now, limit)
return queryPort.findRecentDebutCreators(now, offset, limit, includeAdultContents)
}
fun findFirstAudioContents(
now: LocalDateTime,
limit: Int = DEFAULT_FIRST_AUDIO_CONTENT_LIMIT
offset: Int = 0,
limit: Int = DEFAULT_FIRST_AUDIO_CONTENT_LIMIT,
includeAdultContents: Boolean = false
): List<HomeFirstAudioContentRecord> {
return queryPort.findFirstAudioContents(now, limit)
return queryPort.findFirstAudioContents(now, offset, limit, includeAdultContents)
}
fun findAiCharacterRecommendations(
offset: Int = 0,
limit: Int = DEFAULT_AI_CHARACTER_LIMIT
): List<HomeAiCharacterRecommendationRecord> {
val snapshots = latestSnapshots(RecommendedSectionType.AI_CHARACTER, limit)
val snapshots = snapshotPort.findLatestSnapshots(RecommendedSectionType.AI_CHARACTER, offset, limit)
val detailsById = queryPort.findAiCharacterRecommendationDetails(snapshots.map { it.targetId })
.associateBy { it.characterId }
@@ -63,7 +74,7 @@ class HomeRecommendationQueryService(
fun findCheerCreatorRecommendations(
limit: Int = DEFAULT_CHEER_CREATOR_LIMIT
): List<HomeCheerCreatorRecommendationRecord> {
val snapshots = latestSnapshots(RecommendedSectionType.CHEER_CREATOR, limit)
val snapshots = snapshotPort.findLatestSnapshots(RecommendedSectionType.CHEER_CREATOR).take(limit)
val detailsById = queryPort.findCheerCreatorRecommendationDetails(snapshots.map { it.targetId })
.associateBy { it.creatorId }
@@ -74,7 +85,8 @@ class HomeRecommendationQueryService(
limit: Int = DEFAULT_POPULAR_COMMUNITY_LIMIT,
includeAdultCommunities: Boolean = false
): List<HomePopularCommunityRecommendationRecord> {
val snapshots = latestSnapshots(RecommendedSectionType.POPULAR_COMMUNITY, POPULAR_COMMUNITY_CANDIDATE_LIMIT)
val snapshots = snapshotPort.findLatestSnapshots(RecommendedSectionType.POPULAR_COMMUNITY)
.take(POPULAR_COMMUNITY_CANDIDATE_LIMIT)
val detailsById = queryPort.findPopularCommunityRecommendationDetails(
snapshots.map { it.targetId },
includeAdultCommunities
@@ -112,10 +124,6 @@ class HomeRecommendationQueryService(
}
}
private fun latestSnapshots(sectionType: RecommendedSectionType, limit: Int): List<RecommendationSnapshotRecord> {
return snapshotPort.findLatestSnapshots(sectionType).take(limit)
}
companion object {
private const val DEFAULT_LIVE_LIMIT = 20
private const val DEFAULT_BANNER_LIMIT = 20

View File

@@ -4,15 +4,29 @@ import kr.co.vividnext.sodalive.v2.recommend.domain.RecommendedActivityType
import java.time.LocalDateTime
interface HomeRecommendationQueryPort {
fun findLiveRecommendations(limit: Int): List<HomeLiveRecommendationRecord>
fun findLiveRecommendations(
offset: Int = 0,
limit: Int,
includeAdultLives: Boolean = false
): List<HomeLiveRecommendationRecord>
fun findHomeBanners(limit: Int): List<HomeBannerRecommendationRecord>
fun findRecentlyActiveCreators(limit: Int): List<RecentlyActiveCreatorRecord>
fun findRecentlyActiveCreators(limit: Int, includeAdultActivities: Boolean = false): List<RecentlyActiveCreatorRecord>
fun findRecentDebutCreators(now: LocalDateTime, limit: Int): List<RecentDebutCreatorRecord>
fun findRecentDebutCreators(
now: LocalDateTime,
offset: Int = 0,
limit: Int,
includeAdultContents: Boolean = false
): List<RecentDebutCreatorRecord>
fun findFirstAudioContents(now: LocalDateTime, limit: Int): List<HomeFirstAudioContentRecord>
fun findFirstAudioContents(
now: LocalDateTime,
offset: Int = 0,
limit: Int,
includeAdultContents: Boolean = false
): List<HomeFirstAudioContentRecord>
fun findAiCharacterSnapshots(
windowStart: LocalDateTime,

View File

@@ -4,7 +4,11 @@ import kr.co.vividnext.sodalive.v2.recommend.domain.RecommendedSectionType
import java.time.LocalDateTime
interface RecommendationSnapshotPort {
fun findLatestSnapshots(sectionType: RecommendedSectionType): List<RecommendationSnapshotRecord>
fun findLatestSnapshots(
sectionType: RecommendedSectionType,
offset: Int = 0,
limit: Int = Int.MAX_VALUE
): List<RecommendationSnapshotRecord>
fun replaceSnapshots(
sectionType: RecommendedSectionType,