Skip to content

[Feature] 주문 도메인 API 구현#9

Merged
mingdodev merged 15 commits intomainfrom
feature/8-order
Jul 6, 2025
Merged

[Feature] 주문 도메인 API 구현#9
mingdodev merged 15 commits intomainfrom
feature/8-order

Conversation

@mingdodev
Copy link
Owner

@mingdodev mingdodev commented Jul 6, 2025

Summary by CodeRabbit

  • 신규 기능

    • 주문 관리 기능이 추가되었습니다. 고객이 주문을 생성, 사장님이 주문 내역을 수정 및 상태 변경할 수 있으며, 모든 유저가 자신이 참여한 주문 내역 목록을 조회할 수 있습니다.
    • 주문 관련 REST API 엔드포인트 및 데이터 전송 객체(DTO)가 새롭게 제공됩니다.
    • 주문 엔티티, 주문 아이템, 주문 상태 관리가 지원됩니다.
  • 개선 사항

    • 마켓 목록 조회 시 반환 데이터가 상세 정보로 변경되었습니다.
    • CORS 허용 메서드에 PATCH가 추가되었습니다.
  • 오류 메시지

    • 사용자 및 주문 관련 새로운 에러 메시지가 추가되어, 오류 상황에 대한 안내가 강화되었습니다.

@mingdodev mingdodev linked an issue Jul 6, 2025 that may be closed by this pull request
5 tasks
@coderabbitai
Copy link

coderabbitai bot commented Jul 6, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

주문(Order) 도메인 전체가 새롭게 추가되었으며, 주문 생성, 조회, 수정, 상태 변경을 위한 컨트롤러, 서비스, 엔티티, DTO, 레포지토리 등이 구현되었습니다. 또한, 마켓 관련 DTO 및 서비스 반환 타입이 MarketSummary에서 MarketDetail로 변경되었습니다. CORS 정책에 PATCH 메서드가 추가되고, 주문 및 사용자 관련 에러 메시지가 보강되었습니다.

Changes

파일/경로 요약 변경 내용 요약
.../market/controller/MarketController.java
.../market/service/MarketService.java
.../market/dto/response/MarketDetail.java
마켓 목록 반환 타입 및 DTO가 MarketSummary에서 MarketDetail로 변경됨. Swagger 문구 일부 수정.
.../market/repository/MarketRepository.java userId 집합으로 마켓을 조회하는 findAllByUserIdIn 메서드 추가.
.../order/controller/OrderController.java 주문 도메인 REST 컨트롤러 신설: 고객/가맹점주 주문 조회, 주문 생성, 주문 수정, 주문 상태 변경 API 구현.
.../order/dto/request/OrderCreateRequest.java
.../order/dto/request/OrderItemInfo.java
.../order/dto/request/OrderItemDetail.java
.../order/dto/request/OrderUpdateRequest.java
.../order/dto/request/OrderStatusUpdateRequest.java
주문 생성/수정/상태변경 요청용 DTO 레코드 신설 및 필드별 유효성 검사 추가.
.../order/dto/response/CustomerOrderDetail.java
.../order/dto/response/CustomerSummary.java
.../order/dto/response/MarketSummary.java
.../order/dto/response/MerchantOrderDetail.java
.../order/dto/response/OrderCreateResponse.java
.../order/dto/response/OrderItemDetail.java
.../order/dto/response/OrderStatusUpdateResponse.java
주문 응답용 DTO 레코드 신설 및 엔티티→DTO 변환용 정적 팩토리 메서드 구현.
.../order/entity/Order.java
.../order/entity/OrderItem.java
.../order/entity/OrderStatus.java
주문/주문상품 엔티티 및 주문상태 enum 신설. 주문-주문상품 양방향 연관관계, 상태 업데이트, 생성 메서드 등 구현.
.../order/repository/OrderRepository.java 주문/주문상품 조인 페치 쿼리 메서드(고객/가맹점주별) 추가.
.../order/service/OrderService.java 주문 전체 서비스 구현: 고객/가맹점주 주문 조회, 주문 생성, 주문상품 수정, 상태 변경, 권한 체크 등.
.../global/config/WebConfig.java CORS 허용 메서드에 "PATCH" 추가.
.../global/exception/ErrorMessage.java 주문/사용자 관련 신규 에러 메시지(enum) 추가.
.../global/util/validator/AccessValidator.java 주문 접근 권한 검증 메서드(validateOrderAccess) 추가.

