Skip to main content

Módulos de feature

Las features nuevas del backend no se agregan al árbol plano de controllers/v1 + services/v1: van como módulo autocontenido en src/modules/<nombre>/.

La forma

src/modules/<nombre>/
├── module.ts # singleton: initialize / getControllers / getEntities / getServices
├── module.config.ts # el objeto ModuleConfig (name, version, controllers, entities, providers)
├── index.ts # re-exporta todo lo público del módulo
├── controllers/ services/ entities/ dto/
├── interfaces/ constants/ providers/ # opcionales
└── MODULE.md # opcional pero recomendado

module.config.ts es el "decorador @Module" escrito a mano:

export const STOCKS_MODULE_CONFIG: ModuleConfig = {
name: "StocksModule",
version: "1.0.0",
description: "Module for managing supplies, stock movements, and warehouse inventory",
controllers: [SupplyController],
entities: [Supply, SupplyMovement, SupplyMovementDetail, SupplyNote],
providers: [SupplyService, SupplyServiceV2, /* … */],
};

Los tres enganches

Si falta uno, el módulo no existe:

  1. src/modules/index.tsexport { default as XModule } from "./x/module";
  2. src/AppConfig.tsawait XModule.initialize();
  3. src/controllers/v1/ControllerImportsV1.ts...XModule.getControllers()

Las entidades entran solas al DataSource por el glob src/modules/**/entities/*.ts.

Cómo se importa

// ✅ desde fuera del módulo
import { SupplyService, Supply, CreateSupplyDTO } from "@modules/stocks";

// ✅ desde dentro del módulo
import { SupplyService } from "./services";

// ❌ para uso normal: pierde tipado y autocompletado
const services = StocksModule.getServices();

getServices() y getMetadata() son para tests, debugging e introspección, no para resolver dependencias.

No llames a initialize() desde código de producción

AppConfig ya lo hace en el bootstrap. Solo tiene sentido llamarlo en tests (beforeAll) y en scripts standalone que no pasan por AppConfig.

Los cinco módulos que existen

stocks — inventario

El más grande y el que más se toca.

  • Entidades (viven en la BD finances): Supply, SupplyMovement, SupplyMovementDetail, SupplyMovementHistory, SupplyReservation, SupplyNote, SupplyNoteDetails.
  • Servicios: SupplyService (v1) y services/v2/SupplyService.ts (~3k líneas, el vigente para lo nuevo), SupplyMovementService, SupplyNoteService.
  • Controller: SupplyController/v1/supply.
  • Tiene su propio MODULE.md con la guía de imports.

Lo que mueve stock de verdad no está acá sino en SQL: ver Stock y transferencias.

notifications — notificaciones in-app y push

Notifications (in-app, por usuario) y MobileNotifications (un token de Expo por dispositivo). Ver Notificaciones y push.

whatsapp — mensajería con el paciente

Patrón provider: IWhatsAppProviderMetaWhatsAppProvider, elegido por un factory. Suma WhatsAppTemplateManager, WhatsAppWorker y un validador de firma del webhook. Ver WhatsApp.

repairshop — talleres externos

Un CRUD chico pero importante en el dominio: un taller es un destino válido de un Supply. Buen molde para copiar cuando arrancás un módulo nuevo.

mobileConfig — versionado de BullStock

Una fila por release de la app (versión semver, entorno, URL del build, changelog). La app la consulta al arrancar para decidir si obliga a actualizar. En dev la app no consulta el backend: lee de su .env.

Lo que NO es módulo

Autorizaciones, remitos, hojas de ruta, pacientes, vehículos y reportes siguen en el árbol plano controllers/v1 + services/v1|v2|v3. Son el grueso del sistema y no están migrados; no intentes moverlos "de paso" mientras hacés otra cosa.