Order Module Feature List
Order feature surfaces, queue behavior, and payment lifecycle.
Order Module - Feature List
1. Feature Overview
Order uses a mixed execution model:
- synchronous initiation for checkout and buy-now payment start
- asynchronous processing for cancellation, refund processing, payment reconciliation/retries, and auto-cancel
The customer/mobile surface is authenticated and mounted through the shared mobile composition layer.
2. Route Ownership and Surfaces
| Surface | Route prefix | Owner |
|---|---|---|
| Customer API | /api/orders | OrderCustomerController |
| Mobile-composed customer API | /api/mobile/orders | MobileModule composition of OrderCustomerModule |
| Admin API | /api/admin/orders | OrderAdminController |
| Payment redirect callbacks | `/api/payments/redirect/:paymentId/success | failure` |
| Payment result page | /api/payments/result | PaymentResultController |
Swagger tags used by order controllers:
Orders (Mobile)Orders (Admin)
3. Admin Feature Matrix
| Capability | Endpoint | AuthZ |
|---|---|---|
| List orders (paginated + filters) | GET /api/admin/orders | Orders_READ |
| Order detail | GET /api/admin/orders/:id | Orders_READ |
| Async request status | GET /api/admin/orders/requests/:requestId | Orders_READ |
| Cancel order (async command) | POST /api/admin/orders/:id/cancel | Orders_UPDATE |
| Process refund approve/reject (async command) | POST /api/admin/orders/:id/process-refund | Orders_UPDATE |
| Add admin note | POST /api/admin/orders/:id/notes | Orders_UPDATE |
| Activate care package subscription | POST /api/admin/orders/:id/activate-care-package | CarePackageSubscriptions_UPDATE |
| Assign serial number to order item | PATCH /api/admin/orders/:id/items/:orderItemId/serial | Orders_UPDATE |
4. Customer/Mobile Feature Matrix
| Capability | Endpoint | Runtime mode |
|---|---|---|
| Checkout from active cart | POST /api/orders/checkout | Synchronous payment-init (200) |
| Buy now for single product | POST /api/orders/buy-now | Synchronous payment-init (200) |
| Order history | GET /api/orders | Synchronous read |
| Order detail | GET /api/orders/:id | Synchronous read |
| Async request status | GET /api/orders/requests/:requestId | Synchronous read |
| Cancel order | POST /api/orders/:id/cancel | Async command accepted (202) |
| Request refund | POST /api/orders/:id/request-refund | Synchronous mutation |
Notes:
idempotency-keyheader is required for checkout and buy-now.- Equivalent mobile endpoints are available at
/api/mobile/orders/...via routing composition.
5. Key Business Rules
- Physical products (
productKind = "physical") create orders withorderType: "physical" - Checkout requires an active cart with at least one valid sellable product.
- Checkout and buy-now both require shipping district selection on the active cart.
- Mobile order detail (
GET /api/mobile/orders/:id) includes order-level receiver snapshot fields (receiver,contactNumber) andfulfillmentStatusfor shipping timeline rendering. - Cancellation and refund state transitions are gated by current order status.
- Monetary values are stored in integer minor units (for Stripe, USD cents) and guarded by DB non-negative constraints.
6. Physical Product Support
6.1 Supported Product Types
Product Type (productKind) | Cart Allowed | Buy-now Allowed | Order Type | COD Allowed |
|---|---|---|---|---|
physical | ✅ | ✅ | physical | ✅ |
digital | ✅ | ✅ | digital | ❌ (ORDER_COD_PHYSICAL_ONLY) |
care_package | ✅ (via care-package cart module) | ❌ | care_package (or mixed if combined with physical) | ❌ (ORDER_COD_PHYSICAL_ONLY) |
Buy-now restriction:
care_packageitems are blocked from buy-now. Use cart checkout for care package purchases. Error code:ORDER_BUYNOW_CARE_PACKAGE_NOT_ALLOWED.
6.2 Error Codes
| Error Code | HTTP | Trigger |
|---|---|---|---|
| ORDER_BUYNOW_CARE_PACKAGE_NOT_ALLOWED | 422 | Buy-now attempted with care_package productKind |
| ORDER_COD_PHYSICAL_ONLY | 400 | COD checkout attempted on digital-only or care-package-only cart or buy-now product |
| ORDER_NOT_COD_METHOD | 400 | Admin cash collection attempted on non-COD order |
| CART_CARE_PACKAGE_ITEM_NOT_PHYSICAL | 422 | Cart item is not a physical product when attaching care package |
| ORDER_FULFILLMENT_NOT_PHYSICAL_TYPE | 400 | Fulfillment advance on non-physical/mixed order |
| ORDER_FULFILLMENT_NOT_DIGITAL_TYPE | 400 | Digital delivery on non-digital/mixed order |
| ORDER_ACTIVATE_CARE_PACKAGE_NOT_APPLICABLE | 400 | Activate care package on non-care_package order |
| ORDER_NOT_PAID | 400 | Action requires paid order status |
| ORDER_SERIAL_ITEM_NOT_PHYSICAL | 422 | Serial number assigned to non-physical item |
| ORDER_SERIAL_ALREADY_ASSIGNED | 409 | Item already has a serial number assigned |
| ORDER_SERIAL_AFTER_DELIVERED | 422 | Serial assignment after order is delivered |
| ORDER_SERIAL_DUPLICATE | 409 | Serial number already in use for another item |
6.3 Care Package Product Support
Business rules for care package orders:
- Care-package-only carts produce
orderType = "care_package". - No
shippingDistrictrequired;shippingFee = 0for care-package-only orders. - Mixed carts (physical + care_package) produce
orderType = "mixed"; shipping required for physical items. - Checkout creates
care_package_subscriptionsrows withstatus = "pending_activation". - Activation is triggered via BullMQ after payment success.
7. State Models
7.1 Order status lifecycle
Online orders: created -> payment_pending -> paid / payment_failed -> cancelled / refund_requested -> refund_approved / refund_rejected
COD orders: created -> payment_pending with paymentStatus = "cod_pending" after reservation. Admin cash collection changes paymentStatus to "cod_collected" without changing orderStatus to "paid".
Warranty coupling:
- Warranty claims and warranty-status reads are allowed only while the linked order remains warranty-eligible.
refund_requestedandrefund_pendingdo not block warranty yet.refund_approved,cancelled, andpayment_failedblock warranty operations.- COD orders remain warranty-ineligible until admin collection changes
paymentStatusfromcod_pendingtocod_collected.
7.2 Actor provenance in status history
order_status_history writes use explicit actor model:
customer: customer-initiated state changesadmin: admin-user initiated changes (includes subadmins)system: background jobs, webhook side effects, auto-cancel/reconciliation markers
7.3 Payment initiation model
Checkout and buy-now return one of:
initiationType = form_postinitiationType = redirectinitiationType = cod— COD only; no gateway redirect. Order remainspayment_pendingwithpaymentStatus = "cod_pending"until admin collection. Frontend navigates toreturnUrldirectly.
That COD pending window is fulfillment-eligible but not warranty-eligible.
8. Caching Strategy
Read-side keyspaces:
order:customer:list:order:detail:order:admin:list:order:admin:detail:
Configured TTLs:
ORDER_HISTORY_CACHE_TTL_SECONDS(default120)ORDER_ADMIN_CACHE_TTL_SECONDS(default60)
Invalidation triggers:
- customer/admin async mutations invalidate order list/detail keyspaces
9. Rate Limiting
Customer operation limits:
ORDER_CHECKOUT_RATE_LIMIT(default10)ORDER_CANCEL_RATE_LIMIT(default10)ORDER_REFUND_REQUEST_RATE_LIMIT(default5)ORDER_CHECKOUT_RATE_WINDOW_SECONDS(default60)
Admin operation limits:
ORDER_ADMIN_OPERATION_RATE_LIMIT(default120)ORDER_ADMIN_RATE_WINDOW_SECONDS(default60)
Safety behavior:
- Redis sliding-window checks are used for customer and admin operations.
- Limit breaches throw
RateLimitExceededExceptionand returnRATE_LIMIT_EXCEEDED. - Retry/backoff windows and DLQ warning thresholds are environment-controlled in processing runtime.
10. Queue/Worker Features
| Worker | Queue | Jobs |
|---|---|---|
OrderProcessor | orders | order.payment_success, order.payment_failed, order.payment_retry, order.cancel, order.process_refund, order.auto_cancel |
OrdersMaintenanceProcessor | orders_maintenance | orders_maintenance.dispatch_outbox, orders_maintenance.cleanup_outbox |
CarePackageProcessor | care_package | care_package.activate_subscription, care_package.send_expiry_reminder, care_package.expire_subscriptions, care_package.cancel_subscription |
Maintenance behavior:
- outbox dispatch with queue ownership filtering (
orders,orders_maintenance,cart) - retention cleanup for completed/failed outbox rows
- failed-job threshold monitoring with alert logs
Flow diagram:
11. Error UX Mapping
| errorCode | Typical HTTP | UX action |
|---|---|---|
ORDER_ACTIVE_CART_NOT_FOUND | 404 | Prompt user to add items to cart before checkout |
ORDER_CART_EMPTY | 400 | Show cart-empty message and CTA to browse products |
ORDER_PRODUCT_NOT_AVAILABLE | 400 | Refresh catalog and hide unavailable product |
ORDER_IDEMPOTENCY_MISMATCH | 400/409 | Retry with a fresh idempotency key |
ORDER_CANCEL_NOT_ALLOWED | 400 | Disable cancel CTA for current status |
ORDER_NOT_PENDING_REFUND | 400 | Show current status and hide process-refund CTA |
ORDER_ASYNC_REQUEST_NOT_FOUND | 404 | Stop polling and refresh order detail |
ORDER_NOT_FOUND | 404 | Redirect to order history with not-found notice |
RATE_LIMIT_EXCEEDED | 429 | Backoff and retry after short delay |
ERR_CONFIG_INVALID | 503 | Treat as server issue and show generic retry support message |
12. Release/QA Checklist
- Checkout path returns payment-init payload with valid
initiationTypeandgatewayPayload. - Buy-now path enforces product eligibility and promo-code validation behavior.
- Customer cancel returns
202and request is pollable via/orders/requests/:requestId. - Admin cancel/process-refund paths enforce
Orders_UPDATEpermission. - Status history rows capture actor provenance (
customer/admin/system) correctly. - Processor jobs (
order.payment_*, cancel, refund, auto-cancel) update order state and invalidate caches. - Outbox dispatch/cleanup cron pipeline runs on
orders_maintenancequeue. - Mobile-composed routes (
/api/mobile/orders/...) resolve throughMobileModulerouting. - Payment redirect callbacks and
/api/payments/resulthandoff are functional. - Care package items are rejected from buy-now with
ORDER_BUYNOW_CARE_PACKAGE_NOT_ALLOWED. - Admin
POST /:id/activate-care-packagevalidates order type and subscription pending status. - Admin
PATCH /:id/items/:orderItemId/serialassigns serial number and rejects duplicates withORDER_SERIAL_DUPLICATE.
13. Integration Flows
13.1 Checkout Flow
A customer completes checkout from an active cart with payment initiation.
- Customer calls
POST /api/orders/checkoutwithidempotency-keyheader. - System validates active cart exists and contains valid sellable products.
- System calculates order totals from cart items and applies any applied coupon discount.
- System creates order with status
payment_pending. - System creates
order_status_historyentry with actorcustomer. - System calls payment gateway to initiate payment, returning
initiationType(form_postorredirect) withgatewayPayload. - Cart remains visible in customer flow while payment is pending/failed.
- Cart is cleared only after payment success processing (
order.payment_success-> cart clear job). - Order is now awaiting payment completion via gateway callback or redirect handling.
13.2 Admin Refund Flow
An admin processes a customer refund request after order payment was successful.
- Customer calls
POST /api/orders/:id/request-refundto submit refund request. - System updates order status to
refund_requested. - Admin calls
GET /api/admin/orders/:idto review order and refund request. - Admin calls
POST /api/admin/orders/:id/process-refundwith{ action: "approve" | "reject", remarks: string }. - If approve: system immediately sets order to
refund_approved(manual refund completed). - If reject: system sets order to
refund_rejected, customer can view rejection via order detail. - No payment gateway refund API call is made in this phase.
Warranty effect:
- Approval makes the order permanently warranty-ineligible.
- Rejection keeps the order warranty-eligible, subject to the normal payment and expiry checks.
Related payment docs:
apps/fumadocs/content/docs/developer/payment/cart-checkout-flow.mdx
Time fields in this module are stored as timezone-aware values and should be handled as ISO-8601 instants by API consumers.
See Also
- API Reference: See Order - API & Integration Guide Section 7 (Endpoint Reference + Payload Cheatsheet) for complete request/response DTOs.
- Backend Reference: See Order - Backend Documentation Section 3 (Data Model) for schema details.