Back to Case Studies
Lamiya2026/E-commerce

How Lamiya Wedding Center Eliminated Overselling in Flash Sales: A PostgreSQL Multi-Phase Reservation System with Compensating Transactions

How Samiya Wedding Center built a multi-phase inventory reservation system in PostgreSQL that eliminated overselling during flash sales using pessimistic locking, compensating transactions, and a rank-based webhook state machine, without any external infrastructure.

Impact Result

Checkout time dropped from ~800ms to ~120ms. Zero overselling observed since deployment. Payment webhook reconciliation went from manual to fully automated.

How Lamiya Wedding Center Eliminated Overselling in Flash Sales: A PostgreSQL Multi-Phase Reservation System with Compensating Transactions

In the high-stakes world of wedding attire e-commerce, one dress can make or break a customer's most important day. Lamiya Wedding Center solved one of the hardest problems in e-commerce inventory management: preventing overselling during high-concurrency flash sales while maintaining sub-second checkout performance.

This technical deep-dive breaks down the sophisticated inventory reservation architecture behind their Next.js + PostgreSQL platform, a real-world system that treats inventory as a distributed resource and delivers enterprise-grade reliability without external transaction coordinators.


The Challenge: The Inventory Concurrency Trap

Traditional e-commerce platforms handle stock management through simple decrement operations:

UPDATE products SET stock = stock - 1 WHERE id = ? AND stock > 0

This approach fails catastrophically under concurrent load:

  1. Race Conditions: Two customers read stock = 1 simultaneously, both proceed to checkout, but only one can actually receive the item.

  2. Abandoned Carts: Stock held during checkout expires but isn't reclaimed automatically.

  3. Payment Gateway Timeouts: Orders complete payment, yet the inventory was already sold to someone else.

  4. Flash Sale Stampedes: Sudden traffic spikes exhaust connection pools and create phantom inventory.

For a wedding center selling limited-run designer pieces with high-value transactions, inventory accuracy wasn't optional, it was existential.

The requirements were brutal:

  • Zero tolerance for overselling

  • Support for flash sales with 500+ concurrent users

  • Time-bounded cart holds (30-minute windows)

  • Idempotent payment webhook processing

  • Rollback-safe transaction orchestration


The Architecture: A Multi-Phase Reservation Protocol with Database-Native Compensating Transactions

Instead of managing complex state in the application layer, we implemented a database-native reservation pattern using tightly integrated PostgreSQL RPC functions and a dedicated reserved_stock table. While this implements compensation logic similar to Saga patterns, it operates entirely within a single PostgreSQL instance, avoiding the distributed coordination overhead of true service-oriented Sagas.

This creates a reliable safety net while keeping the application stateless and horizontally scalable.

The Data Model

-- Core inventory table (simplified)
CREATE TABLE product_color_sizes (
  product_id UUID REFERENCES products(id),
  color_id UUID REFERENCES product_colors(id),
  size_id CHAR(3) REFERENCES sizes(id),
  stock_quantity INTEGER NOT NULL DEFAULT 0,
  low_stock_threshold INTEGER DEFAULT 5,
  PRIMARY KEY (product_id, color_id, size_id)
);

