Cart and checkout
From a member's cart to a placed order. The cart lives in the users module; placing the order hands off to orders, which talks to the WMS, Biteship and DOKU.
How this page was verified
Read on 2026-09-15 from the backend cart service (src/users/services/members-carts.service.ts), the order service (src/orders/services/orders.service.ts), and the storefront /checkout/shipping flow.
The cart (backend)
A member has one cart (member_carts) with items (member_cart_items) and chosen shipping methods (member_cart_shipping_methods). Storefront resolvers (storefront-members-carts, all front*, guarded by JwtMemberAuthGuard):
frontMemberCart— read the cart.frontUpdateCartItem,frontDeleteCartItem,frontAddCartItemToTemporaryCart(buy-now).frontUpdateCartAddress— set the delivery address.frontCouriers— courier options for the cart (backend calls Biteship rates).frontUpdateCartCourier— pick one.frontValidateMemberCartCheckout— validate and place the order.
The add-to-cart error has a custom GraphQL formatError that returns message, code and an optional cartId.
Placing the order
frontValidateMemberCartCheckout in the cart service calls ordersService.createOrder(...). createOrder() (in src/orders/services/orders.service.ts) is the core flow:
- Save the
ordersrow and itsorder_itemsandorder_addresses, statuspending_payment. wmsService.createOrder()— reserve the order in the WMS.deliveriesService.createDraftOrder()— create the Biteship draft for the chosen courier.- Create the DOKU payment and return a
paymentLinkUrl.
It emits order.completed-family events for member stats. Order status values: pending_payment, processing, completed, canceled, shipped (see Orders).
Checkout (storefront)
/checkoutredirects to/checkout/shipping(src/app/checkout/shipping/page.tsx). A leave-guard (useCheckoutLeave) warns on navigating away.- Address —
src/modules/shipping/components/address-selection-form.tsx,src/context/address-context.tsx,src/lib/address/. - Courier —
shipping-form.tsxusesfrontCouriers(memberCartId)(name, code, service, price, duration) thenfrontUpdateCartCourier. Biteship is not named in the frontend; courier data comes from the backend. - Voucher —
vouchers-form.tsx,src/lib/vouchers/. See Promotions. - Pay —
frontValidateMemberCartCheckoutreturns apaymentLinkUrl; the DOKU Jokul Checkout script opens it (src/hooks/useDokuCheckoutPayment.tsx, sandbox vs production byNEXT_PUBLIC_DOKU_ENV). On close the user goes to/user/my-order?status=pending_payment. See Payment.
The cart has no /cart route — it is src/context/cart-context.tsx (add, update qty, delete, buy-now temp cart, voucher and discount math) surfaced as a slide-over.
Gotchas
- Checkout is one backend call that does four external things. If placing an order fails on dev, it may be the WMS, Biteship or DOKU leg — and dev points at the simulator, which can force any of them to 500.
- Payment window is
DOKU_PAYMENT_DUE_DATE_MINUTE; the order expiry cron cancels unpaid orders after it.