Appearance
Arquitectura de Bases de Datos
Descripción General
Sistema Bautista implementa tres conceptos arquitectónicos fundamentales e independientes para gestionar datos en un entorno empresarial complejo:
- Multi-Tenant (Schema-Based Tenancy) - Aislamiento de datos mediante schemas PostgreSQL
- Multi-Schema (Cross-Schema Querying) - Búsquedas y consolidación en múltiples schemas simultáneos
- Multi-Modo (Dual Database Pattern) - Separación oficial/prueba mediante bases de datos independientes
Estos tres conceptos son ortogonales entre sí: cada uno resuelve un problema diferente, opera en dimensiones diferentes y pueden combinarse libremente. Un mismo sistema puede ser multi-tenant Y multi-schema Y multi-modo simultáneamente.
¿Por qué existen estos conceptos?
- Multi-Tenant: Cada sucursal/caja necesita sus propios datos aislados en la misma base de datos
- Multi-Schema: A veces necesitamos buscar un registro sin saber en qué sucursal/caja está
- Multi-Modo: Necesitamos simular operaciones sin afectar datos de producción
¿Cómo trabajan juntos?
Aunque son independientes, se complementan:
- Multi-tenant establece el espacio de datos (¿en qué schema trabajo?)
- Multi-schema define el alcance de búsqueda (¿en cuántos schemas busco?)
- Multi-modo determina la base de datos física (¿trabajo en oficial o prueba?)
Tabla Comparativa de los 3 Conceptos
| Aspecto | Multi-Tenant | Multi-Schema | Multi-Modo |
|---|---|---|---|
| QUÉ es | Aislamiento por schema PostgreSQL | Búsquedas cross-schema | Separación oficial/prueba |
| CUÁNDO usar | Siempre (arquitectura base) | Búsquedas sin schema conocido | Simulaciones sin afectar producción |
| Alcance | 1 schema a la vez | N schemas simultáneos | 2 databases independientes |
| Nivel | Schema único por request | Múltiples schemas por query | Database por ambiente |
| Ejemplo | Facturación en suc0001caja001 | Buscar recibo en todas las cajas | Generar asiento en bautista_p |
| Componente clave | ConnectionManager + X-Schema | CrossSchemaQueryable + UNION ALL | prueba parameter + Alias principal |
| Independiente de | Multi-schema, Multi-modo | Multi-tenant, Multi-modo | Multi-tenant, Multi-schema |
Diagrama de Relación entre Conceptos
mermaid
graph TB
subgraph dim1["Dimensión 1: Tenant Isolation"]
MT[Multi-Tenant<br/>Schema-Based]
MT -->|Establece| S1[Schema único<br/>por request]
end
subgraph dim2["Dimensión 2: Query Scope"]
MS[Multi-Schema<br/>Cross-Schema Queries]
MS -->|Busca en| SN[N schemas<br/>simultáneos]
end
subgraph dim3["Dimensión 3: Environment"]
MM[Multi-Modo<br/>Dual Database]
MM -->|Elige| DB[Database<br/>oficial o prueba]
end
S1 -.->|Puede combinarse con| SN
S1 -.->|Puede combinarse con| DB
SN -.->|Puede combinarse con| DB
style MT fill:#e1f5ff
style MS fill:#fff4e1
style MM fill:#f0ffe1Cuándo Usar Cada Concepto
| Necesidad | Concepto a Usar | Configuración |
|---|---|---|
| Cada sucursal/caja tiene sus propios datos | Multi-Tenant | X-Schema header + ConnectionManager |
| Buscar registro sin saber dónde está | Multi-Schema | busqueda_en_todas_las_cajas=true |
| Ver recibo generado en otra caja | Multi-Schema | CrossSchemaQueryable + findFirstAcrossSchemas |
| Consolidar ventas de todas las cajas | Multi-Schema | queryAcrossSchemas + UNION ALL |
| Simular facturación sin afectar producción | Multi-Modo | prueba=true → bautista_p database |
| Comparar oficial vs prueba en reporte | Multi-Modo | Mode 2 (consolidado) en informes |
| Capacitar usuarios con datos de prueba | Multi-Modo | prueba=true + datos separados |
Matriz de Consolidación: 6 Combinaciones Posibles
Los 3 conceptos son ortogonales, lo que genera 6 combinaciones válidas:
| # | Multi-Tenant | Multi-Schema | Multi-Modo | Caso de Uso |
|---|---|---|---|---|
| 1 | ✅ Single schema | ❌ Single schema | ❌ Oficial | Normal: Operación en 1 schema, DB oficial |
| 2 | ✅ Single schema | ❌ Single schema | ✅ Prueba | Testing: Operación en 1 schema, DB prueba |
| 3 | ✅ Single schema | ✅ Multi-schema | ❌ Oficial | Búsqueda cross-schema: Buscar en N schemas, DB oficial |
| 4 | ✅ Single schema | ✅ Multi-schema | ✅ Prueba | Búsqueda en prueba: Buscar en N schemas, DB prueba |
| 5 | ✅ Single schema | ✅ Multi-schema | ⚙️ Consolidado | Reporte modo 2: Consolidar oficial + prueba, N schemas |
| 6 | ✅ Configurable | ✅ Multi-schema | ⚙️ Configurable | Admin reportes: Modo y schemas configurables |
Leyenda:
- ✅ = Activo
- ❌ = Inactivo
- ⚙️ = Configurable por usuario
Diagramas de Casos de Uso Comunes
Caso 1: Operación Normal (Tenant único, DB oficial)
mermaid
sequenceDiagram
participant F as Frontend
participant M as Middleware
participant CM as ConnectionManager
participant PG as PostgreSQL (bautista)
F->>M: POST /api/ventas/facturas<br/>X-Schema: suc0001caja001
M->>CM: getConnection('principal')
CM->>CM: resolve('principal') → 'oficial'<br/>schema: suc0001caja001
CM->>PG: SET search_path = suc0001caja001, suc0001, public
PG-->>CM: Connection ready
CM-->>M: Connection
M->>PG: INSERT INTO facturas (...)
PG-->>F: Factura creada
Note over F,PG: Multi-Tenant: 1 schema<br/>Multi-Schema: NO<br/>Multi-Modo: oficialCaso 2: Búsqueda Cross-Schema (Multi-Schema activo, DB oficial)
mermaid
sequenceDiagram
participant F as Frontend
participant S as Service
participant CSQ as CrossSchemaQueryable
participant MSS as MultiSchemaService
participant PG as PostgreSQL (bautista)
F->>S: GET /api/ctacte/recibos/12345<br/>busqueda_en_todas_las_cajas=true
S->>CSQ: findFirstAcrossSchemas(12345)
CSQ->>MSS: getTargetSchemas()
MSS->>MSS: getCurrentSchema() = suc0001caja001<br/>Extraer sucursal → suc0001
MSS-->>CSQ: [suc0001caja001, suc0001caja002, suc0001caja003]
loop Para cada schema
CSQ->>PG: SELECT * FROM recibos<br/>WHERE id = 12345<br/>(en schema actual)
PG-->>CSQ: Resultado (o vacío)
alt Encontrado
CSQ-->>S: DTO con _schema = suc0001caja002
S-->>F: Recibo encontrado
end
end
Note over F,PG: Multi-Tenant: 1 schema inicial<br/>Multi-Schema: 3 schemas<br/>Multi-Modo: oficialCaso 3: Simulación en Prueba (Tenant único, DB prueba)
mermaid
sequenceDiagram
participant F as Frontend (toggle prueba=true)
participant M as Middleware
participant CM as ConnectionManager
participant PGP as PostgreSQL (bautista_p)
participant PGO as PostgreSQL (bautista)
F->>M: POST /api/contabilidad/asientos<br/>prueba=true<br/>X-Schema: suc0001caja001
M->>CM: getConnection('principal')
CM->>CM: prueba=true → resolve('principal') → 'prueba'<br/>schema: suc0001caja001
CM->>PGP: SET search_path = suc0001caja001, suc0001, public
PGP-->>CM: Connection ready (DB prueba)
Note over CM,PGO: Maestros SIEMPRE de oficial
CM->>PGO: SELECT * FROM plan_cuentas<br/>(getConnection('oficial'))
PGO-->>CM: Cuentas maestras
CM->>PGP: INSERT INTO asientos (...)<br/>(connection 'principal')
PGP-->>F: Asiento creado en prueba
Note over F,PGP: Multi-Tenant: 1 schema<br/>Multi-Schema: NO<br/>Multi-Modo: pruebaEnlaces a Documentación Detallada
Conceptos Fundamentales
Multi-Tenant (Schema-Based Tenancy) - Aislamiento por schemas PostgreSQL
- Niveles de schema (empresa, sucursal, caja)
- ConnectionManager y conexiones nombradas
- X-Schema header y JWT payload
- Search_path jerárquico
- Configuración de niveles de tabla
Multi-Schema (Cross-Schema Querying) - Búsquedas y consolidación
- CrossSchemaQueryable pattern
- Estrategias de búsqueda (batch vs early exit)
- UNION ALL optimization
- JOINs cross-schema
- Consolidación vs búsqueda
Multi-Modo (Dual Database Pattern) - Separación oficial/prueba
- Parámetro
prueba - Alias
principaldinámico - Datos maestros SIEMPRE de oficial
- Modos de consolidación en reportes (0/1/2)
- isPruebaConnection()
- Parámetro
Referencias a Implementación Técnica
Documentación Técnica Existente
Multi-Tenant:
docs/backend/configuration-system.md- Sistema de configuración con nivelesserver/migrations/CLAUDE.md- Migraciones multi-tenant
Multi-Schema:
docs/backend/cross-schema-queryable-pattern.md- Patrón completodocs/architecture/multi-schema-transactional-operations-process.md- Operaciones transaccionalesdocs/architecture/consolidacion-informes-multi-schema.md- Consolidación en informesdocs/architecture/patrones-php/joins/- Patrón unificado de JOINs:- Index - Resumen ejecutivo
- Guía Completa - Componentes y adopción
- Casos Multi-Schema - Consolidación UNION ALL
- Cross-Level Directo - JOINs jerárquicos
- Reglas Arquitecturales - RA-JOIN-*
Multi-Modo:
docs/features/contabilidad/libro-diario-modos-process.md- Ejemplo de modos en reportes
Skills de Claude Code
.claude/skills/bautista-multi-tenant/- Implementar multi-tenancy.claude/skills/bautista-multi-schema-joins/- Implementar JOINs cross-schema.claude/skills/bautista-record-modes/- Implementar dual databases
Código Fuente Clave
Multi-Tenant:
server/connection/ConnectionManager.php- Gestión de conexionesserver/connection/Database.php- Wrapper Doctrine DBALserver/connection/ConnectionUtils.php- Utilidades de schemaserver/Middleware/ConnectionMiddleware.php- Setup por requestserver/Middleware/AuthMiddleware.php- Validación JWT
Multi-Schema:
server/Interface/MultiSchema/CrossSchemaQueryableInterface.php- Contratoserver/Traits/CrossSchemaQueryable.php- Implementaciónserver/service/Config/MultiSchemaService.php- Resolución de schemasserver/service/Config/SchemaService.php- Consulta information_schema
Multi-Modo:
server/connection/ConnectionManager.php- Alias dinámicoprincipalserver/Middleware/ConnectionMiddleware.php- Setup segúnpruebaparameter
Historial de Cambios
| Fecha | Versión | Cambios |
|---|---|---|
| 2025-02-03 | 1.0.0 | Creación inicial de documentación conceptual consolidada |
Siguiente paso: Leer la documentación conceptual específica de cada patrón antes de implementar.