-
Notifications
You must be signed in to change notification settings - Fork 1
✨ feat/custom/KIKI-73-BE-추천 : 키보드 추천 튜토리얼, 유사상품 리스트 조회 구현 #67 #66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The head ref may contain hidden characters: "feat/custom/KIKI-73-BE-\uCD94\uCC9C-\uAE30\uB2A5-\uAD6C\uD604"
Changes from all commits
c697fd9
1e430c7
542b873
f9a3605
29c92df
c72d9b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| package site.kikihi.custom.platform.adapter.in.web.converter; | ||
|
|
||
| import site.kikihi.custom.platform.adapter.in.web.dto.request.product.KeyboardOptions; | ||
|
|
||
| import java.util.Arrays; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
|
|
||
| public class KeyboardOptionsConverter { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 축의 정도를 한번에 다 converter로 처리하게끔 했군요!! |
||
|
|
||
| // Size enum → description 검색 키워드 맵핑 | ||
| public static String mapSizeToDescription(KeyboardOptions.Size size) { | ||
| if (size == null) return null; | ||
| return switch (size) { | ||
| case TENKEYLESS -> "텐키리스"; | ||
| case FULL -> "풀배열"; | ||
| case MINI -> "미니"; | ||
| }; | ||
| } | ||
|
|
||
| // SwitchType enum → options.option_name 중 매칭되는 문자열 배열 리턴 | ||
| public static List<String> mapSwitchTypeToOptionNames(KeyboardOptions.SwitchType switchType) { | ||
| if (switchType == null) return Collections.emptyList(); | ||
|
|
||
| return switch (switchType) { | ||
| case SILENT -> Arrays.asList( | ||
| "저소음 적축", "저소음 갈축", "저소음 흑축", | ||
| "저소음 바다축", "저소음 잉크축", "저소음 바닐라축", | ||
| "저소음 딸기축", "저소음 바나나축" | ||
| ); | ||
| case NORMAL -> Arrays.asList( | ||
| "갈축", "바나나축", "바닐라축", | ||
| "핑크축", "레몬축", "딸기축", "경해축", | ||
| "잉크축 V2", "모가축", "판다축", | ||
| "바다축", "라벤더축", "체리 스피드 실버", | ||
| "리니어 옵티컬" | ||
| ); | ||
| case LOUD -> Arrays.asList( | ||
| "청축", "녹축","백축","clicky" | ||
| ); | ||
| case SMOOTH -> Arrays.asList( | ||
| "적축", "흑축", "자석축", "광축", | ||
| "실버축", "스피드 적축", "잉크축", | ||
| "바다축", "바닐라축", "체리 리니어 옵티컬", | ||
| "라떼축", "모카축", "사파이어축","밀키축", | ||
| "무지개축", "크림축" | ||
| ); | ||
| }; | ||
|
|
||
| } | ||
|
|
||
| // Layout enum → description 검색 키워드 맵핑 | ||
| public static String mapLayoutToDescription(KeyboardOptions.Layout layout) { | ||
| if (layout == null) return null; | ||
| return switch (layout) { | ||
| case ERGONOMIC -> "스텝스컬쳐2"; | ||
| case SIMPLE -> "로우프로파일(LP)"; | ||
| }; | ||
| } | ||
|
|
||
| // 키압에서 g빼기 | ||
| public static Integer mapKeyPressureToSpecTable(KeyboardOptions.KeyPressure keyPressure) { | ||
| if (keyPressure == null) return null; | ||
| return switch (keyPressure) { | ||
| case LIGHT -> 49; | ||
| case NORMAL -> 50; | ||
| }; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,135 @@ | ||||||||||||||||||||||||||||||
| package site.kikihi.custom.platform.adapter.in.web.dto.request.product; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| import com.fasterxml.jackson.annotation.JsonValue; | ||||||||||||||||||||||||||||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||||||||||||||||||||||||||||
| import lombok.Getter; | ||||||||||||||||||||||||||||||
| import lombok.RequiredArgsConstructor; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Getter | ||||||||||||||||||||||||||||||
| @RequiredArgsConstructor | ||||||||||||||||||||||||||||||
| @Schema( | ||||||||||||||||||||||||||||||
| name = "[요청][상품] 키보드 옵션 Enum", | ||||||||||||||||||||||||||||||
| description = "키보드 추천 서비스에서 사용하는 키보드 옵션 Enum입니다." | ||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||
| public class KeyboardOptions { | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Getter | ||||||||||||||||||||||||||||||
| @RequiredArgsConstructor | ||||||||||||||||||||||||||||||
| @Schema(name = "[요청][상품] 배열(Size) Enum", description = "키보드 배열 옵션") | ||||||||||||||||||||||||||||||
| public enum Size { | ||||||||||||||||||||||||||||||
| @Schema(description = "텐키리스 배열", example = "tenkeyless") | ||||||||||||||||||||||||||||||
| TENKEYLESS("tenkeyless"), | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Schema(description = "풀배열", example = "full") | ||||||||||||||||||||||||||||||
| FULL("full"), | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Schema(description = "미니 배열", example = "mini") | ||||||||||||||||||||||||||||||
| MINI("mini"); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| private final String value; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @JsonValue | ||||||||||||||||||||||||||||||
| public String getValue() { | ||||||||||||||||||||||||||||||
| return value; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+16
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Enum 역직렬화 실패 가능성: @JsonCreator 추가 현재 예시 diff(Size 하나만 예시, 동일 방식으로 모든 enum에 추가 필요): public enum Size {
@@
private final String value;
@JsonValue
public String getValue() {
return value;
}
+
+ @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
+ public static Size fromValue(String value) {
+ if (value == null) return null;
+ for (Size v : values()) {
+ if (v.value.equalsIgnoreCase(value) || v.name().equalsIgnoreCase(value)) {
+ return v;
+ }
+ }
+ throw new IllegalArgumentException("Unknown Size: " + value);
+ }
}
필요한 import: +import com.fasterxml.jackson.annotation.JsonCreator;Also applies to: 37-53, 55-71, 73-96, 98-114, 116-132 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Getter | ||||||||||||||||||||||||||||||
| @RequiredArgsConstructor | ||||||||||||||||||||||||||||||
| @Schema(name = "[요청][상품] 키압(Key Pressure) Enum", description = "키압 옵션") | ||||||||||||||||||||||||||||||
| public enum KeyPressure { | ||||||||||||||||||||||||||||||
| @Schema(description = "가벼운 키압 (50g 미만)", example = "light") | ||||||||||||||||||||||||||||||
| LIGHT("light"), | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Schema(description = "보통 키압 (50g 이상)", example = "normal") | ||||||||||||||||||||||||||||||
| NORMAL("normal"); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| private final String value; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @JsonValue | ||||||||||||||||||||||||||||||
| public String getValue() { | ||||||||||||||||||||||||||||||
| return value; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Getter | ||||||||||||||||||||||||||||||
| @RequiredArgsConstructor | ||||||||||||||||||||||||||||||
| @Schema(name = "[요청][상품] 키압(Key Pressure) Enum", description = "키압 옵션") | ||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요기 @Schema 내용 수정해야 될 것 같아욤! |
||||||||||||||||||||||||||||||
| public enum Layout { | ||||||||||||||||||||||||||||||
| @Schema(description = "인체공학적 (스텝스컬쳐2)", example = "egonomic") | ||||||||||||||||||||||||||||||
| ERGONOMIC("egonomic"), | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Schema(description = "심플하고 깔끔한 (low 프로파일)", example = "simple") | ||||||||||||||||||||||||||||||
| SIMPLE("simple"); | ||||||||||||||||||||||||||||||
|
Comment on lines
+57
to
+63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 스키마 설명 라벨 오류
적용 diff: - @Schema(name = "[요청][상품] 키압(Key Pressure) Enum", description = "키압 옵션")
+ @Schema(name = "[요청][상품] 레이아웃(Layout) Enum", description = "레이아웃 옵션")
public enum Layout {📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| private final String value; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @JsonValue | ||||||||||||||||||||||||||||||
| public String getValue() { | ||||||||||||||||||||||||||||||
| return value; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Getter | ||||||||||||||||||||||||||||||
| @RequiredArgsConstructor | ||||||||||||||||||||||||||||||
| @Schema(name = "[요청][상품] 스위치 종류(Switch Type) Enum", description = "스위치 종류 옵션") | ||||||||||||||||||||||||||||||
| public enum SwitchType { | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Schema(description = "조용한", example = "silent") | ||||||||||||||||||||||||||||||
| SILENT("silent"), | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Schema(description = "적당한", example = "normal") | ||||||||||||||||||||||||||||||
| NORMAL("normal"), | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Schema(description = "강한", example = "loud") | ||||||||||||||||||||||||||||||
| LOUD("loud"), | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Schema(description = "부드러운", example = "smooth") | ||||||||||||||||||||||||||||||
| SMOOTH("smooth"); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| private final String value; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @JsonValue | ||||||||||||||||||||||||||||||
| public String getValue() { | ||||||||||||||||||||||||||||||
| return value; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Getter | ||||||||||||||||||||||||||||||
| @RequiredArgsConstructor | ||||||||||||||||||||||||||||||
| @Schema(name = "[요청][상품] 흡음재 여부 Enum", description = "흡음재 유무 옵션") | ||||||||||||||||||||||||||||||
| public enum SoundDampener { | ||||||||||||||||||||||||||||||
| @Schema(description = "흡음재 있음", example = "○") | ||||||||||||||||||||||||||||||
| YES("○"), | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Schema(description = "흡음재 없음", example = "X") | ||||||||||||||||||||||||||||||
| NO("X"); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| private final String value; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @JsonValue | ||||||||||||||||||||||||||||||
| public String getValue() { | ||||||||||||||||||||||||||||||
| return value; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Getter | ||||||||||||||||||||||||||||||
| @RequiredArgsConstructor | ||||||||||||||||||||||||||||||
| @Schema(name = "[요청][상품] RGB 여부 Enum", description = "RGB 유무 옵션") | ||||||||||||||||||||||||||||||
| public enum RGB { | ||||||||||||||||||||||||||||||
| @Schema(description = "RGB 있음", example = "○") | ||||||||||||||||||||||||||||||
| YES("○"), | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @Schema(description = "RGB 없음", example = "X") | ||||||||||||||||||||||||||||||
| NO("X"); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| private final String value; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @JsonValue | ||||||||||||||||||||||||||||||
| public String getValue() { | ||||||||||||||||||||||||||||||
| return value; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| package site.kikihi.custom.platform.adapter.in.web.dto.request.product; | ||
|
|
||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
| import lombok.Getter; | ||
| import lombok.Setter; | ||
|
|
||
| @Getter | ||
| @Setter | ||
| @Schema(name = "[요청][상품] 키보드 추천 요청 DTO", description = "키보드 추천 요청에 사용하는 DTO입니다.") | ||
| public class KeyboardRecommendationRequest { | ||
|
|
||
| @Schema(description = "키보드 배열(Size) 옵션", example = "ten", required = true) | ||
| private KeyboardOptions.Size size; | ||
|
|
||
| @Schema(description = "키압(Key Pressure) 옵션", example = "light", required = true) | ||
| private KeyboardOptions.KeyPressure keyPressure; | ||
|
|
||
| @Schema(description = "레이아웃 종류(Layout) 옵션", example = "egonomic", required = true) | ||
| private KeyboardOptions.Layout layout; | ||
|
|
||
| @Schema(description = "스위치 종류(Switch Type) 옵션", example = "silent", required = true) | ||
| private KeyboardOptions.SwitchType switchType; | ||
|
|
||
| @Schema(description = "흡음재(Sound Dampener) 적용 여부", example = "○", required = true) | ||
| private KeyboardOptions.SoundDampener soundDampener; | ||
|
|
||
| @Schema(description = "RGB 적용 여부", example = "○", required = true) | ||
| private KeyboardOptions.RGB rgb; | ||
|
|
||
| @Schema(description = "최소 가격 (단위: 원)", example = "0", required = true) | ||
| private int minPrice; | ||
|
|
||
| @Schema(description = "최대 가격 (단위: 원)", example = "200000", required = true) | ||
| private int maxPrice; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| package site.kikihi.custom.platform.adapter.in.web.dto.response.product; | ||
|
|
||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
| import lombok.Builder; | ||
| import site.kikihi.custom.platform.domain.product.Product; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| /** | ||
| * 상품 상세 응답 DTO | ||
| * | ||
| * @param id 상품 ID | ||
| * @param thumbnail 상품 썸네일 | ||
| * @param manufacturerName 제조사명 | ||
| * @param productName 제품명 | ||
| * @param price | ||
| * @param likedByMe 나의 북마크 여부 | ||
| */ | ||
|
|
||
| @Builder | ||
| @Schema(name = "KeyboardRecommendationListResponse", description = "튜토리얼 키보드 추천 리스트 응답") | ||
| public record KeyboardRecommendationResponse( | ||
|
|
||
| @Schema(description = "상품 아이디", example = "101") | ||
| String id, | ||
|
|
||
| @Schema(description = "상품 썸네일 이미지 URL", example = "https://example.com/product/101.jpg") | ||
| String thumbnail, | ||
|
|
||
| @Schema(description = "제조사명", example = "독거미") | ||
| String manufacturerName, | ||
|
|
||
| @Schema(description = "제품명", example = "독거미 Aula F99") | ||
| String productName, | ||
|
|
||
| @Schema(description = "정상가(원)", example = "599000.0") | ||
| double price, | ||
|
Comment on lines
+36
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. price 필드 primitive(double)로 인한 NPE 위험
- @Schema(description = "정상가(원)", example = "599000.0")
- double price,
+ @Schema(description = "정상가(원)", example = "599000.0")
+ Double price,또는 - .price(product.getPrice())
+ .price(product.getPrice() != null ? product.getPrice() : null) // null 허용Also applies to: 46-55 🤖 Prompt for AI Agents |
||
|
|
||
| @Schema(description = "북마크(좋아요)한 상품 여부", example = "true") | ||
| boolean likedByMe | ||
|
|
||
| ) { | ||
|
|
||
| /// 정적 팩토리 메서드 | ||
| // 단일 객체 변환 메서드 추가 | ||
| public static KeyboardRecommendationResponse from(Product product) { | ||
| return KeyboardRecommendationResponse.builder() | ||
| .id(product.getId()) | ||
| .thumbnail(product.getThumbnail()) | ||
| .manufacturerName(product.getManufacturer()) | ||
| .productName(product.getName()) | ||
| .price(product.getPrice()) | ||
| .likedByMe(false) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 항상 false이면 안되지않을까요?! 상품과 유저 기반 boolean을 받는 from 메서드도 필요할 것 같습니당! |
||
| .build(); | ||
| } | ||
|
|
||
|
|
||
| // 기존 리스트 변환 메서드는 그대로 유지 | ||
| public static List<KeyboardRecommendationResponse> from(List<Product> productList) { | ||
| return productList.stream() | ||
| .map(KeyboardRecommendationResponse::from) // 단일 객체 변환 메서드 호출 | ||
| .toList(); | ||
| } | ||
|
|
||
|
|
||
|
|
||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
그룹 ID 변경 영향도 점검 및 잔존 패키지 네임스페이스 탐지 제안
artifact 좌표가
com.jiyoung.kikihi→site.kikihi.custom로 변경되었습니다. 배포 파이프라인(예: Artifactory/GitHub Packages), 문서화, 그리고 소스 트리의 최상위 패키지 네임스페이스가 모두 동기화되었는지 확인해주세요. 특히 기존 패키지 선언이 남아 있으면 런타임/리플렉션 스캔 이슈가 날 수 있습니다.다음 스크립트로 잔존 네임스페이스와 스프링 부트/DM 플러그인 버전 호환성을 빠르게 점검할 수 있습니다.
필요하시다면 배포 파이프라인과 README의 좌표 업데이트 PR도 같이 준비해드릴게요.
🏁 Script executed:
Length of output: 1494
그룹 ID 변경 후 잔존 패키지 네임스페이스 수동 수정 필요
@pointcut에 남아있는
com.jiyoung.kikihi.platform.adapter.in.web→site.kikihi.custom.platform.adapter.in.web으로 수정@pointcut에 남아있는
com.jiyoung.kikihi.platform.application.service→site.kikihi.custom.platform.application.service으로 수정위 2개 파일 외에
package com.jiyoung.kikihi선언은 확인되지 않았으며, settings.gradle에도 과거 그룹 참조가 없습니다.build.gradle의 플러그인 버전(
org.springframework.boot 3.4.3,io.spring.dependency-management 1.1.7)은 현행 버전으로, 별도 조치는 불필요합니다.필요하시면 배포 파이프라인·README 문서의 좌표 업데이트도 함께 지원해드리겠습니다.
🤖 Prompt for AI Agents