Skip to content

Case study / Backend system

E-commerce Order Management System

An order system built so a busy store does not sell the same last item twice or freeze at checkout while a payment goes through.

The problem

A busy online store fails in two expensive ways: it sells the same last item to two people, or checkout hangs while a payment is processed.

What it had to do

  • Stay correct and responsive under load
  • Never oversell inventory

What was built

An Express API that sends writes to a PostgreSQL primary and spreads reads across two replicas, with Redis for caching and for the shopping cart.

Redis and Kafka run in Docker Compose. The storefront is a mobile-first React and Tailwind CSS interface, and the payment gateway is simulated.

How it works, step by step

  1. Browsing: product pages are read from the replicas and cached in Redis.
  2. Cart: each shopper’s cart is kept in Redis.
  3. Checkout: stock is reserved in Redis in one atomic step, so two shoppers cannot take the same last item.
  4. The order is written to the primary database and the payment is queued on Kafka. The shopper gets an answer straight away.
  5. A payment worker processes the payment and updates the order. If the payment fails, the reserved stock is released.
  6. The storefront checks the payment status and shows the result.

My part

  • The system design, including the plan for how it grows.
  • The API with its primary and replica databases, and the Redis caching.
  • The Kafka payment worker.
  • The React storefront.
  • The k6 load test scripts.

The rest of the team

A teammate fixed inventory reservation and tuned the system for the load tests.

Decisions that shaped it

  1. Reads and writes go to different databases

    Most of a store’s traffic is people looking, not buying. Reads are spread across two replicas and only writes touch the primary. If a replica is unhealthy, reads fall back to the primary.

  2. The payment runs after the response, not during it

    Checkout queues the payment and answers at once. A slow payment no longer holds the shopper on a spinner, and it is not lost if the worker restarts, because it stays on the queue.

  3. Stock is reserved in one atomic step

    Checking the stock and reducing it happen as a single step in Redis, so there is no gap in which a second shopper can reserve the same last item.

The outcome

The system runs end to end on a local machine: browse, cart, checkout, payment in the background and order history.

The repository holds the system design and k6 scripts that ramp up to 500 simulated shoppers, with pass and fail limits. No measured load test result is published there, so I quote none here.

What you can check

Code

The project folder on the branch that holds my work.

Open: Code, E-commerce Order Management System (opens in a new tab)
System design

The design documents, from a first thousand daily users upward.

Open: System design, E-commerce Order Management System (opens in a new tab)
Load test scripts

The k6 scripts and the limits they check.

Open: Load test scripts, E-commerce Order Management System (opens in a new tab)

Have something like this in mind?

Tell me what you are building. You get a written scope and a fixed price before any work starts.