Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package codel.recommendation.business

import codel.member.domain.Member
import codel.recommendation.domain.AgePreference
import codel.recommendation.domain.RecommendationConfig
import org.springframework.stereotype.Component

/**
* 나이 선호도 설정을 조회하는 Resolver
*
* 현재는 서비스 전역 설정(Config)에서 가져오지만,
* 미래에는 회원별 개인 설정으로 확장 가능
*
* @see AgePreference
*/
@Component
class AgePreferenceResolver(
private val recommendationConfig: RecommendationConfig
) {

/**
* 특정 회원의 나이 선호도 설정을 조회
*
* Phase 1: Config 기본값 반환
* Phase 2 (미래): 회원 설정이 있으면 우선 사용, 없으면 Config fallback
*
* @param member 대상 회원
* @return 해당 회원에게 적용할 나이 선호도 설정
*/
fun resolve(member: Member): AgePreference {
// Phase 1: Config 기본값 반환
// TODO: Phase 2에서 회원별 설정 테이블 조회 로직 추가
// val memberPreference = memberPreferenceRepository.findByMemberId(member.id)
// if (memberPreference != null) {
// return AgePreference(
// preferredMaxDiff = memberPreference.agePreferredMaxDiff,
// cutoffDiff = memberPreference.ageCutoffDiff,
// allowCutoffWhenInsufficient = memberPreference.ageAllowCutoffWhenInsufficient
// )
// }

return AgePreference(
preferredMaxDiff = recommendationConfig.agePreferredMaxDiff,
cutoffDiff = recommendationConfig.ageCutoffDiff,
allowCutoffWhenInsufficient = recommendationConfig.ageAllowCutoffWhenInsufficient
)
}

/**
* 기본 나이 선호도 설정 조회 (회원 정보 없이)
*
* @return Config 기본 나이 선호도 설정
*/
fun resolveDefault(): AgePreference {
return AgePreference(
preferredMaxDiff = recommendationConfig.agePreferredMaxDiff,
cutoffDiff = recommendationConfig.ageCutoffDiff,
allowCutoffWhenInsufficient = recommendationConfig.ageAllowCutoffWhenInsufficient
)
}
}
24 changes: 19 additions & 5 deletions src/main/kotlin/codel/recommendation/business/CodeTimeService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ class CodeTimeService(
private val bucketService: RecommendationBucketService,
private val historyService: RecommendationHistoryService,
private val exclusionService: RecommendationExclusionService,
private val timeZoneService: TimeZoneService
private val timeZoneService: TimeZoneService,
private val agePreferenceResolver: AgePreferenceResolver
) : Loggable {

/**
Expand Down Expand Up @@ -257,22 +258,35 @@ class CodeTimeService(

val excludeIds = getExcludeIdsForCodeTime(user)

// 나이 정보 조회
val userAge = try {
userProfile.getAge()
} catch (e: Exception) {
log.warn { "사용자 나이 정보 조회 실패 - userId: ${user.getIdOrThrow()}, 나이 필터링 없이 진행" }
null
}

val agePreference = agePreferenceResolver.resolve(user)

log.debug {
"코드타임 생성 - userId: ${user.getIdOrThrow()}, " +
"timeSlot: $timeSlot, region: $userMainRegion-$userSubRegion, " +
"excludeCount: ${excludeIds.size}개"
"timeSlot: $timeSlot, region: $userMainRegion-$userSubRegion, userAge: $userAge, " +
"agePreference: preferredMax=${agePreference.preferredMaxDiff}, cutoff=${agePreference.cutoffDiff}, " +
"excludeCount: ${excludeIds.size}개"
}

val candidates = bucketService.getCandidatesByBucket(
userMainRegion = userMainRegion,
userSubRegion = userSubRegion ?: "",
excludeIds = excludeIds,
requiredCount = config.codeTimeCount
requiredCount = config.codeTimeCount,
userAge = userAge,
agePreference = agePreference
)

log.info {
"코드타임 후보자 선정 - userId: ${user.getIdOrThrow()}, " +
"timeSlot: $timeSlot, requested: ${config.codeTimeCount}개, actual: ${candidates.size}개"
"timeSlot: $timeSlot, requested: ${config.codeTimeCount}개, actual: ${candidates.size}개"
}

return candidates
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ class DailyCodeMatchingService(
private val bucketService: RecommendationBucketService,
private val historyService: RecommendationHistoryService,
private val exclusionService: RecommendationExclusionService,
private val timeZoneService: TimeZoneService
private val timeZoneService: TimeZoneService,
private val agePreferenceResolver: AgePreferenceResolver
) : Loggable {

/**
Expand Down Expand Up @@ -167,22 +168,36 @@ class DailyCodeMatchingService(

log.info { "코드매칭 중 제외된 아이디 전부 조회 :::: " + excludeIds.joinToString(",") }

// 3. 나이 정보 조회
val userAge = try {
userProfile.getAge()
} catch (e: Exception) {
log.warn { "사용자 나이 정보 조회 실패 - userId: ${user.getIdOrThrow()}, 나이 필터링 없이 진행" }
null
}

val agePreference = agePreferenceResolver.resolve(user)

log.debug {
"오늘의 코드매칭 생성 - userId: ${user.getIdOrThrow()}, " +
"region: $userMainRegion-$userSubRegion, excludeCount: ${excludeIds.size}개"
"region: $userMainRegion-$userSubRegion, userAge: $userAge, " +
"agePreference: preferredMax=${agePreference.preferredMaxDiff}, cutoff=${agePreference.cutoffDiff}, " +
"excludeCount: ${excludeIds.size}개"
}

// 3. 버킷 정책으로 후보자 조회
// 4. 버킷 정책으로 후보자 조회 (나이 우선순위 적용)
val candidates = bucketService.getCandidatesByBucket(
userMainRegion = userMainRegion,
userSubRegion = userSubRegion ?: "",
excludeIds = excludeIds,
requiredCount = config.dailyCodeCount
requiredCount = config.dailyCodeCount,
userAge = userAge,
agePreference = agePreference
)

log.info {
"오늘의 코드매칭 후보자 선정 - userId: ${user.getIdOrThrow()}, " +
"requested: ${config.dailyCodeCount}개, actual: ${candidates.size}개"
"requested: ${config.dailyCodeCount}개, actual: ${candidates.size}개"
}

return candidates
Expand Down
Loading