MAKITTHandoff
Handoff Boards
finishedorder-admin-revamp

Order Admin Revamp — Handoff Board

Order Admin Revamp — Handoff Board

Status: Closed 2026-05-11 — backbone + UI + E2E (자동 walker 10/10 + click-through 10/10) 통과. 잔여 4건은 README "Known Residuals" 참조.

본 spec 의 AI ↔ Human 핸드오프 인박스. 작업자가 진척 / 차단 / 검증 요청을 여기에 적는다. Step 1 ~ 시나리오 합의 ~ 서버/클라 구현 완료 + 자동 UI 풀루프 (10/10) 통과 (2026-05-09).

스크립트:

  • scripts/e2e/order-admin-revamp-seed.mjs — customer 1명 + 10 주문 슬롯 시드 (manual login 0)
  • scripts/e2e/admin-web-walk.mjs — admin token cookie inject + henriette shop autoselect + /merchant/orders 풀루프
SlotServer statusUI 카드UI 셀러 액션 (count)Server 매칭
1 PAYMENT_PENDINGPAYMENT_PENDING7/103 ✅MANUAL_COMPLETE_PAYMENT / MARK_PAYMENT_FAILED / ADD_NOTE
2 PAIDPAID7/105 ✅START_PROCESSING / MARK_SHIPPED / CANCEL_BY_SELLER / REFUND_FULL / ADD_NOTE
3 PROCESSINGPROCESSING7/104 ✅MARK_SHIPPED / CANCEL_BY_SELLER / REFUND_FULL / ADD_NOTE
4 SHIPPEDSHIPPED7/103 ✅UPDATE_TRACKING / MARK_DELIVERED / ADD_NOTE
5 DELIVEREDDELIVERED7/103 ✅REFUND_FULL / REFUND_PARTIAL / ADD_NOTE
6 CANCEL_REQUESTEDCANCEL_REQUESTED8/103 ✅APPROVE_CANCEL / REJECT_CANCEL / ADD_NOTE
7 RETURN_REQUESTEDRETURN_REQUESTED8/103 ✅APPROVE_RETURN / REJECT_RETURN / ADD_NOTE
8 EXCHANGE_REQUESTEDEXCHANGE_REQUESTED8/103 ✅APPROVE_EXCHANGE / REJECT_EXCHANGE / ADD_NOTE
9 CANCELEDCANCELED8/101 ✅ADD_NOTE (only)
10 DELIVERED + partial refund 시도DELIVERED8/103 ✅REFUND_FULL / REFUND_PARTIAL / ADD_NOTE

UI ↔ server 매칭 100% (10/10).

cards 7~8/10 의 의미: claim/refundRecords/discount/fulfillment 카드는 데이터 없을 때 conditional 미렌더 (정상). meta/customer/shipping/lineItems/pricing/payment/sellerNotes 7개는 항상.

스크린샷: /tmp/admin-revamp-shots/{before,detail}__slot*__order_*.png (20장)

스크립트: scripts/e2e/admin-web-click-through.mjs — 각 슬롯별 1개 액션 실제 UI click + 다이얼로그 입력 + 저장 + server diff 검증.

SlotActionStart → EndVerdict
1 PAYMENT_PENDINGMANUAL_COMPLETE_PAYMENT (confirm only)PAYMENT_PENDING → PAID✅ status 전이
2 PAIDADD_NOTEnotes 0→1✅
3 PROCESSINGADD_NOTEnotes 1→2✅
4 SHIPPEDUPDATE_TRACKING (carrier=한진택배 + number)notes 2→3 (SYSTEM audit 자동 기록)✅
5 DELIVEREDADD_NOTEnotes 3→4✅
6 CANCEL_REQUESTEDREJECT_CANCEL (reason 필드)CANCEL_REQUESTED → PAID (이전 상태 복귀)✅
7 RETURN_REQUESTEDAPPROVE_RETURN (confirm only)RETURN_REQUESTED → RETURN_APPROVED✅
8 EXCHANGE_REQUESTEDAPPROVE_EXCHANGE (confirm only)EXCHANGE_REQUESTED → EXCHANGE_APPROVED✅
9 CANCELEDADD_NOTEnotes 1→2 (terminal 메모)✅
10 DELIVERED + 부분환불REFUND_PARTIAL (라인 1개 qty=1, amount=1000)refundRecords 1→2, latest=FAILED/PARTIAL/1000✅ ledger 적재

slot10 의 latest refund=FAILED 는 의도된 동작: RefundDispatcher 가 MANUAL processor 를 default → UNSUPPORTED_PROCESSOR_MANUAL 로 분기 → 실 PG 안 호출, RefundRecord FAILED 로 ledger 정상 기록. PG 트랙 합류 시 MANUAL 라우팅 추가하거나 stub adapter binding 하면 SUCCESS 됨.

