Sign inSign up

onyxwizard/orders-app

By onyxwizard

β€’Updated 3 months ago

Monolithic order processing system baseline built with Express, PostgreSQL, and Docker.

Image
Languages & frameworks
API management
Web servers
0

50

onyxwizard/orders-app repository overview

β πŸ—οΈ Order Management System β€” Stage 1: The Monolith

A learning project that evolves through three real-world backend architectures.
Stage 1 is the starting point: a single, synchronous Node.js/Express application paired with PostgreSQL. Everything runs inside Docker.

β πŸ“– Overview

This repository contains the Stage 1 implementation of an e‑commerce order backend. The entire system lives in one codebase, one process, and one database. When a user places an order, the server synchronously processes payment, adjusts inventory, generates an invoice, and sends a confirmation email β€” all before returning a response.

The goal of this stage is to establish a realistic performance baseline and to understand the pain points that justify moving to an event‑driven microservices architecture in later stages.

⁠🧱 Architecture (Layered Monolith)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                Docker Compose              β”‚
β”‚                                            β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  orders-appβ”‚        β”‚   orders-db     β”‚ β”‚
β”‚  β”‚ (Node.js)  β”‚ ◄────► β”‚ (PostgreSQL 15) β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Inside the orders-app container:

Client
  β”‚  POST /orders
  β–Ό
Express Server
  β”œβ”€β”€ routes/orderRoutes.js
  β”œβ”€β”€ controllers/orderController.js
  └── services/orderService.js
        β”œβ”€β”€ paymentService.js     (mock – 500β€―ms)
        β”œβ”€β”€ inventoryService.js   (mock – 300β€―ms per item)
        β”œβ”€β”€ invoiceService.js     (mock – 400β€―ms)
        β”œβ”€β”€ emailService.js       (mock – 1000β€―ms)
        └── repositories/
              └── orderRepository.js

All business logic is layered (Controller β†’ Service β†’ Repository). Everything is blocking β€” the HTTP request waits for every step to finish.

β πŸ”§ Technology Stack

LayerTechnology
RuntimeNode.js 20 (Alpine)
FrameworkExpress 4
DatabasePostgreSQL 15 (Alpine)
ContainerizationDocker & Docker Compose
Load Testingautocannon
Mock ServicessetTimeout-based delays

β πŸš€ Running the Project

⁠Prerequisites
⁠1. Clone and start
git clone <your-repo-url>
cd order-system
docker compose up --build
⁠2. Verify it's running
curl -X POST http://localhost:3000/orders \
  -H "Content-Type: application/json" \
  -d '{
    "userId": 1,
    "items": [
      {"productId": "A1", "quantity": 2},
      {"productId": "B2", "quantity": 1}
    ],
    "email": "[email protected]"
  }'

Response (after ~2.5 seconds):

{
  "id": 1,
  "user_id": 1,
  "items": [
    {"productId": "A1", "quantity": 2},
    {"productId": "B2", "quantity": 1}
  ],
  "total_amount": "30.00",
  "status": "CONFIRMED",
  "created_at": "2026-07-06T08:10:00.000Z"
}
⁠3. Run the load test
# Install autocannon globally (only once)
npm install -g autocannon

# Execute the test
node load-test.js

β πŸ“Š Performance Baseline (Stageβ€―1)

Load test configuration: 10 concurrent connections, 10 seconds, POST /orders

MetricValue
Average latency2554.31 ms
Median latency2518 ms
99th percentile2643 ms
Max latency2643 ms
Requests per second3 req/s
Total requests40 (in 10s)

Why is it slow?
Each request executes four sequential mock delays: payment (500β€―ms), inventory (300β€―ms per item), invoice (400β€―ms), and email (1000β€―ms). The user must wait for all of them before getting a response.

⁠⚠️ Known Architectural Smells

  1. Tight coupling – The order service directly depends on every other domain (payment, inventory, etc.). Changing one requires changes to the monolith.
  2. Slow user experience – Non‑critical tasks (invoice, email) block the HTTP response.
  3. Poor fault isolation – An error in the invoice generator can fail the entire order, even if payment was already taken.
  4. No scalability – Scaling the app horizontally still leaves each instance stuck waiting for the same slow mock operations.

These issues motivate the transition to Stageβ€―2: Event‑Driven Microservices, where work is offloaded to background services via RabbitMQ, dramatically cutting user‑facing latency.

β πŸ“ Project Structure (Stageβ€―1)

order-system/
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ package.json
β”œβ”€β”€ .env
β”œβ”€β”€ load-test.js
β”œβ”€β”€ README.md
└── src/
    β”œβ”€β”€ server.js
    β”œβ”€β”€ config/
    β”‚   └── db.js
    β”œβ”€β”€ controllers/
    β”‚   └── orderController.js
    β”œβ”€β”€ services/
    β”‚   β”œβ”€β”€ orderService.js
    β”‚   β”œβ”€β”€ paymentService.js
    β”‚   β”œβ”€β”€ inventoryService.js
    β”‚   β”œβ”€β”€ invoiceService.js
    β”‚   └── emailService.js
    β”œβ”€β”€ repositories/
    β”‚   └── orderRepository.js
    β”œβ”€β”€ models/
    β”‚   └── order.js
    └── routes/
        └── orderRoutes.js

β πŸ“ˆ Roadmap (this is Stageβ€―1 of 3)

  • Stageβ€―1 (this repo) – Monolith with layered architecture & synchronous processing.
  • Stageβ€―2 – Event‑driven microservices: split into Order, Payment, Notification services + RabbitMQ. HTTP returns instantly, work continues asynchronously.
  • Stageβ€―3 – CQRS: add a Redis read model and projections for ultra‑fast order dashboards.

⁠🀝 Contributing

This is a personal learning project, but feedback and suggestions are welcome! Open an issue or a pull request if you spot improvements.

β πŸ“„ License

MIT β€” feel free to use it for your own learning.

Tag summary

Content type

Image

Digest

sha256:312c1e93c…

Size

49.7 MB

Last updated

3 months ago

docker pull onyxwizard/orders-app:v1.0