PROYECTOS
FULLSTACK

Clean Architecture con TypeScript

API REST de pedidos implementada con Clean Architecture estricta: domain, application, infrastructure y composition. Repositorio educativo para ilustrar cómo organizar un backend real sin frameworks en el núcleo.

ROLE
Autor
TIPO
Open Source
AÑO
2026
ESTADO
Activo
4 capas arquitectónicas
0 dependencias en domain
4 tipos de tests

Contexto

Repositorio de referencia para equipos que quieren adoptar Clean Architecture en Node.js. La mayoría de ejemplos que existen usan NestJS como andamiaje, lo que mezcla la arquitectura con las convenciones del framework. Este proyecto demuestra cómo aplicar los mismos principios con dependencias mínimas.

Problema

¿Cómo organizar el código de una aplicación backend para que la lógica de negocio sea independiente del framework, la base de datos y las librerías externas? ¿Cómo estructurar los tests para que el dominio se pueda probar sin levantar ningún servidor ni base de datos?

Solución

API de pedidos con cuatro capas estrictas: domain contiene entidades, value objects y eventos; application orquesta los casos de uso y define los puertos; infrastructure implementa los adaptadores (Fastify, Postgres, in-memory); composition ensambla todo. La regla de dependencia apunta siempre hacia adentro.

flowchart TD subgraph I[" Infrastructure "] HTTP[Fastify] PG[PostgresRepository] IM[InMemoryRepository] end subgraph A[" Application "] UC[Use Cases] RP[OrderRepository port] PS[PricingService port] end subgraph D[" Domain "] OR[Order] VO["Price · Currency · SKU"] EV["OrderCreated · ItemAdded"] end HTTP --> UC PG -.->|implementa| RP IM -.->|implementa| RP UC --> RP & PS UC --> OR OR --> VO & EV

Tech stack

TypeScript estricto en todos los módulos. Fastify para el servidor HTTP. PostgreSQL con migraciones SQL planas (sin ORM). Zod para validación de entorno en la capa composition. Vitest para tests de todas las capas. Docker Compose para el entorno de desarrollo con Postgres.

// DECISIONES_TÉCNICAS
01_RESULT_EN_LUGAR_DE_EXCEPCIONES

Los casos de uso devuelven Result<T, E> para errores esperados (validación, not found, infraestructura) en lugar de lanzar excepciones. El controlador HTTP es el único responsable de traducir esos errores a status codes. Hace el flujo de errores explícito y tipado.

02_PUERTOS_COMO_INTERFACES_TYPESCRIPT

Los casos de uso declaran interfaces (OrderRepository, PricingService, EventBus) sin conocer la implementación. La capa infrastructure proporciona los adaptadores concretos (InMemory, Postgres, HTTP). Cambiar de Postgres a MongoDB no toca una línea de lógica de negocio.

03_EVENTOS_DE_DOMINIO_ACUMULADOS

Order acumula eventos internamente y el caso de uso los extrae con pullEvents() para publicarlos. El dominio describe qué ocurrió; la infraestructura decide dónde publicarlo (outbox, cola, log). Diferencia explícita entre Order.create() (emite OrderCreated) y Order.reconstitute() (reconstruye desde persistencia, sin eventos).

Tags
TypeScript Fastify PostgreSQL Clean Architecture Vitest Docker Zod