Skip to content

feat: 주막 주문 API 구현#86

Open
jhssong wants to merge 12 commits intomainfrom
feat/26-pub-order-api
Open

feat: 주막 주문 API 구현#86
jhssong wants to merge 12 commits intomainfrom
feat/26-pub-order-api

Conversation

@jhssong
Copy link
Contributor

@jhssong jhssong commented Mar 13, 2026

✨ 구현한 기능

  • 주막 주문 CRD 기능을 구현했습니다.

📢 논의하고 싶은 내용

  • PubOrder 엔티티의 id 필드 이름이 pub_table_id로 잘못 지정되어 있었습니다. 아래 SQL문을 통해 배포 DB 스키마 변경이 필요합니다.
ALTER TABLE pub_order RENAME COLUMN pub_table_id TO pub_order_id;

🎸 기타

  • 기존 설계는 주문 시 메뉴를 하나씩만 주문한다는 가정이 있었는데, 실제로는 하나의 메뉴를 여러 개 주문하는 경우도 있으므로 PubOrder 엔티티에 quantity 필드를 추가하였습니다.

  • 아래 코드 리뷰 과정에서 N + 1 쿼리 문제 해결을 위해 PubMenuQueryService에 findAllPubMenuByIds 메서드를 추가하였습니다.

close #26

Summary by CodeRabbit

  • 새로운 기능

    • 관리자용 펍 주문 생성·조회·삭제 API 추가
    • 주문 응답에 메뉴별 수량 및 상세 정보 포함
  • 개선 사항

    • 요청 검증 강화: 주문 수량은 양수만 허용, 주문 목록은 비어있을 수 없음
    • 주문 조회 시 존재하지 않는 주문에 대한 명확한 오류 응답 추가
    • 메뉴 정보 일괄 조회 지원 추가
  • 기타

    • 프로젝트 설정(.gitignore) 업데이트 (개발환경 파일 무시 추가)

@jhssong jhssong self-assigned this Mar 13, 2026
@jhssong jhssong added the Ask 일반적인 PR 패턴 - PR을 요청하고 즉시 머지하지 않고 동료들의 승인을 기다림 label Mar 13, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

📝 Walkthrough

Walkthrough

주막 주문 도메인이 추가됩니다: 주문 엔티티(수량 포함), 저장소, 커맨드/쿼리 응용서비스, 컨트롤러, 요청/응답 DTO들, 예외 코드 및 .gitignore 패턴이 추가되어 주문 생성·조회·삭제 흐름을 구현합니다.

Changes

Cohort / File(s) Summary
설정 및 무시 규칙
/.gitignore
.DS_Store, .*.env, .env*, HELP.md 등 무시 패턴 추가
도메인 엔티티
src/main/java/kr/co/knuserver/domain/pubOrder/entity/PubOrder.java
패키지 변경, PK 컬럼명 pub_order_id로 업데이트, quantity 필드 추가 및 팩토리 메서드에 수량 검증 로직 추가
도메인 저장소
src/main/java/kr/co/knuserver/domain/pubOrder/repository/PubOrderRepository.java
JpaRepository<PubOrder, Long> 인터페이스 추가 및 findAllByPubTableSessionId 선언
응용 서비스 - 커맨드
src/main/java/kr/co/knuserver/application/pubOrder/PubOrderCommandService.java
주문 생성(createOrder) 및 삭제(deleteOrder) 로직 추가: 세션 조회, 메뉴 조회, 엔티티 생성(수량 포함), 저장 및 DTO 반환
응용 서비스 - 쿼리
src/main/java/kr/co/knuserver/application/pubOrder/PubOrderQueryService.java
주문 단건 조회(findByOrderId) 및 세션별 주문 조회(getAllByPubTableSessionId) 추가, 존재하지 않으면 BusinessException 발생
응용 서비스(기존 확장)
src/main/java/kr/co/knuserver/application/pubMenu/PubMenuQueryService.java
findAllPubMenuByIds(List<Long>) 배치 조회 메서드 추가
표현 레이어 - 컨트롤러
src/main/java/kr/co/knuserver/presentation/pubOrder/controller/...
PubOrderCommandController.java, PubOrderQueryController.java
관리자 엔드포인트 /admin/v1/pubOrder에 POST(생성), DELETE(삭제), GET(세션별 조회) 추가
표현 레이어 - DTO/레코드
src/main/java/kr/co/knuserver/presentation/pubOrder/dto/...
OrderMenus.java, OrderedMenus.java, PubOrderRequestDto.java, PubOrderResponseDto.java
요청/응답 레코드와 매핑 팩토리, 검증 애노테이션 추가(수량 포함)
전역 예외 코드
src/main/java/kr/co/knuserver/global/exception/BusinessErrorCode.java
PUB_ORDER_NOT_FOUND(HTTP 404, 코드 "C206") 에러 코드 추가

