Módulos de feature
Cuándo usarlo: para toda área de feature nueva del backend. Preferilo siempre sobre agregar archivos
al árbol plano controllers/v1 + services/v1.
Estructura
Copiá src/modules/health-center/, que es el ejemplo chico y limpio:
src/modules/<feature>/
├── controllers/ # extienden SecuredController
├── services/ # extienden Service, export default new X()
├── dtos/ # class-validator
├── entities/ # entidades TypeORM propias (si tiene)
├── module.config.ts # el manifiesto
├── module.ts # singleton con initialize() / getControllers() / getEntities() / getMetadata()
└── index.ts # barrel: re-exporta módulo, config, entities, dtos, services, controllers
module.config.ts — el manifiesto, sin lógica:
export const HEALTH_CENTER_MODULE_CONFIG: ModuleConfig = {
name: 'HealthCenterModule', version: '1.0.0', description: '…',
controllers: [HealthCenterController],
entities: [HealthCenter, HealthCenterServiceLine],
providers: [HealthCenterService, HealthCenterServiceLineService],
};
module.ts — un singleton estilo NestJS con getInstance(), un initialize() idempotente (avisa por
logger.warn si ya estaba inicializado) y los getters que leen la config.
Enchufarlo a Express
// src/controllers/v1/ControllerImportsV1.ts
export const controllers = [
/* ...los de v1... */
...AppointmentsModule.getControllers(),
...HealthCenterModule.getControllers(),
];
Si el controller no está en esa lista —directo o vía módulo— la ruta no existe y no hay ningún error. Es el error más común al agregar un endpoint.
Los cuatro módulos que existen
rules-engine — motor de reglas por financiador
El módulo más grande: core/ (contratos), entities/ (11), services/ (22, más validators/ con 42
validadores, context/ y practice-sources/), controllers/ (6), dtos/, docs/.
Anticipa los débitos de PAMI antes de facturar. Ver Motor de reglas.
health-center — centros médicos
ABM de centros médicos y sus líneas de atención, más el vínculo con usuarios. Es la base del scoping por centro (Centro médico activo) y el molde canónico del patrón: chico y limpio, copiá este.
authorizations — autorizaciones por afiliado
AuthorizationAdapterRegistry + services/adapters/ con un adapter por origen de datos, y
AuthorizationByAfiliadoController. No tiene entidades propias: reusa finances.Authorization. Ver
Autorizaciones.
appointments — turnos
Módulo de agenda y turnos. Tiene alias de path propio: @appointments.
Gotchas
- Las entidades del módulo las auto-descubre el glob de la conexión. Declararlas en
entities[]es documentación / manifiesto, no el mecanismo de registro. initialize()no crea tablas. El schema se aplica a mano: ver DDL y ops.- No importes cruzado entre módulos por ruta profunda: usá el barrel
index.tsdel otro módulo. - Los módulos se alcanzan con
@modules/<feature>/.... Todo alias nuevo se declara en tres lugares (ver Arquitectura).