Laravel E-commerce Platform Architecture for Scale: Building Orderbase to Handle Millions
by Ferre, Co-Founder / CTO
Building Orderbase with Laravel taught us that e-commerce isn't just about displaying products in Blade templates—it's about orchestrating complex fulfillment workflows using Laravel's job queues, events, and Eloquent models that span inventory, payments, shipping, and customer communications. Here's how we built a Laravel platform that processes over 1 million orders while maintaining 99.9% uptime.
The E-commerce Scale Challenge
When we started building Orderbase, we thought we understood e-commerce. We'd built shopping carts and payment systems before. But true e-commerce scale is different—it's about coordinating dozens of moving parts in real-time while money is changing hands.
The Hidden Laravel Complexity
An "order" in Laravel e-commerce involves:
- Inventory reservation using Laravel's database transactions across multiple warehouse models
- Payment processing with Laravel jobs for fraud detection
- Tax calculation using Laravel services across jurisdictions
- Shipping calculation with Laravel HTTP client for carrier APIs
- Inventory updates using Laravel events in real-time
- Customer notifications using Laravel Mail and broadcasting at every step
- Returns processing using Laravel workflows and inventory restocking
- Analytics tracking using Laravel's event system for business intelligence
Miss any step in your Laravel application, and you have angry customers or lost revenue.
// Laravel Order Processing Pipeline
class OrderProcessingPipeline
{
public function process(Order $order)
{
DB::transaction(function () use ($order) {
// Reserve inventory using Eloquent relationships
$this->reserveInventory($order);
// Process payment with Laravel jobs
ProcessPayment::dispatch($order);
// Calculate tax using Laravel services
$order->tax_amount = app(TaxCalculationService::class)->calculate($order);
// Queue shipping calculation
CalculateShipping::dispatch($order);
// Fire Laravel event for notifications
event(new OrderProcessed($order));
$order->save();
});
}
}
System Architecture Overview
Laravel Services for E-commerce Scale
┌─ Laravel API Gateway (Middleware, auth, routing)
├─ Order Management Laravel App
├─ Inventory Management Laravel App
├─ Payment Processing Laravel App
├─ Shipping & Fulfillment Laravel App
├─ Customer Communication Laravel App
├─ Analytics & Reporting Laravel App
└─ External Integrations (Laravel HTTP client, Guzzle)
Each Laravel application handles a specific domain and can scale independently using Laravel Octane:
Order Management: Eloquent order models, Laravel state machines, business logic in services
Inventory Management: Stock level models, Laravel job queues for reservations, warehouse coordination
Payment Processing: Laravel Cashier integration, payment capture jobs, fraud detection middleware
Shipping: Carrier integration using Laravel HTTP client, label generation jobs, tracking events
Communications: Laravel Mail, Laravel Notifications for SMS, Laravel Broadcasting for real-time updates
Top tip
Design your order state machine carefully upfront. We use 12 distinct order states, and changing this later required migrating millions of orders. Get it right the first time.
Real-Time Inventory Management
The Inventory Sync Problem
E-commerce inventory is a distributed systems problem:
- Multiple sales channels (web, mobile, marketplaces, retail)
- Multiple warehouses with different stock levels
- Concurrent order processing competing for the same items
- Real-time updates without overselling
Our Solution: Event-Driven Inventory
// Inventory reservation system
class InventoryService {
async reserveItems(orderId, items) {
const transaction = await this.db.beginTransaction();
try {
for (const item of items) {
// Atomic reservation with expiration
const reserved = await this.db.query(`
UPDATE inventory
SET reserved_qty = reserved_qty + ?,
updated_at = NOW()
WHERE sku = ? AND warehouse_id = ?
AND (available_qty - reserved_qty) >= ?
`, [item.quantity, item.sku, item.warehouse, item.quantity]);
if (reserved.affectedRows === 0) {
throw new Error(`Insufficient inventory for ${item.sku}`);
}
// Create reservation record with TTL
await this.db.query(`
INSERT INTO inventory_reservations
(order_id, sku, warehouse_id, quantity, expires_at)
VALUES (?, ?, ?, ?, DATE_ADD(NOW(), INTERVAL 30 MINUTE))
`, [orderId, item.sku, item.warehouse, item.quantity]);
}
await transaction.commit();
// Schedule cleanup job for expired reservations
await this.scheduleReservationCleanup(orderId);
} catch (error) {
await transaction.rollback();
throw error;
}
}
}
Multi-Warehouse Optimization
We built an intelligent warehouse allocation system:
class WarehouseOptimizer {
async optimizeAllocation(orderItems, shippingAddress) {
const warehouses = await this.getAvailableWarehouses();
// Score warehouses by:
// 1. Distance to customer (shipping cost/time)
// 2. Inventory availability
// 3. Warehouse capacity and congestion
// 4. Historical performance
const scored = warehouses.map(warehouse => ({
...warehouse,
score: this.calculateWarehouseScore(warehouse, orderItems, shippingAddress)
})).sort((a, b) => b.score - a.score);
// Try to fulfill from single warehouse first
for (const warehouse of scored) {
if (this.canFulfillCompletely(warehouse, orderItems)) {
return [{ warehouse: warehouse.id, items: orderItems }];
}
}
// Fall back to split shipment optimization
return this.optimizeSplitShipment(orderItems, scored);
}
}
Payment Processing Architecture
Handling Payment Complexity
Payment processing at scale involves more than just charging cards:
- Multi-step authorization: Auth → Capture → Settlement
- Fraud detection: Real-time risk scoring and review
- Failed payment recovery: Automatic retry logic with exponential backoff
- Refund processing: Partial and full refunds with inventory updates
- International payments: Multi-currency support and compliance
Our Payment Flow
class PaymentProcessor {
async processPayment(order) {
// 1. Risk assessment first
const riskScore = await this.assessFraudRisk(order);
if (riskScore > 0.8) {
return this.flagForManualReview(order);
}
// 2. Authorization hold
const authResult = await this.authorizePayment(order);
if (!authResult.success) {
return this.handlePaymentFailure(order, authResult);
}
// 3. Inventory reservation (now that payment is authorized)
await this.inventoryService.reserveItems(order.id, order.items);
// 4. Capture payment (convert auth to actual charge)
const captureResult = await this.capturePayment(order, authResult.authId);
if (captureResult.success) {
// 5. Trigger fulfillment
await this.fulfillmentService.createShipment(order);
}
return captureResult;
}
}
Shipping and Fulfillment
Multi-Carrier Integration
We integrate with 15+ shipping carriers globally:
- Rate shopping: Compare rates across carriers in real-time
- Service selection: Balance cost vs. speed based on customer preferences
- Label generation: Automated label creation and tracking number assignment
- Delivery tracking: Proactive notifications about shipment status
Fulfillment Workflow Engine
class FulfillmentEngine {
async processFulfillment(order) {
const workflow = new WorkflowBuilder()
.step('validate_inventory', this.validateInventory)
.step('allocate_warehouse', this.allocateWarehouse)
.step('generate_pick_list', this.generatePickList)
.step('calculate_shipping', this.calculateShipping)
.step('generate_labels', this.generateLabels)
.step('update_tracking', this.updateTracking)
.step('notify_customer', this.notifyCustomer)
.onError(this.handleFulfillmentError)
.build();
return await workflow.execute(order);
}
}
Customer Communication Pipeline
Event-Driven Notifications
Every order event triggers appropriate customer communications:
// Event-driven notification system
const orderEvents = {
ORDER_CONFIRMED: 'Your order has been confirmed',
PAYMENT_PROCESSED: 'Payment received',
ORDER_SHIPPED: 'Your order is on the way',
DELIVERY_ATTEMPTED: 'Delivery attempted',
ORDER_DELIVERED: 'Order delivered',
ORDER_EXCEPTION: 'Issue with your order'
};
class NotificationService {
async handleOrderEvent(event, order) {
const templates = await this.getNotificationTemplates(event.type);
// Multi-channel notifications
const channels = [
this.emailService.send(order.customer.email, templates.email),
this.smsService.send(order.customer.phone, templates.sms),
this.pushService.send(order.customer.deviceId, templates.push)
];
await Promise.allSettled(channels);
// Track notification delivery for analytics
await this.analytics.track('notification_sent', {
orderId: order.id,
eventType: event.type,
channels: channels.length
});
}
}
Performance and Scalability
Database Optimization
Order data grows quickly. Our optimization strategies:
Partitioning: Orders partitioned by date for efficient querying
-- Partition orders table by month
CREATE TABLE orders (
id UUID,
customer_id UUID,
order_date DATE,
status ENUM('pending', 'confirmed', 'shipped', 'delivered'),
-- ... other columns
) PARTITION BY RANGE (YEAR(order_date) * 100 + MONTH(order_date)) (
PARTITION p202501 VALUES LESS THAN (202502),
PARTITION p202502 VALUES LESS THAN (202503),
-- ... additional partitions
);
Read Replicas: Separate analytical queries from transactional workload Connection Pooling: Essential for high-concurrent order processing Caching Strategy: Redis for frequent lookups (product data, tax rates, shipping zones)
Auto-Scaling Configuration
# Kubernetes auto-scaling for order processing
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: orderbase-api
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: orderbase-api
minReplicas: 3
maxReplicas: 50
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Pods
pods:
metric:
name: orders_per_second
target:
type: AverageValue
averageValue: "100"
Monitoring and Observability
Key Metrics We Track
Business Metrics:
- Order conversion rates by traffic source
- Average order value trends
- Cart abandonment rates and recovery
- Customer lifetime value by cohort
Technical Metrics:
- Order processing latency (target: under 500ms)
- Payment success rates (target: above 98%)
- Inventory sync accuracy (target: above 99.9%)
- System uptime (target: above 99.9%)
Custom Dashboards: We built real-time dashboards showing:
- Orders per minute across all channels
- Inventory levels by warehouse
- Payment processing success rates
- Shipping carrier performance
- Customer satisfaction scores
Error Handling and Recovery
Graceful Degradation
When external services fail, we maintain core functionality:
- Payment processor down: Queue orders for processing when service recovers
- Shipping API unavailable: Fall back to cached rates and manual processing
- Inventory service slow: Use cached levels with oversell protection
- Email service down: Queue notifications and use alternative providers
Business Results
Since launching Orderbase:
- Orders processed: 1M+ orders with 99.9% success rate
- Performance: Average order processing time under 500ms
- Accuracy: under 0.1% inventory sync errors
- Customer satisfaction: 4.8/5 average rating
- Cost savings: 30% reduction in fulfillment costs through optimization
Lessons Learned
What Works:
- Event-driven architecture scales better than monolithic order processing
- Inventory reservations with TTL prevent overselling without locking stock forever
- Multi-carrier integration improves delivery performance and reduces costs
- Comprehensive monitoring prevents small issues from becoming big problems
What We'd Do Differently:
- Start with event sourcing for order state management from day one
- Build admin tools earlier - operations teams need visibility
- Invest in automated testing for payment flows upfront
- Plan for international expansion earlier in the architecture
Building e-commerce platforms that scale isn't just about handling traffic—it's about orchestrating complex business processes reliably while maintaining a great customer experience.
Building e-commerce platforms or need fulfillment optimization? We've solved the hard problems of scale, reliability, and performance. Let's discuss your e-commerce challenges.