Conversation
Walkthrough입고 목록 조회 기능을 구현했습니다. 페이징, 발주처 필터링, 상태 필터링, 날짜 범위 필터링을 지원하며, 컨트롤러-서비스-저장소 계층에 걸쳐 엔드포인트와 데이터베이스 쿼리를 추가하고 테스트 커버리지를 확대했습니다. Changes
Sequence DiagramsequenceDiagram
participant Client
participant Controller as ReceiptController
participant Service as ReceiptService
participant Repository as ReceiptRepository
participant DB as Database
Client->>Controller: GET /api/v1/receipt<br/>(page, size, vendorId,<br/>status, fromDate, endDate)
rect rgb(200, 240, 255)
Note over Controller: 요청 검증 & 인증<br/>(AuthenticationPrincipal)
end
Controller->>Service: getReceiptList(userId, page,<br/>size, vendorId, status,<br/>fromDate, toDate)
rect rgb(240, 255, 240)
Note over Service: 필터 조합별<br/>분기 처리
end
Service->>Service: findReceiptsByFilter()<br/>(4가지 케이스)<br/>- 필터 없음<br/>- 상태만<br/>- 발주처만<br/>- 발주처+상태
Service->>Repository: findAllByStoreId*<br/>(해당 필터 쿼리 선택)
Repository->>DB: SQL Query with pagination
DB-->>Repository: Page<Receipt>
Repository-->>Service: Page<Receipt>
rect rgb(255, 250, 240)
Note over Service: Receipt → ReceiptResponse<br/>매핑 및 PageResponse 구성
end
Service-->>Controller: PageResponse<ReceiptResponse>
Controller-->>Client: ApiResponse<br/>(GET_RECEIPT_LIST_SUCCESS,<br/>PageResponse)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 분 추가 검토 주요 대상:
Possibly related issues
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (5)
src/main/java/com/almang/inventory/receipt/repository/ReceiptRepository.java (1)
4-9: 입고 목록용 파생 쿼리 메서드 구성이 도메인/패턴과 잘 맞습니다
storeId + receiptDate Between를 기준으로 하고,ReceiptStatus/order.vendor.id조합으로 4가지 메서드를 나눈 구조가 직관적입니다.OrderRepository쪽의findAllByStoreIdAnd...CreatedAtBetween패턴과도 일관되어, 서비스 계층 코드 가독성이 좋아집니다.ReceiptStatus,LocalDate,Pageable타입 사용도 Spring Data JPA 파생 쿼리 규칙에 맞게 정리되어 있습니다 (공식 문서의 Derived Query Methods 섹션 참고하시면 좋습니다).향후 필터 조건이 더 늘어날 경우에는, 지금과 같은 메서드 폭발을 막기 위해 QueryDSL,
Specification, 혹은 동적 쿼리 빌더로의 전환도 고려해 볼 수 있겠습니다만, 현재 범위에서는 이 정도가 가장 단순하고 명확합니다.Also applies to: 16-26
src/test/java/com/almang/inventory/receipt/controller/ReceiptControllerTest.java (1)
3-12: 입고 목록 조회 컨트롤러 테스트가 핵심 시나리오를 잘 잡았습니다
- 성공 케이스에서
PageResponse를 직접 구성해 두고,status,message,data.totalElements,content[*].receiptId까지 검증한 부분이 좋습니다. “API 스펙이 정확히 이렇게 생겼다”는 계약이 잘 드러납니다.- 두 가지 에러 케이스(사용자 없음, 상점 접근 거부)에 대해 HTTP status와
ErrorCode의httpStatus/message를 그대로 검증한 것도 컨트롤러 예외 매핑을 잘 보호하고 있습니다.개선 아이디어(선택 사항):
- 현재 테스트는 페이지/사이즈만 넘기고 있고,
vendorId,receiptStatus,fromDate,endDate파라미터가 실제로 바인딩되는지는 검증하지 않습니다.
- 예를 들어 아래와 같이 필터 파라미터를 포함한 테스트를 하나 추가하고,
Mockito.verify(receiptService).getReceiptList(userId, page, size, vendorId, status, fromDate, toDate);
형태로 정확한 인자가 전달되는지도 함께 확인하면, 컨트롤러–서비스 사이 계약이 더 견고해집니다.- 이 부분은 Spring MVC의
@RequestParam바인딩 동작을 확인하는 좋은 예제가 되므로, 필요하면 Spring 공식 레퍼런스의 Web MVC – Method Arguments and Return Values 섹션도 같이 참고해 보시면 좋겠습니다.Also applies to: 404-500
src/test/java/com/almang/inventory/receipt/service/ReceiptServiceTest.java (1)
6-6: 입고 목록 조회 서비스 테스트가 필터 동작을 잘 검증하고 있습니다
- 필터 없음 테스트에서:
- 동일 상점의 두 입고와 다른 상점의 입고를 만들어 두고,
- 응답의
storeId가 하나의 상점 ID만 포함되는지,receiptId도receipt1/receipt2만 있는지 확인하는 구조가 멀티테넌시 스코프 검증에 좋습니다.- 발주처 필터 테스트에서:
- 서로 다른 vendor 2개를 두고,
vendor1만 필터링했을 때 1건만 나오고 그게 기대한receipt/order인지 확인하는 흐름이 명확합니다.- 기간 필터 테스트도
minusDays(7)/now()로 데이터를 분리하고,fromDate=now-1,toDate=now로 최근 건만 걸러내는지 잘 확인하고 있습니다. 테스트 시나리오 구성이 교과서적으로 깔끔합니다.보완 아이디어(권장):
- 프로덕션 코드의
findReceiptsByFilter는 4가지 조합(필터 없음 / 상태만 / 발주처만 / 발주처+상태)을 가지는데, 현재 테스트는 “필터 없음 / 발주처 / 기간”만 다룹니다.
ReceiptStatus기준 필터, 그리고vendorId + status동시 필터 케이스도 각각 한 개씩 추가해 두면 분기 전체가 보호되어 유지보수 시 안심하기 좋습니다.- 입고 엔티티/아이템을 만드는 코드가 여러 테스트에 반복되는데, 필요하다면
newReceiptWithItems(Store, Order, LocalDate, int totalBoxCount)정도의 테스트용 헬퍼로 추출해 중복을 줄일 수 있습니다.- 다만 지금도 각 테스트가 “어떤 상황을 위한 데이터인지”를 바로 읽을 수 있어서, 가독성과 DRY 사이에서 현재 상태도 충분히 괜찮은 편입니다.
Also applies to: 431-636
src/main/java/com/almang/inventory/receipt/service/ReceiptService.java (1)
3-7: 입고 목록 조회 서비스 로직이 Order 쪽 패턴과 잘 정렬되어 있습니다좋은 점:
getReceiptList에서
findUserById→store획득 → 로그 →PaginationUtil.createPageRequest(page, size, "createdAt")→findReceiptsByFilter→PageResponse.from의 흐름이 OrderService의getOrderList와 거의 동일해 일관성이 높습니다.@Transactional(readOnly = true)적용으로 조회 성격도 명확히 표현돼 있습니다.findReceiptsByFilter:
fromDate/toDate가 없을 때1970-01-01 ~ LocalDate.now()범위를 기본값으로 두어 “날짜 필터 미지정=전체(과거~오늘)” 동작이 직관적입니다.vendorId/status조합을 boolean 플래그로 나눠 4가지 케이스(없음 / 상태만 / 발주처만 / 발주처+상태)를 명확히 분기한 구조라, 나중에 읽을 때도 조건 해석이 쉽습니다.Receipt.receiptDate가LocalDate타입인 점을 고려해, 별도의LocalDateTime변환 없이Between(LocalDate, LocalDate)를 사용하는 것도 도메인에 잘 맞습니다.개선 제안(권장, 필수 아님):
정렬 기준 컬럼 재검토
- 현재
PaginationUtil.createPageRequest(page, size, "createdAt")로 정렬하고 있는데, 비즈니스적으로 “입고 목록” 화면에서 더 자연스러운 기준이createdAt인지receiptDate인지 한 번 고민해 볼 만합니다.- 실제 사용자가 “입고 처리일(=receiptDate)” 순으로 보고 싶어 한다면,
sortBy를"receiptDate"로 바꾸는 것도 UX 측면에서 더 맞을 수 있습니다. (반대로 “생성 시각 기준 정렬”이 일관성 목표라면 지금도 괜찮습니다.)- 이 부분은 Spring Data JPA의
PageRequest정렬 동작과 직결되므로, 팀 내에서 일관된 기준을 정해 두면 좋습니다.날짜 범위 유효성 검증
- 현재는
fromDate > toDate인 경우에도 그냥Between(startDate, endDate)로 넘어가고, 결과가 빈 목록이 되는 식으로 동작합니다.- 사용자가 잘못된 범위를 넣은 경우를 명시적으로 막고 싶다면,
fromDate와toDate가 모두 null이 아니고,fromDate.isAfter(toDate)이면 예외를 던지거나,- 두 값을 swap해서 자동 교정하는 방식도 고려할 수 있습니다.
- 이건 도메인 정책 문제라 반드시 필요하진 않지만, 나중에 혼동을 줄이는 데 도움이 됩니다.
중복 로직 정리
- OrderService의
findOrdersByFilter와 ReceiptService의findReceiptsByFilter가 개념적으로 거의 동일한 구조(날짜 기본값, vendor/status 조합 분기)를 가지므로,
- 장기적으로는 날짜 범위 계산 부분만이라도 작은 유틸(예:
DateRangeUtil)로 빼두면 정책 변경 시 동시 수정할 곳을 줄일 수 있습니다.- 다만 지금도 코드 길이가 과도하지는 않아서, 리팩터링은 여유 있을 때 진행해도 됩니다.
Also applies to: 21-28, 89-105, 179-213
src/main/java/com/almang/inventory/receipt/controller/ReceiptController.java (1)
4-13: 입고 목록 조회 엔드포인트가 기존 Order/Vendor API와 잘 맞습니다
@GetMapping시그니처가 OrderController의 목록 조회와 거의 동일해, 클라이언트 입장에서/order//receiptAPI를 동일한 감각으로 사용할 수 있다는 점이 좋습니다.
page,size,vendorId,receiptStatus,fromDate,endDate파라미터 구성이 명확합니다.@AuthenticationPrincipal로userId를 꺼내고, 서비스에 그대로 넘긴 뒤SuccessMessage.GET_RECEIPT_LIST_SUCCESS와 함께ApiResponse<PageResponse<ReceiptResponse>>로 감싸는 패턴도 기존 컨트롤러들과 일관됩니다.- Swagger
@Operation으로 요약/설명을 붙여 둔 것도 API 문서화 측면에서 좋습니다. 한 줄 요약이 깔끔하네요.개선 제안(선택 사항):
메서드 이름 정리
- 현재 메서드 이름이
getOrderList인데, ReceiptController 안에서는getReceiptList정도가 더 자연스럽고, 서비스 메서드 이름(getReceiptList)과도 일치합니다.- IDE 리네임으로 쉽게 바꿀 수 있는 부분이라, 나중에 검색/탐색 시 혼동을 줄이기 위해 정리해 두면 좋겠습니다.
Swagger 설명 보강
- 필요하다면
description에 예시 쿼리(?page=1&size=20&vendorId=...&receiptStatus=...&fromDate=...&endDate=...)를 간단히 추가해 두면, 프론트/외부 소비자가 파라미터 조합을 이해하는 데 도움이 됩니다.- 이는 OpenAPI 문서 활용성을 높이는 정도의 개선이라, 여유 있을 때 진행해도 충분합니다.
Also applies to: 21-21, 75-95
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/main/java/com/almang/inventory/global/api/SuccessMessage.java(1 hunks)src/main/java/com/almang/inventory/receipt/controller/ReceiptController.java(3 hunks)src/main/java/com/almang/inventory/receipt/repository/ReceiptRepository.java(1 hunks)src/main/java/com/almang/inventory/receipt/service/ReceiptService.java(4 hunks)src/test/java/com/almang/inventory/receipt/controller/ReceiptControllerTest.java(2 hunks)src/test/java/com/almang/inventory/receipt/service/ReceiptServiceTest.java(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-22T18:12:13.161Z
Learnt from: JoonKyoLee
Repo: almang2/inventory-server PR: 66
File: src/main/java/com/almang/inventory/order/domain/OrderItem.java:41-53
Timestamp: 2025-11-22T18:12:13.161Z
Learning: In the almang2/inventory-server repository, OrderItem entity update methods (updateQuantity, updatePrice in src/main/java/com/almang/inventory/order/domain/OrderItem.java) do not require null checks because OrderService will validate parameters before calling these update methods, following the same pattern as Product entity updates.
<!--
Applied to files:
src/main/java/com/almang/inventory/receipt/service/ReceiptService.java
🧬 Code graph analysis (2)
src/main/java/com/almang/inventory/receipt/service/ReceiptService.java (3)
src/main/java/com/almang/inventory/global/util/PaginationUtil.java (1)
PaginationUtil(7-17)src/main/java/com/almang/inventory/order/service/OrderService.java (2)
Transactional(82-97)findOrdersByFilter(264-301)src/main/java/com/almang/inventory/order/repository/OrderRepository.java (1)
OrderRepository(10-31)
src/main/java/com/almang/inventory/receipt/controller/ReceiptController.java (3)
src/main/java/com/almang/inventory/vendor/controller/VendorController.java (1)
Slf4j(30-136)src/main/java/com/almang/inventory/receipt/domain/Receipt.java (1)
Entity(13-77)src/main/java/com/almang/inventory/order/controller/OrderController.java (1)
Slf4j(33-155)
🔇 Additional comments (1)
src/main/java/com/almang/inventory/global/api/SuccessMessage.java (1)
50-55: 입고 목록 성공 메시지 상수 추가가 일관성 있게 잘 들어갔습니다
- RECEIPT 영역의 다른 상수들과 네이밍(
GET_RECEIPT_LIST_SUCCESS)과 한글 메시지가 잘 맞습니다.- 컨트롤러에서 목록 조회 응답에 사용하기에 의미도 명확합니다.
✨ 작업 내용
📝 적용 범위
/receipt📌 참고 사항
Summary by CodeRabbit
릴리스 노트
✏️ Tip: You can customize this high-level summary in your review settings.