Skip to content
Open
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
3 changes: 2 additions & 1 deletion src/main/java/apptive/fin/global/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) {
// .requestMatchers("/favicon.ico").permitAll()
.requestMatchers("/oauth2/authorization/**", "/login/oauth2/**").permitAll()
.requestMatchers("/auth/**").permitAll()
.requestMatchers("/search/**").permitAll()
.requestMatchers(HttpMethod.POST, "/users").permitAll()
//.anyRequest().permitAll()
.anyRequest().authenticated()
Expand Down Expand Up @@ -101,4 +102,4 @@ public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

}
}
44 changes: 44 additions & 0 deletions src/main/java/apptive/fin/search/BankCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package apptive.fin.search;

import lombok.RequiredArgsConstructor;

import java.util.Arrays;

@RequiredArgsConstructor
public enum BankCode {
KB("국민은행", "obank.kbstar.com"),
SHINHAN("신한은행", "shinhan.com"),
HANA("하나은행", "kebhana.com"),
WOORI("우리은행", "spot.wooribank.com"),
NH("농협은행", "nhlink.nonghyup.com"),
IBK("중소기업은행", "mybank.ibk.co.kr"),
SC("제일은행", "standardchartered.co.kr"),
IM("아이엠뱅크", "imbank.co.kr"),
BUSAN("부산은행", "busanbank.co.kr"),
KJB("광주은행", "www.kjbank.com"),
JB("전북은행", "www.jbbank.co.kr"),
JEJU("제주은행", "www.e-jejubank.com"),
KYONGNAM("경남은행", "knbank.co.kr"),
SUHYUP("수협은행", "www.suhyup-bank.com"),
KAKAO("주식회사 카카오뱅크", "kakaobank.com"),
KBANK("주식회사 케이뱅크", "kbanknow.com"),
TOSS("토스뱅크 주식회사", "tossbank.com");

private final String displayName;
private final String officialHost;

public String displayName() {
return displayName;
}

public String officialHost() {
return officialHost;
}

public static boolean contains(String code) {
if (code == null) return false;

return Arrays.stream(values())
.anyMatch(bankCode -> bankCode.name().equals(code));
}
}
7 changes: 7 additions & 0 deletions src/main/java/apptive/fin/search/ContributionType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package apptive.fin.search;

public enum ContributionType {
NONE,
RATIO,
FIXED_AMOUNT
}
7 changes: 7 additions & 0 deletions src/main/java/apptive/fin/search/ExtractionConfidence.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package apptive.fin.search;

