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
Expand Up @@ -14,7 +14,7 @@
import com.ongil.backend.domain.product.dto.response.ProductOptionResponse;
import com.ongil.backend.domain.product.dto.response.ProductSearchPageResDto;
import com.ongil.backend.domain.product.dto.response.ProductSimpleResponse;
import com.ongil.backend.domain.product.dto.response.RecommendedProductResponse;

import com.ongil.backend.domain.product.dto.response.SizeGuideResponse;
import com.ongil.backend.domain.product.enums.ProductSortType;
import com.ongil.backend.domain.product.service.ProductService;
Expand Down Expand Up @@ -149,11 +149,11 @@ public DataResponse<SizeGuideResponse> getSizeGuide(
"""
)
@GetMapping("/recommend")
public DataResponse<List<RecommendedProductResponse>> getRecommendedProducts(
public DataResponse<List<ProductSimpleResponse>> getRecommendedProducts(
@AuthenticationPrincipal Long userId,
@RequestParam(defaultValue = "10") @Min(1) @Max(100) int size
) {
List<RecommendedProductResponse> products = productService.getRecommendedProducts(userId, size);
List<ProductSimpleResponse> products = productService.getRecommendedProducts(userId, size);
return DataResponse.from(products);
}
Comment on lines +152 to 158
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# 1. Git 이력에서 RecommendedProductResponse 확인
echo "=== RecommendedProductResponse Git 이력 ==="
git log --all --full-history --oneline -- "**/RecommendedProductResponse.java" 2>/dev/null || echo "파일 변경 이력 없음"

# 2. RecommendedProductResponse 삭제 여부 확인
echo -e "\n=== 현재 Repository에서 RecommendedProductResponse 검색 ==="
git ls-files | grep -i "recommendedproduct" || echo "현재 파일 없음"

# 3. 최근 commit에서 DTO 삭제 변경사항 확인
echo -e "\n=== 최근 삭제된 파일 확인 ==="
git log -1 --diff-filter=D --summary -- "*.java" | grep -i "recommend\|delete" || echo "최근 삭제 내역 없음"

# 4. ProductSimpleResponse 현재 정의 확인
echo -e "\n=== ProductSimpleResponse 필드 ==="
find . -type f -name "ProductSimpleResponse.java" 2>/dev/null | head -1 | xargs cat 2>/dev/null

# 5. RecommendedProductResponse 과거 정의 찾기
echo -e "\n=== 과거 RecommendedProductResponse 정의 (Git) ==="
git log -p --all -S "class RecommendedProductResponse" -- "*.java" 2>/dev/null | head -100 || echo "정의 찾을 수 없음"

Repository: IT-Cotato/12th-OnGil-BE

Length of output: 1531


🏁 Script executed:

#!/bin/bash

# 1. 특정 commit에서 RecommendedProductResponse 내용 확인
echo "=== bd664d4 commit에서 RecommendedProductResponse 찾기 ==="
git show bd664d4 -- "**/RecommendedProductResponse.java" 2>/dev/null | head -100

# 2. commit 958546b에서도 확인
echo -e "\n=== 958546b commit에서 RecommendedProductResponse 찾기 ==="
git show 958546b --name-only | grep -i recommendedproduct

# 3. RecommendedProductResponse 마지막 존재 commit 찾기
echo -e "\n=== RecommendedProductResponse가 마지막으로 존재한 내용 ==="
git log --all -p -S "RecommendedProductResponse" -- "*.java" 2>/dev/null | head -150

# 4. ProductController 변경 이력 확인
echo -e "\n=== ProductController 최근 변경 ==="
git log --oneline -10 -- "src/main/java/com/ongil/backend/domain/product/controller/ProductController.java"

# 5. 특정 메서드 변경 확인
echo -e "\n=== getRecommendedProducts 메서드 변경 이력 ==="
git log -p -S "getRecommendedProducts" -- "*.java" 2>/dev/null | head -200

Repository: IT-Cotato/12th-OnGil-BE

Length of output: 8053


getRecommendedProducts API 응답 구조 변경 — 필드 손실로 인한 하위 호환성 파괴

RecommendedProductResponse에서 ProductSimpleResponse로 변경되면서 cartCount 필드가 손실되었습니다. 이전 API는 "장바구니 담긴 횟수" 정보를 응답에 포함했으나, 현재는 해당 필드가 제거되었으므로 클라이언트가 이 데이터에 의존하고 있었다면 사일런트 브레이킹 체인지가 발생합니다.

추가로 purchaseCount(구매 횟수), reviewCount(리뷰 개수) 필드가 신규 추가되었으므로, 의도적 리팩토링이라면 변경 사유와 클라이언트 영향 범위를 명확히 하시기 바랍니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/ongil/backend/domain/product/controller/ProductController.java`
around lines 152 - 158, The API changed the response type in
getRecommendedProducts (ProductController#getRecommendedProducts) from
RecommendedProductResponse to ProductSimpleResponse and dropped the cartCount
field, causing a breaking change; to fix, restore backward compatibility by
returning a DTO that includes cartCount (either revert to using
RecommendedProductResponse or extend ProductSimpleResponse to include
cartCount), update productService.getRecommendedProducts to populate cartCount
alongside purchaseCount/reviewCount, and ensure DataResponse.from(...) wraps the
DTO with the original field present so clients depending on cartCount continue
to work.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

의도된 변경입니다. 홈화면 특가 상품 / 추천 상품 / 추천 브랜드 3개 API의 응답 DTO를
ProductSimpleResponse로 통일하는 리팩토링입니다.

  • cartCount: 프론트엔드에서 사용하지 않는 필드로 확인 후 제거
  • purchaseCount, reviewCount: 기존 특가 상품/추천 브랜드에는 이미 포함되어 있었고, 추천 상품에도
    동일하게 포함되도록 통일

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@neibler, 명확한 설명 감사합니다! 프론트엔드 팀과 확인 후 진행한 의도적인 리팩토링이라면 전혀 문제없습니다. frontend와 backend를 동시에 업데이트할 수 있는 환경에서는 통합된 변경이 문제를 일으키지 않으며, 여러 API 응답 DTO를 하나로 통일하는 것은 유지보수성을 높이는 좋은 아키텍처 결정입니다.

특히 cartCount가 실제로 사용되지 않는 필드였고, purchaseCount/reviewCount는 다른 엔드포인트에 이미 존재했던 것을 표준화한 것이라면 일관성 있는 API 설계를 위한 올바른 접근입니다. 👍


✏️ Learnings added
Learnt from: neibler
Repo: IT-Cotato/12th-OnGil-BE PR: 160
File: src/main/java/com/ongil/backend/domain/product/controller/ProductController.java:152-158
Timestamp: 2026-02-19T10:53:05.953Z
Learning: 홈화면 상품 관련 API(특가 상품, 추천 상품, 추천 브랜드)는 ProductSimpleResponse DTO로 통일되었으며, cartCount 필드는 프론트엔드에서 사용하지 않아 제거되었습니다.

Learnt from: neibler
Repo: IT-Cotato/12th-OnGil-BE PR: 160
File: src/main/java/com/ongil/backend/domain/product/controller/ProductController.java:152-158
Timestamp: 2026-02-19T10:53:05.953Z
Learning: ProductSimpleResponse의 purchaseCount와 reviewCount 필드는 홈화면 상품 API 전반에서 표준화된 필드입니다.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import com.ongil.backend.domain.product.dto.response.ProductOptionResponse;
import com.ongil.backend.domain.product.dto.response.ProductSearchPageResDto;
import com.ongil.backend.domain.product.dto.response.ProductSimpleResponse;
import com.ongil.backend.domain.product.dto.response.RecommendedProductResponse;

import com.ongil.backend.domain.product.dto.response.SizeGuideResponse;
import com.ongil.backend.domain.product.entity.Product;
import com.ongil.backend.domain.product.entity.ProductOption;
Expand Down Expand Up @@ -392,7 +392,7 @@ private SizeGuideResponse buildResponseWithBodyInfoOnly(User user, Product produ
* - 비로그인: 전체 인기 상품
* - 정렬: 전체 고객 기준 viewCount + cartCount 순
*/
public List<RecommendedProductResponse> getRecommendedProducts(Long userId, int size) {
public List<ProductSimpleResponse> getRecommendedProducts(Long userId, int size) {
if (userId == null) {
return getPopularProducts(size);
}
Expand All @@ -402,16 +402,16 @@ public List<RecommendedProductResponse> getRecommendedProducts(Long userId, int
/**
* 인기 상품 조회
*/
private List<RecommendedProductResponse> getPopularProducts(int size) {
private List<ProductSimpleResponse> getPopularProducts(int size) {
Pageable pageable = PageRequest.of(0, size);
List<Product> products = productRepository.findPopularProducts(pageable);
return toRecommendedResponseList(products);
return productConverter.toSimpleResponseList(products);
}

/**
* 개인화 추천 (로그인 사용자)
*/
private List<RecommendedProductResponse> getPersonalizedRecommendations(Long userId, int size) {
private List<ProductSimpleResponse> getPersonalizedRecommendations(Long userId, int size) {
LocalDateTime since = LocalDateTime.now().minusDays(DAYS_TO_LOOK_BACK);

// 1. 최근 30일간 조회한 상품 ID
Expand Down Expand Up @@ -495,37 +495,6 @@ private List<RecommendedProductResponse> getPersonalizedRecommendations(Long use
}
}

return toRecommendedResponseList(recommendations);
}

/**
* Product → RecommendedProductResponse 변환
*/
private RecommendedProductResponse toRecommendedResponse(Product product) {
String thumbnailUrl = null;
if (product.getImageUrls() != null && !product.getImageUrls().isEmpty()) {
String[] urls = product.getImageUrls().split(",");
thumbnailUrl = urls[0].trim();
}

return RecommendedProductResponse.builder()
.id(product.getId())
.name(product.getName())
.price(product.getPrice())
.discountRate(product.getDiscountRate())
.finalPrice(product.getEffectivePrice())
.thumbnailImageUrl(thumbnailUrl)
.brandName(product.getBrand() != null ? product.getBrand().getName() : null)
.productType(product.getProductType())
.viewCount(product.getViewCount())
.cartCount(product.getCartCount())
.reviewRating(product.getReviewRating())
.build();
}

private List<RecommendedProductResponse> toRecommendedResponseList(List<Product> products) {
return products.stream()
.map(this::toRecommendedResponse)
.collect(Collectors.toList());
return productConverter.toSimpleResponseList(recommendations);
}
}