Skip to content

feat: 발주 템플릿 수정 기능 구현#54

Merged
JoonKyoLee merged 7 commits intomainfrom
feat/update-order-template
Nov 22, 2025
Merged

feat: 발주 템플릿 수정 기능 구현#54
JoonKyoLee merged 7 commits intomainfrom
feat/update-order-template

Conversation

@JoonKyoLee
Copy link
Contributor

@JoonKyoLee JoonKyoLee commented Nov 22, 2025

✨ 작업 내용

  • 발주 템플릿 수정 기능 구현

📝 적용 범위

  • /order/template

📌 참고 사항

Summary by CodeRabbit

  • 새로운 기능
    • 발주 템플릿 수정 API 추가: 제목·본문·활성화 상태 및 발주처 변경으로 템플릿을 수정 가능.
  • 버그 수정 / 개선
    • 발주 템플릿 관련 오류 처리 추가: 템플릿 미존재 및 접근 권한 없음에 대한 명확한 오류 코드와 수정 성공 메시지 추가.
  • 테스트
    • 수정 흐름에 대한 단위 및 컨트롤러 테스트 추가로 정상/예외 시나리오 검증 강화.

✏️ Tip: You can customize this high-level summary in your review settings.

@JoonKyoLee JoonKyoLee self-assigned this Nov 22, 2025
@JoonKyoLee JoonKyoLee added the enhancement New feature or request label Nov 22, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 22, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

발주 템플릿 수정 기능을 추가합니다. PATCH 엔드포인트, 서비스 로직(사용자·공급처·템플릿 검증 후 업데이트), 요청 DTO, 에러/성공 메시지 추가, 리포지토리 패키지 조정 및 관련 컨트롤러·서비스 단위/통합 테스트가 포함됩니다.

Changes

코호트 / 파일(s) 변경 사항
API 응답/오류 정의
src/main/java/com/almang/inventory/global/api/SuccessMessage.java, src/main/java/com/almang/inventory/global/exception/ErrorCode.java
SuccessMessage에 UPDATE_ORDER_TEMPLATE_SUCCESS("발주 템플릿 수정 성공") 추가; ErrorCode에 ORDER_TEMPLATE_NOT_FOUND(HttpStatus.NOT_FOUND, "발주 템플릿을 찾을 수 없습니다.")ORDER_TEMPLATE_ACCESS_DENIED(HttpStatus.FORBIDDEN, "해당 발주처의 발주 템플릿이 아닙니다.") 추가
요청 DTO
src/main/java/com/almang/inventory/order/template/dto/request/UpdateOrderTemplateRequest.java
record UpdateOrderTemplateRequest(@NotNull Long vendorId, String title, String body, Boolean activated) 신규 추가
컨트롤러
src/main/java/com/almang/inventory/order/template/controller/OrderTemplateController.java
PATCH /api/v1/order-template/{orderTemplateId} 엔드포인트 추가 — 요청 검증, 인증 주체 사용, 서비스 호출, 표준 ApiResponse 반환
서비스
src/main/java/com/almang/inventory/order/template/service/OrderTemplateService.java
updateOrderTemplate(Long, UpdateOrderTemplateRequest, Long) 구현 — 사용자/공급처/템플릿 조회 및 권한 검증, 엔티티 업데이트 및 OrderTemplateResponse 반환. 보조 private 조회/검증 메서드 추가
리포지토리 패키지 변경 & import 수선
src/main/java/com/almang/inventory/order/template/repository/OrderTemplateRepository.java, src/main/java/com/almang/inventory/vendor/service/VendorService.java, src/test/.../VendorServiceTest.java
OrderTemplateRepository의 패키지 선언을 ...order.template.repository로 변경하고 그에 따른 import 경로 수정
테스트 — 컨트롤러
src/test/java/com/almang/inventory/order/template/controller/OrderTemplateControllerTest.java
컨트롤러 업데이트 시나리오 테스트 추가: 성공, 템플릿 미존재(404), 검증 실패(400), 사용자 미존재(404)
테스트 — 서비스
src/test/java/com/almang/inventory/order/template/service/OrderTemplateServiceTest.java
서비스 로직 테스트 추가: 성공, 사용자/공급처 미존재, 권한 부족(다른 스토어/다른 공급처), 템플릿 미존재 등

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Controller as OrderTemplateController
    participant Service as OrderTemplateService
    participant UserRepo as UserRepository
    participant VendorRepo as VendorRepository
    participant TemplateRepo as OrderTemplateRepository

    User->>Controller: PATCH /api/v1/order-template/{id} (UpdateOrderTemplateRequest)
    Controller->>Service: updateOrderTemplate(id, request, userId)
    Service->>UserRepo: findById(userId)
    alt user found
        UserRepo-->>Service: User
        Service->>VendorRepo: findById(vendorId)
        alt vendor found
            VendorRepo-->>Service: Vendor
            alt vendor.store == user.store
                Service->>TemplateRepo: findById(templateId)
                alt template found
                    TemplateRepo-->>Service: OrderTemplate
                    alt template.vendor == vendor
                        Service->>Service: orderTemplate.updateTemplate(...)
                        Service-->>Controller: OrderTemplateResponse
                        Controller-->>User: 200 OK + UPDATE_ORDER_TEMPLATE_SUCCESS
                    else access denied
                        Service-->>Controller: BaseException(ORDER_TEMPLATE_ACCESS_DENIED)
                        Controller-->>User: 403 Forbidden
                    end
                else template not found
                    Service-->>Controller: BaseException(ORDER_TEMPLATE_NOT_FOUND)
                    Controller-->>User: 404 Not Found
                end
            else vendor access denied
                Service-->>Controller: BaseException(VENDOR_ACCESS_DENIED)
                Controller-->>User: 403 Forbidden
            end
        else vendor not found
            Service-->>Controller: BaseException(VENDOR_NOT_FOUND)
            Controller-->>User: 404 Not Found
        end
    else user not found
        Service-->>Controller: BaseException(USER_NOT_FOUND)
        Controller-->>User: 404 Not Found
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

