Modulo MBA (ms-mba)
ms-mba — Contrato de integracion del microservicio de MBA3 / 4D
Section titled “ms-mba — Contrato de integracion del microservicio de MBA3 / 4D”Proposito
Section titled “Proposito”ms-mba es un microservicio NestJS 11 que actua como unica puerta de entrada entre NoviSuite y el ERP MBA3 (motor 4D v20) del cliente. Expone una capa HTTP estable, independientemente de como MBA3 responda por debajo (HTTP REST o TCP nativo).
Opera con dos backends complementarios hacia 4D:
| Backend | Transporte | Uso |
|---|---|---|
| Consulta Externa (preferido) | HTTP REST multipart -> http://<mba>:8081/ws_Consulta_externa_MBA3/ | Todas las lecturas de catalogo, facturas, cobros, transferencias, clientes |
| MBA3 Web API | HTTP REST JSON -> http://<mba>:8081/mba3api/* | Escrituras (alta/edicion de proveedores) |
| p4d proxy (legacy) | Proxy Python 4D nativo por TCP 19812 | Health check profundo + controladores de retro-compatibilidad (legacy-compat, local-compat) |
Responsabilidades del modulo
Section titled “Responsabilidades del modulo”- Traducir operaciones HTTP de NoviSuite en queries SQL-like de Consulta Externa o POST al MBA3 Web API.
- Sincronizar nightly (22:00 - 22:50 hora Ecuador) los datos maestros hacia PostgreSQL local para lecturas rapidas offline.
- Exponer endpoints de consulta paginados, con busqueda y filtros por fechas.
- Cachear la sesion JWT de MBA3 con single-flight para evitar logins concurrentes.
- Proveer health check y diagnostico profundo para depurar VPN / red / motor 4D.
Flujo objetivo: NoviSuite -> HTTP JSON ->
ms-mba-> Consulta Externa multipart -> 4D -> JSON ->ms-mba-> NoviSuite, con fallback a p4d solo en controladores legacy.
Resumen ejecutivo
Section titled “Resumen ejecutivo”Lectura (99% del trafico)
Section titled “Lectura (99% del trafico)”- Dashboard hace
GET /api/v1/mba/<recurso>?...con Bearer JWT. ms-mbaconsulta Postgres local (datos sincronizados la noche anterior).- Si el endpoint termina en
4d/...ofrom-4d, consulta Consulta Externa en vivo. - Respuesta paginada con
{ data, meta }.
Sincronizacion nightly
Section titled “Sincronizacion nightly”- A las 22:00 hora Ecuador empieza la ventana de sync.
SyncSchedulerServicedispara 7 jobs cron separados cada 5 - 10 min.- Cada
*-sync.service.tshacesyncRecent(1)-> trae los registros del dia via Consulta Externa. - Upsert en chunks de 200 filas a Postgres local (TypeORM
orUpdate).
Escritura (proveedores)
Section titled “Escritura (proveedores)”- Dashboard llama
POST /api/v1/mba/providerscon Bearer JWT. ProvidersServiceobtiene JWT de MBA3 (single-flight) y hacePOST /mba3api/proveedores.- Verifica la creacion via Consulta Externa (hasta 3 intentos con backoff).
- Responde con
{ status: 'verified' | 'not_found' | 'unavailable' }.
Consulta manual en vivo
Section titled “Consulta manual en vivo”GET /api/v1/mba/invoices/4d/:code/claro-flow— consulta factura + lineas en vivo desde 4D.GET /api/v1/mba/products/:id/with-stock— producto + stock actual en todas las bodegas.
Datos base del servicio
Section titled “Datos base del servicio”| Recurso | Valor |
|---|---|
| Puerto HTTP | 3001 |
| Base de datos | mba_service_development / mba_service_production (PostgreSQL) |
| Redis | Cache JWT auth interno (TTL 60 s) |
| Consulta Externa | ${MBA_WEB_API_BASE_URL}/ws_Consulta_externa_MBA3/ |
| MBA3 Web API | ${MBA_WEB_API_BASE_URL}/mba3api/* |
| p4d proxy | TCP 127.0.0.1:5000 -> MBA_API_SERVER:19812 (dentro del contenedor) |
| Red | network_mode: service:vpn-gateway — todo el trafico sale por el tunel OpenVPN del vpn-gateway |
| Zona horaria | TZ=America/Guayaquil (critico para crons nightly) |
| Health check | GET /up (rapido) · GET /api/v1/mba/health/4d (profundo) |
Estructura del modulo
Section titled “Estructura del modulo”src/├── app.controller.ts # /up, /api/v1/mba/health, /api/v1/mba/health/4d, /api/v1/mba/auth/*├── app.module.ts├── main.ts│├── consulta-externa/ # ← BACKEND PREFERIDO│ ├── consulta-externa.service.ts # HTTP client + JWT single-flight│ └── consulta-externa.module.ts│├── mba3-auth/ # Login JWT compartido para /mba3api/*│ ├── mba3-auth.service.ts│ └── mba3-auth.module.ts│├── mba-database/ # ← BACKEND LEGACY p4d│ ├── mba-database.service.ts # Spawn Python + TCP 4D nativo│ ├── proxy.py # Servidor local TCP 5000│ └── p4d_legacy_bridge/│├── auth-client/ # Valida Bearer JWT contra ms-auth│ ├── auth-client.service.ts│ └── auth-client.module.ts│├── sync-scheduler/ # 7 crons nightly (22:00–22:50)│ ├── sync-scheduler.service.ts│ └── sync-scheduler.module.ts│├── warehouses/ # ✓ Consulta Externa├── products/ # ✓ Consulta Externa├── sellers/ # ✓ Consulta Externa├── clients/ # ✓ Consulta Externa├── invoices/ # ✓ Consulta Externa├── payments/ # ✓ Consulta Externa├── inventory-transfers/ # ✓ Consulta Externa├── providers/ # ✓ Consulta Externa (read) + /mba3api (write)│├── legacy-compat/ # ! Endpoints viejos (sobre MbaDatabaseService)├── local-compat/ # ! Endpoints locales (sobre MbaDatabaseService)├── legacy-mba/ # ! Endpoints muy viejos│├── entities/ # TypeORM para Postgres local│ ├── warehouse.entity.ts│ ├── product.entity.ts│ ├── seller.entity.ts│ ├── client.entity.ts│ ├── invoice.entity.ts│ ├── payment.entity.ts│ └── inventory-transfer.entity.ts│├── redis/├── config/├── database/migrations/└── common/ ├── guards/ ├── filters/ └── decorators/Autenticacion
Section titled “Autenticacion”| Esquema | Header | Uso |
|---|---|---|
Bearer JWT | Authorization: Bearer <token> | Dashboard (validado via ms-auth) |
ServiceKey | x-service-key: <key> | Sistemas internos / debug / cron triggers manuales |
Legacy token | Authorization: <AUTH_TOKEN> o ?api_key=<AUTH_TOKEN> | Controladores legacy-compat, local-compat, legacy-mba |
AuthGuard (Bearer JWT)
Section titled “AuthGuard (Bearer JWT)”Extrae el token, lo valida llamando a POST /api/internal/users/validate_token en ms-auth (con cache Redis de 60 s), y adjunta request.user = { id, email, roles, permissions }.
LegacyTokenOrBearerGuard
Section titled “LegacyTokenOrBearerGuard”Para endpoints de compat: acepta cualquiera de los dos esquemas. Si el header es Bearer *, delega al AuthGuard; si es el token plano, lo compara contra AUTH_TOKEN del .env.
ServiceKeyGuard
Section titled “ServiceKeyGuard”Aplicado manualmente en endpoints internos. Compara x-service-key contra SERVICE_KEY con comparacion timing-safe.
Contrato HTTP expuesto
Section titled “Contrato HTTP expuesto”Health y diagnostico
Section titled “Health y diagnostico”| Metodo | Ruta | Auth | Descripcion |
|---|---|---|---|
| GET | /up | — | Health rapido |
| GET | /api/v1/mba/health | — | Ping al p4d proxy |
| GET | /api/v1/mba/health/4d | — | Diagnostico profundo: TCP + proxy + query real |
| GET | /api/v1/mba/auth/status | — | Estado del JWT cacheado de MBA3 |
| POST | /api/v1/mba/auth/refresh | Bearer JWT (admin) | Fuerza re-login contra MBA3 |
Warehouses
Section titled “Warehouses”| Metodo | Ruta | Descripcion |
|---|---|---|
| GET | /api/v1/mba/warehouses | Listado desde Postgres local |
| GET | /api/v1/mba/warehouses/:id | Detalle |
| POST | /api/v1/mba/warehouses | Crear en MBA3 (/mba3api/bodegas) |
| PUT | /api/v1/mba/warehouses/:id | Actualizar en MBA3 |
| DELETE | /api/v1/mba/warehouses/:id | Anular en MBA3 |
| POST | /api/v1/mba/warehouses/sync?days=1 | Forzar sync inmediato |
Sellers
Section titled “Sellers”| Metodo | Ruta | Descripcion |
|---|---|---|
| GET | /api/v1/mba/sellers?page=&limit=&search= | Listado paginado |
| GET | /api/v1/mba/sellers/:code | Detalle |
| POST | /api/v1/mba/sellers/sync?days=1 | Sync manual |
Clients
Section titled “Clients”| Metodo | Ruta | Descripcion |
|---|---|---|
| GET | /api/v1/mba/clients?page=&limit=&search= | Listado paginado |
| GET | /api/v1/mba/clients/search?q=... | Busqueda por nombre/cedula/RUC |
| GET | /api/v1/mba/clients/:code | Detalle |
| POST | /api/v1/mba/clients/sync?days=1 | Sync manual |
Products
Section titled “Products”| Metodo | Ruta | Descripcion |
|---|---|---|
| GET | /api/v1/mba/products?page=&limit=&search= | Listado |
| GET | /api/v1/mba/products/with-stock | Productos + stock combinado |
| GET | /api/v1/mba/products/stock | Saldos |
| GET | /api/v1/mba/products/movements | Movimientos de inventario |
| GET | /api/v1/mba/products/:productId | Detalle |
| GET | /api/v1/mba/products/:productId/with-stock | Detalle + stock en vivo |
| POST | /api/v1/mba/products/sync?days=1 | Sync manual |
Invoices
Section titled “Invoices”| Metodo | Ruta | Descripcion |
|---|---|---|
| GET | /api/v1/mba/invoices?page=&limit= | Listado desde Postgres local |
| GET | /api/v1/mba/invoices/active | Solo no anuladas |
| GET | /api/v1/mba/invoices/seller/:sellerId | Por vendedor |
| GET | /api/v1/mba/invoices/status/active/:sellerId | Activas por vendedor |
| GET | /api/v1/mba/invoices/date-range?start_date=&end_date= | Por rango |
| GET | /api/v1/mba/invoices/number/:number | Por numero de factura |
| GET | /api/v1/mba/invoices/:code | Detalle |
| GET | /api/v1/mba/invoices/:code/find | Busqueda flexible |
| GET | /api/v1/mba/invoices/:code/extended | Con lineas, cobros, cliente |
| GET | /api/v1/mba/invoices/4d/:code | Detalle en vivo desde 4D |
| GET | /api/v1/mba/invoices/4d/:code/claro-flow | Payload listo para ms-recargas |
| POST | /api/v1/mba/invoices/sync?days=1 | Sync manual |
Payments
Section titled “Payments”| Metodo | Ruta | Descripcion |
|---|---|---|
| GET | /api/v1/mba/payments?page=&limit=&search= | Listado |
| GET | /api/v1/mba/payments/date-range?start_date=&end_date= | Por rango |
| GET | /api/v1/mba/payments/:payment | Detalle con cliente + metodos + detalle |
| POST | /api/v1/mba/payments/sync?days=1 | Sync manual |
Inventory Transfers
Section titled “Inventory Transfers”| Metodo | Ruta | Descripcion |
|---|---|---|
| GET | /api/v1/mba/inventories/transfers?page=&limit=&search= | Listado |
| GET | /api/v1/mba/inventories/transfers/confirmed | Solo confirmadas |
| GET | /api/v1/mba/inventories/transfers/date-range | Por rango |
| GET | /api/v1/mba/inventories/transfers/:transfer | Detalle + productos movidos |
| POST | /api/v1/mba/inventories/transfers/sync?days=1 | Sync manual |
Providers (unico modulo de escritura)
Section titled “Providers (unico modulo de escritura)”| Metodo | Ruta | Descripcion |
|---|---|---|
| POST | /api/v1/mba/providers | Crear proveedor (operacion=0) + verificar |
| PUT | /api/v1/mba/providers | Actualizar (operacion=1) + verificar |
| POST | /api/v1/mba/providers/verify | Solo verificar |
Respuesta tipica:
{ "success": true, "operation": "create", "payload": { "codigo_empresa": "NVC01", "nombre_proveedor": "...", "rfc_ruc_ci_proveedor": "1700000000" }, "upstream": { "respuesta": "OK" }, "verification": { "status": "verified", "codigo_proveedor": "PROV-001", "matched_by": "tax_id", "message": null }}Legacy compat
Section titled “Legacy compat”Los controladores legacy-compat (/mba/*), local-compat (/local-mba/*) y legacy-mba (/legacy/mba/*) exponen los mismos datos que los endpoints v1 pero con el shape antiguo. Se mantienen para integraciones legadas; internamente usan MbaDatabaseService (p4d) y no estan cubiertos por el sync nightly.
Integracion con Consulta Externa
Section titled “Integracion con Consulta Externa”Login (/login_Servicio)
Section titled “Login (/login_Servicio)”POST /login_Servicio HTTP/1.1Content-Type: application/json
{ "codigo": "<MBA_WEB_API_CODIGO>", "pwd": "<MBA_WEB_API_PWD>" }Respuesta: { "jwt": "eyJ...", ... } + Set-Cookie: session=....
Query (/ws_Consulta_externa_MBA3/)
Section titled “Query (/ws_Consulta_externa_MBA3/)”POST /ws_Consulta_externa_MBA3/ HTTP/1.1Content-Type: multipart/form-data; boundary=...Authorization: eyJ...Cookie: session=...
--boundaryContent-Disposition: form-data; name="select"
PRODUCT_ID,PRODUCT_NAME,DESCRIPTION,CORP,PRODUCT_TYPE--boundaryContent-Disposition: form-data; name="from"
INVT_Ficha_Principal--boundaryContent-Disposition: form-data; name="where"
CORP = 'NVC01' AND PRODUCT_ID LIKE 'REC%'--boundaryContent-Disposition: form-data; name="orderBy"
PRODUCT_ID ASC--boundary--Respuesta: 200 OK con body JSON [{...}, {...}].
Restricciones de la API
Section titled “Restricciones de la API”- No soporta
AS. Los renombrados se hacen en codigo conmapXxxRow(). - No soporta parametros preparados (
:param). Se usatoSqlString()que escapa comillas simples. - No soporta
LIMIT/OFFSETSQL. El campolimitdel multipart solo acota filas; para paginacion grande se trae todo y se corta en memoria. - Booleanos van como
true/falseliterales:WHERE TRANSFERS = true. - Fechas van como strings ISO:
WHERE FECHA_FACTURA = '2026-04-21'.
Single-flight de sesion
Section titled “Single-flight de sesion”El JWT se cachea hasta 30 s antes de su exp. Si varias requests encuentran el token expirado, una sola dispara performLogin() y las demas comparten la promesa via pendingSession. Si MBA3 devuelve 401, solo se invalida el cache si el JWT que recibio el 401 sigue siendo el cacheado.
Sync Scheduler — ventana nightly
Section titled “Sync Scheduler — ventana nightly”| Hora (ECT) | Cron | Job | Backend |
|---|---|---|---|
| 22:00 | 0 22 * * * | warehouseSync.syncAll() | Consulta Externa |
| 22:05 | 5 22 * * * | sellerSync.syncAll() | Consulta Externa |
| 22:10 | 10 22 * * * | clientSync.syncAll() | Consulta Externa |
| 22:20 | 20 22 * * * | productSync.syncAll() | Consulta Externa |
| 22:30 | 30 22 * * * | invoiceSync.syncRecent(1) | Consulta Externa |
| 22:40 | 40 22 * * * | paymentSync.syncRecent(1) | Consulta Externa |
| 22:50 | 50 22 * * * | transferSync.syncRecent(1) | Consulta Externa |
Cada job respeta un flag syncing (no overlap), trae filas del dia/rango, hace upsert en chunks de 200 con orUpdate y registra synced_from_4d=true + last_synced_at=now.
No hay reintentos automaticos por job fallido; se reintenta al dia siguiente. Para forzar manualmente: POST /api/v1/mba/<recurso>/sync?days=N.
Variables de entorno
Section titled “Variables de entorno”| Variable | Obligatoria | Default | Descripcion |
|---|---|---|---|
NODE_ENV | si | development | En production desactiva synchronize + logging SQL |
PORT | — | 3001 | Puerto HTTP |
TZ | si | America/Guayaquil | Critico para crons nightly |
DB_HOST / DB_PORT / DB_USER / DB_PASSWORD / DB_NAME | si | — | Postgres local |
AUTO_DB_SYNC | — | false | Auto-sync schema TypeORM (solo dev) |
AUTO_RUN_MIGRATIONS | — | true | Migrations al boot |
AUTH_SERVICE_URL | si | — | URL de ms-auth |
SERVICE_KEY | si | — | Llave compartida ServiceKey |
AUTH_TOKEN | si | — | Token legacy (compat controllers) |
REDIS_URL | si | redis://redis:6379 | Cache JWT interno |
ALLOWED_ORIGINS | si | — | CSV de origenes CORS |
THROTTLE_TTL / THROTTLE_LIMIT | — | 60000 / 120 | Rate limit |
MBA_WEB_API_BASE_URL | si | http://192.168.80.190:8081 | Base de MBA3 |
MBA_WEB_API_LOGIN_PATH | — | /login_Servicio | Path de login |
MBA_CONSULTA_EXTERNA_PATH | — | /ws_Consulta_externa_MBA3/ | Path de queries |
MBA_WEB_API_CODIGO | si | — | Usuario MBA3 |
MBA_WEB_API_PWD | si | — | Password MBA3 |
MBA_WEB_API_TIMEOUT | — | 30 (seg) | Timeout HTTP Consulta Externa |
MBA_API_SERVER / MBA_API_SERVER_PORT | — | — | 4D nativo (p4d proxy legacy) |
MBA_API_USER / MBA_API_PASSWORD | — | API/API | Credenciales p4d |
MBA_QUERY_TIMEOUT_MS | — | 5000 | Timeout p4d por query |
MBA_QUERY_MAX_ATTEMPTS | — | 1 | Reintentos p4d |
MBA_MAX_IN_FLIGHT_QUERIES | — | 2 | Concurrencia p4d |
MBA_CIRCUIT_BREAK_MS | — | 10000 | Circuit-breaker p4d |
MBA_PROXY_* | — | — | Tunning proxy Python |
MBA_PROVIDERS_API_PATH | — | /mba3api/proveedores | Path escritura proveedores |
MBA_PROVIDER_OPERATION_CREATE | — | 0 | Codigo operacion crear |
MBA_PROVIDER_OPERATION_UPDATE | — | 1 | Codigo operacion actualizar |
Red y seguridad
Section titled “Red y seguridad”ms-mbacorre connetwork_mode: service:vpn-gateway-> todo el trafico sale por el tunel OpenVPN.- El
vpn-gatewayhace DNAT del puerto3001para que el resto de MS llegue porhttp://vpn-gateway:3001. - La IP publica del tunel debe estar en la whitelist de MBA3. Si recibes
003 - IP No Autorizada, el guard de 4D rechazo. - JWT de MBA3 de 8 h; cache expira 30 s antes del
exp.
Persistencia local (Postgres)
Section titled “Persistencia local (Postgres)”| Entidad | Tabla | PK | Contiene |
|---|---|---|---|
Warehouse | warehouses | code | Bodegas |
Seller | sellers | code | Vendedores (VE*) |
Client | clients | codigo_cliente | Fichas de cliente |
Product | products | product_id + corp | Catalogo |
Invoice | invoices | codigo_factura | Cabecera de facturas |
Payment | payments | codigo_cobro | Cabecera de cobros |
InventoryTransfer | inventory_transfers | doc_id | Transferencias entre bodegas |
Comunes: synced_from_4d boolean, last_synced_at timestamp, created_at, updated_at.
Lineas de factura / metodos de cobro / productos de transferencia no se sincronizan; se cargan en vivo desde Consulta Externa en el detalle.
Health check profundo
Section titled “Health check profundo”GET /api/v1/mba/health/4d:
{ "status": "ok | degraded | down", "checks": { "tcp": { "ok": true, "latency_ms": 4 }, "proxy": { "ok": true, "pid": 42 }, "query": { "ok": true, "rows": 1, "latency_ms": 18 } }, "diagnostic": "Todo OK | Proxy no respondio | VPN caida"}Distingue:
- VPN caida:
tcpfalla -> revisarvpn-gateway. - 4D detenido:
tcpOK peroproxyfalla. - Query lenta: todo OK pero
query.latency_ms > 2000-> saturacion.
Errores y codigos
Section titled “Errores y codigos”| Codigo | Significado | Causa tipica |
|---|---|---|
401 | JWT invalido/expirado | Token del dashboard caduco |
403 | Permisos insuficientes o 003 de MBA3 | IP no whitelisteada |
404 | Registro no existe | |
502 | BadGatewayException | MBA3 devolvio error HTTP o cuerpo invalido |
504 | GatewayTimeoutException | Consulta Externa no respondio en MBA_WEB_API_TIMEOUTs |
Estado de migracion (abril 2026)
Section titled “Estado de migracion (abril 2026)”| Modulo | Backend | Estado |
|---|---|---|
| warehouses | Consulta Externa | OK |
| products | Consulta Externa | OK |
| sellers | Consulta Externa | OK |
| clients | Consulta Externa | OK |
| invoices | Consulta Externa | OK |
| payments | Consulta Externa | OK |
| inventory-transfers | Consulta Externa | OK |
| providers (read) | Consulta Externa | OK |
| providers (write) | MBA3 /mba3api/proveedores | OK (no aplica Consulta Externa) |
| app.controller health | p4d (MbaDatabaseService) | legacy |
| legacy-compat / local-compat / legacy-mba | p4d | retro-compatibilidad |
El p4d proxy (mba-database/) sigue activo solo para diagnostico profundo y controladores de compat.
Referencias
Section titled “Referencias”- HTTP client:
services/ms-mba/src/consulta-externa/consulta-externa.service.ts - Orquestador nightly:
services/ms-mba/src/sync-scheduler/sync-scheduler.service.ts - Escritura proveedores:
services/ms-mba/src/providers/providers.service.ts - Compose produccion:
docker-compose.yml— bloquesms-mba+vpn-gateway - Diagrama tablas 4D:
schema_4d_invoices_tables.md