# 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