스크린샷: /tmp/admin-revamp-click/{slot}__{01_detail,02_dialog,03_filled,04_after}.png (40장)

  • 고객 mypage 일관성 — SHIPPED 처리 후 고객 mypage 에서 송장 조회 (shop-api 응답 일관성)
  • consumer 신규 event 처리 — OrderShippedBySeller / OrderRefunded / OrderTrackingUpdatedBySeller 등이 messaging rule + 적립금 회수 후속 흐름까지 영향
  • REFUND_PARTIAL 누적 정합 — 두 번째 부분환불 + 라인 refundedQuantity 누적. 현재는 RefundDispatcher 가 MANUAL 라우팅 미지원이라 실제 누적 검증 미완 (PG 트랙 합류 후 또는 stub fallback 추가 후)
  • list 정렬/기간 필터 server-side — controller 가 받지만 OrderSearchService 미활용 (open item)
  • operator 식별 자동 주입 — admin 인증 필터 attribute 로 user/email 채워지면 audit 의 actor 자동 기록
  • S11 Argo 자동 콜백 ↔ 셀러 수동 우선순위 — 합의 후 구현
  • 이번 spec 닫기 결정 — finished/ 이동 vs ongoing 유지 (위 후속 중 일부 닫고 가야 할지 사용자 결정)

🔍 2026-05-07 시점 검증해야 할 것들 — web api consumer 재시작 완료. 작업자 본인 ID/email 으로 admin web 어드민 로그인 후 진행:

  • list 페이지 진입 — /merchant/orders

    • 한국어 상태 라벨 / 가격 한국어 통화 포맷 / 주문번호 / 상품 thumbnail+이름 / 결제수단 / 송장번호 컬럼 노출 여부
    • 필터 칩: 20 status 모두 보이는지, 클릭하면 서버 필터 동작
    • 검색: 주문번호, 이메일, 상품명, 송장번호 입력 시 server-side 필터
    • 페이지네이션 정상
  • detail 모달 진입 — 주문 row 클릭

    • 셀러 액션 바: 상태별 가능 액션 버튼 노출 (예: PAID 라면 START_PROCESSING / MARK_SHIPPED / CANCEL_BY_SELLER / REFUND_FULL / ADD_NOTE)
    • 주문 정보 카드 / 주문자(customerSnapshot) 카드 / 배송지+옵션 카드 / 주문 상품 / 가격 (모든 formatted KRW) / 할인 적용 / 결제 / Fulfillment / Claim / RefundRecords / SellerNotes 모든 섹션 채워짐
    • 환불 / 취소 / 메모 audit 누적
  • S1: 정상 풀루프 — PAID 주문 detail → "운송장 입력" → carrier 선택 + 번호 → 저장. status SHIPPED, 추가 액션 (UPDATE_TRACKING / MARK_DELIVERED) 노출. consumer 로그에 OrderShippedBySeller event.

  • S2: 직권 취소 — PAID 주문 → "주문 취소 (직권)" → 사유 입력. CANCELED 전이 + 환불 누적 + RefundRecord 1건 + OrderRefunded/OrderCanceledBySeller event.

  • S3: 고객 취소 요청 → 셀러 승인 — 사용자가 mypage 에서 취소 요청 → 어드민 detail activeClaim 카드 노출 → "취소 승인" 버튼 → CANCELED + 환불.

  • S4: 고객 취소 요청 → 셀러 거절 — "취소 거절" → 이전 상태 복귀 + claim REJECTED.

  • S5: 부분환불 — DELIVERED 주문 → "부분 환불" → 라인 1개 50% → reason. RefundRecord append + line.refundedQuantity 갱신 + OrderPartialRefunded event.

  • S6: 반품 풀루프 (DELIVERED → RETURN_REQUESTED → APPROVE → PICKUP → RETURNED → REFUND_PROCESSING → REFUNDED).

  • S7: 교환 풀루프.

  • S8: 송장 수정 (UPDATE_TRACKING).

  • S9: 메모 audit (ADD_NOTE 셀러 / SYSTEM 자동).

  • S10: list 검색/필터/정렬 종합.

  • S11 결정 후 검증 — Argo 자동 콜백 vs 셀러 수동 입력 우선순위 합의.

