Shop Microservers
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
| Ruta | Servicio | Puerto | Almacenamiento | Responsabilidad |
|---|---|---|---|---|
/api/auth/ | auth | 3004 | auth_db (PG) | Registro, login y emisión de JWT |
/api/catalog/ | catalog | 3001 | catalog_db(PG) | Listado de productos y manejo de stock |
/api/cart/ | cart | 3002 | redis | Carrito efímero por usuario (TTL 7 días) |
/api/orders/ | orders | 3003 | orders_db(PG) | Checkout: valida stock → decrementa → persiste orden → limpia carrito |
/ | frontend | 3000 | — | Next.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:
- Lee el carrito del usuario llamando a cart (
fetchCart). - Decrementa stock producto por producto llamando a catalog (
decrementStock). - Persiste la orden con sus items en
orders_db. - 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 headersUpgrade/Connectionpara 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
| Servicio | Método y ruta (interna) | Descripción |
|---|---|---|
| auth | POST /register | Crea usuario y devuelve JWT |
| auth | POST /login | Autentica y devuelve JWT |
| catalog | GET / | Lista productos |
| catalog | GET /:id | Detalle de un producto |
| catalog | PATCH /:id/stock | Ajusta stock (uso interno) |
| cart | GET / | Obtiene el carrito del usuario |
| cart | POST /items | Agrega un ítem |
| cart | DELETE /items/:productId | Elimina un ítem |
| cart | DELETE / | Vacía el carrito |
| orders | GET / | Lista órdenes del usuario |
| orders | GET /:id | Detalle de una orden |
| orders | POST / | Checkout (crea la orden) |
Modelo de datos
- auth_db →
User(id, email, passwordHash, createdAt). - catalog_db →
Product(id, name, price, imageUrl, stock, category). - orders_db →
Order(con estadoPENDING → CONFIRMED → SHIPPED → DELIVERED / CANCELLED) yOrderItem. - redis → carritos por usuario, sin persistencia.
Cómo ejecutarlo
La aplicación queda disponible en http://localhost (o http://localhost:${GATEWAY_PORT}).
Configuración
| Variable | Valor por defecto | Requerida | Propósito |
|---|---|---|---|
JWT_SECRET | — | Sí | Firma/verifica JWTs (expiran a los 7 días) |
GATEWAY_PORT | 80 | No | Puerto del host para el gateway Nginx (usar 8080 si el 80 está ocupado) |
NEXT_PUBLIC_API_URL | http://localhost | No | URL base de la API para el frontend, embebida en tiempo de build |
POSTGRES_USER / POSTGRES_PASSWORD | shop / shop | No | Credenciales compartidas entre las tres instancias de Postgres — cambiar antes de producción |
AUTH_DB_NAME / CATALOG_DB_NAME / ORDERS_DB_NAME | auth / catalog / orders | No | Nombres de base de datos por servicio |
REDIS_URL | redis://redis:6379 | No | Conexión Redis del servicio cart |
CATALOG_URL / CART_URL | http://catalog:3001 / http://cart:3002 | No | URLs internas que el servicio orders llama durante el checkout |
Cada microservicio también recibe un
DATABASE_URLautogenerado 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_dbnunca bloquea aauthuorders. - 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.