Loading content...
Order processing is where everything comes together—and where everything can go wrong. When a customer clicks 'Place Order', a cascade of operations must execute correctly:
Any of these can fail. Networks are unreliable. Payment gateways timeout. Databases crash. The order system must complete successfully OR fail gracefully with clear recovery paths. A customer should never be charged without receiving their order, and should never receive an order without being charged.
At Amazon's scale—10,000+ orders per second during peak—the order pipeline must be:
By the end of this page, you will understand how to implement the Saga pattern for distributed transactions; design idempotent payment processing that handles retries safely; build order state machines that survive failures; and create audit trails for compliance and debugging.
An order is more than a list of items with a payment—it's a rich document that tracks the complete lifecycle from placement through delivery and potential returns.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
// Core Order Entityinterface Order { id: string; // UUID orderNumber: string; // Human-readable (e.g., "123-4567890-1234567") userId: string; // Order state status: OrderStatus; statusHistory: StatusChange[]; // Items ordered items: OrderItem[]; // Shipping shippingAddress: Address; billingAddress: Address; shippingMethod: ShippingMethod; // Financials subtotal: Money; shippingCost: Money; taxAmount: Money; discountAmount: Money; total: Money; // Payment paymentMethod: PaymentMethodSummary; paymentTransactions: PaymentTransaction[]; // Promotions appliedPromotions: AppliedPromotion[]; // Fulfillment fulfillmentStatus: FulfillmentStatus; shipments: Shipment[]; // Timestamps placedAt: Timestamp; paidAt?: Timestamp; shippedAt?: Timestamp; deliveredAt?: Timestamp; // Metadata source: 'web' | 'mobile' | 'api' | 'marketplace'; ipAddress: string; userAgent: string; locale: string; currency: Currency;} type OrderStatus = | 'PENDING_PAYMENT' // Order created, payment in progress | 'PAYMENT_FAILED' // Payment declined/failed | 'CONFIRMED' // Payment successful, inventory reserved | 'PROCESSING' // In fulfillment workflow | 'PARTIALLY_SHIPPED' // Some items shipped | 'SHIPPED' // All items shipped | 'DELIVERED' // Delivery confirmed | 'CANCELLED' // Order cancelled | 'RETURNED' // Items returned | 'REFUNDED'; // Payment refunded interface OrderItem { id: string; productId: string; variantId: string; sku: string; // Snapshot of product at order time title: string; imageUrl: string; // Quantities quantityOrdered: number; quantityShipped: number; quantityCancelled: number; quantityReturned: number; // Pricing (at order time) unitPrice: Money; lineTotal: Money; discountAmount: Money; // Fulfillment fulfillmentLocationId: string; shipmentId?: string; trackingNumber?: string; // Status itemStatus: OrderItemStatus;} interface PaymentTransaction { id: string; orderId: string; type: 'AUTHORIZATION' | 'CAPTURE' | 'VOID' | 'REFUND'; status: 'PENDING' | 'SUCCESS' | 'FAILED' | 'TIMEOUT'; amount: Money; paymentMethodId: string; // Gateway response gatewayTransactionId: string; gatewayResponse: Record<string, any>; // Idempotency idempotencyKey: string; // Timing initiatedAt: Timestamp; completedAt?: Timestamp; // Retry info attemptNumber: number; previousAttemptId?: string;} interface Shipment { id: string; orderId: string; // Location fulfillmentLocationId: string; // Items items: ShipmentItem[]; // Carrier carrier: string; shippingMethod: string; trackingNumber: string; trackingUrl: string; // Status status: 'PENDING' | 'PICKED' | 'PACKED' | 'SHIPPED' | 'IN_TRANSIT' | 'DELIVERED'; // Timestamps createdAt: Timestamp; shippedAt?: Timestamp; estimatedDelivery?: Timestamp; actualDelivery?: Timestamp; // Tracking events trackingEvents: TrackingEvent[];}Notice that orders store snapshots of product titles, prices, and images at order time. This is crucial—products change, but order records must reflect what the customer actually purchased. Never reference live product data from order records.
Order placement involves multiple services that must coordinate without traditional distributed transactions. We use the Saga pattern—a sequence of local transactions with compensating actions for rollback.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
┌─────────────────────────────────────────────────────────────────────────────────┐│ ORDER PLACEMENT SAGA │├─────────────────────────────────────────────────────────────────────────────────┤│ ││ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────┐ ││ │ VALIDATE │───▶│ RESERVE │───▶│ PROCESS │───▶│ CONFIRM │───▶│CREATE │ ││ │ CART │ │ INVENTORY │ │ PAYMENT │ │ ORDER │ │ ORDER │ ││ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ └───────┘ ││ │ │ │ │ ││ │ Fail │ Fail │ Fail │ Fail ││ │ │ │ │ ││ ▼ ▼ ▼ ▼ ││ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ ││ │ ABORT │◀───│ RELEASE │◀───│ VOID │◀───│ ROLLBACK │ ││ │ ORDER │ │ RESERVED │ │ PAYMENT │ │ ALL │ ││ └───────────┘ │ INVENTORY │ └───────────┘ └───────────┘ ││ └───────────┘ ││ ││ SAGA STEPS: ││ ───────────────────────────────────────────────────────────────────────────────││ 1. VALIDATE CART ││ • Check all items still available ││ • Verify prices haven't changed significantly ││ • Validate shipping address ││ • Compensate: Mark order as validation failed ││ ││ 2. RESERVE INVENTORY ││ • Lock inventory for 15 minutes ││ • Select fulfillment locations ││ • Compensate: Release all reservations ││ ││ 3. PROCESS PAYMENT ││ • Authorize payment (don't capture yet) ││ • Handle 3D Secure if required ││ • Compensate: Void authorization ││ ││ 4. CONFIRM ORDER ││ • Move inventory from reserved to allocated ││ • Capture payment ││ • Compensate: Reverse allocation, refund payment ││ ││ 5. CREATE ORDER ││ • Persist order record ││ • Send confirmation notification ││ • Queue fulfillment workflow ││ • Compensate: N/A (final step) ││ │└─────────────────────────────────────────────────────────────────────────────────┘123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
class OrderPlacementSaga { private steps: SagaStep[] = [ { name: 'VALIDATE_CART', execute: this.validateCart, compensate: this.markValidationFailed }, { name: 'RESERVE_INVENTORY', execute: this.reserveInventory, compensate: this.releaseInventory }, { name: 'PROCESS_PAYMENT', execute: this.processPayment, compensate: this.voidPayment }, { name: 'CONFIRM_ORDER', execute: this.confirmOrder, compensate: this.reverseConfirmation }, { name: 'CREATE_ORDER', execute: this.createOrder, compensate: null }, ]; async execute(request: OrderPlacementRequest): Promise<OrderResult> { const context: SagaContext = { orderId: generateOrderId(), request, completedSteps: [], stepResults: new Map(), }; try { for (const step of this.steps) { console.log(`Executing saga step: ${step.name}`); const result = await this.executeWithRetry(step.execute, context); context.completedSteps.push(step.name); context.stepResults.set(step.name, result); // Record step completion for audit await this.recordSagaProgress(context.orderId, step.name, 'SUCCESS'); } return { success: true, orderId: context.orderId, orderNumber: context.stepResults.get('CREATE_ORDER').orderNumber, }; } catch (error) { console.error(`Saga failed at step: ${context.completedSteps.length}`, error); // Execute compensating actions in reverse order await this.executeCompensation(context, error); return { success: false, error: this.mapErrorToUserMessage(error), failedStep: this.steps[context.completedSteps.length].name, }; } } private async executeCompensation(context: SagaContext, originalError: Error): Promise<void> { // Reverse through completed steps for (let i = context.completedSteps.length - 1; i >= 0; i--) { const stepName = context.completedSteps[i]; const step = this.steps.find(s => s.name === stepName); if (step?.compensate) { try { await step.compensate.call(this, context); await this.recordSagaProgress(context.orderId, stepName, 'COMPENSATED'); } catch (compensationError) { // Compensation failure is critical - needs manual intervention await this.alertCompensationFailure(context, stepName, compensationError); await this.recordSagaProgress(context.orderId, stepName, 'COMPENSATION_FAILED'); } } } } private async validateCart(context: SagaContext): Promise<CartValidationResult> { const { cart } = context.request; // Hard validation of all items const validation = await this.inventoryService.validateForCheckout(cart); if (!validation.canProceed) { throw new CartValidationError(validation.errors); } // Check for significant price changes for (const item of cart.items) { const currentPrice = await this.catalogService.getPrice(item.productId, item.variantId); const priceChange = Math.abs(currentPrice.amount - item.currentPrice.amount); if (priceChange / item.currentPrice.amount > 0.05) { throw new PriceChangeError(item.id, item.currentPrice, currentPrice); } } return validation; } private async reserveInventory(context: SagaContext): Promise<ReservationResult> { const { cart } = context.request; const reservation = await this.inventoryService.reserve({ orderId: context.orderId, items: cart.items.map(item => ({ sku: item.variantId, quantity: item.quantity, })), locationPreferences: { customerLocation: context.request.shippingAddress.coordinates, preferredSpeed: context.request.shippingMethod, }, }); if (!reservation.success) { throw new InventoryReservationError(reservation.failedItem); } return reservation; } private async releaseInventory(context: SagaContext): Promise<void> { const reservation = context.stepResults.get('RESERVE_INVENTORY'); for (const res of reservation.reservations) { await this.inventoryService.release(res.reservationId); } } private async processPayment(context: SagaContext): Promise<PaymentResult> { const { paymentMethod, total } = context.request; // Create idempotency key based on orderId const idempotencyKey = `order-${context.orderId}-payment`; const result = await this.paymentService.authorize({ idempotencyKey, amount: total, paymentMethodId: paymentMethod.id, orderId: context.orderId, billingAddress: context.request.billingAddress, metadata: { orderNumber: context.orderNumber, itemCount: context.request.cart.items.length, }, }); if (result.status === 'DECLINED') { throw new PaymentDeclinedError(result.declineCode, result.declineMessage); } if (result.status === 'REQUIRES_ACTION') { throw new PaymentRequiresActionError(result.actionUrl); } return result; } private async voidPayment(context: SagaContext): Promise<void> { const payment = context.stepResults.get('PROCESS_PAYMENT'); if (payment?.authorizationId) { await this.paymentService.void({ authorizationId: payment.authorizationId, orderId: context.orderId, idempotencyKey: `order-${context.orderId}-void`, }); } }}Payment processing is the most sensitive part of order placement. It involves real money, external dependencies, and strict compliance requirements (PCI DSS). The payment flow must be:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
┌─────────────────────────────────────────────────────────────────────────────────┐│ PAYMENT AUTHORIZATION FLOW │├─────────────────────────────────────────────────────────────────────────────────┤│ ││ Customer Order Service Payment Gateway ││ │ │ │ ││ │ Click "Place Order" │ │ ││ │─────────────────────────────▶│ │ ││ │ │ │ ││ │ │ Check existing payment │ ││ │ │ by idempotency key │ ││ │ │──────────────────┐ │ ││ │ │◀─────────────────┘ │ ││ │ │ (not found) │ ││ │ │ │ ││ │ │ Record payment attempt │ ││ │ │ status: PENDING │ ││ │ │ │ ││ │ │ POST /authorize │ ││ │ │───────────────────────────▶│ ││ │ │ │ ││ │ │ (possible timeout) │ ││ │ │◀ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│ ││ │ │ │ ││ │ │ Query transaction status │ ││ │ │───────────────────────────▶│ ││ │ │ │ ││ │ │ { status: AUTHORIZED } │ ││ │ │◀───────────────────────────│ ││ │ │ │ ││ │ │ Record payment success │ ││ │ │ status: AUTHORIZED │ ││ │ │ │ ││ │ Order Confirmed │ │ ││ │◀─────────────────────────────│ │ ││ │ │ │ ││ ││ ───────────────────────────────────────────────────────────────────────────── ││ ││ CAPTURE (after order ships): ││ ││ Fulfillment Order Service Payment Gateway ││ │ │ │ ││ │ Shipment Created │ │ ││ │─────────────────────────────▶│ │ ││ │ │ │ ││ │ │ POST /capture │ ││ │ │ { authId, amount } │ ││ │ │───────────────────────────▶│ ││ │ │ │ ││ │ │ { status: CAPTURED } │ ││ │ │◀───────────────────────────│ ││ │ │ │ ││ │ │ Update payment record │ ││ │ │ │ ││ │└─────────────────────────────────────────────────────────────────────────────────┘123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
class PaymentService { // Idempotent authorization - safe to retry async authorize(request: PaymentAuthRequest): Promise<PaymentAuthResult> { const { idempotencyKey, amount, paymentMethodId, orderId } = request; // Step 1: Check for existing transaction with this idempotency key const existing = await this.db.paymentTransaction.findUnique({ where: { idempotencyKey }, }); if (existing) { // Return cached result - idempotent! return this.formatResult(existing); } // Step 2: Create pending transaction record BEFORE calling gateway const transaction = await this.db.paymentTransaction.create({ data: { id: generateUUID(), orderId, type: 'AUTHORIZATION', status: 'PENDING', amount: amount.amount, currency: amount.currency, paymentMethodId, idempotencyKey, initiatedAt: new Date(), attemptNumber: 1, }, }); try { // Step 3: Call payment gateway with timeout const gatewayResult = await this.callGatewayWithTimeout( async () => this.gateway.authorize({ amount: amount.amount, currency: amount.currency, paymentMethodToken: paymentMethodId, orderId, idempotencyKey, // Gateway also supports idempotency }), 5000 // 5 second timeout ); // Step 4: Record success await this.db.paymentTransaction.update({ where: { id: transaction.id }, data: { status: gatewayResult.success ? 'SUCCESS' : 'FAILED', gatewayTransactionId: gatewayResult.transactionId, gatewayResponse: gatewayResult, completedAt: new Date(), }, }); return this.formatResult({ ...transaction, ...gatewayResult }); } catch (error) { if (error instanceof TimeoutError) { // Gateway timeout - must query to check actual status return this.handleTimeout(transaction); } // Record failure await this.db.paymentTransaction.update({ where: { id: transaction.id }, data: { status: 'FAILED', gatewayResponse: { error: error.message }, completedAt: new Date(), }, }); throw error; } } private async handleTimeout(transaction: PaymentTransaction): Promise<PaymentAuthResult> { // Wait briefly then query gateway for transaction status await sleep(2000); try { const status = await this.gateway.getTransactionStatus( transaction.idempotencyKey ); if (status.found) { // Transaction went through despite timeout await this.db.paymentTransaction.update({ where: { id: transaction.id }, data: { status: status.result.success ? 'SUCCESS' : 'FAILED', gatewayTransactionId: status.result.transactionId, gatewayResponse: status.result, completedAt: new Date(), }, }); return this.formatResult({ ...transaction, ...status.result }); } // Transaction not found - it failed await this.db.paymentTransaction.update({ where: { id: transaction.id }, data: { status: 'TIMEOUT', gatewayResponse: { error: 'Gateway timeout, transaction not found' }, completedAt: new Date(), }, }); return { success: false, reason: 'TIMEOUT' }; } catch (queryError) { // Couldn't verify status - mark as needs review await this.db.paymentTransaction.update({ where: { id: transaction.id }, data: { status: 'UNKNOWN', gatewayResponse: { error: 'Unable to verify transaction status' }, }, }); // Alert for manual review await this.alertService.paymentReviewNeeded(transaction); return { success: false, reason: 'NEEDS_REVIEW' }; } } // Delayed capture when order ships async capture(request: PaymentCaptureRequest): Promise<PaymentCaptureResult> { const { authorizationId, amount, orderId, idempotencyKey } = request; // Verify authorization exists and is valid const authorization = await this.db.paymentTransaction.findFirst({ where: { orderId, type: 'AUTHORIZATION', status: 'SUCCESS' }, }); if (!authorization) { throw new Error('No valid authorization found'); } // Check if already captured (idempotency) const existingCapture = await this.db.paymentTransaction.findUnique({ where: { idempotencyKey }, }); if (existingCapture) { return this.formatCaptureResult(existingCapture); } // Capture (can be partial for split shipments) const captureResult = await this.gateway.capture({ authorizationId: authorization.gatewayTransactionId, amount: amount.amount, idempotencyKey, }); await this.db.paymentTransaction.create({ data: { id: generateUUID(), orderId, type: 'CAPTURE', status: captureResult.success ? 'SUCCESS' : 'FAILED', amount: amount.amount, idempotencyKey, gatewayTransactionId: captureResult.transactionId, gatewayResponse: captureResult, initiatedAt: new Date(), completedAt: new Date(), }, }); return captureResult; }}Authorization reserves funds; Capture transfers them. Amazon authorizes at checkout but doesn't capture until shipment. This prevents charging for items that turn out to be unavailable. Authorizations typically expire after 7 days—capture must happen before then.
Orders transition through well-defined states. Modeling this as a finite state machine ensures only valid transitions occur and makes debugging straightforward.
12345678910111213141516171819202122232425262728293031323334353637383940414243
┌───────────────────────────────────────────────────────────────┐ │ ORDER STATE MACHINE │ └───────────────────────────────────────────────────────────────┘ ┌─────────────────┐ │ CREATED │ └────────┬────────┘ │ validate ▼ ┌─────────────────┐ ┌─────────│ PENDING_PAYMENT │─────────┐ │ └────────┬────────┘ │ │ │ payment │ payment │ │ success │ failed │ ▼ ▼ │ ┌─────────────────┐ ┌───────────────┐ │ │ CONFIRMED │ │PAYMENT_FAILED │ │ └────────┬────────┘ └───────────────┘ │ │ start fulfillment ▲ │ ▼ │ │ ┌─────────────────┐ │ │ │ PROCESSING │─────────────────┘ │ └────────┬────────┘ retry payment │ │ │ ┌────────────┼────────────┐ │ │ │ │ │ ▼ ▼ ▼ ┌────────┴───────┐ ┌──────────────┐ ┌──────────────────┐ │ CANCELLED │ │PART_SHIPPED │ │ SHIPPED │ └────────────────┘ └──────┬───────┘ └────────┬─────────┘ ▲ │ │ │ │ all shipped │ delivered │ ▼ ▼ │ ┌──────────────┐ ┌──────────────────┐ │ │ SHIPPED │ │ DELIVERED │ │ └──────────────┘ └────────┬─────────┘ │ │ │ ┌──────────┼──────────┐ │ │ │ │ │ ▼ ▼ ▼ │ ┌───────────┐ ┌────────┐ ┌────────┐ └──────────────────│ RETURNED │ │COMPLETE│ │DISPUTED│ └───────────┘ └────────┘ └────────┘123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
class OrderStateMachine { private transitions: Map<OrderStatus, Transition[]> = new Map([ ['CREATED', [ { to: 'PENDING_PAYMENT', trigger: 'START_CHECKOUT', guard: this.hasValidCart }, { to: 'CANCELLED', trigger: 'CANCEL', guard: () => true }, ]], ['PENDING_PAYMENT', [ { to: 'CONFIRMED', trigger: 'PAYMENT_SUCCESS', action: this.onPaymentSuccess }, { to: 'PAYMENT_FAILED', trigger: 'PAYMENT_FAILED', action: this.onPaymentFailed }, { to: 'CANCELLED', trigger: 'CANCEL', guard: this.canCancelPendingPayment }, ]], ['PAYMENT_FAILED', [ { to: 'PENDING_PAYMENT', trigger: 'RETRY_PAYMENT', guard: this.canRetryPayment }, { to: 'CANCELLED', trigger: 'CANCEL' }, ]], ['CONFIRMED', [ { to: 'PROCESSING', trigger: 'START_FULFILLMENT', action: this.startFulfillment }, { to: 'CANCELLED', trigger: 'CANCEL', guard: this.canCancelConfirmed }, ]], ['PROCESSING', [ { to: 'PARTIALLY_SHIPPED', trigger: 'PARTIAL_SHIPMENT', action: this.recordShipment }, { to: 'SHIPPED', trigger: 'ALL_SHIPPED', action: this.recordShipment }, { to: 'CANCELLED', trigger: 'CANCEL', guard: this.canCancelProcessing }, ]], ['PARTIALLY_SHIPPED', [ { to: 'SHIPPED', trigger: 'ALL_SHIPPED', action: this.recordShipment }, ]], ['SHIPPED', [ { to: 'DELIVERED', trigger: 'DELIVERY_CONFIRMED', action: this.recordDelivery }, { to: 'RETURNED', trigger: 'RETURN_INITIATED', guard: this.canReturn }, ]], ['DELIVERED', [ { to: 'RETURNED', trigger: 'RETURN_INITIATED', guard: this.canReturn }, { to: 'DISPUTED', trigger: 'DISPUTE_OPENED' }, { to: 'COMPLETE', trigger: 'AUTO_COMPLETE', guard: this.pastReturnWindow }, ]], ]); async transition( orderId: string, trigger: string, payload?: any ): Promise<TransitionResult> { const order = await this.orderRepository.findById(orderId); if (!order) { throw new OrderNotFoundError(orderId); } const availableTransitions = this.transitions.get(order.status); const transition = availableTransitions?.find(t => t.trigger === trigger); if (!transition) { throw new InvalidTransitionError(order.status, trigger); } // Check guard condition if present if (transition.guard && !await transition.guard(order, payload)) { throw new TransitionGuardFailedError(order.status, trigger); } // Execute transition const previousStatus = order.status; order.status = transition.to; // Record status change order.statusHistory.push({ from: previousStatus, to: transition.to, trigger, timestamp: new Date(), actor: payload?.actor || 'system', metadata: payload?.metadata, }); // Execute action if present if (transition.action) { await transition.action(order, payload); } // Persist order await this.orderRepository.update(order); // Emit event for downstream systems await this.eventBus.publish({ type: 'ORDER_STATUS_CHANGED', orderId, previousStatus, newStatus: transition.to, trigger, timestamp: new Date(), }); return { success: true, newStatus: transition.to }; } // Guard implementations private async canCancelConfirmed(order: Order): Promise<boolean> { // Can cancel if fulfillment hasn't started const fulfillmentStatus = await this.fulfillmentService.getStatus(order.id); return fulfillmentStatus.stage === 'PENDING' || fulfillmentStatus.stage === 'NOT_STARTED'; } private async canReturn(order: Order): Promise<boolean> { // Within return window and items are returnable const daysSinceDelivery = (Date.now() - order.deliveredAt.getTime()) / (1000 * 60 * 60 * 24); return daysSinceDelivery <= 30; // 30-day return window }}E-commerce orders are financial records subject to tax regulations, consumer protection laws, and potential disputes. Every change to an order must be auditable.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
// Event sourcing: Store all changes as immutable events interface OrderEvent { eventId: string; orderId: string; eventType: OrderEventType; timestamp: Timestamp; // Who/what caused this event actor: { type: 'customer' | 'system' | 'employee' | 'automated'; id: string; name?: string; }; // Event data payload: Record<string, any>; // Computed order state after this event orderStateSnapshot?: OrderSnapshot;} type OrderEventType = | 'ORDER_CREATED' | 'ITEM_ADDED' | 'ITEM_REMOVED' | 'QUANTITY_CHANGED' | 'PAYMENT_AUTHORIZED' | 'PAYMENT_CAPTURED' | 'PAYMENT_REFUNDED' | 'SHIPMENT_CREATED' | 'SHIPMENT_SHIPPED' | 'DELIVERY_CONFIRMED' | 'RETURN_INITIATED' | 'RETURN_RECEIVED' | 'ORDER_CANCELLED' | 'DISPUTE_OPENED' | 'DISPUTE_RESOLVED'; class OrderEventStore { async appendEvent(event: OrderEvent): Promise<void> { // Events are append-only, never modified await this.db.orderEvent.create({ data: { eventId: event.eventId, orderId: event.orderId, eventType: event.eventType, timestamp: event.timestamp, actorType: event.actor.type, actorId: event.actor.id, actorName: event.actor.name, payload: event.payload, // Store current sequence number sequenceNumber: await this.getNextSequence(event.orderId), }, }); } async getOrderHistory(orderId: string): Promise<OrderEvent[]> { return this.db.orderEvent.findMany({ where: { orderId }, orderBy: { sequenceNumber: 'asc' }, }); } // Reconstruct order state at any point in time async getOrderAtTime(orderId: string, asOf: Timestamp): Promise<Order> { const events = await this.db.orderEvent.findMany({ where: { orderId, timestamp: { lte: asOf }, }, orderBy: { sequenceNumber: 'asc' }, }); // Replay events to reconstruct state let orderState = this.createInitialOrderState(); for (const event of events) { orderState = this.applyEvent(orderState, event); } return orderState; } private applyEvent(state: Order, event: OrderEvent): Order { switch (event.eventType) { case 'ORDER_CREATED': return { ...state, ...event.payload, status: 'CREATED' }; case 'ITEM_ADDED': return { ...state, items: [...state.items, event.payload.item] }; case 'PAYMENT_AUTHORIZED': return { ...state, status: 'CONFIRMED', paidAt: event.timestamp }; case 'SHIPMENT_SHIPPED': return { ...state, status: 'SHIPPED', shippedAt: event.timestamp }; // ... handle all event types default: return state; } }} // Audit query service for complianceclass OrderAuditService { // Find all actions by specific employee async getEmployeeActions( employeeId: string, dateRange: DateRange ): Promise<OrderEvent[]> { return this.eventStore.findEvents({ actorType: 'employee', actorId: employeeId, timestampRange: dateRange, }); } // Find suspicious patterns async detectAnomalies(): Promise<AnomalyReport[]> { const anomalies: AnomalyReport[] = []; // High-value order modifications by same employee const highValueMods = await this.findHighValueModifications(); anomalies.push(...highValueMods); // Unusual refund patterns const refundPatterns = await this.analyzeRefundPatterns(); anomalies.push(...refundPatterns); // After-hours order changes const afterHoursChanges = await this.findAfterHoursChanges(); anomalies.push(...afterHoursChanges); return anomalies; }}After order confirmation, the fulfillment workflow begins. This involves coordinating with warehouse management systems, shipping carriers, and tracking services.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
class FulfillmentOrchestrator { async initiateFulfillment(order: Order): Promise<void> { // Group items by fulfillment location const fulfillmentGroups = this.groupByLocation(order.items); for (const [locationId, items] of Object.entries(fulfillmentGroups)) { // Create shipment record const shipment = await this.createShipment(order.id, locationId, items); // Send pick request to WMS await this.wmsClient.createPickRequest({ shipmentId: shipment.id, locationId, items: items.map(item => ({ sku: item.sku, quantity: item.quantity, pickLocation: item.warehouseLocation, })), priority: this.calculatePriority(order), cutoffTime: this.getCutoffTime(order.shippingMethod, locationId), }); // Listen for WMS events await this.subscribeToPicks(shipment.id); } } async handleWMSEvent(event: WMSFulfillmentEvent): Promise<void> { switch (event.type) { case 'PICK_COMPLETE': await this.onPickComplete(event); break; case 'PACK_COMPLETE': await this.onPackComplete(event); break; case 'SHIP_COMPLETE': await this.onShipComplete(event); break; case 'PICK_SHORTAGE': await this.handlePickShortage(event); break; } } private async onShipComplete(event: ShipCompleteEvent): Promise<void> { const { shipmentId, trackingNumber, carrier } = event; // Update shipment await this.shipmentRepository.update(shipmentId, { status: 'SHIPPED', trackingNumber, carrier, shippedAt: new Date(), }); // Capture payment for these items const shipment = await this.shipmentRepository.findById(shipmentId); const shipmentTotal = this.calculateShipmentTotal(shipment); await this.paymentService.capture({ orderId: shipment.orderId, amount: shipmentTotal, idempotencyKey: `capture-${shipmentId}`, }); // Send shipping notification await this.notificationService.sendShippingNotification({ orderId: shipment.orderId, trackingNumber, carrier, estimatedDelivery: event.estimatedDelivery, }); // Subscribe to carrier tracking await this.trackingService.subscribe({ carrier, trackingNumber, webhookUrl: `https://api.example.com/tracking/${shipmentId}`, }); // Update order status const order = await this.orderRepository.findById(shipment.orderId); const allShipped = await this.areAllItemsShipped(order); await this.orderStateMachine.transition( order.id, allShipped ? 'ALL_SHIPPED' : 'PARTIAL_SHIPMENT', { shipmentId } ); } private async handlePickShortage(event: PickShortageEvent): Promise<void> { const { shipmentId, sku, requestedQuantity, availableQuantity } = event; if (availableQuantity === 0) { // Item completely unavailable - need to handle order modification await this.handleOutOfStock(shipmentId, sku); } else { // Partial fulfillment possible await this.handlePartialFulfillment(shipmentId, sku, availableQuantity); } } private async handleOutOfStock(shipmentId: string, sku: string): Promise<void> { const shipment = await this.shipmentRepository.findById(shipmentId); const order = await this.orderRepository.findById(shipment.orderId); // Notify customer with options await this.notificationService.sendOutOfStockNotification({ orderId: order.id, sku, options: [ { type: 'WAIT', description: 'Wait for restock (est. 5-7 days)' }, { type: 'SUBSTITUTE', suggestions: await this.findSubstitutes(sku) }, { type: 'CANCEL_ITEM', description: 'Cancel this item for refund' }, ], }); // Create customer service ticket await this.ticketService.createAutoTicket({ type: 'ORDER_ITEM_UNAVAILABLE', orderId: order.id, priority: 'HIGH', data: { sku, shipmentId }, }); }}We've covered the complete architecture of order processing at e-commerce scale. The key patterns:
What's Next:
With the transactional heart of e-commerce covered, we'll explore the Recommendation Engine—the system that personalizes the shopping experience and drives significant additional revenue. You'll learn about collaborative filtering, real-time personalization, and the architecture that serves billions of recommendations daily.
You now understand how to build order processing systems that handle millions of transactions reliably. The central insight: distributed transactions require careful choreography. The Saga pattern, idempotency, and explicit state machines work together to ensure orders either complete successfully or fail cleanly with proper cleanup.