feat(home): 응원 크리에이터 fallback을 홈 조회에 연결한다

This commit is contained in:
2026-07-10 06:07:20 +09:00
parent 391acf9ee5
commit 7d0cf0a82a
2 changed files with 175 additions and 6 deletions

View File

@@ -1,6 +1,7 @@
package kr.co.vividnext.sodalive.v2.recommendation.application
import kr.co.vividnext.sodalive.v2.common.domain.CreatorActivityType
import kr.co.vividnext.sodalive.v2.recommendation.domain.RecommendationSnapshotWindowPolicy
import kr.co.vividnext.sodalive.v2.recommendation.domain.RecommendedSectionType
import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomeAiCharacterRecommendationRecord
import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomeBannerRecommendationRecord
@@ -13,8 +14,10 @@ import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomeRecommendationQue
import kr.co.vividnext.sodalive.v2.recommendation.port.out.RecentDebutCreatorRecord
import kr.co.vividnext.sodalive.v2.recommendation.port.out.RecentlyActiveCreatorRecord
import kr.co.vividnext.sodalive.v2.recommendation.port.out.RecommendationSnapshotPort
import kr.co.vividnext.sodalive.v2.recommendation.port.out.RecommendationSnapshotRecord
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.Clock
import java.time.LocalDateTime
@Service
@@ -22,8 +25,12 @@ import java.time.LocalDateTime
class HomeRecommendationQueryService(
private val queryPort: HomeRecommendationQueryPort,
private val snapshotPort: RecommendationSnapshotPort,
private val aiCharacterSnapshotFallbackService: AiCharacterSnapshotFallbackPort? = null
private val aiCharacterSnapshotFallbackService: AiCharacterSnapshotFallbackPort? = null,
private val cheerCreatorSnapshotFallbackService: CheerCreatorSnapshotFallbackPort? = null,
private val clock: Clock = Clock.systemUTC()
) {
private val snapshotWindowPolicy = RecommendationSnapshotWindowPolicy()
fun findLiveRecommendations(
offset: Long = 0,
limit: Int = DEFAULT_LIVE_LIMIT,
@@ -95,13 +102,28 @@ class HomeRecommendationQueryService(
limit: Int = DEFAULT_CHEER_CREATOR_LIMIT,
memberId: Long? = null
): List<HomeCheerCreatorRecommendationRecord> {
val snapshots = snapshotPort.findLatestSnapshots(RecommendedSectionType.CHEER_CREATOR).take(CHEER_CREATOR_CANDIDATE_LIMIT)
val snapshots = findCheerCreatorSnapshotsWithFallback()
val detailsById = queryPort.findCheerCreatorRecommendationDetails(snapshots.map { it.targetId }, memberId)
.associateBy { it.creatorId }
return snapshots.mapNotNull { detailsById[it.targetId] }.take(limit)
}
private fun findCheerCreatorSnapshotsWithFallback(): List<RecommendationSnapshotRecord> {
val nowUtc = LocalDateTime.now(clock)
val snapshotAt = snapshotWindowPolicy.previousKstDayUtcWindow(nowUtc).snapshotAt
val snapshots = snapshotPort.findSnapshots(
RecommendedSectionType.CHEER_CREATOR,
snapshotAt,
limit = CHEER_CREATOR_CANDIDATE_LIMIT
)
if (snapshots.isNotEmpty()) return snapshots
if (snapshotPort.existsSnapshot(RecommendedSectionType.CHEER_CREATOR, snapshotAt)) return emptyList()
return cheerCreatorSnapshotFallbackService
?.refreshCheerCreatorIfMissing(offset = 0, limit = CHEER_CREATOR_CANDIDATE_LIMIT, nowUtc = nowUtc)
.orEmpty()
}
fun findPopularCommunityRecommendations(
limit: Int = DEFAULT_POPULAR_COMMUNITY_LIMIT,
memberId: Long? = null,