Skip to content

Conversation

@kon28289
Copy link
Contributor

@kon28289 kon28289 commented Sep 6, 2025

What is this PR?🔍

  • 상품 목록 조회 시 각 상품의 찜 횟수를 함께 반환하도록 필드를 추가합니다.
  • 상품 상세 조회는 변경하지 않았습니다.

Changes💻

ScreenShot📷

Summary by CodeRabbit

  • New Features

    • 채팅방에 표시되는 상품 정보가 확장되어 제목, 가격, 판매자 닉네임/프로필, 대표 이미지, 거래 완료 여부가 보다 명확하게 제공됩니다.
    • 상품 목록·검색 결과에 상품별 찜(좋아요) 수가 표시됩니다.
    • 상품 상세에서 현재 사용자가 해당 상품을 찜했는지 여부가 표시됩니다.
  • Refactor

    • 채팅방용 상품 응답 구조를 재정비하여 화면 간 일관성과 데이터 명확성을 높였습니다.

@kon28289 kon28289 self-assigned this Sep 6, 2025
@coderabbitai
Copy link

coderabbitai bot commented Sep 6, 2025

Walkthrough

채팅방 응답의 product 타입을 ProductListResponse에서 ChatRoomProductResponse로 교체하고, 이를 위한 새 DTO를 추가했으며 상품 목록 응답에 zzimCount 집계 및 zzim 조인을 도입해 관련 리포지토리 프로젝션을 수정했다.

Changes

Cohort / File(s) Summary of Changes
채팅방 응답 DTO 교체
src/main/java/.../chat/dto/response/ChatRoomResponse.java
product 필드 타입을 ProductListResponseChatRoomProductResponse로 변경; 팩토리 매핑 호출을 ChatRoomProductResponse.to(...)로 수정.
채팅방 조회 프로젝션 수정
src/main/java/.../chat/repository/CustomChatRoomRepositoryImpl.java
QueryDSL 프로젝션에서 내포된 product DTO를 ProductListResponse.classChatRoomProductResponse.class로 교체; 관련 import 추가.
채팅방용 상품 DTO 추가
src/main/java/.../product/dto/response/ChatRoomProductResponse.java
record ChatRoomProductResponse(Long id, String title, Long price, String sellerName, String sellerPicture, String mainImageUrl, boolean isCompleted) 추가; @QueryProjection 생성자 및 public static ChatRoomProductResponse to(Product) 매퍼 구현.
상품 목록 DTO 확장
src/main/java/.../product/dto/response/ProductListResponse.java
zzimCount: Long 컴포넌트 추가; @QueryProjection 생성자 시그니처에 Long zzimCount 추가; 기존 to(Product) 정적 팩토리 제거.
상품 쿼리 집계 및 zzim 도입
src/main/java/.../product/repository/CustomProductRepositoryImpl.java
QZzim zzim 별칭 추가, 모든 관련 쿼리에 leftJoin(zzim).on(zzim.product.id.eq(product.id)) 추가; 프로젝션에 zzim.id.count() 포함; groupBy에 이미지 URL 포함; getProductDetail에 현재 사용자 기준 isZzimed 서브쿼리 및 매핑 추가.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as 클라이언트
  participant S as ChatRoomService
  participant R as CustomChatRoomRepository
  participant DB as DB

  C->>S: 채팅방 목록 요청
  S->>R: getChatRooms(...)
  R->>DB: 채팅방 + 상품 조인 쿼리 (프로젝션: ChatRoomProductResponse)
  DB-->>R: 조회 결과
  R-->>S: ChatRoomResponse(product=ChatRoomProductResponse ...)
  S-->>C: 응답 반환
  note right of R: product 서브프로젝션이 ChatRoomProductResponse로 변경됨
Loading
sequenceDiagram
  autonumber
  participant C as 클라이언트
  participant S as ProductService
  participant R as CustomProductRepository
  participant DB as DB

  C->>S: 상품 목록/검색 요청
  S->>R: getAllProducts / searchProducts
  R->>DB: product ← user,image LEFT JOIN zzim + COUNT(zzim.id)
  DB-->>R: 집계 결과 (이미지 최소값, zzimCount 등)
  R-->>S: ProductListResponse(..., zzimCount)
  S-->>C: 응답 반환
  note right of R: groupBy 및 프로젝션에 zzimCount 추가
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • AYEOOON

Poem

토끼가 껑충 뛰며 DTO 바꿨네 🐇
채팅 속 상품은 새 옷 입고,
찜(zzim)은 카운트로 쌓여가요.
조인 한 번, 카운트 한 번—
깡충! 응답이 또랑또랑 돌아왔어요.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/product

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/main/java/com/uhdyl/backend/product/repository/CustomProductRepositoryImpl.java (1)

65-83: getMyProducts가 새 DTO 생성자와 불일치(7→8 인자)합니다

ProductListResponse가 zzimCount를 요구하는데, 여기서는 7개 인자만 투영하고 있어 런타임에서 매핑 실패가 납니다. zzim 조인/집계를 추가해 8번째 인자를 채워주세요.