Sequence Diagram(s)

sequenceDiagram
    actor Client
    participant CmdCtrl as PubOrderCommandController
    participant CmdSvc as PubOrderCommandService
    participant TableQS as PubTableSessionQueryService
    participant MenuQS as PubMenuQueryService
    participant OrderRepo as PubOrderRepository
    participant DB as Database

    Client->>CmdCtrl: POST /admin/v1/pubOrder\nPubOrderRequestDto
    CmdCtrl->>CmdSvc: createOrder(request)
    CmdSvc->>TableQS: findByPubTableSessionId(sessionId)
    TableQS-->>CmdSvc: PubTableSession

    loop each orderMenu
        CmdSvc->>MenuQS: findPubMenuById(menuId)
        MenuQS-->>CmdSvc: PubMenu
        CmdSvc->>OrderRepo: save(PubOrder with quantity)
        OrderRepo->>DB: INSERT pub_order
        DB-->>OrderRepo: persisted PubOrder
    end

    CmdSvc-->>CmdCtrl: PubOrderResponseDto
    CmdCtrl-->>Client: 200 OK

    Client->>CmdCtrl: GET /admin/v1/pubOrder/{sessionId}
    CmdCtrl->>PubOrderQueryService: getAllByPubTableSessionId(sessionId)
    PubOrderQueryService->>OrderRepo: findAllByPubTableSessionId(sessionId)
    OrderRepo->>DB: SELECT *
    DB-->>OrderRepo: List<PubOrder>
    loop each pubOrder
        PubOrderQueryService->>MenuQS: findPubMenuById(menuId)
        MenuQS-->>PubOrderQueryService: PubMenu
    end
    PubOrderQueryService-->>CmdCtrl: PubOrderResponseDto (mapped)
    CmdCtrl-->>Client: 200 OK
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • 주막 부스 API 구현 #35: PubMenuQueryService 변경/추가와 연관 — 본 PR에서 PubMenuQueryService를 확장 및 의존하여 메뉴 조회를 사용함.

Suggested reviewers

  • milk-stone

Poem

