Laravel Ecommerce Architecture: Catalog, Cart, Orders, Payments

#laravel #ecommerce architecture #catalog #shopping cart #order management #payment gateway

When you strip away the CSS, the marketing banners, and the recommendation algorithms, every e-commerce application on earth is fundamentally a state machine that moves a user through four distinct architectural pillars: the Catalog, the Cart, the Order, and the Payment.

If you tightly couple these four pillars in a custom Laravel application, you will create a fragile monolith. If a pricing rule changes in the Catalog, it might accidentally alter the historical revenue of a past Order. If a Payment gateway fails, it might accidentally empty the user's Cart.

This is the Micro-Architecture Breakdown. To build a robust, enterprise-grade e-commerce engine in Laravel, you must treat these four pillars as isolated domains that communicate through strict boundaries.

Pillar 1: The Catalog Domain (Read-Heavy, Polymorphic)

The Catalog is the public face of your store. It includes products, categories, variants, pricing rules, and inventory counts.

The Architectural Challenge

The Catalog is overwhelmingly read-heavy. For every one customer who checks out, 99 customers only browse the catalog. Furthermore, products are rarely uniform. You might sell a digital PDF, a t-shirt with size and color variants, and a monthly subscription—all on the same platform.

The Laravel Solution

  • Polymorphic Relationships: Instead of creating a massive products table with 50 nullable columns (e.g., tshirt_size, pdf_download_link), use Laravel's Polymorphic relationships. Create a central purchasables table for shared data (SKU, price, title), and polymorphic relations to specific models (ShirtVariant, DigitalDownload).
  • CQRS (Command Query Responsibility Segregation): Because the Catalog is read-heavy, decouple the read database from the write database. Use Laravel Scout (backed by Algolia or Elasticsearch) to handle all catalog browsing, filtering, and searching. The primary SQL database should only be queried when a product is actively being edited in the admin panel or added to a cart.

Pillar 2: The Cart Domain (Volatile, Session-Based)

The Cart is a temporary holding area. It is highly volatile state. Users add items, change quantities, apply discount codes, and abandon carts daily.

The Architectural Challenge

Because carts are volatile, storing every cart update in the primary SQL database creates unnecessary write-heavy load and fills the database with abandoned cart garbage.

The Laravel Solution

  • Redis-Backed Storage: Do not store active shopping carts in MySQL or PostgreSQL. Use Redis. Serialize the cart contents and store them against the user's session ID or authenticated user ID in Redis with a 7-day Time-To-Live (TTL). This ensures lightning-fast cart updates and automatic garbage collection when a cart is abandoned.
  • The Hydration Pattern: The cart stored in Redis should only contain the bare minimum data: the purchasable_id, purchasable_type, and quantity. Never store the price in the cart cache. When the user views the cart page, "hydrate" the cart by querying the Catalog domain for the real-time prices. This prevents users from leaving an item in their cart for a month and checking out at the old price.

Pillar 3: The Order Domain (Immutable, Write-Once)

The Order domain is the legal and financial ledger of your application. Once a checkout is initiated, the volatile Cart is converted into an immutable Order.

The Architectural Challenge

Historical integrity. If a t-shirt costs $20 today, and a user buys it, the order total is $20. If you increase the price to $25 tomorrow, that historical order must remain $20. A shocking number of custom stores fail this test by joining the orders table to the active products table to calculate revenue.

The Laravel Solution

  • Data Snapshotting: When an Order is created, you must take a snapshot of the Catalog data. The order_items table must have its own static price_paid, tax_paid, and product_name columns. Even if the original product is completely deleted from the database next year, the Order record remains 100% intact and accurate for accounting purposes.
  • State Machines: Orders do not simply exist; they move through a lifecycle (Pending -> Paid -> Processing -> Shipped -> Delivered). Use a State Machine package (like spatie/laravel-model-states) to enforce valid transitions. An order cannot transition to "Shipped" unless its payment state is "Paid."

Pillar 4: The Payment Domain (Asynchronous, Unpredictable)

The Payment domain connects your application to the banking system. It handles credit cards, fraud detection, and refunds.

The Architectural Challenge

The banking system is slow, asynchronous, and prone to network timeouts. If you tie the creation of an Order to a synchronous HTTP response from Stripe, you will eventually lose data during a timeout.

The Laravel Solution

  • The Webhook-First Approach: Never trust the synchronous redirect back to your site after a customer pays. The user might close their browser window before the redirect happens. Instead, treat the frontend checkout merely as an "Intent to Pay." The actual Order status should only be updated to "Paid" via an asynchronous background Webhook sent directly from the payment gateway to your server.
  • Idempotency: Webhooks can be delivered twice by accident. Your Laravel webhook controller must be idempotent. It must check: "Have I already processed payment intent pi_12345?" If yes, return a 200 OK immediately without touching the database. If no, process the payment and update the Order state.

Conclusion

If you build an e-commerce platform where the Catalog, Cart, Order, and Payment logic are all tangled inside a single CheckoutController, you have built a ticking time bomb. By architecting these four pillars as isolated domains, you create a system that can scale, adapt to new business requirements, and process millions in revenue without dropping a single transaction.

If you are planning to build a custom e-commerce architecture and need a developer who understands these strict domain boundaries, review my Laravel development services to see how we can collaborate.


Prakash Tank

Prakash Tank

Full-Stack Architect & Tech Enthusiast. Passionate about building scalable applications and sharing knowledge with the community.