Como crear un nuevo modulo
Guía paso a paso para agregar un módulo completo al ERP: BD (PostgreSQL), API, frontend y deploy.
Antes de empezar: rama nueva desde developer
(feat/<descripcion>); el PR va a developer, nunca a main.
1. Base de datos: migración goose + funciones
Todo cambio de BD nace como migración goose (numeración verificada contra developer):
web/api/migrations/postgres/NNNNN_modulo_inicial.sql # DDL + funciones
web/api/sqlweb-pg/includes/sp/usp_[schema]_*.sql # espejo de cada función Plantillas y trampas de PL/pgSQL en Crear nuevo SP.
sqlweb-mssql/ es legacy
congelado). Ver PostgreSQL — motor único.
2. Crear el módulo API
Los módulos viven en web/api/src/modules/<nombre>/:
web/api/src/modules/[nombre]/
├── [nombre].routes.ts # Express Router + validación Zod
├── [nombre].service.ts # Lógica de negocio (llama funciones vía callSp)
└── types.ts # Interfaces // [nombre].routes.ts
import { Router } from 'express';
import * as svc from './[nombre].service.js';
const router = Router();
// El JWT lo aplica app.ts a nivel /v1 — no repetir aquí.
router.get('/', async (req, res, next) => {
try { res.json(await svc.list(req.companyId!, req.query)); }
catch (err) { next(err); } // SIEMPRE next(err) — nunca String(err)
});
export default router; 3. Registrar rutas en app.ts
Montar el router después del bloque de middleware de /v1
(requireJwt/rbac/datetime) — un router montado antes queda sin autenticación:
// web/api/src/app.ts
import moduloRoutes from './modules/[nombre]/[nombre].routes.js';
app.use('/v1/[nombre]', moduloRoutes);
// + el alias espejo /api/v1/[nombre] junto a los demás 4. Actualizar el contrato OpenAPI
Agregar los endpoints a web/contracts/openapi.yaml en el mismo PR —
el gate audit:openapi del CI falla si un endpoint montado no está en el contrato.
5. Crear la micro-app frontend
Copiar una app existente de web/modular-frontend/apps/ como plantilla y ajustar
nombre, puerto y basePath. Reglas de UI:
- Tablas con
<ZenttoDataGrid>— nunca<table>HTML. - Cero datos mock: catálogos y listas vienen de hooks de API reales.
- Componentes de
@zentto/shared-ui; fetch con@zentto/shared-api. - Dashboards grandes: acordeones colapsables por sección.
- Si la lógica puede servir a un vertical standalone, extraerla a un paquete
packages/module-[nombre](patrón module-pos/module-restaurante).
6. PM2, Docker y navegación
- Entrada en
docker/pm2.config.cjscon puerto,NEXT_BASE_PATHySHELL_URL. - Exponer el puerto en
docker/Dockerfile.frontend. - Regla de proxy en la config de Nginx (repo
zentto-infra— sincronizar, no editar el servidor a mano). - Agregar el módulo a la navegación del shell.
7. Verificación local
# BD local
goose -dir web/api/migrations/postgres postgres "host=localhost dbname=datqboxweb user=postgres" up
# API
cd web/api && npm run dev # + npm run audit:openapi antes del PR
# Frontend
cd web/modular-frontend && npm run dev --workspace @zentto/[nombre] 8. PR y deploy
- Scan local de seguridad (gitleaks + trivy) antes de pushear.
- PR a
developer→ CI verde → merge → verificar enappdev.zentto.net/apidev.zentto.net. - PR
developer → main→ deploy automático a producción. - Documentar el módulo en
zentto-erp-docs(doc funcional + esta sección técnica si cambia la arquitectura).
Checklist final
- BD: migración goose + funciones en
sqlweb-pg/(cero T-SQL) - API: módulo en
modules/, rutas montadas trasrequireJwt, errores connext(err) - OpenAPI: endpoints documentados (gate verde)
- Frontend: ZenttoDataGrid, sin mock, hooks API
- PM2 + Dockerfile + Nginx (si aplica) actualizados
- Verificado en dev antes de promover a main
- Docs actualizados en zentto-erp-docs