erp-mecanicas-diesel/docs/02-definicion-modulos/MMD-001-fundamentos/historias-usuario/US-MMD001-006-rls-aislamiento.md

194 lines
5.5 KiB
Markdown

# US-MMD001-006: Aplicar RLS por Taller
## Metadata
| Campo | Valor |
|-------|-------|
| **ID** | US-MMD001-006 |
| **Epica** | EPIC-MMD-001 - Fundamentos |
| **Modulo** | fundamentos |
| **Prioridad** | P0 |
| **Story Points** | 5 |
| **Sprint** | Sprint 1 |
| **Estado** | Backlog |
| **Asignado a** | Por asignar |
---
## Historia de Usuario
**Como** sistema,
**quiero** aplicar Row-Level Security (RLS) en todas las tablas por workshop_id,
**para** garantizar que cada taller solo vea y modifique sus propios datos.
## Descripcion Detallada
RLS (Row-Level Security) es una caracteristica de PostgreSQL que permite filtrar filas automaticamente basandose en el usuario actual. Cada query se filtra automaticamente por el workshop_id del usuario logueado, garantizando aislamiento total de datos entre talleres.
---
## Criterios de Aceptacion
**Escenario 1: Aislamiento de datos entre talleres**
```gherkin
DADO que existen 2 talleres: "Diesel Express" y "Mecanica Industrial"
CUANDO un usuario de "Diesel Express" consulta ordenes de servicio
ENTONCES solo ve las ordenes de "Diesel Express"
Y no ve ninguna orden de "Mecanica Industrial"
```
**Escenario 2: Contexto de sesion automatico**
```gherkin
DADO que un usuario inicia sesion en "Diesel Express"
CUANDO el sistema establece la sesion
ENTONCES se configura automaticamente app.current_workshop_id = 'uuid-diesel-express'
Y todas las queries filtran por ese workshop_id
```
**Escenario 3: Insercion con workshop_id automatico**
```gherkin
DADO que un usuario de "Diesel Express" crea una nueva orden
CUANDO inserta el registro
ENTONCES el sistema asigna automaticamente workshop_id del contexto
Y no se requiere especificar workshop_id manualmente
```
**Escenario 4: Proteccion contra acceso cruzado**
```gherkin
DADO que un usuario de "Diesel Express" intenta acceder a orden de "Mecanica Industrial"
CUANDO hace GET /api/orders/{id-de-mecanica-industrial}
ENTONCES el sistema retorna 404 Not Found
Y no revela que el registro existe en otro taller
```
**Escenario 5: SuperAdmin ve todos los talleres**
```gherkin
DADO que un SuperAdmin accede al sistema
CUANDO consulta datos
ENTONCES puede ver registros de todos los talleres
Y puede filtrar por taller especifico
```
---
## Implementacion Tecnica
### Configuracion de Contexto
```sql
-- Funcion para establecer contexto
CREATE OR REPLACE FUNCTION set_workshop_context(p_workshop_id UUID)
RETURNS VOID AS $$
BEGIN
PERFORM set_config('app.current_workshop_id', p_workshop_id::TEXT, FALSE);
END;
$$ LANGUAGE plpgsql;
-- Funcion para obtener contexto
CREATE OR REPLACE FUNCTION get_current_workshop_id()
RETURNS UUID AS $$
BEGIN
RETURN NULLIF(current_setting('app.current_workshop_id', TRUE), '')::UUID;
END;
$$ LANGUAGE plpgsql;
```
### Politicas RLS por Tabla
```sql
-- Ejemplo: Tabla service_orders
ALTER TABLE service_management.service_orders ENABLE ROW LEVEL SECURITY;
-- Politica de lectura
CREATE POLICY service_orders_select ON service_management.service_orders
FOR SELECT
USING (workshop_id = get_current_workshop_id() OR is_superadmin());
-- Politica de insercion
CREATE POLICY service_orders_insert ON service_management.service_orders
FOR INSERT
WITH CHECK (workshop_id = get_current_workshop_id());
-- Politica de actualizacion
CREATE POLICY service_orders_update ON service_management.service_orders
FOR UPDATE
USING (workshop_id = get_current_workshop_id());
-- Politica de eliminacion
CREATE POLICY service_orders_delete ON service_management.service_orders
FOR DELETE
USING (workshop_id = get_current_workshop_id());
```
---
## Tablas a Proteger
| Schema | Tabla | RLS |
|--------|-------|-----|
| workshop_core | workshops | Solo SuperAdmin |
| workshop_core | work_bays | Por workshop_id |
| workshop_core | service_catalog | Por workshop_id |
| service_management | service_orders | Por workshop_id |
| service_management | diagnostics | Por workshop_id |
| parts_management | parts | Por workshop_id |
| parts_management | movements | Por workshop_id |
| vehicle_management | vehicles | Por workshop_id |
---
## Tareas Tecnicas
**Database:**
- [ ] DB-015: Crear funcion set_workshop_context()
- [ ] DB-016: Crear funcion get_current_workshop_id()
- [ ] DB-017: Crear funcion is_superadmin()
- [ ] DB-018: Aplicar RLS a todas las tablas de negocio
- [ ] DB-019: Crear trigger para auto-asignar workshop_id en INSERT
**Backend:**
- [ ] BE-020: Middleware para establecer contexto al inicio de request
- [ ] BE-021: Ejecutar set_workshop_context() en cada conexion
- [ ] BE-022: Tests de penetracion entre tenants
**Frontend:**
- [ ] No aplica (transparente para frontend)
---
## Dependencias
**Depende de:**
- [ ] US-MMD001-001: Configurar taller
- [ ] MGN-004 Tenants (Core)
**Bloquea:**
- [ ] Todas las demas US (requieren RLS activo)
---
## Tests de Seguridad Requeridos
| Test | Descripcion | Resultado Esperado |
|------|-------------|-------------------|
| Cross-tenant SELECT | Intentar leer datos de otro taller | 0 registros |
| Cross-tenant UPDATE | Intentar modificar datos de otro taller | 0 registros afectados |
| Cross-tenant DELETE | Intentar eliminar datos de otro taller | 0 registros afectados |
| Direct ID access | Acceder por ID a registro de otro taller | 404 Not Found |
| SuperAdmin access | SuperAdmin accede a cualquier taller | Exito |
---
## Definition of Done (DoD)
- [ ] RLS habilitado en todas las tablas
- [ ] Contexto se establece automaticamente
- [ ] Tests de penetracion pasando
- [ ] SuperAdmin puede ver todo
- [ ] Documentacion de seguridad
---
**Creada por:** Requirements-Analyst
**Fecha:** 2025-12-06