Sequence Diagram(s)

sequenceDiagram
actor Customer
actor Merchant
participant OrderController
participant OrderService
participant OrderRepository
participant MarketRepository
participant UserRepository

Customer->>OrderController: POST /api/orders (OrderCreateRequest)
OrderController->>OrderService: create(request)
OrderService->>MarketRepository: findById(marketId)
OrderService->>UserRepository: findById(merchantId)
OrderService->>OrderRepository: save(order)
OrderService-->>OrderController: OrderCreateResponse
OrderController-->>Customer: ApiResponse<OrderCreateResponse>

Customer->>OrderController: GET /api/customers/me/orders
OrderController->>OrderService: getCustomerOrders()
OrderService->>OrderRepository: findByCustomerIdWithOrderItems(userId)
OrderService->>MarketRepository: findAllByUserIdIn(merchantIds)
OrderService-->>OrderController: List<CustomerOrderDetail>
OrderController-->>Customer: ApiResponse<List<CustomerOrderDetail>>

Merchant->>OrderController: GET /api/merchants/me/orders
OrderController->>OrderService: getMerchantOrders()
OrderService->>OrderRepository: findByMerchantIdWithOrderItems(userId)
OrderService->>UserRepository: findAllById(customerIds)
OrderService-->>OrderController: List<MerchantOrderDetail>
OrderController-->>Merchant: ApiResponse<List<MerchantOrderDetail>>

Merchant->>OrderController: PATCH /api/orders/{orderId}
OrderController->>OrderService: update(orderId, request)
OrderService->>OrderRepository: findById(orderId)
OrderService-->>OrderController: void
OrderController-->>Merchant: ApiResponse<Void>

Merchant->>OrderController: PATCH /api/orders/{orderId}/status
OrderController->>OrderService: updateStatus(orderId, request)
OrderService->>OrderRepository: findById(orderId)
OrderService-->>OrderController: OrderStatusUpdateResponse
OrderController-->>Merchant: ApiResponse<OrderStatusUpdateResponse>
Loading

Possibly related issues


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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

🧹 Nitpick comments (5)
src/main/java/danji/danjiapi/domain/order/dto/response/MarketSummary.java (1)

10-16: null safety 개선을 고려해보세요.

static factory method에서 market 파라미터에 대한 null 검증을 추가하는 것을 고려해보세요.

 public static MarketSummary from(Market market) {
+    Objects.requireNonNull(market, "Market cannot be null");
     return new MarketSummary(
             market.getId(),
             market.getName(),
             market.getAddress()
     );
 }
src/main/java/danji/danjiapi/domain/order/dto/response/CustomerSummary.java (1)

9-15: null safety 개선을 고려해보세요.

static factory method에서 user 파라미터에 대한 null 검증을 추가하는 것을 고려해보세요.

 public static CustomerSummary from(User user) {
+    Objects.requireNonNull(user, "User cannot be null");
     return new CustomerSummary(
             user.getId(),
             user.getName()
     );
 }
src/main/java/danji/danjiapi/domain/order/entity/OrderItem.java (1)

29-30: 상품명 길이 제한이 너무 짧을 수 있습니다.

현재 상품명이 20자로 제한되어 있는데, 실제 상품명은 이보다 길 수 있습니다. 예를 들어 "프리미엄 한우 1++ 등급 꽃등심 스테이크 세트"와 같은 상품명은 20자를 초과합니다.