public enum ExtractionConfidence {
HIGH,
MEDIUM,
LOW
}
8 changes: 6 additions & 2 deletions src/main/java/apptive/fin/search/KeywordValueEnum.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public enum KeywordValueEnum {
STATUS_MILITARY("STATUS_MILITARY"),

// 3. 저축 기간
TERM_OVER_5_YEARS("TERM_OVER_5_YEARS"),
TERM_OVER_3_YEARS("TERM_OVER_3_YEARS"),
TERM_2_TO_3_YEARS("TERM_2_TO_3_YEARS"),
TERM_AROUND_1_YEAR("TERM_AROUND_1_YEAR"),

Expand All @@ -40,6 +40,7 @@ public enum KeywordValueEnum {
BENEFIT_TAX_FREE("BENEFIT_TAX_FREE"),
BENEFIT_EASY_CONDITION("BENEFIT_EASY_CONDITION"),
BENEFIT_GOV_SUBSIDY("BENEFIT_GOV_SUBSIDY"),
BENEFIT_HOUSE_PREPARE("BENIFIT_HOUSE_PREPARE"),

// 5. 상품 관심사
INTEREST_SAVINGS("INTEREST_SAVINGS"),
Expand All @@ -50,7 +51,10 @@ public enum KeywordValueEnum {
BANK_SALARY_TRANSFER("BANK_SALARY_TRANSFER"), // 급여이체우대
BANK_CARD_USAGE("BANK_CARD_USAGE"), // 카드 실적 우대
BANK_AUTO_TRANSFER("BANK_AUTO_TRANSFER"), // 자동이체 우대
BANK_MARKETING("BANK_MARKETING") // 마케팅 동의 우대
BANK_MARKETING("BANK_MARKETING"), // 마케팅 동의 우대
BANK_REDEPOSIT("BANK_REDEPOSIT"), // 재예치
BANK_ONLINE_JOIN("BANK_ONLINE_JOIN"),
BANK_AGE("BANK_AGE"),
;

private final String code;
Expand Down
7 changes: 4 additions & 3 deletions src/main/java/apptive/fin/search/ProductType.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package apptive.fin.search;

public enum ProductType {
DEPOSIT, // 예금 (FSS)
SAVING, // 적금 (FSS)
POLICY // 정책 (ONTONG)
DEPOSIT, // 예금
SAVING, // 적금
POLICY, // 정책
SUBSCRIPTION // 청약
}
6 changes: 6 additions & 0 deletions src/main/java/apptive/fin/search/RequiredKeywordEffect.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package apptive.fin.search;

public enum RequiredKeywordEffect {
REQUIRE,
EXCLUDE
}
10 changes: 5 additions & 5 deletions src/main/java/apptive/fin/search/ScoreWeightEnum.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
public enum ScoreWeightEnum {

// 정부 상품 배점
GOV_BENEFITS ("benefits", 38.0,true),
GOV_PERIOD ("period", 20.0, true),
GOV_IDENTITY("identity",18.0, true),
GOV_DEPOSIT ("deposit",16.0, true),
GOV_BANK_COND("bankCond", 8.0, true),
GOV_BENEFITS ("benefits", 40.0,true),
GOV_PERIOD ("period", 22.0, true),
GOV_IDENTITY("identity",20.0, true),
GOV_DEPOSIT ("deposit",18.0, true),
GOV_BANK_COND("bankCond", 0.0, true),

// 시중은행 상품 배점
BANK_BANK_COND ("bankCond", 40.0, false),
Expand Down
1 change: 1 addition & 0 deletions src/main/java/apptive/fin/search/SearchErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
public enum SearchErrorCode implements ErrorCode {

OPTION_CATEGORY_NOT_FOUND(HttpStatus.NOT_FOUND,"001","올바르지 않은 옵션 카테고리."),
KEYWORD_REQUIRED(HttpStatus.BAD_REQUEST, "002", "키워드를 1개 이상 선택해주세요."),
;

private final String codePrefix = "S";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package apptive.fin.search.controller;

import apptive.fin.auth.security.AuthUserDetails;
import apptive.fin.search.dto.DynamicFormResponseDto;
import apptive.fin.search.dto.ProductSearchResultDto;
import apptive.fin.search.dto.SearchRequestDto;
Expand All @@ -8,6 +9,7 @@
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -27,8 +29,11 @@ public DynamicFormResponseDto dynamicForm(@Valid @RequestBody SearchRequestDto s
}

@PostMapping("/products")
public ResponseEntity<ProductSearchResultDto> search(@Valid @RequestBody SearchRequestDto searchRequestDto) {
return ResponseEntity.ok(searchService.search(searchRequestDto));
public ResponseEntity<ProductSearchResultDto> search(
@Valid @RequestBody SearchRequestDto searchRequestDto,
@AuthenticationPrincipal AuthUserDetails userDetails
) {
return ResponseEntity.ok(searchService.search(searchRequestDto, userDetails));
}

}
31 changes: 31 additions & 0 deletions src/main/java/apptive/fin/search/dto/DetailedOptionsDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,37 @@ public record DetailedOptionsDto(
Boolean isHouseholder, // 세대주 여부
Long monthlySavingsGoal,
List<String> mainBanks,
List<String> neverUsedBanks,
List<String> maturedSavingBanks,
List<PreferentialInterestRateOption> selectedInterestRateOptions
) {
public DetailedOptionsDto(
LocalDate birthdate,
Long annualIncome,
Integer householdSize,
Integer householdIncomePercent,
Integer tenureMonths,
Boolean isFirstJob,
Boolean isHomeless,
Boolean isHouseholder,
Long monthlySavingsGoal,
List<String> mainBanks,
List<PreferentialInterestRateOption> selectedInterestRateOptions
) {
this(
birthdate,
annualIncome,
householdSize,
householdIncomePercent,
tenureMonths,
isFirstJob,
isHomeless,
isHouseholder,
monthlySavingsGoal,
mainBanks,
null,
null,
selectedInterestRateOptions
);
}
}
3 changes: 2 additions & 1 deletion src/main/java/apptive/fin/search/dto/ProductRateDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ public record ProductRateDto(
String source,
double baseRate,
double achievableRate,
boolean rateComparable,
boolean isSubscription,
String subscriptionNote // 금리가 없는 청약 상품용 안내 문구
String subscriptionNote
) {
}
20 changes: 10 additions & 10 deletions src/main/java/apptive/fin/search/dto/ProductSearchResultDto.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package apptive.fin.search.dto;

import lombok.Builder;

import java.util.List;

@Builder
public record ProductSearchResultDto (

// 탭 A : 적합도 기준 정렬 (나에게 맞는 순)
List<ProductMatchDto> governmentRanked,
List<ProductMatchDto> bankRanked,

// 탭 B : 금리 높은 순
List<ProductRateDto> rateRanked,
List<ProductRateDto> subscriptionProducts
){}
public record ProductSearchResultDto(
TabAvailabilityDto tabs,
List<ProductMatchDto> governmentRanked,
List<ProductMatchDto> bankRanked,
List<ProductRateDto> governmentRateRanked,
List<ProductRateDto> bankRateRanked,
List<ProductRateDto> subscriptionProducts
) {
}
11 changes: 11 additions & 0 deletions src/main/java/apptive/fin/search/dto/TabAvailabilityDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package apptive.fin.search.dto;

import lombok.Builder;

@Builder
public record TabAvailabilityDto(
boolean tabAEnabled,
boolean tabBEnabled,
String tabBDisabledReason
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package apptive.fin.search.entity;

import apptive.fin.search.KeywordValueEnum;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.Getter;

import java.math.BigDecimal;

@Entity
@Getter
@Table(name = "product_preferential_rates")
public class ProductPreferentialRate {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_property_id", nullable = false)
private ProductProperty productProperty;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private KeywordValueEnum keywordCode;

@Column(nullable = false, precision = 5, scale = 2)
private BigDecimal rate;

@Column(columnDefinition = "TEXT")
private String description;

private Integer minAge;
private Integer maxAge;
}
27 changes: 27 additions & 0 deletions src/main/java/apptive/fin/search/entity/ProductProperty.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package apptive.fin.search.entity;

import apptive.fin.search.ContributionType;
import apptive.fin.search.InterestRateType;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
Expand Down Expand Up @@ -47,11 +48,29 @@ public class ProductProperty {
@Column(precision = 5, scale = 2)
private BigDecimal govContributionRate;

@Enumerated(EnumType.STRING)
private ContributionType govContributionType;

@Column(precision = 8, scale = 4)
private BigDecimal govMatchingRatio;

private Long govMonthlyFixedContribution;
private Integer govContributionPeriodMonths;

@Column(nullable = false)
private Boolean excludeFromRateComparison = false;

private Long minMonthlyLimit;
private Long maxMonthlyLimit;

private Integer minAge;
private Integer maxAge;

@Column(nullable = false)
private Boolean allowsMilitaryAgeExtension = false;

private Integer militaryMaxAge;

private Long earnMaxAmt;
private Integer earnPercent;
private Integer minTenureMonths;
Expand All @@ -75,4 +94,12 @@ public class ProductProperty {
@BatchSize(size = 100)
@OneToMany(mappedBy = "productProperty", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<ProductKeyword> keywords = new ArrayList<>();

@BatchSize(size = 100)
@OneToMany(mappedBy = "productProperty", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<ProductRequiredKeyword> requiredKeywords = new ArrayList<>();

@BatchSize(size = 100)
@OneToMany(mappedBy = "productProperty", fetch = FetchType.LAZY)
private List<ProductPreferentialRate> preferentialRates = new ArrayList<>();
}
Loading