Skip to content

Proposed Checkout FlowsΒΆ

Design Status

This document contains all proposed sequence diagrams for the new checkout flow. See Overview for the business rationale and Proposed Technical Specification for database schema and state machines.

LegendΒΆ

Sequence Diagram Legend

Highlight Color Meaning
TODO Green Task that still needs to be completed
ROUGH Fuchsia Part that might not be complete or accurate
Go Back to -> Orange Reference to return to a previous step
πŸ“‹ Link Blue Clickable link to another section or flow
πŸ“Š MT-X - Metric tracked at this step - click to view details in metrics tables

Flow Icons

  • πŸ“‹ Main flow - Primary payment flows and major checkout steps
  • πŸ”„ Sub-flow - Nested flows within a payment method (e.g., retry, method switching)
  • ℹ️ Optional - Optional flows that can be skipped
  • ⚠️ Incomplete - Flows that need implementation or are marked as TODO

Main FlowΒΆ

Flow - click to expand
sequenceDiagram
    autonumber
    participant U as User
    participant B as Backend

    U ->> B: <a href="checkout-step-0-cart-review">πŸ“‹ Step 0 - Cart Review</a>
    activate B

    U ->> B: <a href="checkout-step-1-authentication">πŸ“‹ Step 1 - Authentication</a>

    U ->> B: <a href="checkout-step-2-payment-selection--order-creation">πŸ“‹ Step 2 - Payment Selection & Order Creation</a>
    note over B: Order created (status='created')

    alt Payment Method Flows
        note over U,B: iDEAL, PayPal, Klarna, Bank Transfer
        U ->> B: <a href="ideal-flow">πŸ“‹ Payment method - iDEAL</a>
    else
        note over U,B: Creditcard - requires card selection
        U ->> B: <a href="checkout-step-2a-creditcard-selection">πŸ“‹ Step 2a - Creditcard Selection</a>
        U ->> B: <a href="creditcard-flow">πŸ“‹ Payment method - Creditcard</a>
    else
        note over U,B: Bancontact - requires payment option selection
        U ->> B: <a href="checkout-step-2b-bancontact-selection">πŸ“‹ Step 2b - Bancontact Selection</a>
        U ->> B: <a href="bancontact-flow">πŸ“‹ Payment method - Bancontact</a>
    end

    note over B: Order locked (status='pending')

    U ->> B: <a href="checkout-step-3-payment-validation">πŸ“‹ Step 3 - Payment Validation</a>

    U ->> B: <a href="checkout-step-4-order-confirmation">πŸ“‹ Step 4 - Order Confirmation</a>

    deactivate B

Happy Path FlowsΒΆ

πŸ“‹ Checkout step 0 - Cart ReviewΒΆ

Flow - click to expand
sequenceDiagram
    autonumber
    participant U as User
    participant B as Backend

    %% Pre-Checkout
    alt Add to cart
        note over U,B: Add to cart - using PDP or PLP

        note right of U: productId's and productAttributeId's originate from data from the PLP or PDP page
        U ->>  B: POST request to /api/cart/items with productId and productAttributeId in the request body from the PLP or PDP
        note over B: πŸ“Š Track cart item add attempted
        B ->>  B: Validate request to add product to cart (availibility etc.)
        note over B: πŸ“Š Track cart item add result (success/failed with reason)
        B -->> U: Response containing the updated cart data (data is used for the cart popup)
    else
        note over U,B: Add to cart - using My account reorder

        U ->>  B: GET request to /my-account
        B -->> U: Response containing my-account page and data for the first tab
        U ->>  U: Change to order-history tab
        U ->>  B: GET request to /order-history
        B -->> U: Response containing the order-history data (Not the page itself, that was already sent in the original request)

        note right of U: productId's and productAttributeId's originate from data of an old order
        U ->>  B: POST request to /api/cart/items with an array of productId and productAttributeId pairs in the request body from an order in order-history
        note over B: πŸ“Š Track reorder attempted (item count)
        B ->>  B: Validate request to add product to cart (availibility etc.)
        note over B: πŸ“Š Track reorder result (success/partial with counts)
        B -->> U: Response containing the updated cart data (data is used for the cart sidebar)
    end

    U ->>  U: Clicks on 'Cart' button sends user to /cart
    U ->>  B: GET request to /cart
    note over B: πŸ“Š Track cart page viewed
    B ->>  B: Use users session to get cart data
    B -->> U: Response containing Cart page with cart data

