Skip to content

E-Commerce — Cart & Checkout

OWNER: aimee (scoping) ALSO_USED_BY: anna (spec), floris, floor (frontend), urszula, maxim (backend) LAST_VERIFIED: 2026-03-26


Overview

Cart and checkout are the revenue-critical path. Every UX friction point here costs conversions. The average e-commerce cart abandonment rate is 70%. GE builds multi-step checkout with the fewest possible fields and always supports guest checkout.


Feature Decomposition

Cart

SCOPE_ITEM: Cart state management INCLUDES: Add to cart, update quantity, remove item, cart persistence, cart item count in header, cart subtotal display OPTIONAL: Mini-cart dropdown/slide-out, cart drawer (no page navigation required) ESTIMATE_COMPLEXITY: normal

CHECK: Cart storage strategy IF: guest user → localStorage cart synced to server-side cart on checkout start IF: logged-in user → server-side cart (database), survives device changes IF: guest converts to account → merge localStorage cart into DB cart

SCOPE_ITEM: Cart persistence INCLUDES: Cart survives browser close (localStorage + DB), cart expiry after 30 days of inactivity, abandoned cart recovery (email if user is known) OPTIONAL: Cart sharing (generate link), save cart for later COMPLIANCE: Abandoned cart emails require GDPR marketing consent ESTIMATE_COMPLEXITY: normal

SCOPE_ITEM: Cart validation INCLUDES: Real-time stock check on cart view, price update check (warn if price changed since adding), variant availability check, minimum order value enforcement OPTIONAL: Maximum quantity per product, purchase limits ESTIMATE_COMPLEXITY: normal

SCOPE_ITEM: Cart calculations INCLUDES: Line item totals (qty x price), subtotal, VAT breakdown, shipping estimate (before address entry), grand total OPTIONAL: Discount code application (see marketing tools), loyalty points redemption COMPLIANCE: EU — all displayed prices include VAT. Breakdown shows VAT amount separately for transparency. ESTIMATE_COMPLEXITY: normal

Database Schema Pattern

-- Cart tables
carts (id, user_id, session_id, status, currency, expires_at, created_at, updated_at)
cart_items (id, cart_id, product_variant_id, quantity, unit_price_cents, created_at, updated_at)
-- cart_items.unit_price_cents = price at time of adding (snapshot, not live reference)

Checkout Flow

GE standard checkout is 4 steps. Each step is a separate URL for back-button support and analytics tracking.

Step 1: Contact & Shipping Address
Step 2: Shipping Method
Step 3: Payment Method
Step 4: Review & Confirm

SCOPE_ITEM: Guest vs authenticated checkout INCLUDES: Email field (first thing in checkout), check if account exists (offer login), continue as guest always available, offer account creation post-purchase (single checkbox + password field on confirmation page) COMPLIANCE: GDPR — never pre-check "create account" checkbox. Never require account for purchase. ESTIMATE_COMPLEXITY: normal

Step 1: Contact & Shipping Address

SCOPE_ITEM: Shipping address form INCLUDES: Full name, street + number, postal code, city, country (dropdown), phone (for delivery), company name (optional) OPTIONAL: Address autocomplete (PostNL API for NL, Google Places for international), address book selector (logged-in users), "same as billing" checkbox (default checked) COMPLIANCE: Collect only what is necessary for delivery. Phone may be required by carrier. ESTIMATE_COMPLEXITY: simple

CHECK: Address validation IF: NL-only store → PostNL Address Check API (validates postal code + house number) IF: EU-wide → basic format validation per country IF: international → Google Places autocomplete

SCOPE_ITEM: Billing address INCLUDES: "Same as shipping" toggle (default on), separate billing address form when toggled off, VAT number field for business customers OPTIONAL: Company name, chamber of commerce number (KvK), PO box support COMPLIANCE: VAT number validation (VIES API) for B2B reverse charge ESTIMATE_COMPLEXITY: simple

Step 2: Shipping Method

SCOPE_ITEM: Shipping method selection INCLUDES: Available methods based on address and cart contents, method name + description + price + estimated delivery time, cheapest option pre-selected OPTIONAL: Free shipping threshold display ("Add EUR 12.50 for free shipping"), pickup points (PostNL/DHL service points), same-day/next-day delivery options COMPLIANCE: Delivery estimates must be realistic — EU consumer law penalizes misleading delivery promises ESTIMATE_COMPLEXITY: normal

CHECK: Shipping provider IF: NL domestic → PostNL (standard + service points), DHL (alternative) IF: Belgium → PostNL cross-border or Bpost IF: EU-wide → DHL Express or UPS IF: aggregator → MyParcel or Sendcloud (multi-carrier)

