Zstem

E-Commerce Platform

by Zstem · published 2026-07-16 · 0 forks

APIDatabaseEventsArchitectureDocsWorkflowecommerceserverlessevent-driven

Storefront and checkout reference architecture: React storefront, API Gateway, microservices for catalog, cart, orders, payments (Stripe), and inventory, with S

Open & fork this on Zstem →
MicroservicesData StoresCatalogServiceCartServiceOrdersServicePaymentsServiceInventoryServiceProductsTableCarts TableOrdersTableInventoryTableShopperReactStorefrontCognito UserPoolAPI GatewayStripeOrder ProcessingQueueOrderProcessorSESE-Commerce Platformzstem.design

Architecture

Workflow

Event flow

API contract

Database

users
user_idCognito sub
email
full_name
created_at
products
product_id
sku
name
description
price_cents
currency
categoryGSI partition key for category browsing
image_url
active
created_at
updated_at
carts
cart_id
user_idGSI: one active cart per user
statusactive | checked_out | abandoned
created_at
updated_at
ttlepoch seconds; abandons stale carts
cart_items
cart_item_id
cart_id
product_id
quantity
unit_price_centsprice snapshot at add-to-cart
orders
order_id
user_idGSI for order history
statuspending | paid | confirmed | shipped | delivered | cancelled
subtotal_cents
shipping_cents
tax_cents
total_cents
currency
shipping_addressJSON blob: fullName, line1, line2, city, region, postalCode, country
placed_at
updated_at
order_items
order_item_id
order_id
product_id
namedenormalized product name at purchase time
quantity
unit_price_cents
payments
payment_id
order_id
stripe_payment_intent_id
statusrequires_confirmation | succeeded | failed | refunded
amount_cents
currency
created_at
updated_at
inventory
product_id
quantity_available
quantity_reservedheld during checkout, released on payment failure
restock_threshold
updated_at

About this design

What this is

A production-shaped reference architecture for a small-to-mid e-commerce platform on AWS serverless. A React storefront (Cognito-authenticated) talks to API Gateway, which fronts five Lambda-backed domain services — catalog, cart, orders, payments, and inventory — each owning its own DynamoDB table set. Checkout is decoupled from fulfilment with an SQS queue, Stripe handles card processing, and SES sends transactional email. Every view in this project describes the same system: the architecture is the component map, the database schema is the per-domain table design, the API contract is what the storefront calls, the workflow is the checkout state machine, and the event flow is the order lifecycle after checkout.

How it works

Browsing and cart are synchronous: the storefront hits /products and /cart, and each service reads/writes only its own table (prices are snapshotted onto cart items at add-to-cart time).

Checkout is a three-step handshake designed so a customer is never charged without an order existing:

POST /payments/intent — the payments service creates a Stripe PaymentIntent for the cart total and returns the client secret.

The storefront confirms the card with Stripe Elements (card data never touches our backend).

POST /orders — the orders service re-validates the cart, reserves stock with conditional writes on the inventory table, persists the order as pending, and publishes OrderPlaced to SQS.

The order processor consumes the queue asynchronously: it confirms the payment settled (Stripe webhooks land on /webhooks/stripe and update the payments table), decrements reserved stock, flips the order to confirmed, and sends the SES confirmation email. Failures release the reservation — see the workflow view for the exact branches and the event flow for who produces and consumes each event.

How to extend

Good first forks, roughly in order of effort:

Fulfilment/shipping service — add a consumer on the order-notifications topic that books shipments and emits order.shipped.

Search — stream the products table into OpenSearch and add GET /search.

Promotions — a discount engine the orders service consults during validation; add a promotions table.

Caching — put ElastiCache (or CloudFront) in front of catalog reads; it is by far the hottest path.

Hardening — add a DLQ redrive runbook, idempotency keys on POST /orders, and Stripe webhook replay protection.

When you add a service, keep the pattern: one Lambda per domain, one table set per service, cross-domain writes only via events — never let two services share a table.

Open & fork this on Zstem →