Cart removal metrics

When a user removes/updates items from the cart, the following metrics are tracked:

  • πŸ“Š Metric: cart_item_remove (CartController)
  • πŸ“Š Metric: cart_item_remove (My Account API)
  • πŸ“Š Metric: cart_item_update (CartController)
  • πŸ“Š Metric: cart_item_update (My Account API)

πŸ“‹ Checkout step 1 - AuthenticationΒΆ

Flow - click to expand
sequenceDiagram
    autonumber
    participant U as User
    participant B as Backend

    U ->> B: Navigate to checkout - GET /checkout/auth
    activate B
    B ->> B: Check if user is logged in

    alt User login status
        note over U,B: User already logged in
        note over B: πŸ“Š Track auth skip (already logged in)
        B -->> U: Redirect to /checkout/payment-selection
    else
        note over U,B: User not logged in
        B -->> U: Response containing auth page with auth options (Login/Register/Guest/Forgot Password)
        note over B: πŸ“Š Track auth page viewed
    end

    alt Authentication method
        U ->> B: <a href="authentication-method-login">πŸ”„ Login</a>
    else
        U ->> B: <a href="authentication-method-register">πŸ”„ Register</a>
    else
        U ->> B: <a href="authentication-method-guest">πŸ”„ Continue as Guest</a>
    else
        U ->> B: <a href="authentication-method-forgot-password">πŸ”„ Forgot Password</a>
    end

    deactivate B

πŸ”„ Authentication method - LoginΒΆ

Flow - click to expand
sequenceDiagram
    autonumber
    participant U as User
    participant B as Backend

    U ->> U: Navigate to /checkout/auth?mode=login (client-side)
    U ->> U: Enter email and password in login form
    U ->> B: Submit login - POST /checkout/auth?mode=login
    note over B: πŸ“Š Track login attempted

    alt Login result
        note right of U: Login successful
        note over B: πŸ“Š Track login success
        note over B: TODO - Merge guest cart + logged-in cart<br/> TODO (handle 'created' orders attached to either cart)
        B ->> B: Update customer session
        B -->> U: Redirect to /checkout/payment-selection
    else
        note right of U: Login failed
        note over B: πŸ“Š Track login failed (reason)
        B -->> U: Response with error message, stay on /checkout/auth
    end

πŸ”„ Authentication method - RegisterΒΆ

Flow - click to expand
sequenceDiagram
    autonumber
    participant U as User
    participant B as Backend

    U ->> U: Navigate to /checkout/auth?mode=register (client-side)
    U ->> U: Fill in registration form with password field
    note over U: Form includes: email, password, name,<br/>address, phone, country selector (NL/FR/LU only)
    U ->> B: Submit registration - POST /checkout/auth?mode=register
    note over B: πŸ“Š Track register attempted

    alt Registration result
        note right of U: Registration successful
        note over B: πŸ“Š Track register success
        B ->> B: Create customer account (is_guest=false)
        B ->> B: Associate cart with new customer
        B ->> B: Update customer session
        B -->> U: Redirect to /checkout/payment-selection
    else
        note right of U: Registration failed
        note over B: πŸ“Š Track register failed (reason: email exists, validation, etc.)
        B -->> U: Response with error message, stay on /checkout/auth
    end

πŸ”„ Authentication method - GuestΒΆ

Flow - click to expand
sequenceDiagram
    autonumber
    participant U as User
    participant B as Backend

    U ->> U: Navigate to /checkout/auth?mode=guest (client-side)
    U ->> U: Fill in guest registration form (no password field)
    note over U: Form includes: email, name, address,<br/>phone, country selector (FR/LU only)
    U ->> B: Submit guest registration - POST /checkout/auth?mode=guest
    note over B: πŸ“Š Track guest register attempted

    alt Guest registration result
        note right of U: Guest registration successful
        note over B: πŸ“Š Track guest register success
        B ->> B: Create guest customer account (is_guest=true)
        B ->> B: Associate cart with guest customer
        B ->> B: Update customer session
        B -->> U: Redirect to /checkout/payment-selection
    else
        note right of U: Guest registration failed
        note over B: πŸ“Š Track guest register failed (reason)
        B -->> U: Response with error message, stay on /checkout/auth
    end

