Skip to content

Conversation

@seojelee9999
Copy link
Contributor

@seojelee9999 seojelee9999 commented Dec 22, 2025

✨ 변경 사항


Cart도메인 crud기능 추가

✅ 테스트


  • 수동 테스트 완료
  • 테스트 코드 완료

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • 장바구니 관리 기능 추가: 상품 추가/수정, 장바구니 조회, 항목 및 장바구니 삭제 지원
    • 장바구니 API 엔드포인트 제공: 상품 수량 관리, 총 가격 계산 및 개별 항목 제거 가능
    • 사용자별 장바구니 자동 생성 및 관리

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 22, 2025

Walkthrough

쇼핑 카트 기능을 위한 새로운 REST API 엔드포인트, 서비스 계층, JPA 엔티티, 저장소, 그리고 데이터 전송 객체들을 도입합니다. 카트 항목 추가/수정, 조회, 삭제 기능과 사용자 인증 유틸리티가 포함됩니다.

Changes

응집체 / 파일(들) 변경 요약
엔티티 및 리포지토리
src/main/java/com/campustable/be/domain/cart/entity/Cart.java, src/main/java/com/campustable/be/domain/cart/entity/CartItem.java, src/main/java/com/campustable/be/domain/cart/repository/CartRepository.java, src/main/java/com/campustable/be/domain/cart/repository/CartItemRepository.java
Cart 및 CartItem JPA 엔티티 추가. Cart는 사용자와 1:1 연결, CartItem들을 1:N으로 보유. 카트 및 카트 항목 쿼리 메서드를 가진 리포지토리 인터페이스 추가.
DTO 클래스
src/main/java/com/campustable/be/domain/cart/dto/CartRequest.java, src/main/java/com/campustable/be/domain/cart/dto/CartResponse.java, src/main/java/com/campustable/be/domain/cart/dto/CartItemDto.java
카트 요청(menuId, quantity), 카트 응답(items, totalPrice, cartId), 카트 항목 DTO(menuName, quantity, price, menuUrl, cartItemId) 추가.
컨트롤러 및 문서화
src/main/java/com/campustable/be/domain/cart/controller/CartController.java, src/main/java/com/campustable/be/domain/cart/controller/CartControllerDocs.java
/api/cart 기본 경로의 REST 컨트롤러와 OpenAPI 인터페이스 추가. 항목 추가/수정, 조회, 카트 삭제, 항목 삭제 엔드포인트 제공.
서비스 계층
src/main/java/com/campustable/be/domain/cart/service/CartService.java
카트 항목 업데이트, 조회, 삭제 비즈니스 로직 구현. 메뉴 검증, 사용자 인증, 카트 상태 관리 포함.
사용자 엔티티 수정
src/main/java/com/campustable/be/domain/user/entity/User.java
User 엔티티에 Cart와의 1:1 연관 관계 필드 추가.
보안 유틸리티
src/main/java/com/campustable/be/global/common/SecurityUtil.java
Spring Security 컨텍스트에서 현재 사용자 ID를 조회하는 정적 메서드 추가.
에러 코드
src/main/java/com/campustable/be/global/exception/ErrorCode.java
CART_NOT_FOUND, CART_ITEM_NOT_FOUND 열거 상수 추가.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller as CartController
    participant Service as CartService
    participant Repos as Repositories
    participant Entities as Entities & DB

    rect rgb(200, 220, 255)
    Note over Client, Entities: 카트 항목 추가/수정
    Client ->> Controller: POST /api/cart/items (menuId, quantity)
    Controller ->> Service: updateCartItem(menuId, quantity)
    Service ->> Repos: getCurrentUserId()
    Repos -->> Service: userId
    Service ->> Repos: findByUserId(userId)
    Repos -->> Service: Optional<Cart>
    alt Cart 없음
        Service ->> Repos: findMenuById(menuId)
        Repos -->> Service: Menu
        Service ->> Entities: create Cart(user)
        Service ->> Repos: save(cart)
        Repos -->> Entities: persist
    end
    Service ->> Repos: findByCartAndMenu(cart, menu)
    Repos -->> Service: Optional<CartItem>
    alt CartItem 있음
        Service ->> Entities: cartItem.setQuantity(quantity)
    else CartItem 없음
        Service ->> Entities: create CartItem(cart, menu)
        Service ->> Repos: save(cartItem)
        Repos -->> Entities: persist
    end
    Service ->> Repos: flush()
    Service ->> Service: buildCartResponse()
    Service -->> Controller: CartResponse
    Controller -->> Client: ResponseEntity<CartResponse>
    end

    rect rgb(220, 255, 220)
    Note over Client, Entities: 카트 조회
    Client ->> Controller: GET /api/cart
    Controller ->> Service: getCart()
    Service ->> Repos: findByUserId(userId)
    Repos -->> Service: Optional<Cart>
    Service ->> Service: convertToDTO(cartItems)
    Service -->> Controller: CartResponse
    Controller -->> Client: ResponseEntity<CartResponse>
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 분