2026-05-07

  • ✅ Step 1 surface dump → surface-diff.md
  • ✅ E2E 시나리오 (S1~S11) 합의 → scenarios.md
  • ✅ Seller action catalog → seller-actions.md
  • ✅ 결정 게이트: RefundRecord 신설 / RefundPort+Stub / Payment 별도 entity (이미 있음, snapshot read 편의 유지) / Argo 우선순위 추후
  • ✅ 서버 구현 완료:
    • SellerAction enum + OrderStatus.sellerActions() SSOT
    • OrderResponseVo.availableSellerActions 추가
    • RefundRecord 엔티티 + Repository + Service
    • OrderNote 엔티티 (audit append-only)
    • RefundPort interface + StubRefundAdapter
    • RefundApplication (orchestrate)
    • OrderNoteApplication
    • SellerActionApplication (단일 dispatch)
    • 신규 platform events: OrderShippedBySeller / OrderTrackingUpdatedBySeller / OrderCanceledBySeller / OrderRefunded / OrderPartialRefunded
    • admin DTO 정상화: AdminOrderResponse / AdminOrderListResponse / AdminOrderSummaryDto 와 sub DTO 들 (rich, shop-api parity + admin 확장)
    • 새 endpoint: POST /seller-actions/{action} + GET /seller-actions + GET /notes + GET /claims + GET /refund-records
    • OrderController 전면 재작성 (legacy /process /ship /deliver /cancel /refund /event 제거)
    • OrderStateApplication.updateTracking 신규
    • EventCatalog 5 신규 event 등재
  • ✅ 클라이언트 구현 완료:
    • OrderResponse / OrderLineItem / OrderListResponse TS 타입 서버 SSOT 재생성
    • SellerActionName / SellerActionRequestBody / OrderRefundRecord / OrderSellerNote / OrderClaim / OrderFulfillmentSummary / OrderShipment / OrderPayment / OrderPricing 추가
    • order.api.ts 재작성 (셀러 액션 dispatch + sub-resource list)
    • order.queries.ts 재작성
    • useOrder / useOrderList / useOrderSearch 정상화
    • 레거시 useOrders / useUpdateOrderStatus / getOrders / exportOrdersToCSV 제거
    • /merchant/orders/page.tsx 전면 재작성 (multi-card detail / SellerActionBar / SellerActionDialog 11 액션 매핑 / NumberInput / Field.Root + Select / 20 status 필터)
  • ✅ 서버 smoke (HTTP):
    • List rich shape 정상
    • Detail rich shape 정상 (customerSnapshot / availableSellerActions / claimHistory / refundRecords / sellerNotes 등)
    • ADD_NOTE → SELLER_MANUAL note row append-only 저장
    • MARK_SHIPPED → SHIPPED 전이 + SYSTEM audit note + OrderShipped + OrderShippedBySeller event
    • UPDATE_TRACKING → tracking 갱신 + OrderTrackingUpdatedBySeller event
    • REFUND_FULL → RefundRecord(COMPLETED) + StubRefundAdapter mock processorRefundId + OrderRefunded event
    • CANCEL_BY_SELLER → 자동 환불(StubRefundAdapter) + RefundRecord + CANCELED 전이 + OrderRefunded + OrderCanceled + OrderCanceledBySeller (3 events)
    • 422 검증: status 별 불가 액션 거부
  1. admin DTO 를 shop-api 와 같은 shape (rich) 로 재구성 — admin 확장 필드 add-on
  2. 셀러 액션 단일 dispatch endpoint
  3. OpenSearch 결과 enrich 통일 (snake_case raw 노출 X)
  4. RefundRecord 신설 (Order:N) — 부분환불 ledger 정확
  5. PG 호출은 RefundPort 추상 + StubRefundAdapter (PG 트랙 swap-in)
  6. TS 타입 서버 SSOT 재생성 (cancelReason/canceledAt/refundAmount 같은 잘못된 필드 정정)
  7. 페이지네이션은 1-indexed (shop-api 와 정합)
  8. EventCatalog 카탈로그 갱신 (셀러 알림 룰 surface)
  • S11 (Argo vs 수동 우선순위): 사용자 합의 후 구현. 현재 코드는 manual override 동작 (수동 입력이 자동 콜백을 갈음).

  • PG 어댑터 swap-in: PG 트랙 (3-G) 합류 시 RefundPort 의 실제 구현체 (TossRefundAdapter / StripeRefundAdapter) 추가. @Primary 를 stub 에서 제거.

  • DTO 통합 정리 (tech debt): admin 의 AdminOrder* DTO 들이 shop-api 의 OrderDetail*/OrderSummaryDto 와 코드 duplication. 운영 진입 후 makitt-core 또는 별도 shared 모듈로 통합 권장.

  • list 정렬 / 기간 필터 server-side: 컨트롤러 파라미터 받지만 OrderSearchService 가 아직 활용 안 함. 후속 작업.

  • operator user/email 자동 주입: admin 인증 필터에서 HttpServletRequest attribute 로 채워지면 자동. 현재 anonymous 테스트는 null 로 기록됨.

  • 부분환불 line.refundedQuantity 누적 정합: 현재 구현됨. line.refundableQuantity 검증 + 두 번째/세 번째 부분환불 누적까지 단위 검증 필요.

  • 헨리엣 샵 ID: 71261f65-ee4e-4238-9b4f-d56cee9be523

  • spec 파일: surface-diff.md, scenarios.md, seller-actions.md, README.md

  • 메모리: project_platform_events.md (신규 5 event 등재 SSOT)

비어 있음

당신이 처리할 항목

docs / spec / finished / order-admin-revamp / e2e.md