Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
5a1d0e6
[FP-32] 추천된 대출 상품에 뱃지가 존재하지 않을경우 에러코드 추가
sanseongKo Sep 30, 2025
a5fb758
[FP-32] 프로필을 조회할 때 필요한 추천된 상품 개수, 최소금리 필드 추가
sanseongKo Sep 30, 2025
04b6c3c
[FP-32] 추천 상품 도메인에 뱃지 필드 추가
sanseongKo Sep 30, 2025
07ea6f6
[FP-32] 프로필 생성 스펙 뱃지, 최소금리 필드 추가
sanseongKo Sep 30, 2025
9769ac4
[FP-32] 프로필 생성 스펙 뱃지, 최소금리 필드 추가
sanseongKo Sep 30, 2025
ad84261
[FP-32] 프로필 변경 관련 테스트 코드 변경
sanseongKo Sep 30, 2025
cf4ecad
[FP-32] 프로필 최소 금리 자료구조 변경
sanseongKo Sep 30, 2025
e97bb79
[FP-32] 프로필 엔티티 최소금리, 추천 상품 개수 필드추가
sanseongKo Sep 30, 2025
de1d159
[FP-32] 추천 상품 도메인에 뱃지 필드 추가로 인한 관련 클래스 필드 추가
sanseongKo Sep 30, 2025
53e9662
[FP-32] 프로필 필드 업데이트, 상품이 추천된 뒤 실행될 로직 추가
sanseongKo Sep 30, 2025
e74f4db
[FP-32] 프로필 필드 추가로 인한 테스트 코드 변경
sanseongKo Sep 30, 2025
9f8d087
[FP-32] 추천 상품 도메인에 뱃지 필드 추가로 인한 캐싱 데이터 dto변경
sanseongKo Sep 30, 2025
271a450
[FP-32] 상품 추천 이후 프로필 업데이트 로직 추가
sanseongKo Sep 30, 2025
c91f8d4
[FP-32] 프로필 스키마 변경
sanseongKo Oct 2, 2025
e436b11
[FP-32] 프로필 응답객체 및 dto 객체 변경
sanseongKo Oct 2, 2025
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
Expand Up @@ -2,7 +2,11 @@

import finpik.RecommendedLoanProduct;
import finpik.dto.CreateRecommendedLoanProductEvent;
import finpik.entity.enums.LoanProductBadge;
import finpik.error.enums.ErrorCode;
import finpik.error.exception.BusinessException;
import finpik.repository.loanproduct.LoanProductRepository;
import finpik.repository.profile.ProfileRepository;
import finpik.resolver.loanproduct.application.CreateRecommendLoanProductUseCase;
import finpik.sse.service.SseEmitterService;
import lombok.RequiredArgsConstructor;
Expand All @@ -22,6 +26,7 @@ public class CreateRecommendLoanProductUseCaseImpl implements
CreateRecommendLoanProductUseCase
{
private final LoanProductRepository loanProductRepository;
private final ProfileRepository profileRepository;
private final SseEmitterService sseEmitterService;

@Async
Expand All @@ -45,7 +50,17 @@ public void execute(CreateRecommendedLoanProductEvent event) {
)
).toList();

loanProductRepository.saveAllRecommendedLoanProduct(event.profileId(), recommendedLoanProductList);
List<RecommendedLoanProduct> recommendedLoanProducts =
loanProductRepository.saveAllRecommendedLoanProduct(event.profileId(), recommendedLoanProductList);

RecommendedLoanProduct first = recommendedLoanProducts.stream()
.filter(it ->
it.getLoanProductBadges().contains(LoanProductBadge.LOWEST_MIN_INTEREST_RATE)
).findFirst().orElseThrow(() -> new BusinessException(ErrorCode.INVALID_ANNUAL_INCOME));

profileRepository.updateProfileAfterRecommend(
event.profileId(), recommendedLoanProductList.size(), first.getMinInterestRate()
);