-    @Column(length = 20, nullable = false)
+    @Column(length = 100, nullable = false)
     private String name;
src/main/java/danji/danjiapi/domain/order/controller/OrderController.java (2)

30-34: RESTful API 설계 개선이 필요합니다.

현재 /customers/me/orders/merchants/me/orders로 분리되어 있는데, 이는 RESTful 원칙에 맞지 않습니다. 단일 엔드포인트에서 사용자 역할에 따라 필터링하는 것이 더 적절합니다.

-    @GetMapping("/customers/me/orders")
-    @Operation(summary = "고객의 주문 목록 조회", description = "고객이 모든 주문 목록을 조회합니다. 주문은 주문 항목들과 주문 상태를 포함합니다.")
-    public ApiResponse<List<CustomerOrderDetail>> getCustomerOrders() {
-        return ApiResponse.success(orderService.getCustomerOrders());
-    }
-
-    @GetMapping("/merchants/me/orders")
-    @Operation(summary = "사장님의 주문 목록 조회", description = "사장님이 모든 주문 목록을 조회합니다. 주문은 주문 항목들과 주문 상태를 포함합니다.")
-    public ApiResponse<List<MerchantOrderDetail>> getMerchantOrders() {
-        return ApiResponse.success(orderService.getMerchantOrders());
-    }
+    @GetMapping("/orders")
+    @Operation(summary = "주문 목록 조회", description = "사용자의 역할에 따라 주문 목록을 조회합니다.")
+    public ApiResponse<?> getOrders() {
+        // 서비스에서 역할에 따라 적절한 응답 반환
+        return ApiResponse.success(orderService.getOrders());
+    }

Also applies to: 36-40


42-46: 응답 상태 코드를 명시하면 좋습니다.

생성 작업의 경우 201 Created 상태 코드를 반환하는 것이 RESTful 규칙입니다.

     @PostMapping("/orders")
     @Operation(summary = "고객의 주문 요청", description = "고객이 주문을 요청(생성)합니다. 요청은 PENDING 상태로 생성됩니다.")
+    @ResponseStatus(HttpStatus.CREATED)
     public ApiResponse<OrderCreateResponse> create(@Valid @RequestBody OrderCreateRequest request) {
         return ApiResponse.success(orderService.create(request));
     }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4953131 and 90c2d3f.

📒 Files selected for processing (25)
  • src/main/java/danji/danjiapi/domain/market/controller/MarketController.java (2 hunks)
  • src/main/java/danji/danjiapi/domain/market/dto/response/MarketDetail.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/market/repository/MarketRepository.java (2 hunks)
  • src/main/java/danji/danjiapi/domain/market/service/MarketService.java (3 hunks)
  • src/main/java/danji/danjiapi/domain/order/controller/OrderController.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/dto/request/OrderCreateRequest.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/dto/request/OrderItemDetail.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/dto/request/OrderItemInfo.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/dto/request/OrderStatusUpdateRequest.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/dto/request/OrderUpdateRequest.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/dto/response/CustomerOrderDetail.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/dto/response/CustomerSummary.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/dto/response/MarketSummary.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/dto/response/MerchantOrderDetail.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/dto/response/OrderCreateResponse.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/dto/response/OrderItemDetail.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/dto/response/OrderStatusUpdateResponse.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/entity/Order.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/entity/OrderItem.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/entity/OrderStatus.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/repository/OrderRepository.java (1 hunks)
  • src/main/java/danji/danjiapi/domain/order/service/OrderService.java (1 hunks)
  • src/main/java/danji/danjiapi/global/config/WebConfig.java (1 hunks)
  • src/main/java/danji/danjiapi/global/exception/ErrorMessage.java (2 hunks)
  • src/main/java/danji/danjiapi/global/util/validator/AccessValidator.java (2 hunks)
