Shop Microservers is designed around the principle that each service owns its domain completely — its own codebase, its own database, and its own process. No service reaches into another service’s data store. Cross-service coordination happens exclusively over the internal Docker network using well-defined HTTP APIs, with the Nginx gateway acting as the only component exposed to the outside world. This separation makes it straightforward to reason about, test, or replace any single service without touching the rest of the system.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/astrxnomo/shop-microservers/llms.txt
Use this file to discover all available pages before exploring further.
Topology
The following diagram shows how every component in the platform connects:Nginx gateway
The Nginx gateway is the sole public entry point for the entire platform, listening on port 80 (configurable viaGATEWAY_PORT). It uses Docker’s internal DNS resolver (127.0.0.11) to look up upstream service addresses by their Compose service names, with a 30-second TTL. Every inbound request is matched against a location block and proxied to the appropriate upstream — the /api/<service>/ prefix is stripped before the request reaches the service, so services always receive paths relative to their own router roots.
The location block assignments are:
| Location | Upstream | Notes |
|---|---|---|
/api/auth/ | auth:3004 | Standard HTTP proxy |
/api/catalog/ | catalog:3001 | Standard HTTP proxy |
/api/cart/ | cart:3002 | Standard HTTP proxy |
/api/orders/ | orders:3003 | Standard HTTP proxy |
/ | frontend:3000 | Includes Upgrade / Connection headers for WebSocket support |
/health | — | Returns 200 ok directly from Nginx; used by its own Docker healthcheck |
proxy_set_header Upgrade $http_upgrade and proxy_set_header Connection 'upgrade', which enables WebSocket connections — required for Next.js hot-module replacement during development.
Services
Auth — auth:3004
The auth service is an Express application backed by Prisma and a dedicated PostgreSQL 16 instance (auth_db). It exposes endpoints for user registration and login, and issues JWTs signed with the shared JWT_SECRET environment variable. Tokens carry a 7-day expiry. Every other service that requires authentication validates incoming Authorization: Bearer <token> headers against the same secret — there is no token introspection endpoint; validation is purely local to each service.
Catalog — catalog:3001
The catalog service is an Express application backed by Prisma and its own PostgreSQL 16 instance (catalog_db). It stores the Product table and serves product listings to the frontend via the gateway. On startup, it runs an idempotent seed script that inserts 12 products if the table is empty. It also exposes an internal PATCH /:id/stock endpoint used exclusively by the orders service to decrement stock after a successful checkout — this endpoint is not exposed through the gateway.
Cart — cart:3002
The cart service is a lightweight Express application that stores cart data entirely in Redis 7. Each user’s cart is a JSON array keyed by userId with a 7-day TTL — when the TTL expires or the orders service explicitly clears the cart after checkout, the key is simply deleted. There is no SQL database involved. All cart endpoints require a valid Bearer JWT, which the service verifies using the shared JWT_SECRET.
Orders — orders:3003
The orders service is an Express application backed by Prisma and a dedicated PostgreSQL 16 instance (orders_db). It orchestrates the entire checkout flow in a single request: it reads the user’s cart from the cart service, verifies that each product has sufficient stock by calling the catalog service, decrements stock for every line item, writes the Order and OrderItem rows to its own database, and finally asks the cart service to clear the user’s cart. All orders endpoints require a valid Bearer JWT. The service only starts after both the cart and catalog services pass their health checks.
Network
All containers — databases, microservices, gateway, and frontend — are connected to a single Docker bridge network namedshop. Services address each other using their Compose service name as the hostname (e.g., catalog, cart, redis). No service port is published to the host except the gateway’s port 80. The frontend never calls any backend service directly; every API call goes through the gateway on the shop network.
Data storage
| Store | Technology | Tables / Keys | Persistence |
|---|---|---|---|
catalog_db | PostgreSQL 16 | Product | Named Docker volume (catalog_db_data) |
auth_db | PostgreSQL 16 | User | Named Docker volume (auth_db_data) |
orders_db | PostgreSQL 16 | Order, OrderItem | Named Docker volume (orders_db_data) |
| Redis 7 | Redis 7 | Cart JSON keyed by userId | In-memory only — no AOF/RDB persistence |
Running
docker compose down -v removes all named volumes, wiping every database and all Redis data. This is the recommended way to fully reset the development environment.Health checks
Every service exposes aGET /health endpoint that returns 200 OK. Docker Compose uses these endpoints to gate startup ordering — the gateway will not start until all four microservices are healthy, and the orders service will not start until both catalog and cart are healthy. The Nginx gateway has its own health check that hits http://localhost/health, which is handled directly by the Nginx config without proxying to any upstream.
| Service | Health check URL | Interval | Retries |
|---|---|---|---|
| auth | http://localhost:3004/health | 15 s | 5 |
| catalog | http://localhost:3001/health | 15 s | 5 |
| cart | http://localhost:3002/health | 15 s | 5 |
| orders | http://localhost:3003/health | 15 s | 5 |
| frontend | http://localhost:3000 | 20 s | 5 |
| gateway | http://localhost/health | 15 s | 5 |
Inter-service communication
Direct service-to-service calls occur only within the orders service, which needs to coordinate across two other domains at checkout time. The URLs are injected via environment variables indocker-compose.yml:
shop Docker bridge network provides DNS resolution for these hostnames automatically — no service discovery sidecar or external registry is required.
Every route in the system returns a consistent response envelope:On failure,
success is false, data is null, and error contains the error message. This convention applies to all four microservices.