Shop Microservers

DockerNext.jsExpressPostgreSQLRedisNginx

Shop Microservers es una aplicación full-stack de comercio electrónico diseñada para demostrar una arquitectura de microservicios real y desacoplada. Cada dominio de negocio (auth, catálogo, carrito, órdenes) vive en su propio servicio, con su propia base de datos y su propio ciclo de despliegue, mientras un único gateway expone una superficie HTTP coherente al frontend.

Arquitectura y Stack

Arquitectura central

  • Patrón: Microservicios con database-per-service (cada servicio es dueño de sus datos).
  • Gateway: Nginx como reverse proxy y único punto de entrada (puerto 80).
  • Comunicación: HTTP interno sobre una red bridge de Docker (shop), usando los nombres de servicio como hostname.
  • Orquestación: Docker Compose con health checks y dependencias por estado de salud (condition: service_healthy).
  • Contrato de API: Respuesta uniforme { success, data, error } en todos los servicios.

Diagrama de capas

Servicios y responsabilidades

RutaServicioPuertoAlmacenamientoResponsabilidad
/api/auth/auth3004auth_db (PG)Registro, login y emisión de JWT
/api/catalog/catalog3001catalog_db(PG)Listado de productos y manejo de stock
/api/cart/cart3002redisCarrito efímero por usuario (TTL 7 días)
/api/orders/orders3003orders_db(PG)Checkout: valida stock → decrementa → persiste orden → limpia carrito
/frontend3000Next.js App Router (SPA, JWT en localStorage)

En total son 8 contenedores: gateway, frontend, 4 microservicios, 3 PostgreSQL y 1 Redis.

Stack tecnológico

  • Backend: Node.js + TypeScript, Express, Prisma ORM, Zod (validación).
  • Frontend: Next.js 15 (App Router), React 19, Tailwind CSS 3, Radix UI, lucide-react.
  • Bases de datos: PostgreSQL 16 (auth, catalog, orders — una por servicio) y Redis 7 (carrito).
  • Gateway: Nginx (reverse proxy).
  • Orquestación: Docker Compose.

Flujo de una Petición

Herramientas/Servicios de un Vistazo

Características clave

Database-per-service real

Cada servicio con persistencia tiene su propia instancia de PostgreSQL (auth_db, catalog_db, orders_db), eliminando el acoplamiento por base de datos compartida. El schema se aplica con Prisma al arrancar cada contenedor.

Flujo de checkout orquestado

El servicio de órdenes actúa como orquestador de la transacción de compra:

  1. Lee el carrito del usuario llamando a cart (fetchCart).
  2. Decrementa stock producto por producto llamando a catalog (decrementStock).
  3. Persiste la orden con sus items en orders_db.
  4. Limpia el carrito llamando a cart (clearCart).

Carrito efímero en Redis

El carrito vive en Redis con clave cart:{userId} y TTL de 7 días, sin persistencia en disco: ligero, rápido y desechable por diseño.

Autenticación con JWT compartido

El JWT_SECRET se comparte por variable de entorno entre auth, cart y orders, de modo que cualquier servicio puede verificar tokens sin llamar de vuelta a auth. Los tokens expiran a los 7 días; no hay endpoint de introspección, cada servicio valida la firma localmente.

Aspectos técnicos destacados

  • Gateway como única superficie: El frontend nunca llama directo a los servicios — todo pasa por Nginx, que enruta por prefijo (/api/<servicio>/).
  • Health checks en cascada: El gateway depende de que los 4 microservicios estén healthy (intervalo de 15s, 20s para gateway/frontend, 5 reintentos); cada servicio también depende de su propia base de datos healthy, y orders además espera a cart y catalog antes de arrancar.
  • Eliminación de prefijo + WebSocket: Nginx elimina el prefijo /api/<servicio>/ antes de reenviar la petición al upstream, y reenvía los headers Upgrade/Connection para que el HMR de Next.js siga funcionando a través del gateway en desarrollo.
  • Catálogo autopoblado: Se siembra automáticamente con 12 productos en el primer arranque (idempotente).
  • Validación como frontera: Zod valida la entrada en cada servicio antes de tocar la base de datos.
  • Manejo de errores uniforme: AppError + middleware de errores → respuestas consistentes { success, data, error }.

