Skip to content

Conversation

@kjh0718
Copy link
Contributor

@kjh0718 kjh0718 commented Dec 30, 2025

✨ 변경 사항


order 기능 구현
주문하면 메뉴 수량 줄어드는 기능
내 주문 확인
categoryId+ orderId 해서 ordermenu status 바꾸기
userId 로 주문 확인

✅ 테스트


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

Summary by CodeRabbit

새로운 기능

  • 주문 생성 및 조회 기능 추가
  • 주문 상태 관리 (조리 중, 수령 대기, 주문 완료)
  • 메뉴 재고 관리 기능
  • 관리자용 주문 상태 변경 기능

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

@coderabbitai
Copy link

coderabbitai bot commented Dec 30, 2025

개요

이 PR은 주문(Order) 관리 기능을 구현합니다. 신규 JPA 엔티티(Order, OrderItem), REST 컨트롤러, 서비스, 리포지토리, DTO를 추가하고, 메뉴 재고 감소 로직 및 주문 상태 전이 관리 기능을 제공하며, 메서드 레벨 보안을 활성화합니다.

변경 사항

그룹 / 파일 변경 요약
Order 도메인 엔티티
src/main/java/com/campustable/be/domain/order/entity/Order.java, OrderItem.java, OrderStatus.java
Order 및 OrderItem JPA 엔티티, OrderStatus 열거형 추가. Order는 User와 다대일, OrderItem과 일대다 관계 설정. OrderItem은 PREPARING → READY → COMPLETED 상태 전이 로직 포함.
Order DTO
src/main/java/com/campustable/be/domain/order/dto/OrderResponse.java, OrderItemDto.java
OrderResponse 및 OrderItemDto 응답 DTO 추가. Order/OrderItem 엔티티를 응답 형식으로 매핑.
Order API 레이어
src/main/java/com/campustable/be/domain/order/controller/OrderController.java, OrderControllerDocs.java
주문 생성, 조회, 상태 변경 REST 엔드포인트 및 OpenAPI 문서 인터페이스 추가. 어드민 제한 작업은 @PreAuthorize(ROLE_ADMIN) 적용.
Order 리포지토리
src/main/java/com/campustable/be/domain/order/repository/OrderRepository.java, OrderItemRepository.java
Spring Data JPA 리포지토리 추가. Order는 사용자별 조회, OrderItem은 주문/카테고리별 조회 메서드 지원.
Order 서비스
src/main/java/com/campustable/be/domain/order/service/OrderService.java
주문 생성, 카테고리별 상태 업데이트, 사용자별 주문 조회 비즈니스 로직. 장바구니 검증, 재고 감소, 트랜잭션 관리 포함.
Menu 기능 확장
src/main/java/com/campustable/be/domain/menu/entity/Menu.java
decreaseStockQuantity(int) 메서드 추가. 재고 부족 시 예외 발생, 재고 0 시 available 플래그 비활성화.
보안 및 예외 설정
src/main/java/com/campustable/be/global/config/SecurityConfig.java, src/main/java/com/campustable/be/global/exception/ErrorCode.java
@EnableMethodSecurity 활성화, MENU_OUT_OF_STOCK/INVALID_ORDER_STATUS/ORDER_NOT_FOUND/ORDER_ITEM_NOT_FOUND 에러 코드 추가.

시퀀스 다이어그램