이 변경사항은 다중 엔티티 관계(User ↔ Cart ↔ CartItem ↔ Menu), 복잡한 서비스 로직(검증, 상태 관리, 에러 처리), 새로운 REST API 엔드포인트, 보안 통합을 포함합니다. 12개 파일 수정, 중복 패턴 없는 이질적인 변경, CartService의 높은 로직 밀도로 인해 상당한 검토 노력이 필요합니다.

Possibly related PRs

Poem

🐰 카트를 담아, 항목을 정렬하고,
사용자와 메뉴를 맺어주며,
응답을 구성해 보냅니다.
DELETE로 비우고, GET으로 확인하며,
쇼핑 경험을 완성하는 나, 행복합니다! 🛒✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.76% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 Cart 도메인의 CRUD 기능 추가라는 주요 변경사항을 정확하게 요약하고 있으며, 변경 내용과 완전히 관련이 있습니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch test

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.

@seojelee9999
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Dec 23, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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: 6

🧹 Nitpick comments (13)
src/main/java/com/campustable/be/domain/cart/entity/Cart.java (1)

31-33: OneToOne 관계에 LAZY 로딩을 명시적으로 설정하는 것을 권장합니다.

@OneToOne 관계의 기본 fetch 전략은 EAGER입니다. 불필요한 조인을 방지하고 성능을 개선하기 위해 fetch = FetchType.LAZY를 명시하는 것이 좋습니다.

🔎 수정 제안
- @OneToOne
+ @OneToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "user_id")
  private User user;
src/main/java/com/campustable/be/domain/cart/dto/CartResponse.java (1)

13-13: totalPrice를 long 타입으로 변경하는 것을 고려하세요.

int 타입은 최대 약 21억까지만 표현 가능합니다. 장바구니 총액이 커질 경우 오버플로우가 발생할 수 있습니다. long 타입 사용을 권장합니다.

🔎 수정 제안
  private List<CartItemDto> items;
- private int totalPrice;
+ private long totalPrice;
  private Long cartId;
src/main/java/com/campustable/be/domain/cart/entity/CartItem.java (3)

31-35: @JoinColumn 어노테이션 누락

@ManyToOne 관계에서 @JoinColumn을 명시하지 않으면 JPA가 기본 컬럼명(menu_id, cart_id)을 생성하지만, 명시적으로 지정하는 것이 스키마 일관성과 가독성에 좋습니다.

🔎 제안된 수정
 @ManyToOne(fetch = FetchType.LAZY)
+@JoinColumn(name = "menu_id")
 private Menu menu;

 @ManyToOne(fetch = FetchType.LAZY)
+@JoinColumn(name = "cart_id")
 private Cart cart;

37-38: @Min 검증이 자동으로 실행되지 않음

엔티티 필드에 @Min 어노테이션만 추가하면 영속화 시점에 자동으로 검증되지 않습니다. Bean Validation이 동작하려면 hibernate.validator.fail_fast 설정 또는 @Valid 사용이 필요하며, 현재 setQuantity() 호출 시 검증이 우회됩니다.

서비스 레이어에서 quantity 값을 검증하거나, setter에 직접 검증 로직을 추가하는 것을 권장합니다.

🔎 setter에서 검증하는 방식
public void setQuantity(int quantity) {
  if (quantity < 0) {
    throw new IllegalArgumentException("수량은 0 이상이어야 합니다");
  }
  this.quantity = quantity;
}

22-25: 생성자에서 quantity 초기화 누락

생성자에서 quantity를 초기화하지 않아 기본값 0이 설정됩니다. 서비스 코드에서 setQuantity()를 별도로 호출하고 있으나, 생성자 파라미터로 quantity를 받으면 객체 생성이 더 명확해집니다.