πŸ”„ Authentication method - Forgot PasswordΒΆ

Flow - click to expand
sequenceDiagram
    autonumber
    participant U as User
    participant B as Backend
    participant E as Email System

    U ->> B: Click "Forgot Password" link - GET /password-recovery
    B -->> U: Response containing password recovery page
    note over B: πŸ“Š Track password recovery page viewed

    U ->> U: Enter email address
    U ->> B: Submit password reset - POST /password-recovery
    note over B: πŸ“Š Track password reset requested

    alt Password reset
        note right of U: Email exists
        B ->> E: Send password reset email
        note over B: πŸ“Š Track password reset email sent
        E -->> U: Password reset email delivered
        B -->> U: Response with "Check your email" message

        U ->> U: Open email, click reset link
        U ->> B: Open reset link - GET /password-recovery?reset_token=X&id_customer=Y
        B -->> U: Response containing new password form

        U ->> U: Enter new password twice
        U ->> B: Submit new password - POST /password-recovery
        note over B: πŸ“Š Track password reset completed
        B -->> U: Response with "Password changed" message

        U ->> U: Clicks on 'Cart' button sends user to /cart
        U ->> B: GET request to /cart
        B ->> B: Use users session to get cart data
        B -->> U: Response containing Cart page with cart data
        note over U,B: Go Back to -> Checkout step 1 - Authentication
    else
        note right of U: Email not found
        note over B: πŸ“Š Track password reset failed (email not found)
        B -->> U: Response with error message
    end

πŸ“‹ Checkout step 2 - Payment Selection & Order CreationΒΆ

Flow - click to expand
sequenceDiagram
    autonumber
    participant U as User
    participant B as Backend

    U ->> B: View payment selection page - GET /checkout/payment-selection
    activate B
    note over B: πŸ“Š Track payment selection page viewed

    note over B: See: <a href="order-handling-flow">πŸ”„ Order Handling flow</a>

    B ->> B: Get available payment methods for this customer
    B -->> U: Response containing payment methods page

    U ->> U: Select payment method from list
    U ->> B: Submit payment method selection - POST /checkout/payment-selection
    note over B: πŸ“Š Track payment method selected

    alt Payment method routing
        note over U,B: Creditcard selected
        B -->> U: Redirect to <a href="checkout-step-2a-creditcard-selection">⚠️ Step 2a - Creditcard Selection</a>
    else
        note over U,B: Bancontact selected
        B -->> U: Redirect to <a href="checkout-step-2b-bancontact-selection">⚠️ Step 2b - Bancontact Selection</a>
    else
        note over U,B: iDEAL, PayPal, Klarna, or Bank Transfer selected
        B -->> U: Redirect to /checkout/payment?method=METHOD_NAME
        note over U,B: See payment method flows:<br/><a href="ideal-flow">πŸ“‹ iDEAL</a>, <a href="paypal-flow">⚠️ PayPal</a>, <a href="klarna-flow">⚠️ Klarna</a>, <a href="bank-transfer-flow">⚠️ Bank Transfer</a>
    end

    deactivate B

Payment Method FlowsΒΆ

⚠️ Checkout step 2a - Creditcard Selection¢

Status: ⚠️ To be detailed

Flow characteristics:

  • Select existing saved card OR enter new card details
  • Optional: Save card for future use
  • Card tokenization via CM.com
  • Redirect to /checkout/payment after selection

⚠️ Checkout step 2b - Bancontact Selection¢

Status: ⚠️ To be detailed

Flow characteristics:

  • Choose payment option: QR Code, Mobile App, or Card
  • If Card selected: Card selection/entry (similar to creditcard flow)
  • QR code generation for desktop users
  • Redirect to /checkout/payment after selection

πŸ“‹ iDEAL FlowΒΆ