sequenceDiagram
    participant Client
    participant OrderController as OrderController
    participant OrderService as OrderService
    participant CartRepo as CartRepository
    participant MenuRepo as MenuRepository
    participant OrderRepo as OrderRepository
    participant DB as Database

    Client->>OrderController: POST /api/orders
    activate OrderController
    OrderController->>OrderService: createOrder()
    activate OrderService
    
    OrderService->>CartRepo: getCurrentUserCart()
    CartRepo->>DB: SELECT cart items
    DB-->>CartRepo: cart items
    CartRepo-->>OrderService: cart with items
    
    rect rgb(200, 220, 255)
        note over OrderService,MenuRepo: For each cart item
        OrderService->>MenuRepo: getMenu(menuId)
        MenuRepo->>DB: SELECT menu
        DB-->>MenuRepo: menu
        MenuRepo-->>OrderService: menu
        OrderService->>OrderService: menu.decreaseStockQuantity()
        OrderService->>MenuRepo: save(menu)
        MenuRepo->>DB: UPDATE menu stockQuantity
    end
    
    OrderService->>OrderRepo: save(order with items)
    OrderRepo->>DB: INSERT order & order_items
    DB-->>OrderRepo: order created
    OrderRepo-->>OrderService: persisted order
    
    OrderService->>CartRepo: clearCart()
    CartRepo->>DB: DELETE cart items
    
    OrderService->>OrderService: OrderResponse.from(order)
    OrderService-->>OrderController: OrderResponse
    deactivate OrderService
    
    OrderController-->>Client: 200 OK + OrderResponse
    deactivate OrderController
Loading
sequenceDiagram
    participant Client as Admin Client
    participant OrderController as OrderController
    participant OrderService as OrderService
    participant OrderItemRepo as OrderItemRepository
    participant DB as Database

    Client->>OrderController: PATCH /api/orders/{orderId}/categories/{categoryId}/ready
    activate OrderController
    
    rect rgb(200, 255, 220)
        note over OrderController: `@PreAuthorize`(ROLE_ADMIN)
    end
    
    OrderController->>OrderService: updateCategoryToReady(orderId, categoryId)
    activate OrderService
    
    OrderService->>OrderItemRepo: findByOrderOrderIdAndCategoryId(orderId, categoryId)
    OrderItemRepo->>DB: SELECT order_items
    DB-->>OrderItemRepo: items list
    OrderItemRepo-->>OrderService: order items
    
    rect rgb(200, 220, 255)
        note over OrderService: For each item
        OrderService->>OrderService: orderItem.markAsReady()
        note over OrderService: PREPARING → READY
    end
    
    OrderService->>DB: persist(items)
    DB-->>OrderService: success
    
    OrderService-->>OrderController: void (success)
    deactivate OrderService
    
    OrderController-->>Client: 200 OK
    deactivate OrderController
Loading

예상 코드 리뷰 노력

🎯 4 (복잡) | ⏱️ ~50분

관련 가능성이 있는 PR

🐰 장바구니에서 주문으로 변신하고,
재고는 줄어들고 상태는 바뀌고,
어드민 눈으로 주문을 살피며,
완료까지 향하는 여정이 펼쳐지네! ✨🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.70% 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 제목이 주요 변경 사항을 명확하게 요약하고 있습니다. 주문 기본 동작 추가라는 핵심 내용이 잘 전달되어 있습니다.
✨ Finishing touches
  • 📝 Generate docstrings

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 seojelee9999 merged commit 12e078b into test Dec 30, 2025
1 of 2 checks passed
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: 8

🧹 Nitpick comments (7)
src/main/java/com/campustable/be/domain/order/entity/Order.java (1)

47-55: 입력 유효성 검증 추가 고려

팩토리 메서드가 userorderItems의 null 여부를 검증하지 않습니다. 방어적 프로그래밍을 위해 유효성 검증을 추가하는 것이 좋습니다.