🐰 새 주문이 퐁당 들어왔네,
수량 탕탕 장부에 쌓였네,
서비스는 메뉴를 찾아 뛰고,
컨트롤러는 길을 열어주며,
저장소는 조용히 품에 안았네.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive PR의 모든 변경사항은 주막 주문 API 구현(#26)의 범위 내에 있습니다. 다만 update 기능이 요구사항에는 포함되어 있으나 PR에서는 구현되지 않았습니다. Issue #26에서 요구한 update 기능의 구현 여부를 확인하거나, update가 향후 별도 PR로 계획되어 있는지 명확히 해주시기 바랍니다.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 주막 주문 API 구현이라는 주요 변경 사항을 명확하고 간결하게 요약하고 있습니다.
Linked Issues check ✅ Passed PR은 issue #26의 CRD 기능 요구사항을 충족합니다. Create(createOrder), Read(getAllByPubTableSessionId, findByOrderId), Delete(deleteOrder) API를 구현했으며, 요청/응답 DTO와 엔티티를 포함합니다.
Description check ✅ Passed PR 설명은 필수 템플릿 섹션을 모두 포함하고 있으며, 구현한 기능, 논의하고 싶은 내용, 기타 항목이 명확하게 작성되어 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/26-pub-order-api
📝 Coding Plan
  • Generate coding plan for human review comments

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

🧹 Nitpick comments (3)
src/main/java/kr/co/knuserver/presentation/pubOrder/controller/PubOrderCommandController.java (2)

23-26: POST 요청 시 201 Created 반환 권장

리소스 생성 시 REST 규약에 따라 200 OK 대신 201 Created를 반환하는 것이 더 적절합니다.

♻️ HTTP 상태 코드 개선
     `@PostMapping`
     public ResponseEntity<PubOrderResponseDto> createOrder(`@Valid` `@RequestBody` PubOrderRequestDto request) {
-        return ResponseEntity.ok().body(pubOrderCommandService.createOrder(request));
+        return ResponseEntity.status(HttpStatus.CREATED).body(pubOrderCommandService.createOrder(request));
     }

HttpStatus import 추가 필요:

import org.springframework.http.HttpStatus;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/kr/co/knuserver/presentation/pubOrder/controller/PubOrderCommandController.java`
around lines 23 - 26, Change the createOrder handler in
PubOrderCommandController to return 201 Created instead of 200 by using
ResponseEntity.status(HttpStatus.CREATED).body(pubOrderCommandService.createOrder(request));
ensure the HttpStatus import (org.springframework.http.HttpStatus) is added to
the file so the reference resolves; keep the existing call to
pubOrderCommandService.createOrder(request) unchanged.

28-32: DELETE 요청 시 204 No Content 반환 권장

삭제 성공 시 응답 본문이 없으므로 200 OK 대신 204 No Content가 더 적절합니다. AdminPubBoothControllerdelete 메서드에서도 noContent()를 사용하고 있어 일관성 측면에서도 권장됩니다.

♻️ HTTP 상태 코드 개선
     `@DeleteMapping`("/{pubOrderId}")
     public ResponseEntity<Void> deleteOrder(`@PathVariable`("pubOrderId") Long pubOrderId) {
         pubOrderCommandService.deleteOrder(pubOrderId);
-        return ResponseEntity.ok().build();
+        return ResponseEntity.noContent().build();
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/kr/co/knuserver/presentation/pubOrder/controller/PubOrderCommandController.java`
around lines 28 - 32, The deleteOrder method in PubOrderCommandController
currently returns 200 OK; change it to return 204 No Content by replacing the
ResponseEntity.ok().build() with ResponseEntity.noContent().build() in the
deleteOrder(`@PathVariable`("pubOrderId") Long pubOrderId) method and keep
invoking pubOrderCommandService.deleteOrder(pubOrderId) as-is to maintain
behavior consistent with AdminPubBoothController's delete pattern.
src/main/java/kr/co/knuserver/presentation/pubOrder/controller/PubOrderQueryController.java (1)

12-22: LGTM!

쿼리 컨트롤러가 깔끔하게 구현되어 있습니다. 단, Line 21에 ResponseEntity.ok() 앞에 공백이 두 개 있는 사소한 포맷팅 이슈가 있습니다.

-        return  ResponseEntity.ok(pubOrderQueryService.getAllByPubTableSessionId(pubTableSessionId));
+        return ResponseEntity.ok(pubOrderQueryService.getAllByPubTableSessionId(pubTableSessionId));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/kr/co/knuserver/presentation/pubOrder/controller/PubOrderQueryController.java`
around lines 12 - 22, There is an extra double space before the
ResponseEntity.ok() call in the getAllByPubTableSessionId method of
PubOrderQueryController; remove the extra space so the return statement is
formatted consistently (locate the getAllByPubTableSessionId method in class
PubOrderQueryController and adjust the spacing before ResponseEntity.ok(...)).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/kr/co/knuserver/application/pubOrder/PubOrderCommandService.java`:
- Around line 29-42: In createOrder, avoid the N+1 by collecting menu IDs from
request.orderMenus() after saving pubOrders, call a batch fetch (add
PubMenuQueryService.findAllByIds(List<Long> ids) or use
pubMenuRepository.findAllById(ids)) to retrieve all PubMenu entities in one
query, build a Map<Long,PubMenu> keyed by menuId, then map savedPubOrders to
OrderedMenus using the map instead of calling
pubMenuQueryService.findPubMenuById for each PubOrder; update createOrder to use
the batch method and preserve usage of PubOrder.createPubOrder and
pubOrderRepository.saveAll.

In
`@src/main/java/kr/co/knuserver/application/pubOrder/PubOrderQueryService.java`:
- Around line 30-34: 현재 pubOrderList 스트림에서 각 PubOrder마다
pubMenuQueryService.findPubMenuById를 호출해 N+1 문제가 발생합니다; pubOrderList에서 모든
pubMenuId를 수집한 뒤 한 번에 메뉴들을 조회하고 ID->PubMenu 맵을 만든 다음 OrderedMenus.fromEntity를
호출할 때 맵에서 해당 메뉴를 꺼내 사용하도록 변경하세요 (참고 심볼:
pubOrderRepository.findAllByPubTableSessionId,
pubMenuQueryService.findPubMenuById, OrderedMenus.fromEntity, pubOrderList). 만약
bulk 조회 메서드(예: findPubMenusByIds or findAllByIdIn)가 없다면 pubMenuQueryService 또는
레포지토리에 추가해 한 번에 조회하도록 구현하고 기존 per-order 호출을 대체하세요.

In `@src/main/java/kr/co/knuserver/domain/pubOrder/entity/PubOrder.java`:
- Around line 36-41: The createPubOrder factory currently allows
null/zero/negative quantities which can create invalid orders; update
PubOrder.createPubOrder to validate the quantity (e.g., check not null and
quantity > 0) and throw a clear runtime exception (IllegalArgumentException or a
domain-specific exception) when the check fails, then only call
PubOrder.builder()...build() with a verified quantity; reference the
createPubOrder method and the PubOrder builder in your change so all invalid
inputs are blocked at creation time.

In
`@src/main/java/kr/co/knuserver/presentation/pubOrder/dto/PubOrderRequestDto.java`:
- Line 8: In PubOrderRequestDto change the orderMenus declaration to enforce
non-empty and cascade validation: replace the `@NotNull` on the orderMenus field
with `@NotEmpty` and annotate the list elements with `@Valid` (i.e., use List<@Valid
OrderMenus> orderMenus), and add the necessary imports for
javax.validation.Valid and javax.validation.constraints.NotEmpty so nested
OrderMenus field constraints are propagated.

---

Nitpick comments:
In
`@src/main/java/kr/co/knuserver/presentation/pubOrder/controller/PubOrderCommandController.java`:
- Around line 23-26: Change the createOrder handler in PubOrderCommandController
to return 201 Created instead of 200 by using
ResponseEntity.status(HttpStatus.CREATED).body(pubOrderCommandService.createOrder(request));
ensure the HttpStatus import (org.springframework.http.HttpStatus) is added to
the file so the reference resolves; keep the existing call to
pubOrderCommandService.createOrder(request) unchanged.
- Around line 28-32: The deleteOrder method in PubOrderCommandController
currently returns 200 OK; change it to return 204 No Content by replacing the
ResponseEntity.ok().build() with ResponseEntity.noContent().build() in the
deleteOrder(`@PathVariable`("pubOrderId") Long pubOrderId) method and keep
invoking pubOrderCommandService.deleteOrder(pubOrderId) as-is to maintain
behavior consistent with AdminPubBoothController's delete pattern.

In
`@src/main/java/kr/co/knuserver/presentation/pubOrder/controller/PubOrderQueryController.java`:
- Around line 12-22: There is an extra double space before the
ResponseEntity.ok() call in the getAllByPubTableSessionId method of
PubOrderQueryController; remove the extra space so the return statement is
formatted consistently (locate the getAllByPubTableSessionId method in class
PubOrderQueryController and adjust the spacing before ResponseEntity.ok(...)).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 12fb4f19-f265-46b6-bc95-c5a7cff6163b

📥 Commits

Reviewing files that changed from the base of the PR and between 8ff7920 and 1512eb9.

📒 Files selected for processing (12)
  • .gitignore
  • src/main/java/kr/co/knuserver/application/pubOrder/PubOrderCommandService.java
  • src/main/java/kr/co/knuserver/application/pubOrder/PubOrderQueryService.java
  • src/main/java/kr/co/knuserver/domain/pubOrder/entity/PubOrder.java
  • src/main/java/kr/co/knuserver/domain/pubOrder/repository/PubOrderRepository.java
  • src/main/java/kr/co/knuserver/global/exception/BusinessErrorCode.java
  • src/main/java/kr/co/knuserver/presentation/pubOrder/controller/PubOrderCommandController.java
  • src/main/java/kr/co/knuserver/presentation/pubOrder/controller/PubOrderQueryController.java
  • src/main/java/kr/co/knuserver/presentation/pubOrder/dto/OrderMenus.java
  • src/main/java/kr/co/knuserver/presentation/pubOrder/dto/OrderedMenus.java
  • src/main/java/kr/co/knuserver/presentation/pubOrder/dto/PubOrderRequestDto.java
  • src/main/java/kr/co/knuserver/presentation/pubOrder/dto/PubOrderResponseDto.java

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/kr/co/knuserver/domain/pubOrder/entity/PubOrder.java`:
- Line 26: The entity PubOrder's primary key field id was remapped to
`@Column`(name = "pub_order_id") which will break runtime SQL if the deployed DB
still uses the old column name (pub_table_id); revert the column mapping on the
id field to the existing DB column name (use `@Column`(name = "pub_table_id") or
remove the name attribute so it matches the current schema) until the DB
migration that renames pub_table_id→pub_order_id has been applied, and ensure
any deployment that introduces `@Column`(name = "pub_order_id") is gated behind
the corresponding migration being applied in production.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0540f43b-f797-4f2a-8b1f-b0c286641a47

📥 Commits

Reviewing files that changed from the base of the PR and between 1512eb9 and 3743e10.

📒 Files selected for processing (2)
  • src/main/java/kr/co/knuserver/domain/pubOrder/entity/PubOrder.java
  • src/main/java/kr/co/knuserver/presentation/pubOrder/dto/PubOrderRequestDto.java

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/kr/co/knuserver/application/pubOrder/PubOrderCommandService.java`:
- Around line 39-51: The code may NPE when mapping savedPubOrders to menus
because pubMenuMap.get(pubOrder.getPubMenuId()) can be null; before calling
pubOrderRepository.saveAll(pubOrders) perform a validation using
pubMenuQueryService.findAllPubMenuByIds(...) against the incoming pubOrders'
pubMenuId list, detect any missing IDs, and if any are absent throw a
BusinessException listing the invalid menu IDs; then proceed to save and
continue using OrderedMenus.fromEntity(pubOrder, pubMenu) with the guaranteed
non-null pubMenu.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 571baf1b-e8e5-4651-ba65-23cac9524e79

📥 Commits

Reviewing files that changed from the base of the PR and between 3743e10 and 1bff5e9.

📒 Files selected for processing (2)
  • src/main/java/kr/co/knuserver/application/pubMenu/PubMenuQueryService.java
  • src/main/java/kr/co/knuserver/application/pubOrder/PubOrderCommandService.java

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Ask 일반적인 PR 패턴 - PR을 요청하고 즉시 머지하지 않고 동료들의 승인을 기다림

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[🛠 기능 구현] 주막 주문 API 구현

1 participant