아래와 같이 수정 제안드립니다.

         List<ProductListResponse> content = jpaQueryFactory
                 .select(Projections.constructor(ProductListResponse.class,
                         product.id,
                         product.title,
                         product.price,
                         user.nickname.coalesce(user.name).coalesce(""),
                         user.picture,
-                        image.imageUrl.min(),
-                        product.isSale.not()
+                        image.imageUrl.min(),
+                        product.isSale.not(),
+                        zzim.id.countDistinct()
                 ))
                 .from(product)
-                .leftJoin(product.images, image).on(image.imageOrder.eq(0L))
+                .leftJoin(product.images, image).on(image.imageOrder.eq(0L))
+                .leftJoin(zzim).on(zzim.product.id.eq(product.id))
                 .where(product.user.id.eq(userId))
                 .groupBy(product.id, product.title, product.price, user.nickname, user.name, user.picture, product.isSale)

메서드 상단에 별칭 선언도 추가합니다.

         QProduct product = QProduct.product;
         QImage image = QImage.image;
         QUser user = QUser.user;
+        QZzim zzim = QZzim.zzim;
src/main/java/com/uhdyl/backend/chat/repository/CustomChatRoomRepositoryImpl.java (1)

56-64: isCompleted 의미 뒤바뀜: qProduct.isSale → qProduct.isSale.not()로 수정 필요

ChatRoomProductResponse의 마지막 필드는 isCompleted인데, 현재 qProduct.isSale을 그대로 전달하고 있어 의미가 반대입니다.

다음처럼 수정하세요(판매자 이름 null 대비 coalesce도 함께 권장).

                         Projections.constructor(
                                 ChatRoomProductResponse.class,
                                 qProduct.id,
                                 qProduct.title,
                                 qProduct.price,
-                                qProduct.user.nickname,
+                                qProduct.user.nickname.coalesce(qProduct.user.name).coalesce(""),
                                 qProduct.user.picture,
                                 mainImageUrl,
-                                qProduct.isSale
+                                qProduct.isSale.not()
                         ),
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 002475f and 0b38fe0.