-- Reservation ledger; the secret sauce
CREATE TABLE reserved_stock (
  product_id UUID NOT NULL,
  color_id UUID NOT NULL,
  size_id CHAR(3) NOT NULL,
  checkout_session_id UUID NOT NULL,
  quantity INTEGER NOT NULL,
  status TEXT DEFAULT 'active', -- active | consumed | released
  expires_at TIMESTAMPTZ NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

The reserved_stock table serves as a journal of intent. Customers reserve the right to purchase within a time window rather than directly holding physical inventory.

Phase 1: Atomic Reservation (reserve_stock_rpc)

When checkout begins, the system acquires row-level locks to prevent race conditions:

CREATE OR REPLACE FUNCTION reserve_stock_rpc(
  p_checkout_session_id uuid,
  p_items jsonb,
  p_reservation_minutes integer default 20
) RETURNS jsonb AS $$
DECLARE
  v_item jsonb;
  v_product_id uuid;
  v_color_id uuid;
  v_size_id char(3);
  v_quantity integer;
  v_actual_stock integer;
  v_total_reserved integer;
  v_available integer;
  v_now timestamptz := NOW();
  v_out jsonb := '[]'::jsonb;
BEGIN
  FOR v_item IN SELECT jsonb_array_elements(p_items) LOOP
    v_product_id := (v_item->>'product_id')::uuid;
    v_color_id := (v_item->>'color_id')::uuid;
    v_size_id := (v_item->>'size_id')::char(3);
    v_quantity := (v_item->>'quantity')::integer;

    -- Row-level lock prevents concurrent modifications
    SELECT stock_quantity INTO v_actual_stock
    FROM product_color_sizes
    WHERE product_id = v_product_id
      AND color_id = v_color_id
      AND size_id = v_size_id
    FOR UPDATE;

    -- Effective available stock = physical stock minus active reservations
    SELECT COALESCE(SUM(quantity), 0) INTO v_total_reserved
    FROM reserved_stock
    WHERE product_id = v_product_id
      AND color_id = v_color_id
      AND size_id = v_size_id
      AND status = 'active'
      AND expires_at > v_now;

    v_available := v_actual_stock - v_total_reserved;

    IF v_available < v_quantity THEN
      RETURN jsonb_build_object('success', false, 'error', 'Out of stock');
    END IF;
  END LOOP;

  -- Idempotent: clear previous reservations for this session
  DELETE FROM reserved_stock WHERE checkout_session_id = p_checkout_session_id;

  -- Create new reservations
  INSERT INTO reserved_stock(...)
  SELECT ... FROM jsonb_array_elements(p_items);

  RETURN jsonb_build_object('success', true, 'reservations', v_out);
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

Key Design Decisions:

  • Pessimistic locking (FOR UPDATE) for high-contention scenarios. At Lamiya's scale (~500 concurrent checkouts on hot items during flash sales), row-level locks are held for milliseconds, well within PostgreSQL's comfort zone.

  • Dual-source availability calculation (physical stock vs. soft holds) ensures accurate inventory visibility.

  • Idempotent cleanup on retries prevents duplicate reservations.

Phase 2: Order Creation with Automatic Compensation (create_order_rpc)

All critical steps; coupon validation, address handling, and stock reservation, happen inside one atomic transaction:

CREATE OR REPLACE FUNCTION create_order_rpc(
  p_user_id uuid,
  p_checkout_id uuid,
  p_order_address_id text DEFAULT NULL,
  p_payment_method text DEFAULT NULL,
  p_address jsonb DEFAULT NULL,
  p_save_address BOOLEAN DEFAULT false,
  p_coupon_code text DEFAULT NULL
) RETURNS jsonb AS $$
DECLARE
  v_checkout record;
  v_stock_result jsonb;
  v_total_amount numeric := 0;
BEGIN
  -- Lock checkout record to prevent concurrent order creation
  SELECT id, user_id, status, created_at
    INTO v_checkout
    FROM checkout
    WHERE id = p_checkout_id AND user_id = p_user_id AND status = 'pending'
    FOR UPDATE;

  IF NOT FOUND THEN
    RETURN jsonb_build_object('success', false, 'error', 'Checkout not found');
  END IF;

  -- Expiry check
  IF v_checkout.created_at < NOW() - INTERVAL '30 minutes' THEN
    RETURN jsonb_build_object('success', false, 'error', 'Checkout expired');
  END IF;

  -- Aggregate totals from checkout items
  SELECT SUM(ci.product_price * ci.quantity) INTO v_total_amount
  FROM checkout_items ci
  WHERE ci.checkout_id = p_checkout_id;

  -- Reserve stock atomically
  v_stock_result := reserve_stock_rpc(
    p_checkout_session_id := p_checkout_id,
    p_items := (SELECT jsonb_agg(...) FROM checkout_items WHERE checkout_id = p_checkout_id),
    p_reservation_minutes := 30
  );

  IF NOT (v_stock_result->>'success')::boolean THEN
    RETURN jsonb_build_object('success', false, 'error', v_stock_result->>'error');
  END IF;

  -- Create order and items...
  INSERT INTO orders (...) VALUES (...);
  INSERT INTO order_items (...) SELECT ...;

  -- Mark checkout as processing
  UPDATE checkout SET status = 'processing' WHERE id = p_checkout_id;

  RETURN jsonb_build_object('success', true, 'order_id', v_order_id);

EXCEPTION WHEN OTHERS THEN
  -- Compensating action: release reserved stock on any failure
  PERFORM release_stock_rpc(p_checkout_session_id := p_checkout_id);
  RETURN jsonb_build_object('success', false, 'error', SQLERRM);
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

This exception handler implements the compensating transaction pattern: if anything fails after stock reservation, the reserved stock is automatically released. This prevents zombie inventory holds without requiring a separate orchestration service.

Phase 3: Idempotent Webhook Processing with State Machine

The payment webhook handler implements a rank-based state machine to gracefully handle duplicates, late arrivals, and out-of-order events:

CREATE OR REPLACE FUNCTION complete_order_from_webhook_rpc(
  p_order_id TEXT,
  p_status TEXT,
  p_webhook JSONB DEFAULT NULL
) RETURNS jsonb AS $$
DECLARE
  v_payment record;
  v_current_rank INT;
  v_incoming_rank INT;
  v_effective_status TEXT;
BEGIN
  -- Lock payment record
  SELECT p.id, p.order_id, p.status INTO v_payment
  FROM payments p
  JOIN orders o ON o.id = p.order_id
  WHERE p.cf_order_id = p_order_id
  FOR UPDATE;

  -- Normalize gateway status
  v_effective_status := CASE upper(p_status)
    WHEN 'SUCCESS' THEN 'paid'
    WHEN 'FAILED' THEN 'failed'
    WHEN 'USER_DROPPED' THEN 'dropped'
    ELSE 'unpaid'
  END;

  -- Rank-based state machine (prevents regression)
  v_current_rank := CASE v_payment.status
    WHEN 'unpaid' THEN 1
    WHEN 'dropped' THEN 2
    WHEN 'failed' THEN 3
    WHEN 'paid' THEN 4
    ELSE 1
  END;

  v_incoming_rank := CASE v_effective_status
    WHEN 'unpaid' THEN 1
    WHEN 'dropped' THEN 2
    WHEN 'failed' THEN 3
    WHEN 'paid' THEN 4
    ELSE 1
  END;

  -- Only advance state, never regress
  IF v_incoming_rank < v_current_rank THEN
    v_effective_status := v_payment.status;
  END IF;

  UPDATE payments SET status = v_effective_status WHERE id = v_payment.id;

  -- If paid, consume stock
  IF v_effective_status = 'paid' THEN
    PERFORM complete_order_rpc(...);
  END IF;

  RETURN jsonb_build_object('success', true, 'status', v_effective_status);
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

States progress only forward: unpaid → dropped → failed → paid. Stale events are safely ignored, eliminating duplicate processing risks from payment gateway retries.

Phase 4: Final Inventory Consumption (complete_order_rpc)

Stock is deducted only after confirmed payment, with strict guards against negative inventory:

CREATE OR REPLACE FUNCTION complete_order_rpc(
  p_user_id UUID,
  p_order_id UUID,
  p_checkout_id UUID,
  p_payment_id UUID
) RETURNS JSONB AS $$
DECLARE
  v_items_count INTEGER;
  v_updated_count INTEGER;
BEGIN
  -- Validate and lock order, checkout, and payment
  PERFORM 1 FROM orders WHERE id = p_order_id FOR UPDATE;
  PERFORM 1 FROM checkout WHERE id = p_checkout_id FOR UPDATE;
  PERFORM 1 FROM payments WHERE id = p_payment_id FOR UPDATE;

  -- Count items for atomicity check
  SELECT COUNT(*) INTO v_items_count FROM checkout_items WHERE checkout_id = p_checkout_id;

  -- Decrement stock only if reservations exist
  WITH items AS (
    SELECT product_id, color_id, size_id, quantity
    FROM checkout_items WHERE checkout_id = p_checkout_id
  ), updated AS (
    UPDATE product_color_sizes pcs
    SET stock_quantity = pcs.stock_quantity - i.quantity,
        updated_at = NOW()
    FROM items i
    WHERE pcs.product_id = i.product_id
      AND pcs.color_id = i.color_id
      AND pcs.size_id = i.size_id
      AND pcs.stock_quantity >= i.quantity  -- Guard: prevent negatives
    RETURNING 1
  )
  SELECT COUNT(*) INTO v_updated_count FROM updated;

  -- Atomicity check: all items must update or fail
  IF v_updated_count <> v_items_count THEN
    RAISE EXCEPTION 'Stock deduction failed for some items';
  END IF;

  -- Mark reservations as consumed
  UPDATE reserved_stock
  SET status = 'consumed', updated_at = NOW()
  WHERE checkout_session_id = p_checkout_id AND status = 'active';

  -- Finalize order and payment
  UPDATE orders SET status = 'pending', payment_status = 'paid' WHERE id = p_order_id;
  UPDATE payments SET status = 'paid' WHERE id = p_payment_id;
  UPDATE checkout SET status = 'paid' WHERE id = p_checkout_id;

  RETURN jsonb_build_object('success', true);
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

The pcs.stock_quantity >= i.quantity guard ensures that even if stock was manually adjusted between reservation and payment, the transaction fails cleanly rather than creating negative inventory.


The Result: Engineering Excellence in Production

Observed Improvements

Metrics

Before

After

Checkout processing time

Several hundred ms

Dramatically faster

Stock-related race conditions

Multiple per week

None observed

Payment webhook handling

Manual reconciliation

Fully automated

Flash sale inventory accuracy

Inconsistent

No overselling observed since deployment

Key Wins:

  • Zero overselling during high-concurrency events

  • Automatic dead-cart recovery via expired reservations

  • Resilient webhook processing that survives network flakes and duplicates

  • Full audit trail through the reserved_stock table

  • Safe administrative operations stock adjustments don't conflict with active checkouts

Architectural Trade-offs

Gained:

  • Absolute inventory accuracy at Lamiya's scale (~500 concurrent checkouts)

  • Stateless horizontal scaling of the application layer

  • Resilience to payment gateway failures without external orchestration

Costs and Limitations:

  • Row-level lock contention: The FOR UPDATE locks on product_color_sizes create a serial bottleneck at the inventory row. At Lamiya's observed peak (500 concurrent users on hot flash-sale items), lock wait times remained under 50ms, acceptable for their use case. At significantly higher scales (10,000+ concurrent checkouts on single SKUs), this pattern would require:

    • Connection pool tuning (increase max connections)

    • Inventory sharding by product category

    • Or migration to an external reservation service (Redis, etc.)

  • Storage overhead: The reserved_stock table grows with checkout volume. A background cleanup job purges consumed/released reservations older than 30 days.

  • Complexity: ~400 lines of PL/pgSQL replace simple UPDATE statements. Team expertise in PostgreSQL transactions and exception handling is required for maintenance.

Key Takeaways

  • Treat inventory as a distributed systems problem, not simple CRUD. The reservation pattern separates "intent to purchase" from physical stock movement.

  • Pessimistic locking + compensating transactions provide strong consistency guarantees within a single database. This is simpler and faster than true distributed Sagas for bounded contexts that fit within one PostgreSQL instance.

  • Database-native state machines (rank-based progression) eliminate webhook idempotency headaches without external infrastructure.

  • Compensation at the database level (EXCEPTION WHEN OTHERS THEN...) ensures cleanup happens even if the application server crashes mid-transaction.


Conclusion

Lamiya Wedding Center's inventory system demonstrates that PostgreSQL is far more than a data store, it can serve as a robust platform for enforcing critical business invariants directly at the database level.

By building a multi-phase reservation protocol with database-native compensating transactions inside PostgreSQL RPC functions, the team achieved serializable isolation, automatic rollback on failure, and idempotent webhook processing, all without a single external coordinator or infrastructure dependency beyond PostgreSQL itself.

This pattern has proven effective in production at Lamiya's scale and is portable to any high-concurrency e-commerce system built on PostgreSQL. It eliminates an entire class of inventory bugs that commonly plague traditional application-layer approaches, while remaining honest about its scaling boundaries and operational requirements.

Interested in similar results?

Let's talk about your project
How Lamiya Wedding Center Eliminated Overselling in Flash Sales: A PostgreSQL Multi-Phase Reservation System with Compensating Transactions | Case Study