Eventos de dominio & EventBus
El dominio define qué ocurrió (DomainEvent). La aplicación publica a través del puerto EventBus. La infraestructura adapta (Nest EventEmitter hoy; RabbitMQ mañana) y reacciona con handlers.
Incluido cuando scaffoldas con --events (o lo aceptas en el wizard).
Flujo (health-check)
text
HTTP POST /api/v1/health-check/event-emit
│
▼
EventEmitHealthCheckEndpoint
│
▼
EventEmitChecker (application; @Inject(EVENT_BUS_TOKEN))
│ new EventCheckRequested({ message })
│ eventBus.emit([event])
▼
EventBusNest → EventEmitter2.emit('event.emit_check_requested', event)
│
▼
EventCheckRequestedHandler (infrastructure; @OnEvent)Piezas base
| Pieza | Rol |
|---|---|
DomainEvent | Base abstracta (id, name, payload, occurredAt) |
DomainEventId | Extiende Uuid (UUID v7 semántico) |
DomainEventName | VO con formato obligatorio aggregate.action |
AggregateRoot | Acumula eventos (recordEvent / pullEvents) |
EventBus | Puerto: emit(events) |
EVENT_BUS_TOKEN | Token Nest para inyectar el puerto |
EventBusNest | Adapter producción vía @nestjs/event-emitter |
EventBusMemory | Adapter para tests (TEST_MODE_ENABLED=true) |
Cómo añadir un evento nuevo
- Crear
src/<feature>/domain/events/<Nombre>.tsextendiendoDomainEvent. - Definir
static readonly EVENT_NAME = 'aggregate.action'. - Emitir desde un use case con
@Inject(EVENT_BUS_TOKEN). - Crear handler en
infrastructure/event-handlers/con@OnEvent(EVENT_NAME). - Registrar handler + use case en el módulo Nest del feature.
Checklist
- Evento en domain con
EVENT_NAMEvalidado porDomainEventName. - Emisión desde application vía puerto (nunca
EventEmitter2directo). - Handler solo en infrastructure.
- Unit test del use case con fake/
EventBusMemory. - E2E si el evento se dispara desde HTTP.
Wiring
ts
EventBusModule.init({ disable: loadConfig().testModeEnabled })
EventEmitterModule.forRoot({ global: true })TEST_MODE_ENABLED=true cambia a EventBusMemory para assertar eventos emitidos sin el emitter real.
Reglas de handlers
- Viven en infrastructure, no en domain.
- Suscribirse con
@OnEvent(<Event>.EVENT_NAME)coincidiendo exactamente con el string del evento. - Mantenerlos finos: side effects / logging / projections; no invariantes de negocio.
- Registrarlos en
providersdel feature module.