📒 Files selected for processing (5)
  • src/main/java/com/uhdyl/backend/chat/dto/response/ChatRoomResponse.java (3 hunks)
  • src/main/java/com/uhdyl/backend/chat/repository/CustomChatRoomRepositoryImpl.java (2 hunks)
  • src/main/java/com/uhdyl/backend/product/dto/response/ChatRoomProductResponse.java (1 hunks)
  • src/main/java/com/uhdyl/backend/product/dto/response/ProductListResponse.java (1 hunks)
  • src/main/java/com/uhdyl/backend/product/repository/CustomProductRepositoryImpl.java (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
src/main/java/com/uhdyl/backend/chat/dto/response/ChatRoomResponse.java (2)
src/main/java/com/uhdyl/backend/chat/domain/ChatRoom.java (1)
  • Entity (12-43)
src/main/java/com/uhdyl/backend/chat/service/ChatRoomService.java (3)
  • Service (23-102)
  • Transactional (35-64)
  • chatRoomRepository (49-57)
src/main/java/com/uhdyl/backend/chat/repository/CustomChatRoomRepositoryImpl.java (2)
src/main/java/com/uhdyl/backend/chat/repository/ChatRoomRepository.java (1)
  • ChatRoomRepository (8-11)
src/main/java/com/uhdyl/backend/chat/service/ChatRoomService.java (2)
  • Service (23-102)
  • chatRoomRepository (49-57)
src/main/java/com/uhdyl/backend/product/repository/CustomProductRepositoryImpl.java (3)
src/main/java/com/uhdyl/backend/zzim/repository/CustomZzimRepositoryImpl.java (3)
  • RequiredArgsConstructor (19-97)
  • Override (24-64)
  • Override (66-94)
src/main/java/com/uhdyl/backend/zzim/domain/Zzim.java (1)
  • Entity (11-42)
src/main/java/com/uhdyl/backend/zzim/repository/ZzimRepository.java (2)
  • ZzimRepository (10-16)
  • findByUserAndProduct (13-13)
src/main/java/com/uhdyl/backend/product/dto/response/ProductListResponse.java (2)
src/main/java/com/uhdyl/backend/product/dto/response/MyProductListResponse.java (1)
  • MyProductListResponse (5-10)
src/main/java/com/uhdyl/backend/product/domain/Product.java (1)
  • Entity (33-106)
src/main/java/com/uhdyl/backend/product/dto/response/ChatRoomProductResponse.java (3)
src/main/java/com/uhdyl/backend/product/dto/response/ProductDetailResponse.java (1)
  • ProductDetailResponse (5-17)
src/main/java/com/uhdyl/backend/chat/domain/ChatRoom.java (1)
  • Entity (12-43)
src/main/java/com/uhdyl/backend/product/dto/response/ProductCreateResponse.java (1)
  • ProductCreateResponse (5-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (1)
src/main/java/com/uhdyl/backend/chat/dto/response/ChatRoomResponse.java (1)

15-16: ChatRoomProductResponse로의 전환 LGTM

필드 타입 및 팩토리 메서드 전환이 일관적입니다. 상응하는 리포지토리 투영의 isCompleted 의미만 위 파일 수정과 같이 맞춰주세요.

Also applies to: 24-25

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
src/main/java/com/uhdyl/backend/product/repository/CustomProductRepositoryImpl.java (3)

74-76: zzim 카운트는 countDistinct로 안전하게

현재 조인 구성상 중복은 없어 보이지만, 향후 조인 추가/변경으로 중복 행이 생겨도 안전하도록 distinct 집계를 권장합니다.

-                        product.isSale.not(),
-                        zzim.id.count()
+                        product.isSale.not(),
+                        zzim.id.countDistinct()

221-223: getAllProducts: zzim 카운트도 countDistinct 권장

안전한 집계를 위해 distinct 사용을 권장합니다.

-                        product.isSale.not(),
-                        zzim.id.count()
+                        product.isSale.not(),
+                        zzim.id.countDistinct()

277-279: searchProducts: zzim 카운트도 countDistinct 권장

동일 사유로 distinct 집계를 권장합니다.

-                        product.isSale.not(),
-                        zzim.id.count()
+                        product.isSale.not(),
+                        zzim.id.countDistinct()
🧹 Nitpick comments (3)
src/main/java/com/uhdyl/backend/product/repository/CustomProductRepositoryImpl.java (3)

73-73: imageUrl min/그룹바이 불일치: 일관화 제안

getMyProducts는 image.imageUrl.min()을 선택하면서 groupBy에 image.imageUrl을 포함하고 있어 중복된 설정입니다. 다른 메서드와 동일하게 단일 메인이미지를 조인하고 있으므로 min() 없이 imageUrl로 통일하는 편이 단순합니다.

-                        image.imageUrl.min(),
+                        image.imageUrl,

Also applies to: 82-82


72-72: user.picture null 처리 일관성

타 메서드들은 user.picture.coalesce("")를 사용합니다. getMyProducts도 동일하게 처리해 응답 일관성을 맞추는 편이 좋습니다.

-                        user.picture,
+                        user.picture.coalesce(""),

229-239: 검색/목록 성능 고려 사항

  • where(product.isSale = true) 경로가 핵심이므로 DB에 따라 idx_product_is_sale_created_at 같은 복합 인덱스를 고려하세요.
  • 제목 like 검색은 전방/부분 일치로 인덱스 활용이 제한됩니다. MySQL이면 FULLTEXT(ngram), PostgreSQL이면 trigram(GIN) 인덱스 고려를 추천합니다.

Also applies to: 255-263

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b38fe0 and cec23bd.

📒 Files selected for processing (1)
  • src/main/java/com/uhdyl/backend/product/repository/CustomProductRepositoryImpl.java (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/com/uhdyl/backend/product/repository/CustomProductRepositoryImpl.java (3)
src/main/java/com/uhdyl/backend/zzim/repository/CustomZzimRepositoryImpl.java (2)
  • Override (24-64)
  • Override (66-94)
src/main/java/com/uhdyl/backend/zzim/domain/Zzim.java (1)
  • Entity (11-42)
src/main/java/com/uhdyl/backend/zzim/repository/ZzimRepository.java (2)
  • ZzimRepository (10-16)
  • findByUserAndProduct (13-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (3)
src/main/java/com/uhdyl/backend/product/repository/CustomProductRepositoryImpl.java (3)

82-82: groupBy에서 zzim.id 제거: 잘 반영됨

이제 제품 단위로 정확히 집계됩니다. 페이지네이션/카운트 왜곡 이슈 해소에 동의합니다.


231-231: search/getAll의 groupBy 정정 OK

두 쿼리 모두 제품 단위 그룹화로 정리된 점 좋습니다.

Also applies to: 286-286


83-84: GROUP BY 쿼리에서 createdAt 정렬 호환성 확인/보완 필요

기본 정렬이 createdAt DESC인데, GROUP BY 쿼리에서 그룹화되지 않은 컬럼으로 ORDER BY 하면 PostgreSQL 및 MySQL(ONLY_FULL_GROUP_BY ON)에서 오류가 납니다. 그룹 컬럼에 createdAt을 포함하거나, 기본 정렬을 product.id DESC(또는 createdAt.max())로 대체하는 방안을 검토해 주세요.

빠른 완화책(그룹 컬럼 추가):

-                .groupBy(product.id, product.title, product.price, user.nickname, user.name, user.picture, image.imageUrl, product.isSale)
+                .groupBy(product.id, product.title, product.price, user.nickname, user.name, user.picture, image.imageUrl, product.isSale, product.createdAt)

동일 변경을 getAllProducts와 searchProducts의 groupBy에도 적용해 주세요.

Also applies to: 231-233, 286-287

@kon28289 kon28289 merged commit 312a4e3 into dev Sep 6, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants