Conversation
Walkthrough상점의 발주 템플릿 목록을 페이지네이션과 필터링(활성화 상태)을 지원하며 조회하는 기능을 구현합니다. 컨트롤러, 서비스, 레포지토리 계층에 새로운 메서드들을 추가하고 관련 테스트 케이스를 작성했습니다. Changes
Sequence DiagramsequenceDiagram
participant Client
participant StoreController
participant StoreService
participant PaginationUtil
participant OrderTemplateRepository
participant Database
Client->>StoreController: GET /api/v1/store/order-templates<br/>(page, size, activated)
activate StoreController
StoreController->>StoreService: getStoreOrderTemplateList<br/>(userId, page, size, activated)
activate StoreService
StoreService->>PaginationUtil: getPageRequest(page, size)
activate PaginationUtil
PaginationUtil-->>StoreService: PageRequest
deactivate PaginationUtil
alt activated == null
StoreService->>OrderTemplateRepository: findAllByVendorStoreId(storeId, pageable)
else activated == true
StoreService->>OrderTemplateRepository: findAllByVendorStoreIdAndActivatedTrue(storeId, pageable)
else activated == false
StoreService->>OrderTemplateRepository: findAllByVendorStoreIdAndActivatedFalse(storeId, pageable)
end
activate OrderTemplateRepository
OrderTemplateRepository->>Database: Query
activate Database
Database-->>OrderTemplateRepository: Page<OrderTemplate>
deactivate Database
deactivate OrderTemplateRepository
StoreService->>StoreService: Map to OrderTemplateResponse
StoreService->>StoreService: Wrap in PageResponse
StoreService-->>StoreController: PageResponse<OrderTemplateResponse>
deactivate StoreService
StoreController-->>Client: ApiResponse<PageResponse<OrderTemplateResponse>><br/>(GET_STORE_ORDER_TEMPLATE_SUCCESS)
deactivate StoreController
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 분 추가 주의 사항:
Possibly related issues
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (3 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/store/controller/StoreController.java (1)
50-67: 새 엔드포인트 구현 잘 되었습니다!전반적으로 기존 패턴을 잘 따르고 있으며, 인증/로깅/응답 포맷이 일관성 있게 구현되어 있습니다.
다만, Swagger 문서화 개선을 위해
@Parameter어노테이션을 추가하는 것을 권장합니다:@GetMapping("/order-templates") @Operation(summary = "상점 발주 템플릿 목록 조회", description = "현재 상점에 속한 모든 발주 템플릿을 조회합니다.") + @Parameter(name = "page", description = "페이지 번호 (기본값: 1)", example = "1") + @Parameter(name = "size", description = "페이지 크기 (기본값: 20)", example = "20") + @Parameter(name = "activated", description = "활성화 상태 필터 (true: 활성, false: 비활성, null: 전체)", example = "true") public ResponseEntity<ApiResponse<PageResponse<OrderTemplateResponse>>> getStoreOrderTemplates( @AuthenticationPrincipal CustomUserPrincipal userPrincipal, @RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "size", required = false) Integer size, @RequestParam(value = "activated", required = false) Boolean activated ) {필요한 import:
import io.swagger.v3.oas.annotations.Parameter;src/test/java/com/almang/inventory/store/controller/StoreControllerTest.java (1)
130-229: 테스트 커버리지 훌륭합니다! 🎯주요 시나리오(정상 조회, 활성/비활성 필터, 예외 처리)가 모두 커버되어 있습니다.
추가로 고려해볼 만한 엣지 케이스 테스트를 제안합니다 (선택사항):
- 빈 결과 처리: 템플릿이 없는 상점의 조회
- 페이지네이션 엣지 케이스:
- 음수 페이지/사이즈 입력
- 존재하지 않는 페이지 번호 (예: page=999)
- 필터 조합: 활성 필터 + 페이지네이션 조합
이러한 테스트들은 프로덕션 환경에서 발생할 수 있는 예상치 못한 동작을 사전에 검증하는 데 도움이 됩니다.
src/test/java/com/almang/inventory/store/service/StoreServiceTest.java (1)
261-345: 통합 테스트 시나리오 잘 구성되었습니다!전체 조회, 활성/비활성 필터링, 예외 처리까지 핵심 시나리오가 모두 검증되고 있습니다. 페이지네이션 메타데이터(page, size, totalElements) 검증도 꼼꼼하게 되어 있네요.
추가로 보안 측면에서 교차 상점 격리 테스트를 권장합니다:
@Test void 다른_상점의_발주_템플릿은_조회되지_않는다() { // given Store store1 = newStore(); Store store2 = storeRepository.save( Store.builder() .name("다른 상점") .isActivate(true) .defaultCountCheckThreshold(BigDecimal.valueOf(0.2)) .build() ); User userOfStore1 = newUser(store1); Vendor vendorOfStore1 = newVendor(store1, "상점1 발주처"); Vendor vendorOfStore2 = newVendor(store2, "상점2 발주처"); newOrderTemplate(vendorOfStore1, "상점1 템플릿", true); newOrderTemplate(vendorOfStore2, "상점2 템플릿", true); // when PageResponse<OrderTemplateResponse> response = storeService.getStoreOrderTemplateList(userOfStore1.getId(), 1, 20, null); // then assertThat(response.content()).hasSize(1); assertThat(response.content().get(0).title()).isEqualTo("상점1 템플릿"); }이 테스트는 다른 상점의 템플릿이 노출되지 않는지 검증하여 데이터 격리가 올바르게 작동하는지 확인합니다.
src/main/java/com/almang/inventory/order/template/repository/OrderTemplateRepository.java (1)
11-23: 발주처 기준 쿼리도 페이지네이션 고려해보세요현재 상점 기준 쿼리는 페이지네이션을 지원하지만, 발주처 기준 쿼리(Lines 12-16)는
List를 반환합니다.만약 한 발주처에 템플릿이 수백 개 이상 존재할 가능성이 있다면, 발주처 기준 쿼리도 페이지네이션을 지원하도록 오버로드 메서드를 추가하는 것을 고려해보세요:
// 발주처 기준 - 페이지네이션 지원 Page<OrderTemplate> findAllByVendorId(Long vendorId, Pageable pageable); Page<OrderTemplate> findAllByVendorIdAndActivatedTrue(Long vendorId, Pageable pageable); Page<OrderTemplate> findAllByVendorIdAndActivatedFalse(Long vendorId, Pageable pageable);다만 현재 비즈니스 요구사항에서 필요하지 않다면 나중에 추가해도 무방합니다.
src/test/java/com/almang/inventory/vendor/service/VendorServiceTest.java (1)
806-814: 네이밍 규칙 일관성 검토 및 확인 완료검증 결과, 데이터베이스 레벨에서
username필드에unique=true제약조건이 설정되어 있으므로 사용자명 중복으로 인한 테스트 실패는 발생하지 않습니다. 각 테스트는 독립적인 상점과 사용자를 생성하므로 테스트 격리도 정상적으로 작동합니다.다만, 기존 store2 관련 사용자들이 모두
"tester_store2","detail_tester_store2","template_tester2"처럼"_store2"접미사를 따르는 반면,"template_viewer"는 이 규칙을 벗어나 있습니다. 코드의 일관성을 위해 다른 store2 사용자들과 동일한 네이밍 패턴을 따르는 것을 권장합니다:제안:
"template_viewer_store2"로 유지하거나, 의도된 변경이라면 다른 store2 사용자명들도 동일하게 리팩토링하는 것이 좋습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
src/main/java/com/almang/inventory/global/api/SuccessMessage.java(1 hunks)src/main/java/com/almang/inventory/order/template/repository/OrderTemplateRepository.java(1 hunks)src/main/java/com/almang/inventory/store/controller/StoreController.java(2 hunks)src/main/java/com/almang/inventory/store/service/StoreService.java(5 hunks)src/test/java/com/almang/inventory/store/controller/StoreControllerTest.java(2 hunks)src/test/java/com/almang/inventory/store/service/StoreServiceTest.java(4 hunks)src/test/java/com/almang/inventory/vendor/service/VendorServiceTest.java(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-20T10:43:47.489Z
Learnt from: JoonKyoLee
Repo: almang2/inventory-server PR: 33
File: src/main/java/com/almang/inventory/product/domain/Product.java:62-66
Timestamp: 2025-11-20T10:43:47.489Z
Learning: In the almang2/inventory-server repository, Product entity update methods (e.g., updateVendor in src/main/java/com/almang/inventory/product/domain/Product.java) do not require null checks on vendor parameters because ProductService validates vendor existence via findVendorByIdAndValidateAccess before calling update methods, and the vendor field has nullable=false constraint ensuring this.vendor is never null for persisted entities.
Applied to files:
src/test/java/com/almang/inventory/vendor/service/VendorServiceTest.javasrc/test/java/com/almang/inventory/store/service/StoreServiceTest.javasrc/main/java/com/almang/inventory/store/controller/StoreController.java
🧬 Code graph analysis (1)
src/main/java/com/almang/inventory/store/service/StoreService.java (1)
src/main/java/com/almang/inventory/global/util/PaginationUtil.java (1)
PaginationUtil(7-17)
🔇 Additional comments (5)
src/main/java/com/almang/inventory/global/api/SuccessMessage.java (1)
12-12: 새 성공 메시지 추가 LGTM!상점의 발주 템플릿 조회 성공 메시지가 적절히 추가되었습니다. 네이밍과 위치가 기존 패턴과 일관성 있게 유지되고 있습니다.
src/test/java/com/almang/inventory/store/service/StoreServiceTest.java (1)
62-84: 헬퍼 메서드 추가 깔끔합니다!테스트 데이터 생성을 위한
newVendor와newOrderTemplate메서드가 재사용성 있게 잘 구현되었습니다. 매개변수를 받아 유연하게 사용할 수 있는 구조가 좋습니다.src/main/java/com/almang/inventory/store/service/StoreService.java (2)
56-70: 서비스 메서드 구현 잘 되었습니다!사용자 검증, 페이지네이션 처리, 엔티티-DTO 매핑, 로깅까지 모든 레이어가 깔끔하게 구현되었습니다.
@Transactional(readOnly = true)사용으로 읽기 최적화도 잘 되어 있네요.한 가지 질문이 있습니다:
정렬 기준 선택에 대한 확인
Line 64에서
PaginationUtil.createPageRequest(page, size, "title")를 사용하여title기준 오름차순 정렬을 하고 있습니다.발주 템플릿 목록 조회 시 정렬 기준으로
title이 적절한가요? 일반적으로는:
- 생성일시 역순 (
createdAt DESC): 최신 템플릿을 먼저 보여줌- 수정일시 역순 (
updatedAt DESC): 최근 수정된 템플릿을 먼저 보여줌- 사용 빈도순: 자주 사용하는 템플릿을 먼저 보여줌
와 같은 기준이 사용자 경험(UX) 관점에서 더 유용할 수 있습니다. 제품 기획 의도를 확인해주세요.
만약 OrderTemplate 엔티티에 createdAt 필드가 있다면:
PageRequest pageable = PaginationUtil.createPageRequest(page, size, "createdAt");그리고 PaginationUtil에서 Direction을 DESC로 변경하거나, createPageRequest 메서드에 Direction 파라미터를 추가하는 것을 고려해보세요.
90-103: 필터링 로직 명확하고 좋습니다!null 체크와 Boolean.TRUE.equals() 사용으로 NPE를 방지하면서도 코드가 읽기 쉽게 작성되었습니다.
src/main/java/com/almang/inventory/order/template/repository/OrderTemplateRepository.java (1)
18-23:vendors테이블의store_id컬럼에 인덱스를 추가하세요.현재
Vendor.java의store_idFK에 명시적 인덱스 정의가 없으며, 리포지토리 코드베이스 전체에서도@Index어노테이션을 사용하지 않고 있습니다.findAllByVendorStoreId*쿼리들이 대규모 데이터셋에서 Full Table Scan을 유발할 수 있습니다.개선 방법:
Vendor 엔티티의
@Table어노테이션에 인덱스를 정의하세요:@Table(name = "vendors", indexes = { @Index(name = "idx_vendor_store_id", columnList = "store_id") })또는 개별 컬럼에 정의:
@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "store_id", nullable = false) @Index(name = "idx_vendor_store_id") private Store store;참고:
- Spring Data JPA
@Index는 Hibernate가 자동으로 DDL에 포함시킵니다- FK 컬럼은 자동으로 인덱싱되지 않으므로 명시적 정의가 필요합니다
- Hibernate 공식 문서 참조
✨ 작업 내용
📝 적용 범위
/store📌 참고 사항
Summary by CodeRabbit
릴리스 노트
새로운 기능
테스트
✏️ Tip: You can customize this high-level summary in your review settings.