Endpoints principales

ServicioMétodo y ruta (interna)Descripción
authPOST /registerCrea usuario y devuelve JWT
authPOST /loginAutentica y devuelve JWT
catalogGET /Lista productos
catalogGET /:idDetalle de un producto
catalogPATCH /:id/stockAjusta stock (uso interno)
cartGET /Obtiene el carrito del usuario
cartPOST /itemsAgrega un ítem
cartDELETE /items/:productIdElimina un ítem
cartDELETE /Vacía el carrito
ordersGET /Lista órdenes del usuario
ordersGET /:idDetalle de una orden
ordersPOST /Checkout (crea la orden)

Modelo de datos

  • auth_dbUser (id, email, passwordHash, createdAt).
  • catalog_dbProduct (id, name, price, imageUrl, stock, category).
  • orders_dbOrder (con estado PENDING → CONFIRMED → SHIPPED → DELIVERED / CANCELLED) y OrderItem.
  • redis → carritos por usuario, sin persistencia.

Cómo ejecutarlo

cp .env.example .env
docker compose up --build

La aplicación queda disponible en http://localhost (o http://localhost:${GATEWAY_PORT}).

Configuración

VariableValor por defectoRequeridaPropósito
JWT_SECRETFirma/verifica JWTs (expiran a los 7 días)
GATEWAY_PORT80NoPuerto del host para el gateway Nginx (usar 8080 si el 80 está ocupado)
NEXT_PUBLIC_API_URLhttp://localhostNoURL base de la API para el frontend, embebida en tiempo de build
POSTGRES_USER / POSTGRES_PASSWORDshop / shopNoCredenciales compartidas entre las tres instancias de Postgres — cambiar antes de producción
AUTH_DB_NAME / CATALOG_DB_NAME / ORDERS_DB_NAMEauth / catalog / ordersNoNombres de base de datos por servicio
REDIS_URLredis://redis:6379NoConexión Redis del servicio cart
CATALOG_URL / CART_URLhttp://catalog:3001 / http://cart:3002NoURLs internas que el servicio orders llama durante el checkout

Cada microservicio también recibe un DATABASE_URL autogenerado por interpolación de Docker Compose — sin configuración manual.

Estructura del proyecto

shopflow-microservices/
├── docker-compose.yml        # Orquesta los 8 contenedores
├── gateway/                  # Nginx (reverse proxy)
├── frontend/                 # Next.js 15 (login, catálogo, carrito, órdenes)
└── services/
    ├── auth/                 # Express + Prisma → auth_db
    ├── catalog/              # Express + Prisma → catalog_db
    ├── cart/                 # Express + ioredis → redis
    └── orders/               # Express + Prisma → orders_db (orquesta checkout)

Impacto y Escalabilidad

  • Escalado independiente: cada microservicio (auth, catalog, cart, orders) puede escalarse, redesplegarse o revertirse por separado, sin afectar a los demás.
  • Dominios de fallo aislados: database-per-service implica que una consulta lenta o una caída en catalog_db nunca bloquea a auth u orders.
  • Servicios sin estado detrás del gateway: cada servicio puede correr múltiples réplicas detrás de Nginx sin necesidad de sesiones pegajosas, ya que el estado vive en Postgres/Redis, no en el proceso.
  • Límites claros entre equipos: el contrato uniforme { success, data, error } y los esquemas Prisma por servicio facilitan que distintos dueños evolucionen cada servicio de forma independiente.

Notas

Este informe refleja la arquitectura actual con bases de datos independientes por servicio (auth, catalog y orders), comunicación HTTP interna sobre Docker y un gateway Nginx como único punto de entrada. El diseño prioriza el desacoplamiento, los health checks y un contrato de API uniforme entre todos los servicios. El código es público en GitHub.