🔎 제안된 수정
-public CartItem(Cart cart, Menu menu){
+public CartItem(Cart cart, Menu menu, int quantity){
   this.cart = cart;
   this.menu = menu;
+  this.quantity = quantity;
 }
src/main/java/com/campustable/be/domain/cart/dto/CartRequest.java (1)

6-11: 요청 DTO에 입력 검증 누락

API 문서에 따르면 menuId는 필수이고 quantity는 0 이상이어야 합니다. 클라이언트에서 잘못된 값을 보내면 검증 없이 서비스 레이어까지 전달됩니다. @Valid와 함께 사용할 수 있도록 검증 어노테이션을 추가하세요.

🔎 제안된 수정
 package com.campustable.be.domain.cart.dto;

 import lombok.Getter;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;

 @Getter
 public class CartRequest {

+  @NotNull(message = "메뉴 ID는 필수입니다")
   private Long menuId;
+
+  @Min(value = 0, message = "수량은 0 이상이어야 합니다")
   private int quantity;
 }

컨트롤러에서도 @Valid 어노테이션을 추가해야 검증이 동작합니다:

public ResponseEntity<CartResponse> addOrUpdateItems(@Valid @RequestBody CartRequest request)
src/main/java/com/campustable/be/domain/cart/controller/CartControllerDocs.java (1)

69-69: 삭제 API의 응답 타입 일관성

deleteCartdeleteCartItem 메서드가 void를 반환하면 HTTP 상태 코드를 명시적으로 제어하기 어렵습니다. 다른 엔드포인트와 일관성을 위해 ResponseEntity<Void>를 반환하고 204 No Content를 명시하는 것을 권장합니다.

Also applies to: 87-87

src/main/java/com/campustable/be/domain/cart/service/CartService.java (4)

56-67: 조건문 스타일 일관성

Line 60에서 else 브랜치에 중괄호가 없습니다. 코드 일관성과 유지보수성을 위해 항상 중괄호를 사용하는 것이 좋습니다.

🔎 제안된 수정
     if (cartItemOpt.isPresent()) {
-      if (quantity == 0){
+      if (quantity == 0) {
         cartItemRepository.delete(cartItemOpt.get());
+      } else {
+        cartItemOpt.get().setQuantity(quantity);
       }
-      else cartItemOpt.get().setQuantity(quantity);
     } else {

84-86: 중복 코드: totalPrice 계산 로직

totalPrice 계산 로직이 updateCartItemgetCart 메서드에서 동일하게 반복됩니다. 별도의 private 메서드로 추출하면 유지보수성이 향상됩니다.

🔎 제안된 수정
private int calculateTotalPrice(List<CartItemDto> cartItems) {
  return cartItems.stream()
      .mapToInt(item -> item.getPrice() * item.getQuantity())
      .sum();
}

Also applies to: 150-152


134-168: 읽기 전용 트랜잭션 최적화

getCart() 메서드는 데이터를 조회만 하므로 @Transactional(readOnly = true)를 사용하면 Hibernate의 dirty checking을 비활성화하여 성능이 향상됩니다.

🔎 제안된 수정
+@Transactional(readOnly = true)
 public CartResponse getCart(){

75-82: 중복 코드: 빈 장바구니 삭제 로직

빈 장바구니를 삭제하는 로직이 updateCartItemdeleteCartItem에서 반복됩니다. private 메서드로 추출하여 재사용하는 것을 권장합니다.

🔎 제안된 수정
private void deleteCartIfEmpty(Cart cart) {
  if (cartItemRepository.findByCart(cart).isEmpty()) {
    cart.getUser().setCart(null);
    cartRepository.delete(cart);
  }
}

Also applies to: 111-114

src/main/java/com/campustable/be/domain/cart/controller/CartController.java (2)

46-59: DELETE 엔드포인트 응답 개선

void를 반환하면 Spring이 기본적으로 200 OK를 반환합니다. RESTful 관례상 삭제 성공 시 204 No Content를 반환하는 것이 적절합니다.

🔎 제안된 수정
 @DeleteMapping("/{cartId}")
-public void deleteCart(@PathVariable Long cartId) {
+public ResponseEntity<Void> deleteCart(@PathVariable Long cartId) {
   cartService.deleteCart(cartId);
+  return ResponseEntity.noContent().build();
 }

 @DeleteMapping("/items/{cartItemId}")
-public void deleteCartItem(@PathVariable Long cartItemId) {
+public ResponseEntity<Void> deleteCartItem(@PathVariable Long cartItemId) {
   cartService.deleteCartItem(cartItemId);
+  return ResponseEntity.noContent().build();
 }

22-22: 사용되지 않는 @Slf4j 어노테이션

컨트롤러에서 log 객체를 사용하지 않습니다. 불필요한 어노테이션은 제거하거나, 디버깅/모니터링 목적의 로깅을 추가하세요.

📜 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 7cca723 and 7034172.

📒 Files selected for processing (13)
  • src/main/java/com/campustable/be/domain/cart/controller/CartController.java
  • src/main/java/com/campustable/be/domain/cart/controller/CartControllerDocs.java
  • src/main/java/com/campustable/be/domain/cart/dto/CartItemDto.java
  • src/main/java/com/campustable/be/domain/cart/dto/CartRequest.java
  • src/main/java/com/campustable/be/domain/cart/dto/CartResponse.java
  • src/main/java/com/campustable/be/domain/cart/entity/Cart.java
  • src/main/java/com/campustable/be/domain/cart/entity/CartItem.java
  • src/main/java/com/campustable/be/domain/cart/repository/CartItemRepository.java
  • src/main/java/com/campustable/be/domain/cart/repository/CartRepository.java
  • src/main/java/com/campustable/be/domain/cart/service/CartService.java
  • src/main/java/com/campustable/be/domain/user/entity/User.java
  • src/main/java/com/campustable/be/global/common/SecurityUtil.java
  • src/main/java/com/campustable/be/global/exception/ErrorCode.java
🧰 Additional context used
🧬 Code graph analysis (6)
src/main/java/com/campustable/be/domain/cart/dto/CartRequest.java (2)
src/main/java/com/campustable/be/domain/cart/dto/CartItemDto.java (1)
  • Getter (8-24)
src/main/java/com/campustable/be/domain/cart/dto/CartResponse.java (1)
  • Getter (8-15)
src/main/java/com/campustable/be/domain/cart/service/CartService.java (1)
src/main/java/com/campustable/be/global/common/SecurityUtil.java (1)
  • Slf4j (9-33)
src/main/java/com/campustable/be/domain/cart/entity/CartItem.java (5)
src/main/java/com/campustable/be/domain/cart/entity/Cart.java (1)
  • Entity (20-43)
src/main/java/com/campustable/be/domain/user/entity/User.java (1)
  • Entity (13-49)
src/main/java/com/campustable/be/domain/cart/dto/CartRequest.java (1)
  • Getter (6-11)
src/main/java/com/campustable/be/domain/cart/dto/CartItemDto.java (1)
  • Getter (8-24)
src/main/java/com/campustable/be/domain/cart/dto/CartResponse.java (1)
  • Getter (8-15)
src/main/java/com/campustable/be/domain/cart/entity/Cart.java (5)
src/main/java/com/campustable/be/domain/cart/entity/CartItem.java (1)
  • Entity (16-43)
src/main/java/com/campustable/be/domain/user/entity/User.java (1)
  • Entity (13-49)
src/main/java/com/campustable/be/domain/cart/dto/CartRequest.java (1)
  • Getter (6-11)
src/main/java/com/campustable/be/domain/cart/dto/CartItemDto.java (1)
  • Getter (8-24)
src/main/java/com/campustable/be/domain/cart/dto/CartResponse.java (1)
  • Getter (8-15)
src/main/java/com/campustable/be/domain/cart/dto/CartItemDto.java (3)
src/main/java/com/campustable/be/domain/cart/dto/CartRequest.java (1)
  • Getter (6-11)
src/main/java/com/campustable/be/domain/cart/dto/CartResponse.java (1)
  • Getter (8-15)
src/main/java/com/campustable/be/domain/auth/dto/ReissueRequest.java (1)
  • Setter (8-15)
src/main/java/com/campustable/be/domain/cart/dto/CartResponse.java (1)
src/main/java/com/campustable/be/domain/cart/dto/CartItemDto.java (1)
  • Getter (8-24)
🔇 Additional comments (6)
src/main/java/com/campustable/be/global/exception/ErrorCode.java (1)

66-71: LGTM!

Cart 도메인을 위한 에러 코드가 올바르게 추가되었습니다. 기존 패턴과 일관되게 구현되었습니다.

src/main/java/com/campustable/be/domain/user/entity/User.java (1)

27-28: LGTM!

User-Cart 양방향 관계가 올바르게 설정되었습니다. cascadeorphanRemoval 설정도 적절합니다.

src/main/java/com/campustable/be/domain/cart/repository/CartItemRepository.java (1)

11-18: LGTM!

CartItem 조회를 위한 쿼리 메서드들이 Spring Data JPA 네이밍 규칙에 따라 올바르게 정의되었습니다.

src/main/java/com/campustable/be/global/common/SecurityUtil.java (1)

14-31: LGTM!

인증 정보 검증과 에러 처리가 적절하게 구현되었습니다. 로깅도 잘 되어 있고, NumberFormatException 처리도 적절합니다.

src/main/java/com/campustable/be/domain/cart/repository/CartRepository.java (1)

9-14: LGTM!

Cart 조회를 위한 메서드들이 적절하게 정의되었습니다. findByUserfindByUserId 모두 각각의 사용 시나리오에서 유용합니다.

src/main/java/com/campustable/be/domain/cart/service/CartService.java (1)

69-69: flush() 호출의 필요성 검토

@Transactional 범위 내에서 명시적인 flush() 호출은 일반적으로 불필요합니다. 트랜잭션 커밋 시점에 자동으로 flush됩니다. 특별한 이유(예: 삭제 후 즉시 카운트 조회)가 있다면 주석으로 의도를 명시해 주세요.

Also applies to: 109-109

Comment on lines +30 to +31
public ResponseEntity<CartResponse> addOrUpdateItems(@RequestBody CartRequest request) {
CartResponse response = cartService.updateCartItem(request.getMenuId(), request.getQuantity());
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

@Valid 어노테이션 누락

CartRequest에 검증 어노테이션을 추가했다면, @Valid를 함께 사용해야 Bean Validation이 동작합니다.

🔎 제안된 수정
-public ResponseEntity<CartResponse> addOrUpdateItems(@RequestBody CartRequest request) {
+public ResponseEntity<CartResponse> addOrUpdateItems(@Valid @RequestBody CartRequest request) {

import 추가:

import jakarta.validation.Valid;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public ResponseEntity<CartResponse> addOrUpdateItems(@RequestBody CartRequest request) {
CartResponse response = cartService.updateCartItem(request.getMenuId(), request.getQuantity());
public ResponseEntity<CartResponse> addOrUpdateItems(@Valid @RequestBody CartRequest request) {
CartResponse response = cartService.updateCartItem(request.getMenuId(), request.getQuantity());
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/cart/controller/CartController.java
around lines 30-31, the CartRequest parameter is missing the @Valid annotation
so bean validation won't run; add the jakarta.validation.Valid import and
annotate the @RequestBody parameter with @Valid (i.e., change the method
signature to accept @Valid @RequestBody CartRequest request) so validation
constraints on CartRequest are enforced.

Comment on lines +14 to +17
description = """
### 요청 파라미터
- `menu_id` (Long, required): 장바구니에 담을 메뉴 ID
- `quantity` (int, required): 담을 수량
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

API 문서와 DTO 필드명 불일치

문서에서 menu_id로 설명하고 있지만, 실제 CartRequest DTO는 menuId (camelCase)를 사용합니다. 커밋 메시지에서도 camelCase로 통일했다고 언급되어 있으니, 문서도 일치시켜 주세요.

🔎 제안된 수정
       description = """
           ### 요청 파라미터
-          - `menu_id` (Long, required): 장바구니에 담을 메뉴 ID
+          - `menuId` (Long, required): 장바구니에 담을 메뉴 ID
           - `quantity` (int, required): 담을 수량  
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
description = """
### 요청 파라미터
- `menu_id` (Long, required): 장바구니에 담을 메뉴 ID
- `quantity` (int, required): 담을 수량
description = """
### 요청 파라미터
- `menuId` (Long, required): 장바구니에 담을 메뉴 ID
- `quantity` (int, required): 담을 수량
🤖 Prompt for AI Agents
In
src/main/java/com/campustable/be/domain/cart/controller/CartControllerDocs.java
around lines 14 to 17, the API doc uses snake_case `menu_id` while the
CartRequest DTO uses camelCase `menuId`; update the documentation to use
`menuId` to match the DTO (and adjust any other doc occurrences of `menu_id` in
this file), keeping parameter type and description unchanged so docs and DTO are
consistent.

Comment on lines +17 to +23
public CartItemDto(CartItem entity) {
this.menuName = entity.getMenu().getMenuName();
this.price = entity.getMenu().getPrice();
this.quantity = entity.getQuantity();
this.menuUrl = entity.getMenu().getMenuUrl();
this.cartItemId = entity.getCartItemId();
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

생성자에서 null 안전성을 확보하세요.

entity.getMenu()null일 경우 NullPointerException이 발생합니다. MenuCartItem 간의 관계가 @ManyToOne으로 설정되어 있어 이론적으로 null이 가능하므로, 방어 코드를 추가하는 것이 좋습니다.

🔎 수정 제안
  public CartItemDto(CartItem entity) {
+   if (entity.getMenu() == null) {
+     throw new IllegalArgumentException("CartItem must have a Menu");
+   }
    this.menuName = entity.getMenu().getMenuName();
    this.price = entity.getMenu().getPrice();
    this.quantity = entity.getQuantity();
    this.menuUrl =  entity.getMenu().getMenuUrl();
    this.cartItemId = entity.getCartItemId();
  }
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/cart/dto/CartItemDto.java around
lines 17 to 23, the constructor assumes entity.getMenu() is non-null which can
cause a NullPointerException; update the constructor to defensively check that
entity and entity.getMenu() are not null and assign menuName, price, menuUrl
from the Menu only when present (otherwise set sensible defaults or null), and
still assign cartItemId and quantity from entity; you can implement this with
simple null checks (if/else) or using Optional/ternary operators to keep
assignments null-safe.

Comment on lines +26 to +29
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cart_id")
private Long cart_id;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Java 네이밍 규칙 위반: 필드명을 camelCase로 수정하세요.

필드명 cart_id는 Java 네이밍 규칙을 위반합니다. @Column 어노테이션이 이미 데이터베이스 컬럼명을 "cart_id"로 매핑하고 있으므로, 필드명은 cartId로 작성해야 합니다.

🔎 수정 제안
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "cart_id")
- private Long cart_id;
+ private Long cartId;
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/cart/entity/Cart.java around lines 26
to 29, the field name cart_id violates Java camelCase conventions; rename the
private field to cartId, keep the @Column(name = "cart_id") annotation unchanged
so the DB mapping stays the same, and update all references (getters/setters,
constructors, equals/hashCode, usages) in this class and any other classes to
use cartId.

Comment on lines +38 to +40
public Cart(User user) {
this.user = user;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

양방향 관계를 올바르게 유지하도록 생성자를 수정하세요.

생성자에서 user만 설정하고 User 엔티티의 cart 필드는 설정하지 않아 양방향 관계가 불완전합니다. JPA 영속성 컨텍스트 외부에서 객체를 사용할 때 일관성 문제가 발생할 수 있습니다.

🔎 수정 제안
  public Cart(User user) {
    this.user = user;
+   if (user != null) {
+     user.setCart(this);
+   }
  }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/cart/entity/Cart.java around lines 38
to 40, the Cart constructor sets only this.user leaving the User side of the
bidirectional relation unset; update the constructor to assign this.user = user
and also set the back-reference on the User (e.g., if user != null then
user.setCart(this)) so the bidirectional association stays consistent outside
JPA.

Comment on lines +102 to +104
if (!cartItem.getCart().getUser().getUserId().equals(userId)) {
throw new CustomException(ErrorCode.ACCESS_DENIED);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

소유권 검증 시 NPE 위험

cartItem.getCart().getUser().getUserId()cart.getUser().getUserId() 체인에서 중간 객체가 null이면 NullPointerException이 발생할 수 있습니다. LAZY 로딩으로 인해 연관 객체가 로드되지 않았거나 데이터 정합성 문제가 있을 경우를 대비한 방어 코드가 필요합니다.

🔎 Line 102-104 수정 제안
+    Cart cart = cartItem.getCart();
+    if (cart == null || cart.getUser() == null) {
+      throw new CustomException(ErrorCode.CART_NOT_FOUND);
+    }
+
-    if (!cartItem.getCart().getUser().getUserId().equals(userId)) {
+    if (!cart.getUser().getUserId().equals(userId)) {
       throw new CustomException(ErrorCode.ACCESS_DENIED);
     }
-
-    Cart cart = cartItem.getCart();

Also applies to: 125-127

🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/cart/service/CartService.java around
lines 102-104 (and similarly for 125-127), the chained calls
cartItem.getCart().getUser().getUserId() (and cart.getUser().getUserId()) can
throw NPE if any intermediate object is null; replace the direct chain with
defensive null-checks (or Optional) to ensure cartItem.getCart() and its
getUser() are non-null before comparing IDs, and use a null-safe comparison
(e.g., Objects.equals or compare non-null userId values) so that if any required
object or ID is missing you treat it as access denied and throw
CustomException(ErrorCode.ACCESS_DENIED).

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