Files
vmall/openspec/changes/add-aftersale-refunds/tasks.md
T

4.1 KiB

1. Persistence and shared contract

  • 1.1 Add migration 0017_aftersales.sql with aftersales and append-only aftersale_messages tables, order/customer/shop/order-item foreign keys, refund_only/return_refund type checks, status checks, i64 minor-unit amounts, evidence URL arrays, localized JSONB reason/content fields, timestamps, ownership indexes, and a partial unique index allowing only one active aftersale per order_item_id.
  • 1.2 Add shared aftersale enums, DTOs, paginated summaries, state/action types, bilingual reason/message fields, and API client methods for customer, shop-admin, and platform-admin flows. Keep all money as integer minor units and expose refund_total_minor/remaining refundable amounts from the contract.

2. Rust aftersale module and behavioral proof

  • 2.1 Implement apps/api/src/modules/aftersale/ repository, service, DTO, handlers, routes, and module registration for customer applications/list/detail/cancel/reopen/messages/return tracking, shop processing, and platform arbitration.
  • 2.2 Enforce paid-or-shipped order-item eligibility, configured post-confirmation window, amount not exceeding the guarded remaining refundable amount, evidence URL validation, one active aftersale per line, customer ownership, own_shop scope for shop roles, and platform-admin arbitration.
  • 2.3 Implement guarded state transitions: pending to approved or rejected; return-refund approved to buyer_shipping to merchant_confirmed to refunded; cancellation from any non-terminal pending state; one rejected-to-pending reopen appeal. Reject stale transitions with 409.
  • 2.4 Complete refunds transactionally: conditionally update the aftersale and order refund total, append one customer_accounts ledger credit, emit the hookable refund_completed event, and make retries idempotent so no duplicate credit is possible.
  • 2.5 Add focused API integration tests under apps/api/tests/ reusing tests/common/mod.rs for eligibility/window boundaries, amount guards, uniqueness, ownership/RBAC, every transition and illegal transition, one-time reopen, messages, ledger/order totals, concurrent completion, and idempotent retry.

3. Mall customer surfaces and adapter parity

  • 3.1 Add the aftersale methods and deterministic mutable fixtures to apps/mall/mock/api.ts, preserving the shared contract for applications, messages, cancellation, reopen, return tracking, and refund totals.
  • 3.2 Add the aftersale domain and exact method picks to Mall LIVE_PICKS; keep fixed fallback behavior and localized en/zh labels in @vmall/shared.
  • 3.3 Add Mall order-detail eligible-item entry, aftersale list/detail, reason/amount/evidence form, bilateral message thread, cancel/reopen actions, and return-shipping tracking form, with sign-in redirect and reload-safe state.

4. Merchant and platform console surfaces

  • 4.1 Add shop-admin aftersale workspace with shop-scoped list/detail filters, item and evidence display, bilingual messages, approve/reject actions, return-receipt-and-refund action, and guarded error states.
  • 4.2 Add platform-admin read-only aftersale list/detail and dispute arbitration actions for terminal refund or rejection, with role-protected routes and visible ledger/order-total outcomes.
  • 4.3 Route all three frontends through @vmall/shared contracts and @vmall/ui primitives; do not duplicate API types or bypass own_shop authorization.

5. Verification

  • 5.1 Run the aftersale integration tests in apps/api/tests/ with the shared tests/common/mod.rs fixtures and exercise customer, merchant, and platform paths.
  • 5.2 Build affected frontends: pnpm --filter @vmall/mall build, pnpm --filter @vmall/shop-admin build, and pnpm --filter @vmall/admin build.
  • 5.3 Browser-smoke the Mall application/detail/message/cancel/return-tracking/refund-history flow, shop-admin processing, and platform arbitration against the local stack, including fixed-adapter fallback.
  • 5.4 Run openspec change validate add-aftersale-refunds --strict and openspec validate --all --strict.