Skip to content

Arquitectura

Arquitectura hexagonal / clean por módulo de negocio. El dominio no depende de Nest, HTTP ni infraestructura.

text
src/
├── ApiModule.ts                 # composición raíz (+ EventBusModule, EventEmitter)
├── main.ts                      # bootstrap Nest
├── config.ts                    # env (incl. TEST_MODE_ENABLED)
├── shared/                      # piezas transversales
│   ├── domain/
│   │   ├── errors/              # DomainError + DomainErrorCode + errores compartidos
│   │   ├── event-bus/           # puerto EventBus + EVENT_BUS_TOKEN
│   │   ├── hasher/              # puerto HasherService + HASHER_SERVICE_TOKEN
│   │   ├── events/              # AggregateRoot, DomainEvent, DomainEventId/Name
│   │   ├── use-case/            # contrato UseCase<T, U>
│   │   └── value-objects/       # SingleValueObject, Uuid, Email, Password, Salt, HashedString
│   └── infrastructure/
│       ├── errors/              # filtro HTTP + mapeo status codes
│       ├── event-bus/           # EventBusModule, EventBusNest, EventBusMemory
│       └── hasher/              # HasherBcrypt
├── health-check/                # módulo ejemplo (bounded context)
│   ├── HealthCheckModule.ts
│   ├── domain/
│   │   ├── models/
│   │   └── events/              # EventCheckRequested (con --events)
│   ├── application/
│   │   └── use-cases/           # HealthChecker, EventEmitChecker
│   └── infrastructure/
│       ├── adapters/
│       │   ├── endpoints/
│       │   └── dtos/
│       └── event-handlers/      # EventCheckRequestedHandler (@OnEvent)
└── users/                       # bounded context de usuarios (con database)
    ├── UsersModule.ts
    ├── domain/
    │   ├── models/              # User, UserId, UserName, UserSurname
    │   ├── errors/
    │   └── repositories/        # puerto UserRepository + token
    ├── application/
    │   └── use-cases/           # UserCreator
    └── infrastructure/
        └── adapters/
            ├── endpoints/       # CreateUserEndpoint
            └── dtos/

TIP

Con create-bb-app, users, EventBus y health de BD solo aparecen si eliges los extras correspondientes. La base siempre incluye el shared kernel y el liveness de health-check.

Flujo del ejemplo health-check

text
HTTP GET /api/v1/health-check


HealthCheckEndpoint   (infrastructure / adapter)


HealthChecker         (application / use case)


HealthCheckMessage    (domain)

Flujo de creación de usuario (users)

text
HTTP POST /api/v1/users


CreateUserEndpoint            (infrastructure / adapter)
        │  Email / Password / UserName / UserSurname VOs

UserCreator                   (application; hasher + UserRepository ports)
        │  hasher.generateSalt() + hasher.hash(password, salt)
        │  User.createNew(...)
        │  userRepository.save(user)

TypeOrmUserRepository / MongoUserRepository

UserDetailsDto                (respuesta HTTP; sin password/salt)

Regla de oro

domain no importa Nest, TypeORM/Mongoose ni detalles de transporte. Si un caso de uso “necesita” importar infraestructura directamente, falta una interfaz en el dominio.

Direction of dependencies

text
infrastructure → application → domain

Nunca al revés.

Cómo añadir un feature nuevo

  1. Crear src/<feature-kebab>/ con domain/, application/use-cases/, infrastructure/adapters/endpoints/.
  2. Añadir <FeaturePascal>Module.ts registrando controllers + providers.
  3. Importar el módulo en ApiModule.
  4. Añadir unit specs junto a use cases / domain.
  5. Añadir e2e bajo test/<feature-kebab>.e2e-spec.ts.
  6. Espejar health-check como referencia.

MIT License · Scaffold from backend-boiler