Conversation
Walkthrough구매 주문 관리 모듈을 추가했습니다. JPA 엔티티(주문·항목), DTO, 저장소, 서비스, REST 컨트롤러를 도입하고 주문 생성·조회·취소·삭제 및 상태·긴급도·텍스트 기반 페이징 검색을 구현하며 프로젝트 버전을 1.0.0으로 변경했습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Controller as PurchaseController
participant Service as PurchaseService
participant OrderRepo as PurchaseOrderRepository
participant ItemRepo as PurchaseOrderItemRepository
participant DB as Database
Note over Client,DB: 주문 생성 흐름 (간략)
Client->>Controller: POST / (PurchaseOrderRequestDto)
Controller->>Service: createMaterialOrder(requestDto)
Service->>Service: calculateUrgency(requiredAt)
Service->>Service: generateOrderCode()
Service->>OrderRepo: findTopByCodeStartingWith(prefix)
OrderRepo->>DB: SELECT latest code
DB-->>OrderRepo: result
Service->>OrderRepo: save(PurchaseOrder)
OrderRepo->>DB: INSERT purchase_order
DB-->>OrderRepo: saved order
Service->>ItemRepo: saveAll(items linked to order)
ItemRepo->>DB: INSERT purchase_order_item
DB-->>ItemRepo: saved items
Service-->>Controller: PurchaseOrderResponseDto
Controller-->>Client: 201 CREATED (ApiResponse)
sequenceDiagram
participant Client
participant Controller as PurchaseController
participant Service as PurchaseService
participant OrderRepo as PurchaseOrderRepository
participant Order as PurchaseOrder
participant DB as Database
Note over Client,DB: 주문 취소 흐름 (간략)
Client->>Controller: PATCH /{orderId}/cancel
Controller->>Service: cancelOrder(orderId)
Service->>OrderRepo: findById(orderId)
OrderRepo->>DB: SELECT
DB-->>OrderRepo: PurchaseOrder
OrderRepo-->>Service: Optional<PurchaseOrder>
Service->>Order: cancel()
alt 현재 상태 == ORDERED
Order->>Order: status=CANCELED, canceledAt=now()
Service->>OrderRepo: save(order)
OrderRepo->>DB: UPDATE purchase_order
DB-->>OrderRepo: updated order
Service-->>Controller: PurchaseOrderResponseDto
Controller-->>Client: 200 OK (ApiResponse)
else 상태 불가
Order-->>Service: throw BadRequestException
Service-->>Controller: error response
Controller-->>Client: 4xx
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45분
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
💤 Files with no reviewable changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (8)
build.gradle (1)
8-8: 버전 전략 재검토 권장새로운 API 구현에 대해 0.0.1-SNAPSHOT에서 1.0.0으로 바로 올리는 것은 다소 공격적일 수 있습니다. 1.0.0은 일반적으로 안정적이고 프로덕션 준비가 완료된 릴리스를 의미합니다. 초기 구현의 경우 0.1.0이나 0.1.0-SNAPSHOT 같은 버전을 사용하는 것이 더 적절할 수 있습니다.
src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderResponseDto.java (1)
39-53: Stream API 단순화 고려Line 51에서
.collect(Collectors.toList())를 사용하고 있습니다. Java 16 이상에서는 더 간결한.toList()를 사용할 수 있습니다.다음과 같이 수정할 수 있습니다:
- .items(orderItems.stream().map(PurchaseOrderItemDto::from).collect(Collectors.toList())) + .items(orderItems.stream().map(PurchaseOrderItemDto::from).toList())참고:
.toList()는 불변 리스트를 반환하지만, 대부분의 경우 문제없이 사용할 수 있습니다.src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderItemDto.java (1)
22-30: 선택적 리팩토링: 방어적 프로그래밍을 위한 null 체크 추가
PurchaseOrderItemDto.from()메서드는PurchaseOrderResponseDto.from()에서 스트림 처리 시 호출되고 있습니다.orderItems는 주로 repository 쿼리 결과로 제공되므로 현재 null이 발생할 가능성은 낮으나, 방어적 프로그래밍 관점에서 다음과 같은 개선을 권장합니다:public static PurchaseOrderItemDto from(PurchaseOrderItem item) { + if (item == null) { + return null; + } return PurchaseOrderItemDto.builder()또는 더 명시적으로
Objects.requireNonNull()을 사용:+import java.util.Objects; public static PurchaseOrderItemDto from(PurchaseOrderItem item) { + Objects.requireNonNull(item, "PurchaseOrderItem cannot be null"); return PurchaseOrderItemDto.builder()src/main/java/com/sampoom/purchase/api/purchase/entity/PurchaseOrder.java (2)
17-18: 주요 컬럼 제약과 인덱스/유니크 추가 제안
- 주문코드 고유성 보장을 위해 유니크가 필요합니다.
- 조회 빈도 높은 컬럼에 인덱스 권장:
orderAt,status,urgency,factoryId.- 널 불가 제약 추가 권장:
code,orderAt,status,factoryId.적용 예시(diff):
-@Table(name = "purchase_order") +@Table( + name = "purchase_order", + indexes = { + @Index(name = "idx_po_order_at", columnList = "orderAt"), + @Index(name = "idx_po_status", columnList = "status"), + @Index(name = "idx_po_urgency", columnList = "urgency"), + @Index(name = "idx_po_factory_id", columnList = "factoryId") + } +) ... - private String code; - private LocalDateTime orderAt; + @Column(nullable = false, unique = true) + private String code; + @Column(nullable = false) + private LocalDateTime orderAt; ... - @Enumerated(EnumType.STRING) - private OrderStatus status; + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private OrderStatus status; ... - private Long factoryId; + @Column(nullable = false) + private Long factoryId;Also applies to: 30-31, 37-38, 41-51
53-68: 시간 소스 주입으로 테스트 용이성 개선
LocalDateTime.now()대신Clock주입 또는 서비스 계층에서 시간 생성 후 주입을 권장합니다. 재현성 있는 테스트가 쉬워집니다.src/main/java/com/sampoom/purchase/api/purchase/entity/PurchaseOrderItem.java (2)
20-33: 널/도메인 제약 및 인덱스 추가 제안
- 수량/단가/자재정보 컬럼에 널 불가 및 유효성 제약 권장.
- 조인 컬럼(
purchase_order_id) 인덱스 권장.적용 예시(diff):
-@Table(name = "purchase_order_item") +@Table( + name = "purchase_order_item", + indexes = { @Index(name = "idx_poi_order_id", columnList = "purchase_order_id") } +) ... - private Long quantity; + @Column(nullable = false) + private Long quantity; ... - private String materialCode; + @Column(nullable = false, length = 100) + private String materialCode; ... - private String materialName; + @Column(nullable = false, length = 255) + private String materialName; ... - private String unit; + @Column(nullable = false, length = 30) + private String unit; ... - @Column(precision = 19, scale = 2) + @Column(precision = 19, scale = 2, nullable = false) private BigDecimal unitPrice;또한 DTO/컨트롤러 단에
@NotNull,@Positive등의 Bean Validation 추가를 권장합니다.
22-24: 주문 삭제와 품목 수명주기 정합성주문은 소프트 삭제인데 품목은 소프트 삭제가 없습니다. 데이터 정합성을 위해 품목에도 소프트 삭제 적용 또는 ON DELETE CASCADE(물리 삭제) 정책 중 하나를 명확히 하는 것을 권장합니다.
src/main/java/com/sampoom/purchase/api/purchase/controller/PurchaseController.java (1)
26-30: 입력값 검증 추가 권장(@Valid, @min 등)요청 본문/쿼리 파라미터에 Bean Validation 추가를 권장합니다.
예시(diff):
+import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; @@ - public ResponseEntity<ApiResponse<PurchaseOrderResponseDto>> createMaterialOrder( - @RequestBody PurchaseOrderRequestDto requestDto) { + public ResponseEntity<ApiResponse<PurchaseOrderResponseDto>> createMaterialOrder( + @Valid @RequestBody PurchaseOrderRequestDto requestDto) { @@ - @RequestParam(defaultValue = "0") int page, - @RequestParam(defaultValue = "10") int size) { + @Min(0) @RequestParam(defaultValue = "0") int page, + @Min(1) @RequestParam(defaultValue = "10") int size) {Also applies to: 59-65
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
build.gradle(1 hunks)src/main/java/com/sampoom/purchase/api/purchase/controller/PurchaseController.java(1 hunks)src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderItemDto.java(1 hunks)src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderRequestDto.java(1 hunks)src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderResponseDto.java(1 hunks)src/main/java/com/sampoom/purchase/api/purchase/entity/OrderStatus.java(1 hunks)src/main/java/com/sampoom/purchase/api/purchase/entity/PurchaseOrder.java(1 hunks)src/main/java/com/sampoom/purchase/api/purchase/entity/PurchaseOrderItem.java(1 hunks)src/main/java/com/sampoom/purchase/api/purchase/entity/UrgencyLevel.java(1 hunks)src/main/java/com/sampoom/purchase/api/purchase/repository/PurchaseOrderItemRepository.java(1 hunks)src/main/java/com/sampoom/purchase/api/purchase/repository/PurchaseOrderRepository.java(1 hunks)src/main/java/com/sampoom/purchase/api/purchase/service/PurchaseService.java(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
src/main/java/com/sampoom/purchase/api/purchase/entity/PurchaseOrder.java (4)
src/main/java/com/sampoom/purchase/common/exception/BadRequestException.java (1)
BadRequestException(6-19)src/main/java/com/sampoom/purchase/api/purchase/entity/PurchaseOrderItem.java (1)
Entity(8-34)src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderRequestDto.java (1)
Getter(13-28)src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderResponseDto.java (1)
Getter(19-54)
src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderRequestDto.java (2)
src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderItemDto.java (1)
Getter(11-31)src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderResponseDto.java (1)
Getter(19-54)
src/main/java/com/sampoom/purchase/api/purchase/service/PurchaseService.java (1)
src/main/java/com/sampoom/purchase/common/exception/NotFoundException.java (1)
NotFoundException(6-18)
src/main/java/com/sampoom/purchase/api/purchase/entity/PurchaseOrderItem.java (3)
src/main/java/com/sampoom/purchase/api/purchase/entity/PurchaseOrder.java (1)
Entity(15-69)src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderItemDto.java (1)
Getter(11-31)src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderResponseDto.java (1)
Getter(19-54)
src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderResponseDto.java (2)
src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderItemDto.java (1)
Getter(11-31)src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderRequestDto.java (1)
Getter(13-28)
src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderItemDto.java (2)
src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderRequestDto.java (1)
Getter(13-28)src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderResponseDto.java (1)
Getter(19-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (java-kotlin)
🔇 Additional comments (8)
src/main/java/com/sampoom/purchase/api/purchase/entity/OrderStatus.java (1)
4-8: 잘 구현되었습니다주문 상태를 명확하게 정의한 깔끔한 enum입니다. 한글 주석도 적절하게 추가되어 있습니다.
src/main/java/com/sampoom/purchase/api/purchase/entity/UrgencyLevel.java (1)
3-7: 잘 구현되었습니다긴급도를 명확하게 정의한 깔끔한 enum입니다.
src/main/java/com/sampoom/purchase/api/purchase/repository/PurchaseOrderItemRepository.java (1)
8-10: 잘 구현되었습니다Spring Data JPA 네이밍 컨벤션을 올바르게 따른 깔끔한 Repository 인터페이스입니다.
findByPurchaseOrderId메서드는 자동으로 적절한 쿼리를 생성합니다.src/main/java/com/sampoom/purchase/api/purchase/repository/PurchaseOrderRepository.java (2)
27-27: 쿼리 메서드 구현 확인
findTopByCodeStartingWithOrderByCodeDesc메서드는 주어진 prefix로 시작하는 코드 중 가장 최근(내림차순 정렬 시 첫 번째) 주문을 찾습니다. 이는 주문 코드 생성 로직에 사용되는 것으로 보입니다. 메서드 네이밍과 로직이 올바르게 구현되어 있습니다.
16-25: 리뷰 댓글은 부정확합니다 - 코드를 변경할 필요가 없습니다.PurchaseOrder 엔티티를 확인한 결과,
@OneToMany컬렉션이 존재하지 않습니다. 관계는 PurchaseOrderItem에서 PurchaseOrder로 향하는 단방향@ManyToOne관계만 있습니다. 따라서 현재 사용된left join PurchaseOrderItem i on i.purchaseOrder = po구문은 올바르고 필요합니다.리뷰 댓글에서 제시한 대체 방법
left join po.items i는 PurchaseOrder 측에 items 컬렉션이 없으므로 사용할 수 없습니다. 현재 명시적 ON 절을 사용한 구문이 유일한 유효한 옵션입니다.Likely an incorrect or invalid review comment.
src/main/java/com/sampoom/purchase/api/purchase/service/PurchaseService.java (1)
75-81: 마감일 과거값 처리 정책 확인
days <= 1이면 HIGH이므로 과거 날짜(음수)도 HIGH로 분류됩니다. 의도된 정책인지 확인 부탁드립니다.정책이 다르면
days < 0 → HIGH등 명시 조건으로 조정 가능합니다.src/main/java/com/sampoom/purchase/api/purchase/entity/PurchaseOrder.java (2)
3-3: import 경로는 정확합니다 - 리뷰 의견 재검토 필요검증 결과, 해당 import 문은 컴파일 오류가 발생하지 않습니다.
com.sampoom.purchase.common.entitiy.SoftDeleteEntity라는 import 경로는 실제 패키지 구조와 정확히 일치합니다. SoftDeleteEntity.java와 BaseTimeEntity.java의 패키지 선언이 모두com.sampoom.purchase.common.entitiy로 되어 있으므로, import 문은 올바른 위치를 참조하고 있습니다. PurchaseOrder 클래스가 SoftDeleteEntity를 상속하고 있어 해당 import도 정상적으로 사용되고 있습니다."entitiy"라는 철자는 "entity"의 오타로 보이지만, 이는 패키지 디렉토리 구조 전체에 걸친 일관된 명명 규칙이며, import 문이 잘못된 것은 아닙니다.
Likely an incorrect or invalid review comment.
21-23: 컬럼 매핑 검증 완료 - 이슈 없음
SoftDeleteEntity의 필드 정의를 확인한 결과:
deleted필드:@Column(nullable = false)→deleted컬럼으로 매핑deletedAt필드:@Column없음 → Spring Boot 기본 전략에 의해deleted_at컬럼으로 자동 변환 (camelCase → snake_case)
PurchaseOrder의@SQLDelete/@SQLRestriction에서 참조하는"deleted","deleted_at"컬럼명이 실제 매핑과 일치합니다. Spring Boot의 기본SpringPhysicalNamingStrategy가 camelCase를 snake_case로 자동 변환하므로 명시적인@Column(name="deleted_at")선언이 불필요하며, 현재 코드의 컬럼 매핑은 정상입니다.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderRequestDto.java (1)
8-8: 사용하지 않는 import 제거
DateTimeFormatimport가 코드에서 사용되지 않습니다. 이전 리뷰에서@DateTimeFormat어노테이션을 제거했지만 import 문은 남아있는 것으로 보입니다.다음 diff를 적용하여 사용하지 않는 import를 제거하세요:
-import org.springframework.format.annotation.DateTimeFormat;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderRequestDto.java(1 hunks)src/main/java/com/sampoom/purchase/api/purchase/entity/PurchaseOrderItem.java(1 hunks)src/main/java/com/sampoom/purchase/api/purchase/repository/PurchaseOrderItemRepository.java(1 hunks)src/main/java/com/sampoom/purchase/api/purchase/service/PurchaseService.java(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- src/main/java/com/sampoom/purchase/api/purchase/entity/PurchaseOrderItem.java
- src/main/java/com/sampoom/purchase/api/purchase/repository/PurchaseOrderItemRepository.java
- src/main/java/com/sampoom/purchase/api/purchase/service/PurchaseService.java
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderRequestDto.java (2)
src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderItemDto.java (1)
Getter(11-31)src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderResponseDto.java (1)
Getter(19-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (java-kotlin)
🔇 Additional comments (1)
src/main/java/com/sampoom/purchase/api/purchase/dto/PurchaseOrderRequestDto.java (1)
13-27: DTO 구조가 적절합니다클래스 구조와 필드 정의가 잘 되어 있습니다:
- Lombok 어노테이션을 적절히 사용하여 boilerplate 코드를 줄였습니다
@JsonFormat을 통해 날짜 형식을 올바르게 지정했습니다- 필드 타입과 구조가 적절합니다
📝 Summary
🙏 Question & PR point
📬 Reference
Summary by CodeRabbit
New Features
Chores