🧰 Additional context used
🧠 Learnings (7)
src/main/java/danji/danjiapi/domain/market/repository/MarketRepository.java (1)
Learnt from: mingdodev
PR: mingdodev/danji-api#7
File: src/main/java/danji/danjiapi/domain/product/service/ProductService.java:23-32
Timestamp: 2025-07-06T10:15:26.201Z
Learning: danji-api 프로젝트의 데이터 스키마에서는 사용자당 하나의 마켓만 존재하도록 설계되어 있어서 MarketRepository.findByUserId()를 사용하는 것이 적절하다.
src/main/java/danji/danjiapi/domain/order/dto/response/MarketSummary.java (1)
Learnt from: mingdodev
PR: mingdodev/danji-api#7
File: src/main/java/danji/danjiapi/domain/product/service/ProductService.java:23-32
Timestamp: 2025-07-06T10:15:26.201Z
Learning: danji-api 프로젝트의 데이터 스키마에서는 사용자당 하나의 마켓만 존재하도록 설계되어 있어서 MarketRepository.findByUserId()를 사용하는 것이 적절하다.
src/main/java/danji/danjiapi/domain/market/service/MarketService.java (1)
Learnt from: mingdodev
PR: mingdodev/danji-api#7
File: src/main/java/danji/danjiapi/domain/product/service/ProductService.java:23-32
Timestamp: 2025-07-06T10:15:26.201Z
Learning: danji-api 프로젝트의 데이터 스키마에서는 사용자당 하나의 마켓만 존재하도록 설계되어 있어서 MarketRepository.findByUserId()를 사용하는 것이 적절하다.
src/main/java/danji/danjiapi/domain/market/dto/response/MarketDetail.java (1)
Learnt from: mingdodev
PR: mingdodev/danji-api#7
File: src/main/java/danji/danjiapi/domain/product/service/ProductService.java:23-32
Timestamp: 2025-07-06T10:15:26.201Z
Learning: danji-api 프로젝트의 데이터 스키마에서는 사용자당 하나의 마켓만 존재하도록 설계되어 있어서 MarketRepository.findByUserId()를 사용하는 것이 적절하다.
src/main/java/danji/danjiapi/global/util/validator/AccessValidator.java (2)
Learnt from: mingdodev
PR: mingdodev/danji-api#7
File: src/main/java/danji/danjiapi/global/util/validator/AccessValidator.java:18-22
Timestamp: 2025-07-06T11:51:16.126Z
Learning: danji-api 프로젝트에서 Product-Market-User 관계는 설계상 반드시 존재해야 하며, 검증 리소스가 null일 때 이미 예외가 발생하는 구조로 되어 있어서 AccessValidator에서 추가적인 null 체크는 가독성을 해칠 수 있다.
Learnt from: mingdodev
PR: mingdodev/danji-api#7
File: src/main/java/danji/danjiapi/domain/product/service/ProductService.java:23-32
Timestamp: 2025-07-06T10:15:26.201Z
Learning: danji-api 프로젝트의 데이터 스키마에서는 사용자당 하나의 마켓만 존재하도록 설계되어 있어서 MarketRepository.findByUserId()를 사용하는 것이 적절하다.
src/main/java/danji/danjiapi/domain/order/repository/OrderRepository.java (1)
Learnt from: mingdodev
PR: mingdodev/danji-api#7
File: src/main/java/danji/danjiapi/domain/product/service/ProductService.java:23-32
Timestamp: 2025-07-06T10:15:26.201Z
Learning: danji-api 프로젝트의 데이터 스키마에서는 사용자당 하나의 마켓만 존재하도록 설계되어 있어서 MarketRepository.findByUserId()를 사용하는 것이 적절하다.
src/main/java/danji/danjiapi/domain/market/controller/MarketController.java (1)
Learnt from: mingdodev
PR: mingdodev/danji-api#7
File: src/main/java/danji/danjiapi/domain/product/service/ProductService.java:23-32
Timestamp: 2025-07-06T10:15:26.201Z
Learning: danji-api 프로젝트의 데이터 스키마에서는 사용자당 하나의 마켓만 존재하도록 설계되어 있어서 MarketRepository.findByUserId()를 사용하는 것이 적절하다.
🧬 Code Graph Analysis (3)
src/main/java/danji/danjiapi/domain/order/entity/OrderStatus.java (1)
src/main/java/danji/danjiapi/global/exception/CustomException.java (1)
  • CustomException (3-14)