🔎 유효성 검증 추가 제안
 public static Order createOrder(User user, List<OrderItem> orderItems) {
+  if (user == null) {
+    throw new IllegalArgumentException("User cannot be null");
+  }
+  if (orderItems == null || orderItems.isEmpty()) {
+    throw new IllegalArgumentException("Order items cannot be null or empty");
+  }
   Order order = new Order();
   order.setUser(user);
   for (OrderItem orderItem : orderItems) {
     order.addOrderItem(orderItem);
   }
src/main/java/com/campustable/be/domain/order/entity/OrderItem.java (1)

19-21: 엔티티에 @Setter 사용을 최소화하세요.

엔티티 전체에 @Setter를 적용하면 외부에서 내부 상태를 임의로 변경할 수 있어 도메인 무결성이 훼손될 수 있습니다. createOrderItem 팩토리 메서드를 사용하는 현재 패턴이 좋으므로, @Setter를 제거하고 필요한 경우에만 개별 setter나 비즈니스 메서드를 제공하는 것을 권장합니다.

src/main/java/com/campustable/be/domain/order/controller/OrderControllerDocs.java (1)

24-34: 상태 변경 API에 에러 응답 문서를 추가하세요.

updateCategoryToReadyupdateCategoryToComplete 메서드에 @ApiResponses 어노테이션이 누락되어 있습니다. 다른 엔드포인트처럼 가능한 에러 응답(400, 403, 404 등)을 문서화하면 API 사용자에게 도움이 됩니다.

🔎 수정 제안
  @Operation(summary = "카테고리별 조리 완료 처리 (관리자)", description = "특정 주문(OrderId) 내의 특정 카테고리(CategoryId) 메뉴들을 모두 '조리 완료'로 변경합니다.")
+  @ApiResponses(value = {
+      @ApiResponse(responseCode = "200", description = "상태 변경 성공"),
+      @ApiResponse(responseCode = "400", description = "올바르지 않은 상태 변경"),
+      @ApiResponse(responseCode = "403", description = "관리자 권한 없음"),
+      @ApiResponse(responseCode = "404", description = "해당 주문 메뉴를 찾을 수 없음")
+  })
  ResponseEntity<Void> updateCategoryToReady(
src/main/java/com/campustable/be/domain/order/service/OrderService.java (4)

42-44: 빈 장바구니에 대해 더 명확한 에러 코드를 사용하세요.

빈 장바구니와 존재하지 않는 장바구니는 다른 상황입니다. CART_NOT_FOUND 대신 CART_EMPTY 또는 CART_ITEMS_NOT_FOUND와 같은 별도의 에러 코드를 사용하면 클라이언트가 적절한 안내 메시지를 표시할 수 있습니다.


89-101: 불필요한 User 객체 조회를 제거하세요.

Line 92-96에서 User 객체를 조회하지만, 실제로 사용되지 않고 userId만 쿼리에 사용됩니다. 사용자 존재 여부 검증이 목적이라면, userRepository.existsById(userId)를 사용하는 것이 더 효율적입니다.

🔎 수정 제안
  public List<OrderResponse> getMyOrders() {
    Long userId = SecurityUtil.getCurrentUserId();

-   User user = userRepository.findById(userId).
-       orElseThrow(() -> {
-         log.error("getMyOrders userId : {}를 db에서 발견하지못했음", userId);
-         return new CustomException(ErrorCode.USER_NOT_FOUND);
-       });
+   if (!userRepository.existsById(userId)) {
+     log.error("getMyOrders userId : {}를 db에서 발견하지못했음", userId);
+     throw new CustomException(ErrorCode.USER_NOT_FOUND);
+   }

    return orderRepository.findByUserUserIdOrderByCreatedAtDesc(userId).stream()
        .map(OrderResponse::from)
        .toList();
  }

103-112: getOrdersByUserId에서도 동일하게 불필요한 User 조회가 있습니다.

Line 105-106에서 조회한 User 객체가 사용되지 않습니다. getMyOrders()와 동일하게 existsById()로 변경하거나, 두 메서드의 공통 로직을 추출하는 것을 고려하세요.


69-69: 메서드 시그니처의 포맷팅을 개선하세요.

파라미터 사이에 공백이 누락되었습니다: (Long orderId,Long categoryId)(Long orderId, Long categoryId)

🔎 수정 제안
-  public void updateCategoryToReady(Long orderId,Long categoryId) {
+  public void updateCategoryToReady(Long orderId, Long categoryId) {
-  public void updateCategoryToComplete(Long orderId,Long categoryId) {
+  public void updateCategoryToComplete(Long orderId, Long categoryId) {

Also applies to: 79-79

📜 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 dbafc4d and 1ee8cdf.

📒 Files selected for processing (13)
  • src/main/java/com/campustable/be/domain/menu/entity/Menu.java
  • src/main/java/com/campustable/be/domain/order/controller/OrderController.java
  • src/main/java/com/campustable/be/domain/order/controller/OrderControllerDocs.java
  • src/main/java/com/campustable/be/domain/order/dto/OrderItemDto.java
  • src/main/java/com/campustable/be/domain/order/dto/OrderResponse.java
  • src/main/java/com/campustable/be/domain/order/entity/Order.java
  • src/main/java/com/campustable/be/domain/order/entity/OrderItem.java
  • src/main/java/com/campustable/be/domain/order/entity/OrderStatus.java
  • src/main/java/com/campustable/be/domain/order/repository/OrderItemRepository.java
  • src/main/java/com/campustable/be/domain/order/repository/OrderRepository.java
  • src/main/java/com/campustable/be/domain/order/service/OrderService.java
  • src/main/java/com/campustable/be/global/config/SecurityConfig.java
  • src/main/java/com/campustable/be/global/exception/ErrorCode.java
🧰 Additional context used
🧬 Code graph analysis (3)
src/main/java/com/campustable/be/domain/order/entity/OrderStatus.java (3)
src/main/java/com/campustable/be/domain/order/dto/OrderItemDto.java (1)
  • Getter (8-33)
src/main/java/com/campustable/be/domain/order/dto/OrderResponse.java (1)
  • Getter (10-30)
src/main/java/com/campustable/be/domain/order/entity/OrderItem.java (1)
  • Getter (19-75)
src/main/java/com/campustable/be/domain/order/dto/OrderItemDto.java (2)
src/main/java/com/campustable/be/domain/order/dto/OrderResponse.java (1)
  • Getter (10-30)
src/main/java/com/campustable/be/domain/order/entity/OrderItem.java (1)
  • Getter (19-75)
src/main/java/com/campustable/be/domain/order/dto/OrderResponse.java (2)
src/main/java/com/campustable/be/domain/order/dto/OrderItemDto.java (1)
  • Getter (8-33)
src/main/java/com/campustable/be/domain/order/entity/OrderItem.java (1)
  • Getter (19-75)
🔇 Additional comments (12)
src/main/java/com/campustable/be/global/config/SecurityConfig.java (1)

9-9: 메서드 레벨 보안 활성화 승인

OrderController에서 @PreAuthorize 어노테이션을 사용하기 위한 @EnableMethodSecurity 추가가 적절합니다.

Also applies to: 19-19

src/main/java/com/campustable/be/domain/order/repository/OrderRepository.java (1)

8-11: 리포지토리 인터페이스 구현 확인

쿼리 메서드 findByUserUserIdOrderByCreatedAtDesc가 올바르게 정의되었으며, 사용자별 주문 조회 및 생성일 기준 정렬이 적절합니다.

src/main/java/com/campustable/be/domain/order/repository/OrderItemRepository.java (1)

7-10: 카테고리별 주문 항목 조회 구현 확인

findByOrderOrderIdAndCategoryId 메서드가 주문 ID와 카테고리 ID로 주문 항목을 조회하도록 올바르게 정의되어 있습니다. 카테고리별 상태 변경 기능을 지원합니다.

src/main/java/com/campustable/be/domain/order/entity/OrderStatus.java (1)

8-17: 주문 상태 Enum 정의 확인

주문 처리 흐름(조리 중 → 수령 대기 → 주문 완료)을 명확하게 표현하는 3단계 상태 정의가 적절합니다.

src/main/java/com/campustable/be/domain/order/controller/OrderController.java (3)

32-41: 카테고리별 준비 완료 처리 구현 확인

관리자 권한 검증과 함께 주문 항목 상태를 카테고리별로 변경하는 엔드포인트가 적절하게 구현되었습니다.


43-53: 카테고리별 완료 처리 구현 확인

관리자 권한으로 카테고리별 주문 완료 처리를 수행하는 엔드포인트가 올바르게 구현되었습니다.


27-30: 장바구니 시스템을 통해 주문 데이터를 전달받으므로 추가 조치 없음

createOrder 메서드는 SecurityContext에서 사용자를 가져오고, 사용자의 장바구니에서 주문 항목을 조회합니다. 따라서 @RequestBody 파라미터는 필요하지 않으며, 장바구니에 담긴 항목들이 주문으로 변환되는 설계가 정상적으로 작동합니다.

src/main/java/com/campustable/be/global/exception/ErrorCode.java (1)

76-81: LGTM!

주문 관련 에러 코드가 적절하게 추가되었습니다. 각 에러 코드가 해당 도메인 로직(INVALID_ORDER_STATUS, ORDER_NOT_FOUND, ORDER_ITEM_NOT_FOUND)과 잘 연결되어 있습니다.

src/main/java/com/campustable/be/domain/order/entity/OrderItem.java (2)

60-73: LGTM!

상태 전이 로직이 명확하고, 잘못된 상태에서의 전이 시도를 적절히 예외 처리하고 있습니다. PREPARING → READY → COMPLETED 흐름이 비즈니스 규칙에 맞게 구현되었습니다.


45-54: menu.getCategory()에 대한 null 체크는 필요 없습니다.

Menu 엔티티의 category 필드는 @NotNull 어노테이션과 @JoinColumn(nullable = false) 제약 조건이 있으며, MenuService에서 Menu 생성 시 category의 존재 여부를 사전에 검증합니다. 따라서 menu.getCategory()가 null을 반환할 수 없으므로 추가 null 체크는 불필요합니다.

Likely an incorrect or invalid review comment.

src/main/java/com/campustable/be/domain/order/controller/OrderControllerDocs.java (1)

13-49: LGTM!

OpenAPI 문서화가 체계적으로 작성되어 있습니다. 각 엔드포인트의 요약, 설명, 파라미터가 명확하게 정의되었습니다.

src/main/java/com/campustable/be/domain/order/service/OrderService.java (1)

46-58: 재고 감소 실패 시 롤백 동작을 확인하세요.

스트림 내에서 menu.decreaseStockQuantity()가 중간에 예외를 발생시키면, 이전에 감소된 재고도 함께 롤백되어야 합니다. @Transactional이 클래스 레벨에 적용되어 있으므로 정상적으로 롤백될 것으로 예상되지만, 통합 테스트로 검증하는 것을 권장합니다.

Comment on lines +89 to +97
public void decreaseStockQuantity(int quantity) {
if(this.stockQuantity - quantity < 0) {
throw new CustomException(ErrorCode.MENU_OUT_OF_STOCK);
}
else if(this.stockQuantity - quantity == 0) {
this.available = false;
}
this.stockQuantity -= quantity;
}
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

동시성 제어 누락으로 인한 재고 오버셀링 위험

decreaseStockQuantity 메서드는 동기화 메커니즘 없이 재고를 감소시킵니다. 여러 주문이 동시에 발생하면 check-then-act 경합 상태가 발생하여 재고가 음수가 될 수 있습니다.

예시:

  • 초기 재고: 1개
  • 주문 A와 B가 동시에 발생
  • 둘 다 stockQuantity - quantity >= 0 체크 통과
  • 둘 다 감소 실행 → 최종 재고: -1개
🔎 동시성 제어 방법 제안

방법 1 (권장): 비관적 락 사용

OrderService에서 Menu 조회 시 락 적용:

@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT m FROM Menu m WHERE m.id = :id")
Optional<Menu> findByIdWithLock(@Param("id") Long id);

방법 2: 낙관적 락 사용

Menu 엔티티에 버전 필드 추가:

 public class Menu {
+  @Version
+  private Long version;

방법 3: 데이터베이스 제약 조건

ALTER TABLE menu ADD CONSTRAINT check_stock_non_negative 
CHECK (stock_quantity >= 0);

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

Comment on lines +57 to +60
@GetMapping
public ResponseEntity<List<OrderResponse>> getMyOrders() {
return ResponseEntity.ok(orderService.getMyOrders());
}
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

페이지네이션 누락으로 인한 성능 저하 가능성

getMyOrders 엔드포인트가 사용자의 모든 주문을 한 번에 반환합니다. 주문이 많은 사용자의 경우 메모리 사용량 증가와 응답 지연이 발생할 수 있습니다.

Pageable 파라미터를 추가하여 페이지네이션을 구현하는 것을 권장합니다.

🔎 페이지네이션 구현 제안
 @Override
 @LogMonitoringInvocation
 @GetMapping
-public ResponseEntity<List<OrderResponse>> getMyOrders() {
-  return ResponseEntity.ok(orderService.getMyOrders());
+public ResponseEntity<Page<OrderResponse>> getMyOrders(Pageable pageable) {
+  return ResponseEntity.ok(orderService.getMyOrders(pageable));
 }

OrderService와 Repository도 함께 수정 필요:

// Repository
Page<Order> findByUserUserIdOrderByCreatedAtDesc(Long userId, Pageable pageable);

// Service
Page<OrderResponse> getMyOrders(Pageable pageable) {
  // ... implementation
}

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

🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/order/controller/OrderController.java
around lines 57-60, the getMyOrders endpoint currently returns all orders at
once which can cause memory and latency issues; update the controller to accept
a Pageable parameter (e.g., Pageable pageable) and return a paged result, then
update OrderService to expose getMyOrders(Pageable) returning a
Page<OrderResponse> and change the repository to a paged query (e.g.,
Page<Order> findByUserUserIdOrderByCreatedAtDesc(Long userId, Pageable
pageable)); ensure the controller maps the Page from the service into the
ResponseEntity and keep sorting/default page size via @PageableDefault if
needed.

Comment on lines +63 to +67
@GetMapping("/users/{userId}")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public ResponseEntity<List<OrderResponse>> getOrdersByUserId(@PathVariable Long userId) {
return ResponseEntity.ok(orderService.getOrdersByUserId(userId));
}
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

관리자 조회 엔드포인트에도 페이지네이션 필요

getOrdersByUserId도 모든 주문을 한 번에 반환하므로 getMyOrders와 동일한 성능 문제가 있습니다. 관리자가 주문이 많은 사용자를 조회할 때 특히 문제가 될 수 있습니다.

페이지네이션 적용을 권장합니다.


import com.campustable.be.domain.order.entity.OrderItem;
import com.campustable.be.domain.order.entity.OrderStatus;
import lombok.AccessLevel;
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

사용되지 않는 import를 제거하세요.

AccessLevel이 import되었지만 사용되지 않습니다.

🔎 수정 제안
-import lombok.AccessLevel;
📝 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
import lombok.AccessLevel;
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/order/dto/OrderItemDto.java around
line 5, the import 'lombok.AccessLevel' is unused; remove that import line and
reformat/import-organize the file (or run your IDE's optimize imports) so only
necessary imports remain.

Comment on lines +21 to +31
public OrderItemDto(OrderItem orderItem) {
this.orderItemId = orderItem.getOrderItemId();
this.menuId = orderItem.getMenu().getId();
this.menuName = orderItem.getMenu().getMenuName();
this.orderPrice = orderItem.getOrderPrice(); //주문 당시가격
this.quantity = orderItem.getQuantity();
this.subTotal = orderItem.getOrderPrice() * orderItem.getQuantity();
this.menuUrl = orderItem.getMenu().getMenuUrl();
this.status = orderItem.getStatus();
this.categoryId=orderItem.getCategoryId();
}
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

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "Menu.java" | head -20

Repository: CampusTable/campus-table-be

Length of output: 134


🏁 Script executed:

find . -type f -name "OrderItem.java" | head -20

Repository: CampusTable/campus-table-be

Length of output: 140


🏁 Script executed:

git ls-files | grep -E "(Menu|OrderItem)\.java$"

Repository: CampusTable/campus-table-be

Length of output: 200


🏁 Script executed:

wc -l ./src/main/java/com/campustable/be/domain/menu/entity/Menu.java

Repository: CampusTable/campus-table-be

Length of output: 137


🏁 Script executed:

cat -n ./src/main/java/com/campustable/be/domain/menu/entity/Menu.java

Repository: CampusTable/campus-table-be

Length of output: 3303


🏁 Script executed:

wc -l ./src/main/java/com/campustable/be/domain/order/entity/OrderItem.java

Repository: CampusTable/campus-table-be

Length of output: 143


🏁 Script executed:

cat -n ./src/main/java/com/campustable/be/domain/order/entity/OrderItem.java

Repository: CampusTable/campus-table-be

Length of output: 2596


OrderItem의 getTotalPrice() 메서드를 재사용하세요.

subTotal 계산에서 이미 존재하는 OrderItem.getTotalPrice() 메서드를 재사용하면 코드 중복을 제거할 수 있습니다:

-    this.subTotal = orderItem.getOrderPrice() * orderItem.getQuantity();
+    this.subTotal = orderItem.getTotalPrice();
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/order/dto/OrderItemDto.java around
lines 21 to 31, the constructor computes subTotal by multiplying orderPrice and
quantity instead of reusing OrderItem.getTotalPrice(); replace the manual
calculation with a call to orderItem.getTotalPrice() to remove duplication and
ensure consistent logic, i.e., set this.subTotal to orderItem.getTotalPrice()
(preserving existing field types/units).

Comment on lines +20 to +29
public static OrderResponse from(Order order) {
return OrderResponse.builder()
.orderId(order.getOrderId())
.totalPrice(order.getTotalPrice())
.orderDate(order.getCreatedAt()) // BaseTimeEntity의 생성일
.orderItems(order.getOrderItems().stream()
.map(OrderItemDto::new)
.toList())
.build();
}
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

🧩 Analysis chain

🏁 Script executed:

find src -type f -name "OrderRepository.java" | head -5

Repository: CampusTable/campus-table-be

Length of output: 148


🏁 Script executed:

find src -type f -name "OrderItemDto.java" | head -5

Repository: CampusTable/campus-table-be

Length of output: 138


🏁 Script executed:

find src -type f -name "Order.java" -o -name "OrderItem.java" | grep -E "(Order\.java|OrderItem\.java)$" | head -10

Repository: CampusTable/campus-table-be

Length of output: 202


🏁 Script executed:

git ls-files src/main/java/com/campustable/be/domain/order | head -20

Repository: CampusTable/campus-table-be

Length of output: 801


🏁 Script executed:

cat -n src/main/java/com/campustable/be/domain/order/repository/OrderRepository.java

Repository: CampusTable/campus-table-be

Length of output: 506


🏁 Script executed:

cat -n src/main/java/com/campustable/be/domain/order/dto/OrderItemDto.java

Repository: CampusTable/campus-table-be

Length of output: 1309


🏁 Script executed:

cat -n src/main/java/com/campustable/be/domain/order/entity/Order.java

Repository: CampusTable/campus-table-be

Length of output: 2299


🏁 Script executed:

cat -n src/main/java/com/campustable/be/domain/order/entity/OrderItem.java

Repository: CampusTable/campus-table-be

Length of output: 2596


🏁 Script executed:

rg -n "OrderResponse.from\(" src/main/java/com/campustable/be --type java -B 2 -A 2

Repository: CampusTable/campus-table-be

Length of output: 1049


🏁 Script executed:

rg -n "hibernate.show_sql|show-sql|format_sql" src/main/resources -t properties -t yaml

Repository: CampusTable/campus-table-be

Length of output: 105


🏁 Script executed:

cat -n src/main/java/com/campustable/be/domain/order/service/OrderService.java

Repository: CampusTable/campus-table-be

Length of output: 4631


🏁 Script executed:

find src/main/resources -type f \( -name "application*.properties" -o -name "application*.yml" \)

Repository: CampusTable/campus-table-be

Length of output: 105


🏁 Script executed:

cat -n src/main/resources/application.yml

Repository: CampusTable/campus-table-be

Length of output: 1195


주문 조회 시 N+1 쿼리 발생 가능

OrderService.getMyOrders()getOrdersByUserId() 메서드에서 findByUserUserIdOrderByCreatedAtDesc() 호출 시, Order와 관련 OrderItem이 함께 로드되지 않으면 N+1 쿼리 문제가 발생합니다. 각 OrderItem의 Menu도 OrderItemDto 생성자에서 지연로드되므로 추가 쿼리가 발생합니다.

OrderRepository의 findByUserUserIdOrderByCreatedAtDesc() 메서드에 @entitygraph 또는 JOIN FETCH를 적용하여 필요한 데이터를 함께 로드하세요:

@EntityGraph(attributePaths = {"orderItems", "orderItems.menu"})
List<Order> findByUserUserIdOrderByCreatedAtDesc(Long userId);

또는 JPQL 사용:

@Query("SELECT o FROM Order o " +
       "JOIN FETCH o.orderItems oi " +
       "JOIN FETCH oi.menu " +
       "WHERE o.user.userId = :userId " +
       "ORDER BY o.createdAt DESC")
List<Order> findByUserUserIdOrderByCreatedAtDesc(Long userId);
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/order/dto/OrderResponse.java around
lines 20 to 29, the Order→OrderItem→Menu relationships are being lazily loaded
which can cause N+1 queries when mapping orders to DTOs; update the
OrderRepository.findByUserUserIdOrderByCreatedAtDesc(...) to eagerly fetch
orderItems and their menu either by adding @EntityGraph(attributePaths =
{"orderItems", "orderItems.menu"}) on the repository method or replacing it with
a JPQL @Query that JOIN FETCH o.orderItems and JOIN FETCH oi.menu for the given
userId and ordered by createdAt DESC so that the DTO mapping in
OrderResponse.from uses already-loaded associations and avoids extra queries.

Comment on lines +41 to +42
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<>();
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

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and examine the Order.java file
find . -name "Order.java" -path "*/domain/order/entity/*"

Repository: CampusTable/campus-table-be

Length of output: 136


🏁 Script executed:

# Read the Order.java file to verify the cascade configuration
cat -n src/main/java/com/campustable/be/domain/order/entity/Order.java | head -60

Repository: CampusTable/campus-table-be

Length of output: 2282


🏁 Script executed:

# Check for soft delete patterns in the codebase
rg -n "deleted|DeletedDate|@SQLDelete" --type java -i

Repository: CampusTable/campus-table-be

Length of output: 53


🏁 Script executed:

# Check for audit-related annotations and listeners
rg -n "@Audited|@EntityListeners|AuditingEntityListener|@CreatedDate|@LastModifiedDate" --type java

Repository: CampusTable/campus-table-be

Length of output: 601


🏁 Script executed:

# Check CascadeType patterns in other entities
rg -n "CascadeType\.(ALL|REMOVE|PERSIST|MERGE)" --type java -B 1 -A 1

Repository: CampusTable/campus-table-be

Length of output: 1347


주문 항목 삭제 전략 재검토 필요

CascadeType.ALL은 주문 삭제 시 모든 주문 항목도 함께 삭제됩니다. Order는 BaseTimeEntity를 통해 생성/수정 시간은 기록되지만, 데이터 삭제 자체는 차단되지 않습니다. 주문 이력이 감사 및 규정 준수 목적으로 보존되어야 한다면 현재 구성은 적절하지 않습니다.

다른 엔티티들(User-Cart, Cart-CartItems)과의 일관성을 위해 orphanRemoval = true를 추가하거나, 주문은 절대 삭제되지 않아야 하는지 재검토하시기 바랍니다.

🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/order/entity/Order.java around lines
41-42, the current @OneToMany uses CascadeType.ALL which will physically delete
OrderItem rows when an Order is removed; to preserve order history you should
either remove REMOVE from the cascade (e.g., use cascade = {PERSIST, MERGE}) and
add orphanRemoval = true if you want automatic cleanup of detached items, or
alternatively forbid hard-deletes of Order by implementing a soft-delete flag
and keeping cascade limited, ensuring order items are not physically removed for
audit compliance; update the annotation accordingly and adjust delete logic to
use soft-delete if required.


import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.boot.autoconfigure.graphql.GraphQlProperties.Http;
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

사용되지 않는 import를 제거하세요.

org.springframework.boot.autoconfigure.graphql.GraphQlProperties.Http는 이 파일에서 사용되지 않습니다.

🔎 수정 제안
-import org.springframework.boot.autoconfigure.graphql.GraphQlProperties.Http;
📝 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
import org.springframework.boot.autoconfigure.graphql.GraphQlProperties.Http;
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/global/exception/ErrorCode.java around line
5, the import
org.springframework.boot.autoconfigure.graphql.GraphQlProperties.Http is unused;
remove that import line (or run your IDE's organize/imports or reformat action)
to eliminate the unused import and then recompile to ensure no references
remain.

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.

3 participants