Skip to content

Repository files navigation

StockLock — High-Concurrency Inventory Reservation Platform

StockLock is an enterprise-grade inventory reservation system built to solve one of the most common and complex problems in e-commerce: The Checkout Race Condition.

When selling highly limited, high-value items (like Super Cars), multiple users attempting to buy the last available unit at the exact same millisecond can result in overselling and database corruption. StockLock solves this by implementing a distributed double-lock strategy, guaranteeing that one physical unit maps exclusively to one buyer.

The Tech Stack

  • Framework: Next.js 16 (App Router) with Turbopack
  • Language: TypeScript
  • Database: PostgreSQL (Hosted on Supabase)
  • ORM: Prisma
  • Caching & Locking: Upstash Redis (Serverless Redis)
  • Styling: Tailwind CSS v4 + Shadcn UI
  • Real-Time Sync: Server-Sent Events (SSE) via Native Node.js EventEmitter

Core Engineering Architecture

This project was built to demonstrate advanced backend concurrency management and system design:

1. The "Double-Lock" Strategy

To prevent race conditions when two users click "Reserve" at the exact same time:

  • Layer 1: Redis Distributed Lock (SET NX EX) Before hitting the database, the API attempts to acquire an exclusive lock on the specific productId and warehouseId combination in Redis. If acquired, the request proceeds. If not, it means another thread is actively reserving that item, and a 429 Too Many Requests is returned.
  • Layer 2: Postgres Transactions & Row-Level Locking Inside the database, operations are wrapped in a strict $transaction. The system dynamically checks if (total_stock - reserved_stock) >= requested_quantity before applying the atomic update.

2. Idempotency Keys

Network drops happen. If a user clicks "Checkout" and their internet reconnects and fires the request a second time, they shouldn't be charged twice or reserve two cars.

  • Every reservation request generates a unique Idempotency-Key (UUID) from the frontend.
  • The backend stores this key alongside the successful response. If a duplicate request arrives with the same key within 24 hours, the backend bypasses processing and simply replays the exact same HTTP response.

3. Real-Time UI with Server-Sent Events (SSE)

Instead of relying on heavy client-side polling (setInterval), this app utilizes a custom Server-Sent Events streaming endpoint (/api/stock/stream).

  • When a reservation is successfully created, confirmed, or released, a global Node.js EventEmitter fires.
  • The SSE endpoint instantly catches this event and pushes the updated live stock counts directly to every connected browser. This creates an incredibly dynamic "live auction" feel with zero manual reloading required.

4. Sliding Window Rate Limiting (Anti-Bot)

Luxury cars are prime targets for scalper bots. To prevent a bot from spamming the reservation endpoint and maliciously locking up all the stock:

  • An Upstash Redis Sliding Window Rate Limiter protects the core API.
  • It enforces a strict limit: A maximum of 3 reservation attempts per IP address every 10 seconds. Excess requests are blocked in single-digit milliseconds to protect the Postgres database from DDoS.

5. Multi-Currency Global Engine

A globally accessible context (CurrencyProvider) allowing the frontend to dynamically switch between USD, INR, EUR, and GBP. It applies accurate formatting algorithms based on the user's locale (e.g., standard Western commas vs. the Indian Numbering System).


Database Schema

The relational data model revolves around the concept of holding temporary reservations without permanently destroying stock until payment is confirmed.

  • Product: Details about the item (e.g., Porsche 911 GT3).
  • Warehouse: Physical locations storing the items.
  • Stock: The junction table tracking the exact amount of a Product in a specific Warehouse. It holds total (physical boxes) and reserved (items currently sitting in someone's 10-minute checkout window).
  • Reservation: Tracks the status of the hold (PENDING, CONFIRMED, RELEASED) and its strict expiry timestamp.

Local Setup & Execution

Prerequisites

  1. Node.js v18+
  2. A free Supabase account (for Postgres)
  3. A free Upstash account (for Redis)

Installation

  1. Clone the repository and install dependencies:

    npm install
  2. Create a .env file in the root directory and add your credentials:

    # Supabase Postgres
    DATABASE_URL="postgresql://[USER]:[PASS]@[HOST]:6543/postgres?pgbouncer=true"
    DIRECT_URL="postgresql://[USER]:[PASS]@[HOST]:5432/postgres"
    
    # Upstash Redis
    UPSTASH_REDIS_REST_URL="https://[YOUR-UPSTASH-URL].upstash.io"
    UPSTASH_REDIS_REST_TOKEN="[YOUR-UPSTASH-TOKEN]"
    
    RESERVATION_EXPIRY_MINUTES=10
    NEXT_PUBLIC_APP_URL="http://localhost:3000"
  3. Push the database schema:

    npx prisma generate
    npx prisma db push
  4. Seed the database with the Super Cars:

    npm run prisma:seed 
    # (or: npx prisma db seed)
  5. Run the development server:

    npm run dev

Open http://localhost:3000 to view the application!


Built for the Allo Health Engineering Challenge.

Releases

Packages

Contributors

Languages