검토 시 우선 확인할 항목:

  • OrderTemplateService
    • 권한 경계(스토어 소속 검사 vs 템플릿 소유자 검사)가 요구사항과 정확히 일치하는지 확인하세요.
    • find...ById... 메서드들이 던지는 예외 코드와 컨트롤러의 응답 매핑이 일관된지 점검하세요.
  • 트랜잭션 경계
    • 업데이트 메서드에 @Transactional 적절성(쓰기 전파, 롤백 정책) 확인.
  • 리포지토리 패키지 변경
    • 패키지 이동으로 인한 다른 클래스들의 import 누락/빌드 오류 가능성 점검.
  • 테스트
    • 단위 테스트에서 Mock/실제 레포지토리 사용 혼합 여부와 테스트 격리 확인.

권장 참조:

짧게: 컨벤션과 예외 매핑만 확인하면 됩니다 — 잘했습니다. 😉

Possibly related PRs

Poem

작은 PATCH가 길을 열면,
권한은 단단히, 로그는 친절히,
테스트는 듬뿍, 에러는 명확히,
템플릿은 고쳐지고 서비스는 웃네 — 🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 '발주 템플릿 수정 기능 구현'으로 변경 내용의 핵심을 명확하게 반영하고 있습니다.
Description check ✅ Passed PR 설명이 템플릿의 필수 섹션(작업 내용, 적용 범위, 참고 사항)을 모두 포함하고 있습니다.
Linked Issues check ✅ Passed PR의 모든 코드 변경사항이 #51 이슈의 '발주 템플릿 수정 기능' 구현 목표를 충족합니다.
Out of Scope Changes check ✅ Passed OrderTemplateRepository 패키지 이동과 관련 import 업데이트는 구조 정리로서 기능 구현과 밀접하게 연관되어 있습니다.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b79c4c8 and d78fd5b.

📒 Files selected for processing (1)
  • src/main/java/com/almang/inventory/order/template/service/OrderTemplateService.java (1 hunks)

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

🧹 Nitpick comments (3)
src/test/java/com/almang/inventory/order/template/service/OrderTemplateServiceTest.java (1)

27-258: 서비스 레이어 성공/실패 플로우가 잘 커버되어 있습니다.

성공 케이스부터 USER_NOT_FOUND, VENDOR_NOT_FOUND, VENDOR_ACCESS_DENIED, ORDER_TEMPLATE_NOT_FOUND, ORDER_TEMPLATE_ACCESS_DENIED까지 핵심 분기들이 모두 테스트되어 있어서 회귀를 잡는 데 도움이 많이 될 것 같습니다. newStore/newUser/newVendor/newOrderTemplate 헬퍼 메서드로 픽스처를 정리해 둔 것도 읽기 좋아요.

자잘한 부분으로는, 다른_상점_발주처면_발주_템플릿_수정시_접근이_거부된다 테스트에서 생성한 store2User는 사용되지 않으니 제거하면 더 깔끔해집니다. 또, 유사한 예외 테스트들이 많으니 나중에 여유가 생기면 파라미터라이즈드 테스트로 정리해 보는 것도 유지보수에 도움이 될 것 같습니다.

src/test/java/com/almang/inventory/order/template/controller/OrderTemplateControllerTest.java (1)

31-167: 컨트롤러 단 HTTP 플로우 테스트 구성이 좋습니다.

200/404/400 응답, 메시지, data 필드 존재 여부까지 모두 검증하고 있어서 API 계약이 깨지는 걸 잘 잡아줄 것 같습니다. @WebMvcTest + @MockitoBean 조합도 적절하게 사용하셨네요.

다만 발주_템플릿_수정_요청값_검증에_실패하면_예외가_발생한다 테스트는 실제로는 vendorId@NotNull에만 의존하고 있으니, 제목/본문에 추가 제약을 둘 계획이라면 그에 맞는 별도 테스트를 추가해 주면 더 명확해질 것 같습니다(예: 빈 문자열일 때 @NotBlank 위반을 기대하는 테스트 등). 또, 나중에 여유가 생기면 ORDER_TEMPLATE_ACCESS_DENIED에 대한 403 응답 케이스도 컨트롤러 단에서 한 번 더 검증해 두면 전체 에러 핸들링 일관성을 확인하는 데 도움이 되겠습니다.

