erp-core/docs/01-fase-foundation/MGN-004-tenants/historias-usuario/US-MGN004-003.md

5.0 KiB

US-MGN004-003: Aislamiento de Datos Multi-Tenant

Identificacion

Campo Valor
ID US-MGN004-003
Modulo MGN-004 Tenants
RF Relacionado RF-TENANT-003
Prioridad P0 - Critica
Story Points 13
Sprint TBD

Historia de Usuario

Como Usuario del sistema Quiero que mis datos esten completamente aislados de otros tenants Para garantizar la seguridad y privacidad de la informacion de mi organizacion


Criterios de Aceptacion

AC-001: Usuario solo ve datos de su tenant

Given usuario de Tenant A autenticado
  And 100 productos en Tenant A
  And 50 productos en Tenant B
When consulta GET /api/v1/products
Then solo ve los 100 productos de Tenant A
  And no ve ningun producto de Tenant B

AC-002: No acceso a recurso de otro tenant

Given usuario de Tenant A autenticado
  And producto "P-001" pertenece a Tenant B
When intenta GET /api/v1/products/P-001
Then el sistema responde con status 404
  And el mensaje es "Recurso no encontrado"
  And NO revela que el recurso existe en otro tenant

AC-003: Asignacion automatica de tenant_id

Given usuario de Tenant A autenticado
When crea un producto sin especificar tenant_id
Then el sistema asigna automaticamente tenant_id de Tenant A
  And el producto queda en Tenant A

AC-004: No permitir modificar tenant_id

Given usuario de Tenant A autenticado
  And producto existente en Tenant A
When intenta actualizar tenant_id a Tenant B
Then el sistema responde con status 400
  And el mensaje es "No se puede cambiar el tenant de un recurso"

AC-005: RLS previene acceso sin contexto

Given conexion a base de datos sin app.current_tenant_id
When se ejecuta SELECT * FROM core_users.users
Then el resultado es vacio
  And no se produce error
  And RLS previene acceso a datos

AC-006: TenantGuard valida tenant activo

Given usuario con token JWT valido
  And tenant en estado "suspended"
When intenta acceder a cualquier endpoint
Then el sistema responde con status 403
  And el mensaje indica "Tenant suspendido"

AC-007: TenantGuard detecta trial expirado

Given usuario de tenant en estado "trial"
  And trial_ends_at fue hace 2 dias
When intenta acceder a cualquier endpoint
Then el sistema responde con status 403
  And el mensaje indica "Periodo de prueba expirado"

AC-008: Platform Admin switch explicito

Given Platform Admin autenticado
  And tiene acceso a todos los tenants
When NO ha hecho switch a ningun tenant
Then no puede ver datos de ningun tenant
  And debe hacer POST /api/v1/platform/switch-tenant/:id primero

AC-009: Middleware setea contexto PostgreSQL

Given request autenticado con tenant_id en JWT
When pasa por TenantContextMiddleware
Then se ejecuta SET app.current_tenant_id = :tenantId
  And todas las queries posteriores filtran por ese tenant

AC-010: Indices optimizados por tenant

Given tabla users con 1M registros distribuidos en 100 tenants
When usuario de Tenant A busca por email
Then la query usa indice compuesto (tenant_id, email)
  And tiempo de respuesta < 50ms

Tareas Tecnicas

ID Tarea Estimacion
T-001 Crear migracion RLS policies 3 SP
T-002 Implementar TenantGuard 2 SP
T-003 Implementar TenantContextMiddleware 2 SP
T-004 Crear TenantBaseEntity 1 SP
T-005 Crear TenantAwareService base 2 SP
T-006 Tests de aislamiento 3 SP
Total 13 SP

Notas de Implementacion

Migracion RLS

-- Habilitar RLS en tablas
ALTER TABLE core_users.users ENABLE ROW LEVEL SECURITY;

-- Funcion para obtener tenant actual
CREATE OR REPLACE FUNCTION current_tenant_id()
RETURNS UUID AS $$
BEGIN
  RETURN NULLIF(current_setting('app.current_tenant_id', true), '')::UUID;
END;
$$ LANGUAGE plpgsql STABLE;

-- Politica de SELECT
CREATE POLICY tenant_isolation_select ON core_users.users
  FOR SELECT USING (tenant_id = current_tenant_id());

-- Politica de INSERT
CREATE POLICY tenant_isolation_insert ON core_users.users
  FOR INSERT WITH CHECK (tenant_id = current_tenant_id());

TenantBaseEntity

export abstract class TenantBaseEntity {
  @Column({ name: 'tenant_id' })
  tenantId: string;

  @ManyToOne(() => Tenant)
  @JoinColumn({ name: 'tenant_id' })
  tenant: Tenant;
}

Mockup de Referencia

Ver RF-TENANT-003.md diagramas de arquitectura.


Dependencias

Tipo Descripcion
Database PostgreSQL 12+ con RLS
Auth JWT con tenant_id claim
Backend Schema core_tenants creado

Definition of Done

  • RLS habilitado en TODAS las tablas de negocio
  • TenantGuard implementado y aplicado globalmente
  • TenantContextMiddleware seteando variable de sesion
  • Tests de aislamiento pasando (cross-tenant access blocked)
  • Performance test con queries filtradas por tenant
  • Security review aprobado
  • Documentacion de patrones para nuevas tablas