Flow - click to expand
sequenceDiagram
    autonumber
    participant U as User
    participant B as Backend
    participant CM as CM.com REST API
    participant Bank as iDEAL Bank

    note over U,B: Coming from <a href="checkout-step-2-payment-selection-order-creation">πŸ“‹ Step 2 - Payment Selection</a><br/>User selected iDEAL as payment method

    U ->> B: Initiate payment - GET /checkout/payment?method=ideal
    activate B
    note over B: πŸ“Š Track payment page viewed (method=ideal)

    B ->> B: Load order from cart (via session)
    B ->> B: Create payment attempt (status='initiated')
    note over B: Payment Attempt ID: 67890<br/>Order ID: 12345<br/>Method: ideal<br/>Status: initiated
    B ->> B: Update order status to 'pending' (lock cart/prices)
    note over B: Order is now LOCKED - no more changes allowed

    B ->> CM: Create iDEAL transaction - POST /paymentmethods/ideal/v1/transactions
    activate CM
    note over CM: Request includes:<br/>- amount<br/>- returnUrls (success, cancelled, expired, failed)<br/>- consumer info<br/>- order reference
    CM -->> B: Response with transaction (status=OPEN)<br/>+ redirect URL
    note over B: CM Transaction ID: abc123<br/>Status: OPEN
    deactivate CM

    B ->> B: Store CM transaction ID in payment attempt
    note over B: πŸ“Š Track payment initiated (cm_transaction_id)
    B -->> U: Redirect to iDEAL (via CM.com)
    deactivate B

    U ->> Bank: User completes payment at iDEAL
    activate Bank
    note over U,Bank: User selects bank, authenticates, and confirms payment via mobile app

    Bank ->> CM: Payment result (SUCCESS/CANCELLED/EXPIRED/FAILURE)
    CM ->> B: Webhook notification with status
    Bank -->> U: Redirect to returnUrl: /checkout/validate?attempt_id=67890
    deactivate Bank

    note over U,B: Go to -> <a href="checkout-step-4-payment-validation">πŸ“‹ Checkout step 4 - Payment Validation</a><br/>Backend will check webhook data to determine actual status

⚠️ PayPal Flow¢

Status: ⚠️ To be detailed

Flow characteristics:

  • REST-based payment method
  • Redirect to PayPal login
  • External authentication
  • Return callback

⚠️ Creditcard Flow¢

Status: ⚠️ To be detailed

Flow characteristics:

  • Uses selected/entered card from step 2a
  • 3D Secure authentication
  • SOAP to REST migration needed

⚠️ Bancontact Flow¢

Status: ⚠️ To be detailed

Flow characteristics:

  • Multiple sub-flows based on selection from step 2b
  • QR code scanning (desktop)
  • Mobile app redirect
  • Card payment with 3D Secure
  • SOAP to REST migration needed

⚠️ Klarna Flow¢

Status: ⚠️ To be detailed

Flow characteristics:

  • Phone number requirement
  • External redirect
  • SOAP to REST migration needed

⚠️ Bank Transfer Flow¢

Status: ⚠️ To be detailed

Flow characteristics:

  • No immediate payment
  • Display payment instructions
  • Manual confirmation
  • SOAP to REST migration needed

πŸ“‹ Checkout step 4 - Payment ValidationΒΆ

Flow - click to expand
sequenceDiagram
    autonumber
    participant U as User
    participant B as Backend
    participant CM as CM.com REST API

    Note over U,CM: User returns from payment provider

    U ->> B: Validate payment - GET /checkout/validate?attempt_id=67890
    activate B
    B ->> CM: Check payment status - GET /payments/{transaction_id}
    activate CM
    CM -->> B: Response: {status, reason}
    deactivate CM

    alt Payment Success
        B ->> B: Update payment attempt (status='success')
        B ->> B: Update order (status='confirmed')
        note over B: πŸ“Š Track payment success
        B -->> U: Redirect to /checkout/confirmation?order_id=12345
    else Payment Failed
        B ->> B: Update payment attempt (status='failed', error_code)
        note over B: Order remains status='pending'
        note over B: πŸ“Š Track payment failed (with reason)
        B -->> U: Redirect to /checkout/payment-selection?error=payment_failed
        note right of U: See: <a href="#unhappy-path---failed-payment-retry">πŸ”„ Failed Payment Retry flow</a><br/>Modal opens with error message
    else Payment Cancelled
        B ->> B: Update payment attempt (status='cancelled')
        note over B: Order remains status='pending'
        note over B: πŸ“Š Track payment cancelled
        B -->> U: Redirect to /checkout/payment-selection?cancelled=true
        note right of U: See: <a href="#unhappy-path---payment-method-switch">πŸ”„ Payment Method Switch flow</a><br/>Modal opens with cancellation message
    end

    deactivate B