sseEmitterService.notifyRecommendationCompleted(
event.eventId(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import finpik.entity.enums.PurposeOfLoan;
import lombok.Getter;

import java.time.LocalDateTime;

@Getter
public class ProfileResultDto {
Long profileId;
Expand All @@ -20,6 +22,9 @@ public class ProfileResultDto {
Integer profileSeq;
ProfileColor profileColor;
Integer annualIncome;
LocalDateTime createdAt;
Integer recommendedLoanProductCount;
Float minInterestRate;

public ProfileResultDto(Profile profile) {
profileId = profile.getId();
Expand All @@ -33,5 +38,8 @@ public ProfileResultDto(Profile profile) {
profileColor = profile.getProfileColor();
profileSeq = profile.getSeq();
annualIncome = profile.getOccupationDetail().getAnnualIncome();
createdAt = profile.getCreatedAt();
recommendedLoanProductCount = profile.getRecommendedLoanProductCount();
minInterestRate = profile.getMinInterestRate();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import finpik.resolver.profile.application.dto.ProfileResultDto;
import lombok.Builder;

import java.time.LocalDateTime;

@Builder
public record ProfileResult(
Long profileId,
Expand All @@ -19,7 +21,10 @@ public record ProfileResult(
Integer profileSeq,
String profileName,
ProfileColor profileColor,
Integer annualIncome
Integer annualIncome,
LocalDateTime createdAt,
Integer recommendedLoanProductCount,
Float minInterestRate
) {

public static ProfileResult of(ProfileResultDto profile) {
Expand All @@ -35,6 +40,9 @@ public static ProfileResult of(ProfileResultDto profile) {
.profileSeq(profile.getProfileSeq())
.profileColor(profile.getProfileColor())
.annualIncome(profile.getAnnualIncome())
.createdAt(profile.getCreatedAt())
.recommendedLoanProductCount(profile.getRecommendedLoanProductCount())
.minInterestRate(profile.getMinInterestRate())
.build();
}
}
3 changes: 3 additions & 0 deletions finpik-api/src/main/resources/graphql/profile.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ type ProfileResult {
profileSeq: Int!
profileName: String!
profileColor: ProfileColor!
createdAt: DateTime!
recommendedLoanProductCount: Int!
minInterestRate: Float!
}

enum Occupation {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public enum ErrorCode {
NOT_FOUND_LOAN_PRODUCT("대출 상품을 찾을 수 없습니다.", "LPD-0001", CustomHttpStatus.NOT_FOUND),
NOT_CONVERT_KAFKA_MESSAGE_LOAN_PRODUCT("카프카에서 받은 추천 대출 상품 메세지를 컨버팅할 수 없습니다.", "LPD-0002", CustomHttpStatus.BAD_REQUEST),
NOT_CONVERT_KAFKA_MESSAGE("카프카에 메세지를 보내기 위한 추천 대출 상품의 조건을 문자열로 변경이 실패했습니다.", "LPD-0003", CustomHttpStatus.BAD_REQUEST),
EMPTY_BADGES("추천된 상품에 뱃지를 받은 상품이 존재하지 않습니다.", "LPD-0004", CustomHttpStatus.BAD_REQUEST),

//System
ORDER_BY_PROPERTY_NOT_FOUND("정렬 조건을 찾을 수 없습니다. 개발자에게 문의 부탁드립니다.", "ITN-0001", CustomHttpStatus.INTERNAL_SERVER_ERROR),;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package finpik;

import finpik.entity.enums.LoanProductBadge;
import finpik.util.Preconditions;
import finpik.vo.InterestRate;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Getter
Expand All @@ -21,6 +24,7 @@ public class RecommendedLoanProduct {
private InterestRate interestRate;
private Long maxLoanLimitAmount;
private Float similarity;
private List<LoanProductBadge> loanProductBadges;

public static RecommendedLoanProduct of(
Long profileId,
Expand All @@ -33,6 +37,7 @@ public static RecommendedLoanProduct of(
Float similarity
) {
InterestRate interestRate = new InterestRate(maxInterestRate, minInterestRate);
List<LoanProductBadge> loanProductBadges = new ArrayList<>();

return new RecommendedLoanProduct(
null,
Expand All @@ -42,7 +47,8 @@ public static RecommendedLoanProduct of(
Preconditions.require(productName, "productName must not be null"),
interestRate,
maxLoanLimitAmount,
Preconditions.require(similarity, "similarity must not be null")
Preconditions.require(similarity, "similarity must not be null"),
loanProductBadges
);
}

Expand All @@ -55,7 +61,8 @@ public static RecommendedLoanProduct rebuild(
Float maxInterestRate,
Float minInterestRate,
Long maxLoanLimitAmount,
Float similarity
Float similarity,
List<LoanProductBadge> loanProductBadges
) {
InterestRate interestRate = new InterestRate(maxInterestRate, minInterestRate);

Expand All @@ -67,7 +74,8 @@ public static RecommendedLoanProduct rebuild(
Preconditions.require(productName, "productName must not be null"),
interestRate,
maxLoanLimitAmount,
Preconditions.require(similarity, "similarity must not be null")
Preconditions.require(similarity, "similarity must not be null"),
loanProductBadges
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public class Profile {
private ProfileColor profileColor;
private OccupationDetail occupationDetail;
private User user;
private Integer recommendedLoanProductCount;
private Float minInterestRate;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;

Expand Down Expand Up @@ -70,6 +72,8 @@ private static Profile create(
require(spec.profileColor(), "profileColor must not be null."),
occupationDetail,
require(spec.user(), "user must not be null."),
spec.recommendedLoanProductCount(),
spec.minInterestRate(),
spec.createdAt() == null ? createdAt : spec.createdAt(),
spec.updatedAt()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public record ProfileCreationSpec(
BusinessType businessType,
EmploymentForm employmentForm,
User user,
Integer recommendedLoanProductCount,
Float minInterestRate,
LocalDateTime createdAt,
LocalDateTime updatedAt
) {
Expand All @@ -43,14 +45,18 @@ public static ProfileCreationSpec createNew(
LocalDate employmentDate, Occupation occupation,
EmploymentForm employmentForm, User user, BusinessType businessType
) {
Integer newRecommendedLoanProductCount = 0;
Float newMinInterestRate = 0.0f;

return new ProfileCreationSpec(
null, desiredLoanAmount, loanProductUsageCount,
totalLoanUsageAmount, creditScore,
profileName, null, creditGradeStatus,
loanProductUsageStatus, purposeOfLoan,
profileColor, annualIncome, businessStartDate,
employmentDate, occupation, businessType,
employmentForm, user, null, null
employmentForm, user, newRecommendedLoanProductCount,
newMinInterestRate, null, null
);
}

Expand All @@ -61,8 +67,8 @@ public static ProfileCreationSpec rebuild(
LoanProductUsageStatus loanProductUsageStatus, PurposeOfLoan purposeOfLoan,
ProfileColor profileColor, Integer annualIncome, LocalDate businessStartDate,
LocalDate employmentDate, Occupation occupation, BusinessType businessType,
EmploymentForm employmentForm, User user,
LocalDateTime createdAt, LocalDateTime updatedAt
EmploymentForm employmentForm, User user, Integer recommendedLoanProductCount,
Float minInterestRate, LocalDateTime createdAt, LocalDateTime updatedAt
) {
return new ProfileCreationSpec(
id, desiredLoanAmount, loanProductUsageCount,
Expand All @@ -71,7 +77,8 @@ public static ProfileCreationSpec rebuild(
loanProductUsageStatus, purposeOfLoan,
profileColor, annualIncome, businessStartDate,
employmentDate, occupation, businessType,
employmentForm, user, createdAt, updatedAt
employmentForm, user, recommendedLoanProductCount,
minInterestRate, createdAt, updatedAt
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ private Profile getDefaultProfile(Long profileId) {
null,
null,
user,
0,
0.0f,
LocalDateTime.now(),
LocalDateTime.now()
);
Expand Down
6 changes: 6 additions & 0 deletions finpik-domain/profile/src/test/java/entity/ProfileTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ void validateCredits() {
null,
EmploymentForm.CONTRACT,
null,
0,
0.0f,
LocalDateTime.now(),
LocalDateTime.now()
);
Expand Down Expand Up @@ -142,6 +144,8 @@ void determineCreditGradeStatusByScore() {
null,
EmploymentForm.CONTRACT,
user,
0,
0.0f,
LocalDateTime.now(),
LocalDateTime.now()
);
Expand Down Expand Up @@ -192,6 +196,8 @@ private Profile getDefaultProfile(User user) {
null,
null,
user,
0,
0.0f,
LocalDateTime.now(),
LocalDateTime.now()
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
package entity.policy;

import finpik.entity.User;
import finpik.entity.enums.BusinessType;
import finpik.entity.enums.CreditGradeStatus;
import finpik.entity.enums.EmploymentForm;
import finpik.entity.enums.Gender;
import finpik.entity.enums.LoanProductUsageStatus;
import finpik.entity.enums.Occupation;
import finpik.entity.enums.ProfileColor;
import finpik.entity.enums.PurposeOfLoan;
import finpik.entity.enums.RegistrationType;
import finpik.entity.enums.*;
import finpik.entity.policy.ProfileCreationSpec;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;
Expand Down Expand Up @@ -43,6 +36,8 @@ void createTest() {
Occupation occupation = Occupation.EMPLOYEE;
EmploymentForm employmentForm = EmploymentForm.FULL_TIME;
User user = new User(1L, "username", "user@example.com", Gender.MALE, RegistrationType.KAKAO, LocalDateTime.now(), LocalDate.of(1995, 1, 1));
Float minInterestRate = 0.0f;
Integer recommendedLoanProductCount = 0;
LocalDateTime createdAt = LocalDateTime.now();
LocalDateTime updatedAt = LocalDateTime.now();
BusinessType businessType = null;
Expand All @@ -52,7 +47,8 @@ void createTest() {
id, desiredLoanAmount, loanProductUsageCount, totalLoanUsageAmount,
creditScore, profileName, seq, creditGradeStatus, loanProductUsageStatus,
purposeOfLoan, profileColor, annualIncome, businessStartDate, employmentDate,
occupation, businessType, employmentForm, user, createdAt, updatedAt
occupation, businessType, employmentForm, user,
recommendedLoanProductCount, minInterestRate, createdAt, updatedAt
);

//then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ public class ProfileEntity {
@JoinColumn(name = "user_id")
private UserEntity user;

private Integer recommendedLoanProductCount;
private Float minInterestRate;

@Column(updatable = false)
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
Expand All @@ -100,7 +103,8 @@ public static ProfileEntity from(Profile profile, UserEntity userEntity) {
profile.getLoanProductUsageStatus(), profile.getPurposeOfLoan(),
mapper.occupation(), profile.getProfileColor(), mapper.employmentDate(),
mapper.businessStartDate(), mapper.businessType(),
userEntity, profile.getCreatedAt(), profile.getUpdatedAt()
userEntity, profile.getRecommendedLoanProductCount(), profile.getMinInterestRate(),
profile.getCreatedAt(), profile.getUpdatedAt()
);
}

Expand All @@ -110,7 +114,8 @@ public Profile toDomain() {
creditScore, profileName, seq, creditGradeStatus, loanProductUsageStatus,
purposeOfLoan, profileColor, annualIncome, businessStartDate,
employmentDate, occupation, businessType, employmentForm,
user.toDomain(), createdAt, updatedAt
user.toDomain(), recommendedLoanProductCount,
minInterestRate, createdAt, updatedAt
);

return Profile.withId(spec);
Expand Down Expand Up @@ -140,4 +145,8 @@ public void updateAllFields(Profile profile) {
public void updateSeq(Integer seq) {
this.seq = seq;
}

public void updateRecommendedLoanProductCount(Integer recommendedLoanProductCount) {
this.recommendedLoanProductCount = recommendedLoanProductCount;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public Slice<RecommendedLoanProductProjection> findAllByProfileId(Long productId
loanProductEntity.maxInterestRate,
loanProductEntity.minInterestRate,
loanProductEntity.maxLoanLimitAmount,
recommendedLoanProductEntity.similarity
recommendedLoanProductEntity.similarity,
recommendedLoanProductEntity.loanProductBadgeList
))
.from(recommendedLoanProductEntity)
.where(recommendedLoanProductEntity.profileId.eq(productId))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package finpik.jpa.repository.loanproduct.projection;

import finpik.entity.enums.LoanProductBadge;

import java.util.List;
import java.util.UUID;

public record RecommendedLoanProductProjection(
Expand All @@ -11,6 +14,7 @@ public record RecommendedLoanProductProjection(
Float minInterestRate,
Float maxInterestRate,
Long maxLoanLimitAmount,
Float similarity
Float similarity,
List<LoanProductBadge> loanProductBadges
) {
}
Loading
Loading