src/main/java/danji/danjiapi/domain/order/entity/OrderItem.java (1)
src/main/java/danji/danjiapi/domain/order/entity/Order.java (1)
  • Entity (25-78)
src/main/java/danji/danjiapi/domain/order/entity/Order.java (1)
src/main/java/danji/danjiapi/domain/order/entity/OrderItem.java (1)
  • Entity (18-55)
🔇 Additional comments (23)
src/main/java/danji/danjiapi/domain/market/repository/MarketRepository.java (1)

15-16: 효율적인 쿼리 구현이 잘 되어 있습니다.

JOIN FETCH를 사용하여 N+1 문제를 방지하고, Set 타입을 사용하여 IN 절의 성능을 최적화한 좋은 구현입니다.

src/main/java/danji/danjiapi/global/config/WebConfig.java (1)

16-16: PATCH 메서드 추가가 적절합니다.

주문 업데이트 엔드포인트를 위한 PATCH 메서드 추가가 올바르게 구현되었습니다.

src/main/java/danji/danjiapi/domain/order/dto/request/OrderItemInfo.java (1)

7-15: 유효성 검증과 데이터 타입 선택이 적절합니다.

상품 정보 DTO 구현이 잘 되어 있습니다:

  • 가격에 BigDecimal 사용으로 정확한 금액 계산 지원
  • 적절한 유효성 검증 어노테이션과 한국어 메시지
  • Record 사용으로 불변성 보장
src/main/java/danji/danjiapi/domain/order/dto/response/OrderCreateResponse.java (1)

5-13: 팩토리 메서드 패턴이 잘 구현되어 있습니다.

주문 생성 응답 DTO의 구현이 깔끔하고 적절합니다. 정적 팩토리 메서드를 통해 엔티티에서 응답 객체로의 변환을 명확하게 처리하고 있습니다.

src/main/java/danji/danjiapi/domain/order/dto/request/OrderStatusUpdateRequest.java (1)

5-8: 좋은 구현입니다.

검증 어노테이션과 한국어 에러 메시지가 적절하게 사용되었습니다. 간단하고 명확한 구조가 좋습니다.

src/main/java/danji/danjiapi/domain/order/dto/request/OrderItemDetail.java (1)

7-17: 훌륭한 구현입니다.

  • 모든 필드에 대한 적절한 검증 어노테이션 사용
  • 금융 계산에 적합한 BigDecimal 사용
  • 일관된 한국어 에러 메시지
  • 깔끔한 record 구조
src/main/java/danji/danjiapi/global/util/validator/AccessValidator.java (2)

4-4: 새로운 Order 엔티티 임포트 추가 확인

주문 도메인 구현을 위한 Order 엔티티 임포트가 적절하게 추가되었습니다.


23-28: 주문 접근 권한 검증 메서드 구현 확인

주문 접근 권한 검증 로직이 기존 패턴과 일관성 있게 구현되었습니다. 사장님만 주문 수정이 가능하다는 비즈니스 로직이 명확하게 반영되어 있고, 한국어 주석으로 의도가 잘 설명되어 있습니다.

src/main/java/danji/danjiapi/domain/market/dto/response/MarketDetail.java (1)

5-18: MarketSummary에서 MarketDetail로 클래스명 변경 확인

클래스명을 MarketSummary에서 MarketDetail로 변경한 것이 의미적으로 더 명확합니다. 팩토리 메서드도 일관성 있게 업데이트되었습니다.

src/main/java/danji/danjiapi/domain/market/service/MarketService.java (2)

4-4: MarketDetail 임포트 업데이트 확인

