[STK5-07] 주문 정정·취소 API

작업 내용 (설계 의도)

변경 사항

STK5-06(주문 접수)으로 생성된 주문을 정정하거나 취소하는 API를 구현한다. Order Entity의 상태 전이(OrderStatus.canTransitTo)가 STK5-03에서 이미 구현되어 있으므로, 이 티켓은 UseCase·Controller 레이어에 집중한다.

CUD 처리 원칙 (ADR-502): Toss API 성공 → MySQL UPDATE. Toss 실패 시 예외 전파, MySQL 미변경.

구성 범위:

  • application UseCase: CorrectOrderUseCase, CancelOrderUseCase
  • application command: CorrectOrderCommand
  • presentation: OrderApiController에 엔드포인트 2개 추가
  • application response: CorrectOrderResponse

API 엔드포인트:

  • PATCH /api/v1/orders/{id} — 주문 정정 (수량·가격 변경). PENDING·CORRECTED 상태만 허용.
  • DELETE /api/v1/orders/{id} — 주문 취소. PENDING·CORRECTED 상태만 허용. 204 No Content.

다이어그램

처리 흐름 (정정)

sequenceDiagram
    participant C as OrderApiController
    participant U as CorrectOrderUseCase
    participant D as OrderDomainService
    participant G as OrderGateway
    participant R as OrderRepository
    C->>U: execute(CorrectOrderCommand)
    U->>D: correctOrder(command)
    D->>R: findBy(id)
    R-->>D: Order
    alt 상태 전이 불가 (COMPLETED / CANCELLED)
        D-->>U: InvalidOrderStateException
        U-->>C: 400
    else 전이 가능 (PENDING / CORRECTED)
        D->>G: correctOrder(tossOrderId, quantity, price)
        alt Toss 성공
            G-->>D: OK
            D->>D: order.correct(quantity, price)
            D->>R: save(Order CORRECTED)
            D-->>U: Order
            U-->>C: 200 CorrectOrderResponse
        else Toss 실패
            G-->>D: TossApiException
            D-->>U: 예외 전파 (MySQL 미변경)
            U-->>C: 500
        end
    end

처리 흐름 (취소)

sequenceDiagram
    participant C as OrderApiController
    participant U as CancelOrderUseCase
    participant D as OrderDomainService
    participant G as OrderGateway
    participant R as OrderRepository
    C->>U: execute(id)
    U->>D: cancelOrder(id)
    D->>R: findBy(id)
    R-->>D: Order
    alt 상태 전이 불가
        D-->>U: InvalidOrderStateException
        U-->>C: 400
    else 전이 가능
        D->>G: cancelOrder(tossOrderId)
        alt Toss 성공
            G-->>D: OK
            D->>D: order.cancel()
            D->>R: save(Order CANCELLED)
            D-->>U: void
            U-->>C: 204 No Content
        else Toss 실패
            G-->>D: TossApiException
            D-->>U: 예외 전파 (MySQL 미변경)
            U-->>C: 500
        end
    end

클래스 의존

flowchart LR
    subgraph Presentation["presentation"]
        OC[OrderApiController]
    end
    subgraph Application["application"]
        COU[CorrectOrderUseCase]
        CAU[CancelOrderUseCase]
        COC[CorrectOrderCommand]
        COR[CorrectOrderResponse]
    end
    subgraph Domain["domain"]
        ODS[OrderDomainService]
        OGW[OrderGateway]
        OR[OrderRepository]
        O[Order Entity]
        OS[OrderStatus]
    end
    subgraph Infra["infrastructure"]
        TOG[TossOrderGateway]
        ORI[OrderRepositoryImpl]
    end
    OC --> COU
    OC --> CAU
    COU --> ODS
    CAU --> ODS
    ODS --> OGW
    ODS --> OR
    ODS --> O
    O --> OS
    TOG -.->|implements| OGW
    ORI -.->|implements| OR

테스트 케이스

  • CANCELLED 상태의 주문에 PATCH /api/v1/orders/{id}를 요청하면 Toss API를 호출하지 않고 400을 반환한다.
  • COMPLETED 상태의 주문에 DELETE /api/v1/orders/{id}를 요청하면 Toss API를 호출하지 않고 400을 반환한다.
  • PENDING 상태의 주문 정정 성공 시 MySQL 상태가 CORRECTED로 변경되고 200을 반환한다.
  • CORRECTED 상태의 주문 취소 성공 시 MySQL 상태가 CANCELLED로 변경되고 204를 반환한다.
  • Toss 정정 API가 실패할 때 MySQL 주문 상태는 변경되지 않는다.
  • 존재하지 않는 주문 ID로 정정 요청 시 404를 반환한다.