src/main/java/com/almang/inventory/order/template/controller/OrderTemplateController.java (1)

31-45: 엔드포인트 설계와 서비스 연동이 전반적으로 잘 정리되어 있습니다.

PATCH /api/v1/order-template/{orderTemplateId} + @Valid DTO + CustomUserPrincipal 조합이 기존 구조와 자연스럽게 맞고, ApiResponse.success(SuccessMessage.UPDATE_ORDER_TEMPLATE_SUCCESS...)로 응답 형식도 일관성을 유지하고 있습니다. 로그에 userId, orderTemplateId를 남기는 것도 추적에 유용해 보입니다.

설계 관점에서 한 가지만 참고용으로 말씀드리면, 현재는 orderTemplateId(path) + vendorId(body)를 모두 받아서 서비스에서 교차 검증을 하고 있는데, 템플릿의 소속 발주처/상점은 orderTemplateId만으로도 역으로 찾아갈 수 있으므로, 장기적으로는 body에서 vendorId를 제거하고 service에서 템플릿 → 발주처 → 상점 순으로 권한을 검증하는 구조도 고려해볼 수 있습니다. 지금 구조가 이미 다른 API들과 맞춰진 것이라면 유지하셔도 무방합니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5d54860 and c7481e9.

📒 Files selected for processing (7)
  • src/main/java/com/almang/inventory/global/api/SuccessMessage.java (1 hunks)
  • src/main/java/com/almang/inventory/global/exception/ErrorCode.java (1 hunks)
  • src/main/java/com/almang/inventory/order/template/controller/OrderTemplateController.java (1 hunks)
  • src/main/java/com/almang/inventory/order/template/dto/request/UpdateOrderTemplateRequest.java (1 hunks)
  • src/main/java/com/almang/inventory/order/template/service/OrderTemplateService.java (1 hunks)
  • src/test/java/com/almang/inventory/order/template/controller/OrderTemplateControllerTest.java (1 hunks)
  • src/test/java/com/almang/inventory/order/template/service/OrderTemplateServiceTest.java (1 hunks)
🔇 Additional comments (2)
src/main/java/com/almang/inventory/global/api/SuccessMessage.java (1)

36-39: 발주 템플릿 수정 성공 메시지 추가가 기존 패턴과 잘 맞습니다.

CREATE_ORDER_TEMPLATE_SUCCESS와 짝을 이루는 UPDATE_ORDER_TEMPLATE_SUCCESS를 분리해서 두니, 도메인별 성공 메시지 관리가 한눈에 들어옵니다. 컨트롤러/서비스에서 공통 메시지로 재사용하기에도 좋아 보여요.

src/main/java/com/almang/inventory/global/exception/ErrorCode.java (1)

33-38: 발주 템플릿 전용 에러 코드 분리가 깔끔합니다.

*_NOT_FOUND, *_ACCESS_DENIED 패턴을 그대로 따라가서, 서비스 레이어에서 어떤 상황에서 어떤 에러가 날지 읽기 쉽습니다. 향후 ORDER 관련 에러가 늘어나도 이 섹션에만 추가하면 되어 유지보수성이 좋겠습니다.

Comment on lines +1 to +10
package com.almang.inventory.order.template.dto.request;

import jakarta.validation.constraints.NotNull;

public record UpdateOrderTemplateRequest(
@NotNull Long vendorId,
String title,
String body,
Boolean activated
) {}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

activated 필드의 null 허용/검증 규칙을 명확히 하는 게 좋습니다.

현재 DTO는 vendorId@NotNull이고, title, body, activated는 nullable입니다. 그런데 OrderTemplateService.updateOrderTemplate에서 orderTemplate.updateTemplate(request.title(), request.body(), request.activated());로 바로 넘기고 있어서, activated가 null인 요청이 들어오면 오토 언박싱이나 엔티티 필드 타입에 따라 NPE가 발생할 수 있습니다(자바에서 Booleanboolean 변환 시 null이면 NPE).
선택지는 크게 두 가지로 보입니다.

  • 전체 필드 필수 업데이트 모델이라면
    activated에도 검증을 맞추는 쪽이 자연스럽습니다.
    public record UpdateOrderTemplateRequest(
            @NotNull Long vendorId,
            String title,
            String body,
  •     Boolean activated
    
  •     @NotNull Boolean activated
    
    ) {}
    혹은 타입을 `boolean`으로 바꾸어 null 자체를 허용하지 않는 방식도 가능합니다.
    
    
  • 진짜 부분 업데이트(PATCH)로 설계한다면
    activated가 null일 수 있다는 걸 서비스/엔티티에서 명시적으로 처리해야 합니다.
    if (request.activated() != null) {
        orderTemplate.changeActivated(request.activated());
    }
    처럼 필드별로 업데이트 여부를 분리하는 식입니다.

또, 생성용 DTO가 이미 있다면 그쪽 검증 규칙과 맞추어 두면 클라이언트 입장에서도 제약을 예측하기 쉬울 것 같습니다.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 발주 템플릿 수정

1 participant