# 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
