How aviavinash24/orderflow works
Purpose and Entry Points
OrderFlow is a concurrency-safe e-commerce order backend with a React/Vite client. It reserves stock, transitions orders through payment/cancel/expiry states, applies payment webhooks idempotently, and reliably publishes side effects via an outbox.
• API process and lifespan: app/main.py
• RQ worker process: app/worker.py
• Browser entry/UI root: frontend/src/main.jsx, frontend/src/App.jsx
HTTP and Authentication Boundary
FastAPI routers are the business-logic boundary; handlers use explicit async PostgreSQL transactions rather than an ORM. JWT authentication protects order operations, while simulated payment webhooks are unauthenticated. Redis enforces a fixed-window per-user order creation limit.
• Routing: app/routers/auth.py, app/routers/orders.py, app/routers/webhooks.py
• Security/dependencies/rate limiting: app/core/security.py, app/core/deps.py, app/core/rate_limit.py
• API DTOs: app/schemas/orders.py, app/schemas/webhooks.py
Ordering and Inventory Reservation
POST /orders is the central correctness path. Within one transaction it sorts requested items by product ID to establish lock order, conditionally decrements available inventory and increments reserved inventory, creates a placed order with an expiry, and persists line-item price snapshots. Insufficient stock aborts the full transaction.
Cancellation locks the order, permits only placed/paid, changes it to cancelled, and returns reserved inventory to available.
• Order flows: app/routers/orders.py
• Inventory/order schema: migrations/0004_create_inventory.sql, migrations/0005_create_orders.sql, migrations/0006_create_order_items.sql
Payment and Transactional Outbox
Payment webhooks lock the referenced order and record each gateway event. A unique gateway event ID makes duplicate delivery idempotent. A successful event changes only a currently placed order to paid; in that same transaction it creates an order.paid outbox event. The webhook always responds successfully to avoid retry storms, including duplicates or unknown orders.
• Webhook state transition: app/routers/webhooks.py
• Payment/outbox persistence: migrations/0007_create_payment_events.sql, migrations/0008_create_outbox_events.sql
Background State Reconciliation
The API lifespan owns the reservation-expiry loop. It claims expired unpaid placed orders using row locking with SKIP LOCKED, marks them expired, and releases their reservations. This enables concurrent pollers without duplicate work.
A separate RQ worker polls/enqueues and drains pending outbox rows, claims batches with SKIP LOCKED, handles events, and marks them processed. Database outbox state is the durability boundary; Redis is a broker/wake-up mechanism, not the system of record.
• Expiry job: app/jobs/expire_reservations.py, app/main.py
• Outbox processing: app/jobs/outbox.py, app/worker.py
Persistence and Infrastructure
PostgreSQL 16 is authoritative for users, catalog, inventory counters, orders, payment events, and outbox events; access is raw SQL through asyncpg. Ordered migrations establish constraints and indexes supporting correctness and polling. Redis 7 supports rate limits and RQ. Docker Compose runs API, worker, database, and Redis.
• DB/config boundary: app/core/db.py, app/core/config.py
• Migration execution and base schema: scripts/run_migrations.py, migrations/0001_enable_uuid.sql
• Service topology: docker-compose.yml, Dockerfile
Frontend Client
The Vite React SPA manages auth state and cart state locally, calls the API through a shared client, and exposes product, cart, order, and authentication pages. It is a consumer of the API rather than a source of business-state correctness.
• API/auth/cart clients: frontend/src/api.js, frontend/src/auth.jsx, frontend/src/cart.jsx
• Primary pages: frontend/src/pages/ProductsPage.jsx, frontend/src/pages/CartPage.jsx, frontend/src/pages/OrderPage.jsx
Main entry points: main.py FastAPI app · docker-compose.yml Docker Compose · db.py PostgreSQL 16 · orders.py Order routes
Components 16
React client
- Vite React SPA · Local auth and cart state; consumes the API.
frontend/src/main.jsx - API client
frontend/src/api.js
API process
- FastAPI app · Owns HTTP serving and the reservation-expiry lifecycle.
app/main.py - Auth routes
app/routers/auth.py - Order routes · Creates, cancels, and reads orders in explicit async SQL transactions.
app/routers/orders.py - Payment webhooks · Records gateway events and transitions placed orders to paid.
app/routers/webhooks.py - JWT and order limits · Authenticates order users and applies fixed-window creation limits.
app/core/security.py
Background processing
- Reservation expiry · Claims expired placed orders, expires them, and releases stock.
app/jobs/expire_reservations.py - RQ worker
app/worker.py - Outbox processor · Claims pending events, handles them, and marks them processed.
app/jobs/outbox.py
Data and infrastructure
- PostgreSQL 16 · System of record for catalog, inventory, orders, payment events, and outbox state.
app/core/db.py - Inventory and orders · Available/reserved counters, order state, expiry, and price snapshots.
migrations/0005_create_orders.sql - Payment events and outbox · Unique gateway events and durable side-effect events.
migrations/0007_create_payment_events.sql - Redis 7 · Broker and wake-up mechanism, not durable outbox state.
- Ordered migrations · Establishes database constraints and polling indexes.
scripts/run_migrations.py - Docker Compose · Runs API, worker, PostgreSQL, and Redis.
docker-compose.yml
Connections 21
- Vite React SPA → API client: uses
- API client → FastAPI app: HTTP
- FastAPI app → Auth routes: serves
- FastAPI app → Order routes: serves
- FastAPI app → Payment webhooks: serves
- Order routes → JWT and order limits: authenticates and limits
- JWT and order limits → Redis 7: fixed-window counters
- Order routes → Inventory and orders: reserve, place, cancel · Locks rows, reserves stock, and rolls back insufficient-stock requests.
- Payment webhooks → Payment events and outbox: idempotent paid event · Records gateway delivery and creates order.paid atomically.
- Inventory and orders → PostgreSQL 16: stored in
- Payment events and outbox → PostgreSQL 16: stored in
- FastAPI app → Reservation expiry: runs in lifespan
- Reservation expiry → Inventory and orders: SKIP LOCKED expiry
- RQ worker → Outbox processor: runs
- Outbox processor → Payment events and outbox: claims and processes · Uses SKIP LOCKED batches and marks completed events.
- RQ worker → Redis 7: RQ broker
- Ordered migrations → PostgreSQL 16: creates schema
- Docker Compose → FastAPI app: runs
- Docker Compose → RQ worker: runs
- Docker Compose → PostgreSQL 16: runs
- Docker Compose → Redis 7: runs