Dual Database
Zentto soporta dos motores de base de datos simultáneamente: SQL Server y PostgreSQL. El motor activo se controla con una sola variable de entorno. Esta arquitectura permite usar SQL Server para clientes on-premise (Windows) y PostgreSQL para despliegues cloud en producción.
REGLA CRITICA
Todo cambio de base de datos DEBE reflejarse en AMBOS directorios
(sqlweb/ y sqlweb-pg/). Si solo actualizas uno, el otro motor
queda roto. No hay excepciones.
Switch de motor: DB_TYPE
La variable DB_TYPE en web/api/.env determina qué motor se usa:
# Usar SQL Server
DB_TYPE=sqlserver
# Usar PostgreSQL
DB_TYPE=postgres
El archivo web/api/src/db/query.ts lee esta variable al iniciar y selecciona
el pool de conexiones y la sintaxis de llamada correspondiente. No se requiere reiniciar
la app entre cambios si se usa el mecanismo de recarga.
Tabla de traducción SQL Server a PostgreSQL
| SQL Server | PostgreSQL |
|---|---|
| CREATE PROCEDURE | CREATE OR REPLACE FUNCTION ... LANGUAGE plpgsql |
| NVARCHAR(n) | VARCHAR(n) |
| BIT | BOOLEAN |
| DATETIME / DATETIME2 | TIMESTAMP |
| INT IDENTITY(1,1) | INT GENERATED ALWAYS AS IDENTITY |
| SYSUTCDATETIME() | NOW() AT TIME ZONE 'UTC' |
| ISNULL() | COALESCE() |
| OPENJSON | jsonb_array_elements |
| BEGIN TRY / CATCH | EXCEPTION WHEN OTHERS THEN |
| N'texto' | 'texto' |
| GO | (se omite) |
Helpers de BD: query.ts
Tres funciones centralizan toda interacción con la BD, abstrayendo las diferencias entre motores:
// web/api/src/db/query.ts
// Consulta simple — retorna filas
const rows = await callSp('usp_Master_Product_List', {
CompanyId: 1,
Search: 'widget',
PageSize: 20,
PageNumber: 1
});
// Con parámetros de salida
const { result, outputs } = await callSpOut('usp_Doc_Invoice_Insert', {
CompanyId: 1,
CustomerId: 42,
Items: JSON.stringify(items)
}, ['Resultado', 'Mensaje']);
// Transaccional (múltiples operaciones)
await callSpTx([
{ sp: 'usp_Doc_Invoice_Insert', params: { ... } },
{ sp: 'usp_Acct_Journal_Post', params: { ... } }
]);
Estructura de archivos SQL
web/api/
├── sqlweb/ # SQL Server
│ ├── run_all.sql # Script maestro (ejecutar en SSMS)
│ └── includes/
│ └── sp/
│ ├── usp_sec.sql # Seguridad (login, roles)
│ ├── usp_master.sql # Maestros (productos, clientes)
│ ├── usp_doc.sql # Documentos (facturas, NC)
│ ├── usp_inv.sql # Inventario
│ ├── usp_acct.sql # Contabilidad
│ └── seed_data.sql # Datos iniciales
│
└── sqlweb-pg/ # PostgreSQL
├── run_all.sql # Script maestro: psql -f run_all.sql
└── includes/
└── sp/
├── usp_sec.sql # Mismos SPs, sintaxis plpgsql
├── usp_master.sql
├── usp_doc.sql
├── usp_inv.sql
├── usp_acct.sql
└── seed_data.sql
Despliegue de scripts
SQL Server
-- En SSMS, abrir run_all.sql y ejecutar
-- Usa directivas :r para incluir archivos
:r includes/sp/usp_sec.sql
:r includes/sp/usp_master.sql
-- ...
PostgreSQL
# Desde terminal
psql -U postgres -d datqboxweb -f run_all.sql
# En producción
psql -U zentto_app -d zentto_prod -f run_all.sql
Checklist para cambios de BD
- Escribir el SP/función en
sqlweb/includes/sp/(T-SQL) - Traducir a
sqlweb-pg/includes/sp/(plpgsql) usando la tabla de arriba - Agregar ambos al
run_all.sqlcorrespondiente - Probar en SQL Server local
- Probar en PostgreSQL local
- Actualizar el contrato OpenAPI si es un endpoint nuevo
- Actualizar los tipos TypeScript en la API