MarketSummary에서 MarketDetail로 변경된 DTO에 맞춰 임포트가 적절하게 업데이트되었습니다.


25-36: MarketDetail 반환 타입 업데이트 확인

메서드 반환 타입과 매핑 함수가 MarketDetail로 일관성 있게 업데이트되었습니다. 기존 로직은 유지하면서 DTO 변경사항만 반영되었습니다.

src/main/java/danji/danjiapi/domain/order/dto/response/OrderItemDetail.java (1)

6-20: OrderItemDetail 레코드 클래스 구현 확인

주문 아이템 상세 정보를 담는 레코드 클래스가 적절하게 구현되었습니다. 특히 금액 필드에 BigDecimal 타입을 사용한 것이 올바르며, 정적 팩토리 메서드도 기존 패턴을 잘 따르고 있습니다.

src/main/java/danji/danjiapi/domain/order/entity/OrderStatus.java (2)

6-9: OrderStatus 열거형 상수 정의 확인

주문 상태를 나타내는 열거형 상수들이 적절하게 정의되었습니다. PENDING, REJECTED, ACCEPTED는 일반적인 주문 상태 흐름을 잘 표현합니다.


11-17: 문자열 검증 및 변환 메서드 구현 확인

문자열을 OrderStatus로 변환하는 메서드가 적절하게 구현되었습니다. toUpperCase()를 사용한 대소문자 무관 처리와 IllegalArgumentException을 적절한 커스텀 예외로 변환하는 로직이 올바릅니다.

src/main/java/danji/danjiapi/domain/order/repository/OrderRepository.java (2)

11-12: JOIN FETCH 사용으로 N+1 문제 방지 - 좋은 구현입니다.

JOIN FETCH를 사용하여 orderItems를 즉시 로딩하고 DISTINCT로 중복을 제거하여 성능을 최적화했습니다.


14-15: 가맹점 주문 조회 쿼리도 잘 구현되었습니다.

고객 주문 조회와 동일한 패턴으로 일관성 있게 구현되었습니다.

src/main/java/danji/danjiapi/domain/market/controller/MarketController.java (2)

4-4: DTO 타입 변경이 적절합니다.

MarketSummary에서 MarketDetail로의 변경이 일관성 있게 적용되었습니다.


24-25: 용어 통일 및 API 문서 개선

"회원"을 "고객"으로 변경하여 도메인 용어의 일관성을 확보했습니다.

src/main/java/danji/danjiapi/domain/order/dto/response/CustomerOrderDetail.java (1)

18-36: 정적 팩토리 메서드가 잘 구현되었습니다.

엔티티에서 DTO로의 변환 로직이 깔끔하게 구현되었고, 총 가격 계산도 정확합니다.

src/main/java/danji/danjiapi/domain/order/dto/response/MerchantOrderDetail.java (1)

18-35: 정적 팩토리 메서드 구현이 우수합니다.

CustomerOrderDetail과 동일한 패턴으로 일관성 있게 구현되었습니다.

src/main/java/danji/danjiapi/global/exception/ErrorMessage.java (1)

26-26: 추가된 에러 메시지들이 적절합니다.

주문 도메인에 필요한 에러 메시지들이 잘 정의되었습니다. HTTP 상태 코드도 각 상황에 맞게 적절히 매핑되어 있습니다.

Also applies to: 43-48

src/main/java/danji/danjiapi/domain/order/service/OrderService.java (1)

152-154: 주문 상태 검증 로직이 좋습니다.

이미 처리된 주문에 대한 상태 변경을 방지하는 로직이 적절히 구현되어 있습니다.

src/main/java/danji/danjiapi/domain/order/controller/OrderController.java (1)

48-54: 성공 메시지가 적절합니다.

주문 수정 완료 메시지를 명시적으로 반환하는 것이 좋은 UX를 제공합니다.

Comment on lines +70 to +72
public void updateStatus(OrderStatus status) {
this.status = status;
}
Copy link

@coderabbitai coderabbitai bot Jul 6, 2025

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

