Web Commerce Domain
Location: api/nextango/apps/web_commerce/
Added: November 2025
Last Updated: 2026-07-08
Overview
The Web Commerce domain handles web checkout sessions, cart management, and inventory reservations for the web storefront. It mirrors the POS domain architecture but is optimized for web checkout flows with TTL-based sessions instead of heartbeat-based terminal sessions.
The app's URLconf mounts at web-commerce/ on the root URLconf (nextango/urls.py:167), so every Django-level endpoint is an absolute path under /web-commerce/. See Views for the full endpoint list and the storefront proxy prefix distinction.
Key Architectural Principles
- Pure orchestration: services coordinate existing domain services (
TransactionService,PaymentService,InventoryAdjustmentService) rather than implementing business logic - TTL-based sessions: checkout sessions expire after 30 minutes by default, with auto-expiry of inventory reservations
- Guest and authenticated: supports both guest checkout and authenticated customer checkout
- Atomic inventory: row-level locking ensures inventory reservations are consistent
- Ownership-based cart and checkout access: cart and checkout endpoints authorize by
web_sessionFK ownership, not by trustingsession['cart_id']byte-equality. A cart-session token (X-Cart-Session-Tokenheader, hashed with SHA-256 and stored onWebSession.cart_token_hash) is the primary identity credential, with the session cookie as fallback, so identity survives cookie-hostile contexts such as embedded webviews. See Views for the authorization gates and Services forSessionService.
Domain Structure
web_commerce/
├── models.py # CheckoutSession, CheckoutReservationContext
├── services/
│ ├── cart_service.py # Cart validation and composition
│ ├── checkout_service.py # Checkout flow orchestration
│ ├── email_service.py # Order confirmation & notification emails (Updated Dec 2025)
│ ├── reservation_service.py # Inventory reservation management
│ ├── session_service.py # Web session management
│ └── lifecycle_service.py # Session cleanup and expiry
├── views.py # API endpoints
├── serializers.py # DRF serializers
├── middleware.py # Session/CSRF middleware
├── signals.py # Event handlers
├── tasks.py # Celery background tasks
└── urls.py # URL routing
Relationship to Other Domains
┌─────────────────────────────────────────────────────────────┐
│ WEB COMMERCE │
│ (Orchestrates checkout flow for web storefront) │
├─────────────────────────────────────────────────────────────┤
│ │
│ CheckoutSession ─────────────► transactions.SaleTransaction │
│ │ │ │
│ └──► transactions.Cart │ │
│ │ │ │
│ └──► web_auth.WebSession │ │
│ │ │
│ CheckoutReservationContext ▼ │
│ │ transactions.Fulfillment │
│ └──► products.InventoryLevel │ │
│ transactions.Shipment│
│ │
└─────────────────────────────────────────────────────────────┘
Key Relationships:
- transactions.Cart: Uses the existing Cart model with JSONField line_items
- transactions.SaleTransaction: Creates transaction on checkout completion
- transactions.Fulfillment/Shipment: Created for shipping orders
- products.InventoryLevel: Reservations increment
stock_reserved - web_auth.WebSession: Guest/authenticated session context
Checkout Flow
┌─────────────────────────────────────────────────────────────┐
│ CHECKOUT FLOW │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. CART STAGE │
│ └──► CartService.add_to_cart() │
│ └──► CartService.validate_cart() │
│ │
│ 2. INITIATE CHECKOUT │
│ └──► CheckoutService.initiate_checkout() │
│ - Creates CheckoutSession │
│ - Sets fulfillment_method (ship/pickup/digital) │
│ - Validates cart │
│ │
│ 3. COLLECT INFORMATION │
│ - Frontend collects address, payment, delivery │
│ - Session expires_at extended on activity │
│ │
│ 4. COMPLETE CHECKOUT │
│ └──► CheckoutService.complete_checkout() │
│ - Creates SaleTransaction │
│ - Adds line items │
│ - Processes payment │
│ - Commits inventory │
│ - Creates Fulfillment/Shipment │
│ - Clears cart │
│ │
└─────────────────────────────────────────────────────────────┘
Inventory Reservation Lifecycle
┌─────────────────────────────────────────────────────────────┐
│ RESERVATION LIFECYCLE │
├─────────────────────────────────────────────────────────────┤
│ │
│ ACTIVE ──────────► COMMITTED (checkout completed) │
│ │ │
│ └────────────► RELEASED (checkout cancelled) │
│ │ │
│ └────────────► EXPIRED (TTL elapsed) │
│ │
│ Process: │
│ 1. reserve_for_checkout() increments stock_reserved │
│ 2. On completion: commit_reservations() marks committed │
│ 3. On cancel: release_reservations() decrements reserved │
│ 4. Background task: expire_old_reservations() auto-release │
│ │
└─────────────────────────────────────────────────────────────┘
Documentation Files
- Models:
CheckoutSession,CheckoutReservationContext - Services:
CartService,CheckoutService,ReservationService,SessionService,LifecycleService - Views: API endpoints, including ownership-based authorization and guest order tracking
- Serializers: request/response serialization
- Middleware:
CartValidationMiddleware - Signals: reservation cleanup on session lifecycle events
- Tasks: periodic cleanup Celery tasks
Storefront API Proxy (Next.js)
The storefront (storefront/web/) uses a Next.js API route to proxy requests to Django.
Location: storefront/web/app/api/[[...path]]/route.ts
How It Works
- All methods proxied: GET, POST, PUT, PATCH, DELETE
- Cookie forwarding: Browser cookies forwarded to Django for session validation
- Service account auth: Injects
Authorization: Token <token>from Docker secret or env var - URL mapping:
/api/foo/baron storefront maps tohttp://api:8000/foo/baron Django
Configuration
| Environment Variable | Purpose | Default |
|---|---|---|
DJANGO_API_URL | Backend API URL | http://api:8000 |
DJANGO_API_TOKEN | Service account token | Docker secret fallback |
Docker Secret Path
Token can be stored at /run/secrets/storefront_api_token for Docker Swarm deployments.
Request Flow
Browser → Storefront (/api/products/) → Proxy → Django (http://api:8000/products/)
↓
+ Cookie header
+ Authorization header
+ X-Forwarded-Proto: https
Guest Order Tracking
Added: December 2025
Enables guest customers to track orders without creating an account.
Flow
- Checkout completion:
guest_access_tokengenerated and stored onSaleTransaction - Confirmation email: Token included in order confirmation
- Order lookup: Guest uses token via
POST /web-commerce/guest-order/
Security
- 32-character alphanumeric token generated with
secrets.choice() - Rate-limited endpoint (
AnonRateThrottle) - Generic error messages prevent token enumeration
- No personal data in URL (POST body only)
Related Documentation
- Transactions Domain - Cart, SaleTransaction, Fulfillment models
- Transactions Views - FulfillmentViewSet, ShipmentViewSet
- Products Domain - InventoryLevel model
- Web Auth Domain - WebSession model
- POS Gateway Domain - Similar architecture for POS