Conversation
Walkthrough상품 키워드 검색 기능이 Repository, Service, Controller에 추가되고, Controller에 입력 검증( Changes
Sequence DiagramsequenceDiagram
actor Client
participant Controller as ProductController
participant Service as ProductService
participant Repository as ProductRepository
participant DB as Database
Client->>Controller: GET /api/products/search?keyword=...&page=0
Controller->>Service: searchProducts(keyword, pageable)
Service->>Service: keyword 검증 (trim, null/empty 체크)
Service->>Repository: searchByKeyword(keyword, pageable)
Repository->>DB: JPQL 쿼리 실행 (name, brand.name, category.name, colors 검색)
DB-->>Repository: Page<Product> 반환
Repository-->>Service: Page<Product>
Service->>Service: Product → ProductSimpleResponse 변환
Service-->>Controller: Page<ProductSimpleResponse>
Controller-->>Client: DataResponse<Page<ProductSimpleResponse>>
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/main/java/com/ongil/backend/product/service/ProductService.java (1)
95-114: 비슷한 상품 추천 로직이 합리적입니다.기준 가격의 ±20% 범위와 동일 카테고리 조건으로 유사 상품을 찾는 로직이 적절합니다. 현재 상품 제외(
IdNot) 처리와 최대 6개 제한도 명확합니다.선택적 개선: 향후 추천 알고리즘 고도화 시 브랜드 선호도, 태그 유사도 등을 추가로 고려할 수 있습니다.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/main/java/com/ongil/backend/domain/product/repository/ProductRepository.javasrc/main/java/com/ongil/backend/product/controller/ProductController.javasrc/main/java/com/ongil/backend/product/service/ProductService.java
🧰 Additional context used
📓 Path-based instructions (1)
src/main/java/**/*.java
⚙️ CodeRabbit configuration file
SOLID 원칙, 스프링 어노테이션, 의존성 주입 패턴, 예외 처리에 중점을 둔다
Files:
src/main/java/com/ongil/backend/product/controller/ProductController.javasrc/main/java/com/ongil/backend/domain/product/repository/ProductRepository.javasrc/main/java/com/ongil/backend/product/service/ProductService.java
🔇 Additional comments (3)
src/main/java/com/ongil/backend/product/service/ProductService.java (3)
116-124: 방어적 프로그래밍이 잘 구현되었습니다.키워드의 null/empty 체크와 trim() 처리가 적절합니다. 컨트롤러에서
@RequestParam으로 필수 파라미터를 받지만, 서비스 계층에서도 방어 로직을 구현한 것은 좋은 관행입니다.선택적 개선 사항: 컨트롤러에서 입력 검증을 추가하면(위 리뷰 참조) 더욱 견고해집니다.
85-93: 특가 상품 조회 로직 확인특가 상품을 TOP 10으로 제한하고 할인율 기준 내림차순 정렬하는 로직이 명확합니다.
ProductType.SPECIAL_SALE필터링도 적절합니다.
126-130: AI 설명 생성 조건 개선
aiMaterialCarenull 체크를 추가하여 AI 설명 생성 필요 여부를 더 정확히 판단합니다. 세 가지 필드(advantages, disadvantages, care) 중 하나라도 null이면 생성하는 로직이 일관성 있습니다.
| // 키워드 검색 (브랜드명, 카테고리명, 색상, 상품명) | ||
| @EntityGraph(attributePaths = {"brand", "category"}) | ||
| @Query(""" | ||
| SELECT p FROM Product p | ||
| WHERE p.onSale = true | ||
| AND ( | ||
| LOWER(p.name) LIKE LOWER(CONCAT('%', :keyword, '%')) | ||
| OR LOWER(p.brand.name) LIKE LOWER(CONCAT('%', :keyword, '%')) | ||
| OR LOWER(p.category.name) LIKE LOWER(CONCAT('%', :keyword, '%')) | ||
| OR LOWER(p.colors) LIKE LOWER(CONCAT('%', :keyword, '%')) | ||
| ) | ||
| """) | ||
| Page<Product> searchByKeyword(@Param("keyword") String keyword, Pageable pageable); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# ProductRepository와 Product 엔티티 찾기
fd -type f -name "ProductRepository.java" -o -name "Product.java" | head -20Repository: IT-Cotato/12th-OnGil-BE
Length of output: 237
🏁 Script executed:
# 스키마 및 마이그레이션 파일 찾기
fd -type f \( -name "*.sql" -o -name "*.xml" \) | grep -i -E "(schema|migration|flyway)" | head -20Repository: IT-Cotato/12th-OnGil-BE
Length of output: 237
🏁 Script executed:
# 전체 파일 구조 확인
git ls-files | grep -i product | head -30Repository: IT-Cotato/12th-OnGil-BE
Length of output: 1215
🏁 Script executed:
# ProductRepository 확인 (라인 수 먼저 확인)
wc -l src/main/java/com/ongil/backend/domain/product/repository/ProductRepository.javaRepository: IT-Cotato/12th-OnGil-BE
Length of output: 150
🏁 Script executed:
# Product 엔티티 확인
wc -l src/main/java/com/ongil/backend/domain/product/entity/Product.javaRepository: IT-Cotato/12th-OnGil-BE
Length of output: 137
🏁 Script executed:
# 마이그레이션/스키마 파일 찾기
find . -type f \( -name "*.sql" -o -name "*.xml" \) | grep -v node_modules | grep -v ".gradle" | head -30Repository: IT-Cotato/12th-OnGil-BE
Length of output: 49
🏁 Script executed:
# ProductRepository.java 전체 읽기
cat -n src/main/java/com/ongil/backend/domain/product/repository/ProductRepository.javaRepository: IT-Cotato/12th-OnGil-BE
Length of output: 3004
🏁 Script executed:
# Product.java 전체 읽기
cat -n src/main/java/com/ongil/backend/domain/product/entity/Product.javaRepository: IT-Cotato/12th-OnGil-BE
Length of output: 4636
🏁 Script executed:
# resources 디렉토리에서 스키마 찾기
find src/main/resources -type f \( -name "*.sql" -o -name "*.xml" \) 2>/dev/nullRepository: IT-Cotato/12th-OnGil-BE
Length of output: 49
🏁 Script executed:
# application 설정 파일 찾기
fd -type f -name "application*.yml" -o -name "application*.properties" | head -10Repository: IT-Cotato/12th-OnGil-BE
Length of output: 237
🏁 Script executed:
# ProductService에서 searchByKeyword 사용 패턴
cat -n src/main/java/com/ongil/backend/product/service/ProductService.java | head -100Repository: IT-Cotato/12th-OnGil-BE
Length of output: 4303
🏁 Script executed:
# 전체 ProductService 크기 확인
wc -l src/main/java/com/ongil/backend/product/service/ProductService.javaRepository: IT-Cotato/12th-OnGil-BE
Length of output: 138
🏁 Script executed:
# ProductService의 나머지 부분 읽기 (키워드 검색 메서드 포함)
cat -n src/main/java/com/ongil/backend/product/service/ProductService.java | tail -80Repository: IT-Cotato/12th-OnGil-BE
Length of output: 3100
🏁 Script executed:
# application 설정 파일 찾기 (다시 수정된 쿼리)
find . -name "application*.yml" -o -name "application*.properties" 2>/dev/null | head -10Repository: IT-Cotato/12th-OnGil-BE
Length of output: 225
🏁 Script executed:
# application.yml 확인
cat src/main/resources/application.ymlRepository: IT-Cotato/12th-OnGil-BE
Length of output: 912
🏁 Script executed:
# application-prod.yml 확인 (프로덕션 설정)
cat src/main/resources/application-prod.ymlRepository: IT-Cotato/12th-OnGil-BE
Length of output: 495
🏁 Script executed:
# Product 엔티티의 @Table 어노테이션 다시 확인 (인덱스 포함 여부)
sed -n '16,20p' src/main/java/com/ongil/backend/domain/product/entity/Product.javaRepository: IT-Cotato/12th-OnGil-BE
Length of output: 201
LIKE 검색 성능 최적화를 우선적으로 검토하세요.
현재 searchByKeyword 메서드는 LIKE LOWER(CONCAT('%', :keyword, '%')) 패턴으로 4개 필드(name, brand.name, category.name, colors)를 동시에 검색합니다. 이 패턴은 인덱스를 활용할 수 없어 데이터 증가에 따라 성능 저하가 예상됩니다.
검토 항목:
- 검색 컬럼에 데이터베이스 인덱스 설정 (Product 엔티티에 @Index 어노테이션 또는 DDL에 명시)
- 대규모 데이터셋에서는 Full-Text Search 도입 검토 (MySQL FULLTEXT INDEX, Elasticsearch 등)
colors필드를 별도 엔티티로 분리하면 정규화와 동시에 검색 최적화 가능
- 검증로직 추가
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @src/main/java/com/ongil/backend/product/controller/ProductController.java:
- Around line 76-87: GlobalExceptionHandler is missing a handler for
javax.validation.ConstraintViolationException which causes parameter validation
failures (from methods like ProductController.searchProducts using
@NotBlank/@Size) to return 500; add an
@ExceptionHandler(ConstraintViolationException.class) method in
GlobalExceptionHandler with signature matching (ConstraintViolationException e,
HttpServletRequest request) that logs the error and returns
ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ErrorResponse.of(ErrorCode.INVALID_PARAMETER,
request)); ensure you import ConstraintViolationException and use the same
ErrorResponse and ErrorCode types used elsewhere.
🧹 Nitpick comments (1)
src/main/java/com/ongil/backend/product/controller/ProductController.java (1)
80-81: 검증 제약 조건 중복 (선택사항)
@NotBlank는 이미 문자열을 trim한 후 비어있지 않음을 보장하므로,@Size의min=1은 기술적으로 중복입니다. 하지만 명시적인 의도를 나타내므로 현재 상태로 유지해도 무방합니다.♻️ 중복 제거 옵션 (선택사항)
- @Size(min = 1, max = 50, message = "검색 키워드는 1-50자 이내여야 합니다") + @Size(max = 50, message = "검색 키워드는 50자 이내여야 합니다")
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/main/java/com/ongil/backend/product/controller/ProductController.java
🧰 Additional context used
📓 Path-based instructions (1)
src/main/java/**/*.java
⚙️ CodeRabbit configuration file
SOLID 원칙, 스프링 어노테이션, 의존성 주입 패턴, 예외 처리에 중점을 둔다
Files:
src/main/java/com/ongil/backend/product/controller/ProductController.java
🔇 Additional comments (2)
src/main/java/com/ongil/backend/product/controller/ProductController.java (2)
8-8: 검증 로직 추가 승인커밋 메시지에서 언급한 대로 클래스 레벨에
@Validated어노테이션과 필요한 제약 조건 import를 추가하여 메서드 파라미터 검증을 올바르게 활성화했습니다.Also applies to: 20-21, 25-25
76-87: 검색 엔드포인트 구현 승인새로운 검색 API가 Spring MVC 패턴을 올바르게 따르고 있으며, 입력 검증이 적절히 적용되었습니다:
- 컨트롤러는 HTTP 계층 관심사만 처리하고 비즈니스 로직은 서비스에 위임 (SRP 준수)
- 페이지네이션 기본값 설정으로 API 사용성 향상
- Swagger 문서화로 API 명세 제공
src/main/java/com/ongil/backend/product/controller/ProductController.java
Show resolved
Hide resolved
ConstraintViolationException 핸들러 추가
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/main/java/com/ongil/backend/global/common/exception/GlobalExceptionHandler.java (2)
63-76: 요청 정보 로깅을 추가하여 일관성을 개선하세요.
handleAppException과handleAllException은 에러 발생 지점(요청 메서드와 URI)을 별도로 로깅하지만, 이 핸들러는 해당 로깅이 누락되어 있습니다. 디버깅 시 요청 컨텍스트를 파악하기 어려울 수 있습니다.♻️ 일관된 로깅 패턴 적용
@ExceptionHandler(ConstraintViolationException.class) public ResponseEntity<ErrorResponse> handleConstraintViolationException( ConstraintViolationException e, HttpServletRequest request ) { log.error("ConstraintViolation 에러 발생: {}", e.getMessage()); + log.error("에러가 발생한 지점: {} {}", request.getMethod(), request.getRequestURI()); ErrorResponse errorResponse = ErrorResponse.of( ErrorCode.INVALID_PARAMETER, request ); return ResponseEntity .status(HttpStatus.BAD_REQUEST) .body(errorResponse); }
68-68: 검증 실패 상세 정보를 로깅하여 디버깅을 개선하세요.
e.getMessage()는 모든 제약 위반을 하나의 문자열로 연결하지만,e.getConstraintViolations()를 사용하면 각 위반 사항(속성 경로, 잘못된 값, 메시지)을 구조화된 형태로 확인할 수 있어 디버깅이 더 용이합니다.♻️ 상세한 제약 위반 정보 로깅
- log.error("ConstraintViolation 에러 발생: {}", e.getMessage()); + log.error("ConstraintViolation 에러 발생: {}", e.getConstraintViolations());
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/main/java/com/ongil/backend/global/common/exception/GlobalExceptionHandler.java
🧰 Additional context used
📓 Path-based instructions (1)
src/main/java/**/*.java
⚙️ CodeRabbit configuration file
SOLID 원칙, 스프링 어노테이션, 의존성 주입 패턴, 예외 처리에 중점을 둔다
Files:
src/main/java/com/ongil/backend/global/common/exception/GlobalExceptionHandler.java
🔍️ 작업 내용
상품 검색 기능
✨ 상세 설명
🛠️ 추후 리팩토링 및 고도화 계획
📸 스크린샷 (선택)
💬 리뷰 요구사항
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.