SCOPE_ITEM: Shipping cost calculation INCLUDES: Flat rate per zone (NL, EU, world), weight-based calculation (optional), free shipping above threshold OPTIONAL: Real-time carrier rates via API, dimensional weight calculation ESTIMATE_COMPLEXITY: simple (flat) to normal (dynamic)

Step 3: Payment Method

SCOPE_ITEM: Payment method selection INCLUDES: Available payment methods displayed with logos, method selection, redirect to payment provider (Mollie hosted checkout) OPTIONAL: Saved payment methods (logged-in users), payment method filtering by country/amount COMPLIANCE: PSD2/SCA — handled by Mollie. Never store raw card data. PCI compliance via hosted checkout. ESTIMATE_COMPLEXITY: normal STACK_REF: wiki/docs/archetypes/e-commerce/payments.md

Step 4: Review & Confirm

SCOPE_ITEM: Order review INCLUDES: Full order summary (items, quantities, prices), shipping address display, shipping method and cost, payment method display, total with VAT breakdown, terms & conditions checkbox (required), edit links back to each step COMPLIANCE: EU — "Order with obligation to pay" or equivalent clear wording on submit button. Consumer must explicitly acknowledge payment obligation. ESTIMATE_COMPLEXITY: simple

SCOPE_ITEM: Order placement INCLUDES: Create order in DB (status: pending_payment), redirect to Mollie for payment, handle payment callback (success/failure/pending), order confirmation page, confirmation email OPTIONAL: Order number format (configurable prefix + sequential), fraud scoring ESTIMATE_COMPLEXITY: normal

Post-Checkout

SCOPE_ITEM: Order confirmation page INCLUDES: Order number, summary, estimated delivery, "create account" option (if guest), cross-sell recommendations OPTIONAL: Social sharing, print receipt, tracking info ESTIMATE_COMPLEXITY: simple

SCOPE_ITEM: Order confirmation email INCLUDES: Order number, items with images, prices, shipping address, estimated delivery, contact info for support COMPLIANCE: Must be sent immediately. Include withdrawal rights information (14-day cooling period). Include link to return/withdrawal form. ESTIMATE_COMPLEXITY: simple

SCOPE_ITEM: Abandoned cart recovery INCLUDES: Detect abandoned carts (items added, checkout started, no order within 1 hour), send recovery email with cart contents, direct link back to checkout OPTIONAL: Second reminder after 24 hours, discount incentive in third email COMPLIANCE: GDPR — only send if user provided email AND consented to marketing. Unsubscribe link required. ESTIMATE_COMPLEXITY: normal


Implementation Patterns

Cart Merge Strategy

On login:
  1. Load DB cart for user
  2. Load localStorage cart
  3. For each localStorage item:
     - If item exists in DB cart → keep higher quantity
     - If item not in DB cart → add it
  4. Clear localStorage cart
  5. Return merged DB cart

Checkout State Machine

checkout_started → contact_entered → shipping_selected → payment_initiated →
  → payment_success → order_confirmed
  → payment_failed → retry_payment
  → payment_pending → await_webhook
  → payment_expired → order_cancelled

Stock Reservation

On checkout start:
  Reserve stock for 15 minutes (cart_items.reserved_until)
  Show countdown on checkout page

On payment success:
  Convert reservation to permanent stock decrease

On reservation expiry:
  Release stock back to available
  Warn user if they return to checkout

Anti-Patterns

ANTI_PATTERN: Requiring login before checkout FIX: Guest checkout is mandatory. 35% of abandonment is due to forced account creation.

ANTI_PATTERN: Single-page checkout with all fields visible FIX: Multi-step reduces cognitive load. Each step has clear purpose and progress indicator.

ANTI_PATTERN: No stock validation at checkout FIX: Validate stock at cart view, checkout start, AND payment initiation. Race conditions are real.

ANTI_PATTERN: Storing cart prices as live references FIX: Snapshot price at add-to-cart time. Show warning if price changed. Never silently charge a different amount.

ANTI_PATTERN: "Place Order" button without payment obligation wording FIX: EU law requires "Order with obligation to pay" or equivalent. "Buy now" is legally insufficient in some member states.

ANTI_PATTERN: Checkout form with country field defaulting to US FIX: Default to Netherlands (or detect from IP/browser locale). Wrong default = wrong shipping cost = wrong VAT = angry customer.


Cross-References

READ_ALSO: wiki/docs/archetypes/e-commerce/payments.md READ_ALSO: wiki/docs/archetypes/e-commerce/order-management.md READ_ALSO: wiki/docs/archetypes/e-commerce/authentication.md READ_ALSO: wiki/docs/archetypes/e-commerce/compliance.md READ_ALSO: wiki/docs/archetypes/e-commerce/integrations.md READ_ALSO: wiki/docs/stack/nextjs/index.md