Checkout & payments
Shopping Cart
Generated from docs/plan/core/shopping-cart/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.
Customers need to hold products before purchase. A shopping cart is a fundamental e-commerce feature that holds items, allows quantity adjustment, and persists across sessions.
The problem
Without a shopping cart, customers either add items directly to a purchase (no browsing first) or manually remember what they wanted. A cart lets shoppers collect items, review totals, and adjust quantities before checkout.
What it does
- Cart stored in browser session storage (or localStorage for persistence); synced with server at checkout
- Add items: { product_id, variant_id (optional), qty } → add to cart or increment existing line
- Remove items: delete a line from cart
- Update quantity: change qty on a line; if qty becomes 0, remove the line
- View cart: display all lines with product name, variant, qty, unit price, line total
- Coupon application: append coupon code to cart; API validates and applies discount
- Shipping method selection: user chooses from available methods; cart recalculates total with shipping
- Totals calculation: display subtotal, discount, shipping, tax, total (read-only; recomputed server-side at checkout)
What it deliberately does NOT do
Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.
- Cart merge on login — if a guest adds items, then logs in, do we merge the guest cart with their saved cart? This is a UX design choice left to the storefront theme.
- Saved carts or wishlists — separate features from the active cart.
- Abandoned cart recovery — that’s marketing, not the cart itself. (There is a separate paid ‘cart-abandonment-recovery’ module.)
Data model
Cart is client-side only (stored in localStorage or sessionStorage). On the server side, no Cart collection — checkout validates items against live product data at POST /api/orders. Transient state: no persistence.
API
- POST /api/cart/add — add item, return updated cart
- POST /api/cart/remove — remove item by product_id + variant_id
- POST /api/cart/update — update qty by product_id + variant_id
- GET /api/cart — return current cart contents (optional; used for server-side cart implementation if chosen)
- POST /api/orders/quote — preview totals (subtotal, shipping, tax) for current cart without creating order
Every route added here must also appear in src/pages/openapi.json.ts — a test
fails the build if it does not.
Admin
No admin interface. Cart is a storefront feature.
The seam — why this is core
Core owns the quote engine (POST /api/orders/quote) and checkout validation (POST /api/orders). Theme owns the cart UI and client-side storage logic.
Core owns the interface + honest cart container; shopping cart is core infrastructure, not a support commitment or credential.
Dependencies
- product management (core) — cart references product ids, which must exist
- payment-status-tracking — cart leads to checkout, which creates an order with payment_status
Acceptance checks
Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.
- Add product A (qty 1) to cart; cart shows 1 item, total €25
- Add product B (qty 2) to cart; cart shows 2 items (different products), total €25 + €30 = €55
- Add product A again (qty 1); cart shows product A qty 2 (not a new line), total €50 + €30 = €80
- Remove product B; cart shows 1 item (product A qty 2), total €50
- Update product A qty to 3; cart total updates to €75
- Cart persists after page reload (if localStorage-backed)
- Quote for current cart shows subtotal, shipping methods available, and estimated tax
- Apply coupon code; quote recalculates with discount applied
Risks
Cart can become invalid: if a product is deleted or a variant goes out of stock after being added to cart, checkout must re-validate and reject with a clear message. If cart size exceeds server limits (e.g., 1000 line items), quote/checkout may fail; theme should warn or cap cart size. If two devices (laptop and phone) both have the same user’s cart in localStorage, they are out of sync — next checkout uses whichever device made the request (no merge). This is by design (simple) but must be documented.
Commercial context
| Suggested price | free (core) |
| Rival anchor | Shopify: included; Magento: included |
The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.
Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full
catalogue and ../../AI-GUIDE.md for how to work on this repository.