πŸ“‹ Checkout step 5 - Order ConfirmationΒΆ

Flow - click to expand
sequenceDiagram
    autonumber
    participant U as User
    participant B as Backend

    U ->> B: View confirmation - GET /checkout/confirmation?order_id=12345
    activate B
    B ->> B: Load order details
    B -->> U: Display order confirmation
    note over B: πŸ“Š Track order confirmation viewed
    deactivate B

Unhappy Path FlowsΒΆ

πŸ”„ Unhappy Path - Failed Payment RetryΒΆ

Failed Payment with Retry - click to expand

Modal-based Retry

When payment fails, user is redirected to /checkout/payment-selection?error=payment_failed. A modal opens showing the error message with two options:

  • "Try Again" - Retry with the same payment method
  • "Close" - Close modal and select a different method
sequenceDiagram
    autonumber
    participant U as User
    participant B as Backend

    note over U,B: <span style="color:#FF9800; font-weight:bold;">Go Back to -></span> <a href="#checkout-step-3---payment-validation">Checkout step 3 - Payment Validation</a><br/>Payment failed, redirected to /checkout/payment-selection?error=payment_failed

    Note over U: Modal opens: "Payment failed: insufficient funds"<br/>Options: "Try Again" | "Close"

    alt User clicks "Try Again"
        U ->> B: Click "Try Again" - POST /checkout/payment-selection
        activate B
        B ->> B: Create new payment attempt<br/>(order_id=12345, retry_count=1, status='initiated')
        note over B: Payment Attempt ID: 2<br/>Same method as attempt 1
        note over B: πŸ“Š Track payment retry
        B -->> U: Redirect to /checkout/payment?attempt_id=2
        deactivate B

        note over U,B: <span style="color:#FF9800; font-weight:bold;">Go Back to -></span> Payment method flow<br/>Process attempt 2 (succeeds)

        note over U,B: <span style="color:#FF9800; font-weight:bold;">Go Back to -></span> <a href="#checkout-step-3---payment-validation">Checkout step 3 - Payment Validation</a>

        note over U,B: <span style="color:#FF9800; font-weight:bold;">Go Back to -></span> <a href="#checkout-step-4---order-confirmation">Checkout step 4 - Order Confirmation</a>
    else User clicks "Close" (switch method)
        U -->> U: Close modal, stay on /checkout/payment-selection
        note over U: User can now select different payment method
        note over U,B: See: <a href="#unhappy-path---payment-method-switch">πŸ”„ Payment Method Switch flow</a>
    end

    note over B: πŸ’‘ Result: Order 12345 has 2 payment attempts:<br/>Attempt 1: failed | Attempt 2: success (or cancelled if switched)

πŸ”„ Unhappy Path - Payment Method SwitchΒΆ

Payment Method Switching - click to expand

Modal-based Method Switch

When payment is cancelled, user is redirected to /checkout/payment-selection?cancelled=true. A modal opens showing cancellation message with options to retry or switch.

sequenceDiagram
    autonumber
    participant U as User
    participant B as Backend

    note over U,B: <span style="color:#FF9800; font-weight:bold;">Go Back to -></span> <a href="#checkout-step-3---payment-validation">Checkout step 3 - Payment Validation</a><br/>Payment cancelled, redirected to /checkout/payment-selection?cancelled=true

    Note over U: Modal opens: "Payment cancelled"<br/>Options: "Try Again" | "Close"

    U -->> U: Close modal (switching method)
    Note over U: User stays on /checkout/payment-selection

    U ->> B: Select different method (PayPal) - POST /checkout/payment-selection
    activate B
    B ->> B: Create new payment attempt<br/>(order_id=12345, method='paypal', status='initiated')
    note over B: Payment Attempt ID: 2
    note over B: πŸ“Š Track payment method switch (from=ideal, to=paypal)
    B -->> U: Redirect to /checkout/payment?attempt_id=2
    deactivate B

    note over U,B: <span style="color:#FF9800; font-weight:bold;">Go Back to -></span> New payment method flow (e.g., <a href="#paypal-flow">PayPal</a>)<br/>Process attempt 2

    note over U,B: <span style="color:#FF9800; font-weight:bold;">Go Back to -></span> <a href="#checkout-step-3---payment-validation">Checkout step 3 - Payment Validation</a><br/>Validate attempt 2 (succeeds)

    note over U,B: <span style="color:#FF9800; font-weight:bold;">Go Back to -></span> <a href="#checkout-step-4---order-confirmation">Checkout step 4 - Order Confirmation</a>

    note over B: πŸ’‘ Result: Order 12345 has 2 attempts:<br/>Attempt 1: iDEAL, cancelled<br/>Attempt 2: PayPal, success

