Skip to content

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:

  1. Multi-Tenant (Schema-Based Tenancy) - Aislamiento de datos mediante schemas PostgreSQL
  2. Multi-Schema (Cross-Schema Querying) - Búsquedas y consolidación en múltiples schemas simultáneos
  3. 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

AspectoMulti-TenantMulti-SchemaMulti-Modo
QUÉ esAislamiento por schema PostgreSQLBúsquedas cross-schemaSeparación oficial/prueba
CUÁNDO usarSiempre (arquitectura base)Búsquedas sin schema conocidoSimulaciones sin afectar producción
Alcance1 schema a la vezN schemas simultáneos2 databases independientes
NivelSchema único por requestMúltiples schemas por queryDatabase por ambiente
EjemploFacturación en suc0001caja001Buscar recibo en todas las cajasGenerar asiento en bautista_p
Componente claveConnectionManager + X-SchemaCrossSchemaQueryable + UNION ALLprueba parameter + Alias principal
Independiente deMulti-schema, Multi-modoMulti-tenant, Multi-modoMulti-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:#f0ffe1

Cuándo Usar Cada Concepto

NecesidadConcepto a UsarConfiguración
Cada sucursal/caja tiene sus propios datosMulti-TenantX-Schema header + ConnectionManager
Buscar registro sin saber dónde estáMulti-Schemabusqueda_en_todas_las_cajas=true
Ver recibo generado en otra cajaMulti-SchemaCrossSchemaQueryable + findFirstAcrossSchemas
Consolidar ventas de todas las cajasMulti-SchemaqueryAcrossSchemas + UNION ALL
Simular facturación sin afectar producciónMulti-Modoprueba=truebautista_p database
Comparar oficial vs prueba en reporteMulti-ModoMode 2 (consolidado) en informes
Capacitar usuarios con datos de pruebaMulti-Modoprueba=true + datos separados

Matriz de Consolidación: 6 Combinaciones Posibles

Los 3 conceptos son ortogonales, lo que genera 6 combinaciones válidas:

#Multi-TenantMulti-SchemaMulti-ModoCaso de Uso
1✅ Single schema❌ Single schema❌ OficialNormal: Operación en 1 schema, DB oficial
2✅ Single schema❌ Single schema✅ PruebaTesting: Operación en 1 schema, DB prueba
3✅ Single schema✅ Multi-schema❌ OficialBúsqueda cross-schema: Buscar en N schemas, DB oficial
4✅ Single schema✅ Multi-schema✅ PruebaBúsqueda en prueba: Buscar en N schemas, DB prueba
5✅ Single schema✅ Multi-schema⚙️ ConsolidadoReporte modo 2: Consolidar oficial + prueba, N schemas
6✅ Configurable✅ Multi-schema⚙️ ConfigurableAdmin 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: oficial

Caso 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: oficial

Caso 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: prueba

Enlaces 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 principal dinámico
    • Datos maestros SIEMPRE de oficial
    • Modos de consolidación en reportes (0/1/2)
    • isPruebaConnection()

Referencias a Implementación Técnica

Documentación Técnica Existente

Multi-Tenant:

Multi-Schema:

Multi-Modo:

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 conexiones
  • server/connection/Database.php - Wrapper Doctrine DBAL
  • server/connection/ConnectionUtils.php - Utilidades de schema
  • server/Middleware/ConnectionMiddleware.php - Setup por request
  • server/Middleware/AuthMiddleware.php - Validación JWT

Multi-Schema:

  • server/Interface/MultiSchema/CrossSchemaQueryableInterface.php - Contrato
  • server/Traits/CrossSchemaQueryable.php - Implementación
  • server/service/Config/MultiSchemaService.php - Resolución de schemas
  • server/service/Config/SchemaService.php - Consulta information_schema

Multi-Modo:

  • server/connection/ConnectionManager.php - Alias dinámico principal
  • server/Middleware/ConnectionMiddleware.php - Setup según prueba parameter

Historial de Cambios

FechaVersiónCambios
2025-02-031.0.0Creación inicial de documentación conceptual consolidada

Siguiente paso: Leer la documentación conceptual específica de cada patrón antes de implementar.