주문 상태 전환 검증이 필요합니다.

현재는 어떤 상태에서든 다른 상태로 변경이 가능합니다. 비즈니스 로직에 따라 허용된 상태 전환만 가능하도록 검증이 필요합니다.


🏁 Script executed:

#!/bin/bash
# OrderStatus enum의 구현을 확인하여 상태 전환 검증 로직이 있는지 확인
ast-grep --pattern 'enum OrderStatus {
  $$$
}'

Length of output: 49


OrderStatus enum 정의와 구현 내용을 확인하기 위해 아래 스크립트를 실행해주세요.


🏁 Script executed:

#!/bin/bash
# OrderStatus enum 파일 위치와 내용을 출력
files=$(fd -t f OrderStatus.java)
if [ -z "$files" ]; then
  echo "OrderStatus.java 파일을 찾을 수 없습니다."
else
  for f in $files; do
    echo "===== $f ====="
    sed -n '1,200p' "$f"
  done
fi

Length of output: 933


주문 상태 전환 검증 로직 추가 필요

현재 Order.updateStatus() 메서드는 어떤 상태에서든 임의의 OrderStatus로 변경이 가능하며, OrderStatus enum에도 전환 허용 여부를 판단하는 로직이 없습니다. 비즈니스 룰에 맞는 상태 전환만 허용하도록 아래와 같이 개선이 필요합니다.

  • 검증 위치 제안

    • OrderStatus enum 내부에 canTransitionTo(OrderStatus next) 같은 메서드를 두고, 각 상태별 허용 가능한 다음 상태를 정의
    • 또는 Order.updateStatus()에서 OrderStatus의 검증 메서드를 호출
  • 파일·위치

    • src/main/java/danji/danjiapi/domain/order/entity/Order.java
      • 메서드: public void updateStatus(OrderStatus status)
    • src/main/java/danji/danjiapi/domain/order/entity/OrderStatus.java
      • enum 정의부
  • 예시 Diff

 public enum OrderStatus {
     PENDING,
     REJECTED,
     ACCEPTED;
+
+    private static final Map<OrderStatus, Set<OrderStatus>> ALLOWED =
+        Map.of(
+            PENDING, Set.of(ACCEPTED, REJECTED),
+            ACCEPTED, Set.of(),
+            REJECTED, Set.of()
+        );
+
+    public boolean canTransitionTo(OrderStatus next) {
+        return ALLOWED.getOrDefault(this, Set.of()).contains(next);
+    }
 }

 public class Order {
-    public void updateStatus(OrderStatus status) {
-        this.status = status;
-    }
+    public void updateStatus(OrderStatus nextStatus) {
+        if (!this.status.canTransitionTo(nextStatus)) {
+            throw new CustomException(ErrorMessage.ORDER_INVALID_STATUS_TRANSITION);
+        }
+        this.status = nextStatus;
+    }
 }

위와 같이 허용된 전환만 수행되도록 검증 로직을 추가해주세요.

🤖 Prompt for AI Agents
In src/main/java/danji/danjiapi/domain/order/entity/Order.java around lines 70
to 72, the updateStatus method currently allows any status change without
validation. To fix this, add a validation step before assigning the new status
by calling a method like canTransitionTo on the current OrderStatus. Implement
this canTransitionTo method inside the OrderStatus enum in
src/main/java/danji/danjiapi/domain/order/entity/OrderStatus.java, defining
allowed next states for each enum value. This ensures only valid status
transitions according to business rules are permitted.

Copy link
Owner Author

Choose a reason for hiding this comment

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

다음 배포 때 ...

Copy link

Choose a reason for hiding this comment

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

@mingdodev 네, 알겠습니다. 현재 PR에서는 주문 상태 전환 검증 로직을 추가하지 않고 다음 배포 때 적용하시겠다는 것으로 이해했습니다.