πŸ”„ Order Handling FlowΒΆ

Order Creation and Re-evaluation - click to expand

When This Flow Triggers

This flow runs every time a user navigates to /checkout/payment-selection:

  • No order exists: First time visiting β†’ create new order
  • Order in 'created' state: User returns (refresh, back from cart) β†’ re-evaluate cart changes
  • Order in 'pending' state: User returns after failed/cancelled payment β†’ retry or switch method
sequenceDiagram
    autonumber
    participant U as User
    participant B as Backend

    B ->> B: Load cart from session
    B ->> B: Check if order exists linked to cart

    alt Order status
        note over U,B: No order exists
        B ->> B: Create order (status='created')
        B ->> B: Link order to cart
        note over B: πŸ“Š Track order created
        note over U,B: Go to -> Continue with payment selection
    else
        note over U,B: Order exists (status='pending')
        note over B: Order is LOCKED - cannot modify cart<br/>User is retrying/switching payment method
        B ->> B: Load existing order
        note over U,B: Go to -> Continue with payment selection (retry/switch)
    else
        note over U,B: Order exists (status='created')
        note over B: Order can still be modified - cart not locked
        B ->> B: Load existing order
        B ->> B: Compare order with current cart state
    end

    alt Cart comparison
        note over U,B: Cart unchanged
        note over U,B: Go to -> Continue with payment selection
    else
        note over U,B: Cart has changed
        B ->> B: Validate stock availability
        B ->> B: Recalculate totals (prices, tax, shipping)
    end

    alt Validation result
        note over U,B: Validation successful
        B ->> B: Update order line items and totals
        note over B: πŸ“Š Track order updated
        note over U: Notification: "Your order has been updated"
        note over U,B: Go to -> Continue with payment selection
    else
        note over U,B: Out of stock or validation failed
        note over B: πŸ“Š Track order validation failed
        B -->> U: Redirect to /cart with error message
        note over U: "Some items are no longer available"
    end

State machinesΒΆ

Order State MachineΒΆ

stateDiagram-v2
    [*] --> Created: Order Created (at payment-selection)

    note right of Created
        Customer can still modify cart/address
        Order gets updated when they return to payment-selection page
        ---
        Prices re-validated on return
    end note

    Created --> Pending: First Payment Attempt (at /checkout/payment)

    note right of Pending
        Order is LOCKED - no changes allowed
        Prices locked
        Can have multiple payment attempts
        ---
        30-minute timeout β†’ Abandoned
    end note

    Pending --> Confirmed: Payment Success
    Pending --> Failed: Payment Failed (max retries exceeded)
    Pending --> Cancelled: User Cancels
    Pending --> Abandoned: Timeout (30 min, lazy evaluation)

    note left of Abandoned
        Customer left during payment
        ---
        If customer returns: create new order with current prices/stock
    end note

    note left of Cancelled
        Customer actively clicked cancel during the payment process
    end note

    Confirmed --> Shipped: Order Shipped
    Confirmed --> Refunded: Refund Issued

    Shipped --> Delivered: Delivery Confirmed

    Abandoned --> [*]
    Cancelled --> [*]
    Failed --> [*]
    Refunded --> [*]
    Delivered --> [*]

Payment Attempt State MachineΒΆ

stateDiagram-v2
    [*] --> Initiated: Create Payment Attempt

    Initiated --> Cancelled: User Cancels (before processing)
    Initiated --> Processing: Sent to CM.com

    Processing --> Cancelled: Timeout/User Cancel
    Processing --> Failed: Payment Rejected
    Processing --> Success: Payment Approved

    Cancelled --> [*]: Allow Retry
    Failed --> [*]: Allow Retry
    Success --> [*]: Update Order

    note left of Cancelled
        ***Failed and Cancelled***
        Both states allow creating
        a new payment attempt
    end note