workspace-v1/shared/knowledge-base/architecture/PATRON-MULTI-TENANT.md
rckrdmrd 66161b1566 feat: Workspace-v1 complete migration with NEXUS v3.4
Sistema NEXUS v3.4 migrado con:

Estructura principal:
- core/orchestration: Sistema SIMCO + CAPVED (27 directivas, 28 perfiles)
- core/catalog: Catalogo de funcionalidades reutilizables
- shared/knowledge-base: Base de conocimiento compartida
- devtools/scripts: Herramientas de desarrollo
- control-plane/registries: Control de servicios y CI/CD
- orchestration/: Configuracion de orquestacion de agentes

Proyectos incluidos (11):
- gamilit (submodule -> GitHub)
- trading-platform (OrbiquanTIA)
- erp-suite con 5 verticales:
  - erp-core, construccion, vidrio-templado
  - mecanicas-diesel, retail, clinicas
- betting-analytics
- inmobiliaria-analytics
- platform_marketing_content
- pos-micro, erp-basico

Configuracion:
- .gitignore completo para Node.js/Python/Docker
- gamilit como submodule (git@github.com:rckrdmrd/gamilit-workspace.git)
- Sistema de puertos estandarizado (3005-3199)

Generated with NEXUS v3.4 Migration System
EPIC-010: Configuracion Git y Repositorios
2026-01-04 03:37:42 -06:00

5.5 KiB

Patron Multi-Tenant con RLS

Categoria: Architecture Version: 1.0.0 Origen: projects/gamilit, projects/erp-core Fecha: 2025-12-27


Descripcion

Este documento describe el patron de arquitectura multi-tenant utilizado en todos los proyectos del workspace, basado en Row-Level Security (RLS) de PostgreSQL.

Principios

  1. Aislamiento completo: Cada tenant solo ve sus propios datos
  2. Transparencia: El codigo de aplicacion no necesita filtrar por tenant
  3. Performance: RLS optimizado con indices apropiados
  4. Seguridad: Imposible acceder a datos de otros tenants

Arquitectura

                    ┌─────────────────────────────────┐
                    │         Application             │
                    │  (NestJS / Express)             │
                    └───────────────┬─────────────────┘
                                    │
                    ┌───────────────▼─────────────────┐
                    │      Tenant Middleware          │
                    │  SET app.current_tenant_id      │
                    └───────────────┬─────────────────┘
                                    │
                    ┌───────────────▼─────────────────┐
                    │        PostgreSQL               │
                    │    Row-Level Security           │
                    │  (USING tenant_id = ...)        │
                    └─────────────────────────────────┘

Implementacion

1. Variable de Sesion

-- Configurar en cada request
SET app.current_tenant_id = 'uuid-del-tenant';

-- Obtener en queries
current_setting('app.current_tenant_id', true)::UUID

2. Middleware NestJS

// src/middleware/tenant.middleware.ts
@Injectable()
export class TenantMiddleware implements NestMiddleware {
  constructor(private dataSource: DataSource) {}

  async use(req: Request, res: Response, next: NextFunction) {
    const tenantId = this.extractTenantId(req);

    if (tenantId) {
      await this.dataSource.query(
        `SET app.current_tenant_id = $1`,
        [tenantId]
      );
    }

    next();
  }

  private extractTenantId(req: Request): string | null {
    // 1. Del JWT token
    if (req.user?.tenantId) return req.user.tenantId;

    // 2. Del header
    if (req.headers['x-tenant-id']) return req.headers['x-tenant-id'];

    // 3. Del subdominio
    const host = req.headers.host;
    // tenant.example.com -> tenant

    return null;
  }
}

3. RLS Policies

-- Habilitar RLS en tabla
ALTER TABLE my_table ENABLE ROW LEVEL SECURITY;

-- Politica de aislamiento
CREATE POLICY tenant_isolation ON my_table
    FOR ALL
    USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);

-- Para INSERT, asegurar que se use el tenant correcto
CREATE POLICY tenant_insert ON my_table
    FOR INSERT
    WITH CHECK (tenant_id = current_setting('app.current_tenant_id', true)::UUID);

4. Estructura de Tabla

CREATE TABLE my_table (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id),
    -- ... otros campos ...
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- Indice para performance
CREATE INDEX idx_my_table_tenant ON my_table(tenant_id);

Best Practices

DO (Hacer)

  • Siempre incluir tenant_id en tablas de datos
  • Crear indice en tenant_id
  • Habilitar RLS en TODAS las tablas con datos de tenant
  • Usar el middleware en TODAS las rutas protegidas
  • Testear aislamiento en cada nueva tabla

DON'T (No hacer)

  • No filtrar manualmente por tenant_id (dejar a RLS)
  • No desactivar RLS para "queries rapidas"
  • No hardcodear tenant_id en codigo
  • No compartir conexiones entre requests sin reset

Tablas Exentas de RLS

Algunas tablas son globales y no tienen tenant_id:

  • auth.tenants - Lista de todos los tenants
  • config.feature_flags - Flags globales
  • billing.plans - Planes disponibles

Testing

describe('Tenant Isolation', () => {
  it('should not see data from other tenant', async () => {
    // Crear datos en tenant A
    await setTenant(tenantA);
    await createRecord({ name: 'Record A' });

    // Cambiar a tenant B
    await setTenant(tenantB);
    const records = await getRecords();

    // No debe ver record de tenant A
    expect(records).not.toContainEqual(
      expect.objectContaining({ name: 'Record A' })
    );
  });
});

Troubleshooting

Error: "Permission denied for table"

  • Verificar que RLS esta habilitado
  • Verificar que la politica existe
  • Verificar que app.current_tenant_id esta configurado

Query retorna todos los registros

  • Verificar que el middleware esta activo
  • Verificar que current_setting retorna el UUID correcto
  • Verificar que la politica no tiene errores

Performance lenta

  • Crear indice en tenant_id
  • Verificar que el indice se usa (EXPLAIN ANALYZE)
  • Considerar particionamiento por tenant_id

Referencias

  • core/catalog/multi-tenancy/ - Modulo del catalogo
  • projects/erp-core/database/ddl/ - Ejemplos de DDL
  • PostgreSQL RLS Documentation

Knowledge Base - Workspace v1