# 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

```gherkin
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

```gherkin
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

```gherkin
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

```gherkin
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

```gherkin
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

```gherkin
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

```gherkin
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

```gherkin
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

```gherkin
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

```gherkin
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

```sql
-- 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

```typescript
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