이 개선사항을 추후에 놓치지 않도록 GitHub 이슈로 생성해 드릴까요? 주문 상태 전환 검증 로직 추가에 대한 follow-up 이슈를 만들어 두시면 다음 배포 계획 시 참고하실 수 있을 것 같습니다.


🧠 Learnings used
Learnt from: mingdodev
PR: mingdodev/danji-api#9
File: src/main/java/danji/danjiapi/domain/order/dto/response/OrderStatusUpdateResponse.java:9-11
Timestamp: 2025-07-06T18:16:17.988Z
Learning: danji-api 프로젝트에서 Order 엔티티의 status 필드는 도메인 설계상 항상 존재하도록 되어 있어서, OrderStatusUpdateResponse.from() 메서드에서 order.getStatus()에 대한 null 체크는 불필요하다.

Comment on lines +42 to +67
public List<CustomerOrderDetail> getCustomerOrders() {
String currentUserRole = currentUserResolver.getCurrentUserRole();
Long currentUserId = currentUserResolver.getCurrentUserId();

List<Order> orders;

if (currentUserRole.equals(Role.CUSTOMER.name())) {
orders = orderRepository.findByCustomerIdWithOrderItems(currentUserId);
} else {
throw new CustomException(ErrorMessage.ORDER_FORBIDDEN);
}

Set<Long> merchantIds = orders.stream()
.map(order -> order.getMerchant().getId())
.collect(Collectors.toSet());

Map<Long, Market> marketMap = marketRepository.findAllByUserIdIn(merchantIds).stream()
.collect(Collectors.toMap(m -> m.getUser().getId(), Function.identity()));

return orders.stream()
.map(o -> {
Market market = marketMap.get(o.getMerchant().getId());
return CustomerOrderDetail.from(o, market);
})
.toList();
}
Copy link

@coderabbitai coderabbitai bot Jul 6, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

페이징 처리가 필요합니다.

주문 목록이 많아질 경우를 대비해 페이징 처리가 필요합니다. 현재는 모든 주문을 한 번에 조회하고 있어 성능 문제가 발생할 수 있습니다.

Spring Data JPA의 Pageable을 사용하여 페이징을 구현하는 것을 권장합니다.

public Page<CustomerOrderDetail> getCustomerOrders(Pageable pageable) {
    // 페이징 처리 구현
}
🤖 Prompt for AI Agents
In src/main/java/danji/danjiapi/domain/order/service/OrderService.java between
lines 42 and 67, the getCustomerOrders method currently fetches all orders
without pagination, which can cause performance issues with large datasets.
Modify the method signature to accept a Pageable parameter and update the
repository call to use a pageable query method that returns a Page<Order>. Then,
map the Page<Order> content to CustomerOrderDetail objects and return a
Page<CustomerOrderDetail> to enable efficient paging of order results.

Copy link
Owner Author

Choose a reason for hiding this comment

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

다음 이 시간에 ...

Copy link

Choose a reason for hiding this comment

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

@mingdodev 네, 이해했습니다! 페이징 처리는 다음에 구현하시면 됩니다. 현재 주문 도메인 구현에 집중하시는 것이 좋겠네요.

언제든지 페이징 구현이 필요할 때 다시 말씀해 주세요! 🐰


🧠 Learnings used
Learnt from: mingdodev
PR: mingdodev/danji-api#7
File: src/main/java/danji/danjiapi/domain/product/service/ProductService.java:23-32
Timestamp: 2025-07-06T10:15:26.201Z
Learning: danji-api 프로젝트의 데이터 스키마에서는 사용자당 하나의 마켓만 존재하도록 설계되어 있어서 MarketRepository.findByUserId()를 사용하는 것이 적절하다.

@mingdodev mingdodev merged commit de67ff4 into main Jul 6, 2025
1 check passed
@mingdodev mingdodev deleted the feature/8-order branch July 6, 2025 18:22
@coderabbitai coderabbitai bot mentioned this pull request Jan 20, 2026
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.

[Feature] 주문 도메인 API 구현

1 participant