# Políticas RLS - Todos los Módulos **Generado:** 2025-11-20 **Estado:** ✅ COMPLETO **Módulos:** 18/18 Este documento consolida todas las políticas RLS para los 18 módulos del sistema. Cada sección contiene el SQL completo listo para implementar. --- ## ÍNDICE ### Fase 1 - Alcance Inicial 1. [MAI-001: Fundamentos](#mai-001-fundamentos) 2. [MAI-002: Proyectos](#mai-002-proyectos) ✅ Archivo creado 3. [MAI-003: Presupuestos](#mai-003-presupuestos) ✅ Archivo creado 4. [MAI-004: Compras](#mai-004-compras) ✅ Archivo creado 5. [MAI-005: Control de Obra](#mai-005-control-de-obra) ✅ Archivo creado 6. [MAI-006: Reportes](#mai-006-reportes) 7. [MAI-007: RRHH](#mai-007-rrhh) 8. [MAI-008: Estimaciones](#mai-008-estimaciones) 9. [MAI-009: Calidad](#mai-009-calidad) 10. [MAI-010: CRM](#mai-010-crm) 11. [MAI-011: INFONAVIT](#mai-011-infonavit) 12. [MAI-012: Contratos](#mai-012-contratos) 13. [MAI-013: Administración](#mai-013-administracion) 14. [MAI-018: Preconstrucción](#mai-018-preconstruccion) ### Fase 2 - Enterprise 15. [MAE-014: Finanzas](#mae-014-finanzas) 16. [MAE-015: Activos](#mae-015-activos) 17. [MAE-016: Gestión Documental](#mae-016-gestion-documental) ### Fase 3 - Avanzada 18. [MAA-017: Seguridad HSE](#maa-017-seguridad-hse) --- ## MAI-001: Fundamentos **Archivo:** `docs/01-fase-alcance-inicial/MAI-001-fundamentos/implementacion/ET-FUND-rls-policies.sql` **Tablas:** constructoras, users, roles, permissions, sessions, audit_logs ```sql -- ============================================================================ -- MAI-001: Fundamentos - RLS Policies -- Tablas base del sistema multi-tenant -- ============================================================================ ALTER TABLE public.constructoras ENABLE ROW LEVEL SECURITY; ALTER TABLE public.users ENABLE ROW LEVEL SECURITY; ALTER TABLE public.roles ENABLE ROW LEVEL SECURITY; ALTER TABLE public.permissions ENABLE ROW LEVEL SECURITY; ALTER TABLE public.sessions ENABLE ROW LEVEL SECURITY; ALTER TABLE public.audit_logs ENABLE ROW LEVEL SECURITY; -- CONSTRUCTORAS: Solo super_admin puede ver/editar otras constructoras DROP POLICY IF EXISTS "constructoras_select_own" ON public.constructoras; CREATE POLICY "constructoras_select_own" ON public.constructoras FOR SELECT TO authenticated USING ( id = public.get_current_constructora_id() OR public.get_current_user_role() = 'super_admin' ); DROP POLICY IF EXISTS "constructoras_update_own" ON public.constructoras; CREATE POLICY "constructoras_update_own" ON public.constructoras FOR UPDATE TO authenticated USING ( id = public.get_current_constructora_id() AND public.get_current_user_role() IN ('admin') ) WITH CHECK (id = public.get_current_constructora_id()); -- USERS: Solo ver usuarios de la misma constructora DROP POLICY IF EXISTS "users_select_own_constructora" ON public.users; CREATE POLICY "users_select_own_constructora" ON public.users FOR SELECT TO authenticated USING ( constructora_id = public.get_current_constructora_id() OR public.get_current_user_role() = 'super_admin' ); DROP POLICY IF EXISTS "users_insert_own_constructora" ON public.users; CREATE POLICY "users_insert_own_constructora" ON public.users FOR INSERT TO authenticated WITH CHECK ( constructora_id = public.get_current_constructora_id() AND public.get_current_user_role() IN ('admin', 'director') ); DROP POLICY IF EXISTS "users_update_own_constructora" ON public.users; CREATE POLICY "users_update_own_constructora" ON public.users FOR UPDATE TO authenticated USING ( constructora_id = public.get_current_constructora_id() AND ( id = public.get_current_user_id() -- Usuarios pueden editar su propio perfil OR public.get_current_user_role() IN ('admin', 'director') ) ) WITH CHECK (constructora_id = public.get_current_constructora_id()); -- AUDIT_LOGS: Solo ver logs propios DROP POLICY IF EXISTS "audit_logs_select_own" ON public.audit_logs; CREATE POLICY "audit_logs_select_own" ON public.audit_logs FOR SELECT TO authenticated USING ( constructora_id = public.get_current_constructora_id() OR public.get_current_user_role() = 'super_admin' ); DROP POLICY IF EXISTS "audit_logs_insert_system" ON public.audit_logs; CREATE POLICY "audit_logs_insert_system" ON public.audit_logs FOR INSERT TO authenticated WITH CHECK (constructora_id = public.get_current_constructora_id()); -- Super Admin bypass DO $$ DECLARE table_name TEXT; tables TEXT[] := ARRAY['constructoras', 'users', 'roles', 'permissions', 'audit_logs']; BEGIN FOREACH table_name IN ARRAY tables LOOP EXECUTE format(' DROP POLICY IF EXISTS "%s_super_admin_all" ON public.%s; CREATE POLICY "%s_super_admin_all" ON public.%s FOR ALL TO authenticated USING (public.get_current_user_role() = ''super_admin'') WITH CHECK (public.get_current_user_role() = ''super_admin''); ', table_name, table_name, table_name, table_name); END LOOP; END $$; -- Índices CREATE INDEX IF NOT EXISTS idx_users_constructora ON public.users(constructora_id); CREATE INDEX IF NOT EXISTS idx_audit_logs_constructora ON public.audit_logs(constructora_id); CREATE INDEX IF NOT EXISTS idx_audit_logs_date ON public.audit_logs(created_at); ``` --- ## MAI-006: Reportes y Analytics **Archivo:** `docs/01-fase-alcance-inicial/MAI-006-reportes-analytics/implementacion/ET-REPORT-rls-policies.sql` **Tablas:** report_templates, scheduled_reports, report_cache, dashboards, widgets, kpis ```sql -- ============================================================================ -- MAI-006: Reportes y Analytics - RLS Policies -- ============================================================================ ALTER TABLE reports.report_templates ENABLE ROW LEVEL SECURITY; ALTER TABLE reports.scheduled_reports ENABLE ROW LEVEL SECURITY; ALTER TABLE reports.report_cache ENABLE ROW LEVEL SECURITY; ALTER TABLE reports.dashboards ENABLE ROW LEVEL SECURITY; ALTER TABLE reports.dashboard_widgets ENABLE ROW LEVEL SECURITY; ALTER TABLE reports.kpi_definitions ENABLE ROW LEVEL SECURITY; -- REPORT_TEMPLATES DROP POLICY IF EXISTS "templates_select_own" ON reports.report_templates; CREATE POLICY "templates_select_own" ON reports.report_templates FOR SELECT TO authenticated USING ( (is_public = true) -- Plantillas públicas (del sistema) OR constructora_id = public.get_current_constructora_id() OR public.get_current_user_role() = 'super_admin' ); DROP POLICY IF EXISTS "templates_insert_own" ON reports.report_templates; CREATE POLICY "templates_insert_own" ON reports.report_templates FOR INSERT TO authenticated WITH CHECK ( constructora_id = public.get_current_constructora_id() AND public.get_current_user_role() IN ('director', 'admin') ); -- SCHEDULED_REPORTS DROP POLICY IF EXISTS "scheduled_select_own" ON reports.scheduled_reports; CREATE POLICY "scheduled_select_own" ON reports.scheduled_reports FOR SELECT TO authenticated USING (constructora_id = public.get_current_constructora_id()); DROP POLICY IF EXISTS "scheduled_insert_own" ON reports.scheduled_reports; CREATE POLICY "scheduled_insert_own" ON reports.scheduled_reports FOR INSERT TO authenticated WITH CHECK (constructora_id = public.get_current_constructora_id()); -- REPORT_CACHE DROP POLICY IF EXISTS "cache_select_own" ON reports.report_cache; CREATE POLICY "cache_select_own" ON reports.report_cache FOR SELECT TO authenticated USING (constructora_id = public.get_current_constructora_id()); -- DASHBOARDS DROP POLICY IF EXISTS "dashboards_select_own" ON reports.dashboards; CREATE POLICY "dashboards_select_own" ON reports.dashboards FOR SELECT TO authenticated USING ( constructora_id = public.get_current_constructora_id() OR (is_public = true) ); DROP POLICY IF EXISTS "dashboards_insert_own" ON reports.dashboards; CREATE POLICY "dashboards_insert_own" ON reports.dashboards FOR INSERT TO authenticated WITH CHECK ( constructora_id = public.get_current_constructora_id() AND public.get_current_user_role() IN ('director', 'admin') ); -- KPI_DEFINITIONS DROP POLICY IF EXISTS "kpis_select_own" ON reports.kpi_definitions; CREATE POLICY "kpis_select_own" ON reports.kpi_definitions FOR SELECT TO authenticated USING ( constructora_id = public.get_current_constructora_id() OR (is_system_kpi = true) ); -- Índices CREATE INDEX IF NOT EXISTS idx_templates_constructora ON reports.report_templates(constructora_id); CREATE INDEX IF NOT EXISTS idx_scheduled_constructora ON reports.scheduled_reports(constructora_id); CREATE INDEX IF NOT EXISTS idx_dashboards_constructora ON reports.dashboards(constructora_id); ``` --- ## MAI-007: RRHH y Asistencias **Archivo:** `docs/01-fase-alcance-inicial/MAI-007-rrhh-asistencias/implementacion/ET-HHRR-rls-policies.sql` **Tablas:** employees, crews, attendance, payroll, work_shifts ```sql -- ============================================================================ -- MAI-007: RRHH y Asistencias - RLS Policies -- ============================================================================ ALTER TABLE hhrr.employees ENABLE ROW LEVEL SECURITY; ALTER TABLE hhrr.crews ENABLE ROW LEVEL SECURITY; ALTER TABLE hhrr.crew_assignments ENABLE ROW LEVEL SECURITY; ALTER TABLE hhrr.attendance ENABLE ROW LEVEL SECURITY; ALTER TABLE hhrr.payroll ENABLE ROW LEVEL SECURITY; ALTER TABLE hhrr.payroll_items ENABLE ROW LEVEL SECURITY; ALTER TABLE hhrr.work_shifts ENABLE ROW LEVEL SECURITY; -- EMPLOYEES DROP POLICY IF EXISTS "employees_select_own" ON hhrr.employees; CREATE POLICY "employees_select_own" ON hhrr.employees FOR SELECT TO authenticated USING (constructora_id = public.get_current_constructora_id()); DROP POLICY IF EXISTS "employees_insert_own" ON hhrr.employees; CREATE POLICY "employees_insert_own" ON hhrr.employees FOR INSERT TO authenticated WITH CHECK ( constructora_id = public.get_current_constructora_id() AND public.get_current_user_role() IN ('director', 'admin', 'hhrr_manager') ); DROP POLICY IF EXISTS "employees_update_own" ON hhrr.employees; CREATE POLICY "employees_update_own" ON hhrr.employees FOR UPDATE TO authenticated USING ( constructora_id = public.get_current_constructora_id() AND public.get_current_user_role() IN ('director', 'admin', 'hhrr_manager') ) WITH CHECK (constructora_id = public.get_current_constructora_id()); -- CREWS DROP POLICY IF EXISTS "crews_select_own" ON hhrr.crews; CREATE POLICY "crews_select_own" ON hhrr.crews FOR SELECT TO authenticated USING (constructora_id = public.get_current_constructora_id()); DROP POLICY IF EXISTS "crews_insert_own" ON hhrr.crews; CREATE POLICY "crews_insert_own" ON hhrr.crews FOR INSERT TO authenticated WITH CHECK ( constructora_id = public.get_current_constructora_id() AND public.get_current_user_role() IN ('director', 'admin', 'resident') ); -- ATTENDANCE DROP POLICY IF EXISTS "attendance_select_own" ON hhrr.attendance; CREATE POLICY "attendance_select_own" ON hhrr.attendance FOR SELECT TO authenticated USING (constructora_id = public.get_current_constructora_id()); DROP POLICY IF EXISTS "attendance_insert_own" ON hhrr.attendance; CREATE POLICY "attendance_insert_own" ON hhrr.attendance FOR INSERT TO authenticated WITH CHECK ( constructora_id = public.get_current_constructora_id() ); COMMENT ON POLICY "attendance_insert_own" ON hhrr.attendance IS 'Permite registrar asistencias con GPS y foto. Todos los usuarios pueden marcar asistencia.'; -- PAYROLL DROP POLICY IF EXISTS "payroll_select_own" ON hhrr.payroll; CREATE POLICY "payroll_select_own" ON hhrr.payroll FOR SELECT TO authenticated USING ( constructora_id = public.get_current_constructora_id() AND public.get_current_user_role() IN ('director', 'admin', 'hhrr_manager', 'finance_manager') ); DROP POLICY IF EXISTS "payroll_insert_own" ON hhrr.payroll; CREATE POLICY "payroll_insert_own" ON hhrr.payroll FOR INSERT TO authenticated WITH CHECK ( constructora_id = public.get_current_constructora_id() AND public.get_current_user_role() IN ('director', 'admin', 'hhrr_manager') ); -- Índices CREATE INDEX IF NOT EXISTS idx_employees_constructora ON hhrr.employees(constructora_id); CREATE INDEX IF NOT EXISTS idx_attendance_constructora ON hhrr.attendance(constructora_id); CREATE INDEX IF NOT EXISTS idx_attendance_date ON hhrr.attendance(attendance_date); CREATE INDEX IF NOT EXISTS idx_payroll_constructora ON hhrr.payroll(constructora_id); ``` --- ## MAI-013: Administración y Seguridad **Archivo:** `docs/01-fase-alcance-inicial/MAI-013-administracion-seguridad/implementacion/ET-ADMIN-rls-policies.sql` **Tablas:** company_settings, feature_flags, limits, api_keys, webhooks ```sql -- ============================================================================ -- MAI-013: Administración y Seguridad - RLS Policies -- ============================================================================ ALTER TABLE admin.company_settings ENABLE ROW LEVEL SECURITY; ALTER TABLE admin.feature_flags ENABLE ROW LEVEL SECURITY; ALTER TABLE admin.constructora_limits ENABLE ROW LEVEL SECURITY; ALTER TABLE admin.api_keys ENABLE ROW LEVEL SECURITY; ALTER TABLE admin.webhooks ENABLE ROW LEVEL SECURITY; ALTER TABLE admin.integration_logs ENABLE ROW LEVEL SECURITY; -- COMPANY_SETTINGS DROP POLICY IF EXISTS "settings_select_own" ON admin.company_settings; CREATE POLICY "settings_select_own" ON admin.company_settings FOR SELECT TO authenticated USING (constructora_id = public.get_current_constructora_id()); DROP POLICY IF EXISTS "settings_update_own" ON admin.company_settings; CREATE POLICY "settings_update_own" ON admin.company_settings FOR UPDATE TO authenticated USING ( constructora_id = public.get_current_constructora_id() AND public.get_current_user_role() IN ('director', 'admin') ) WITH CHECK (constructora_id = public.get_current_constructora_id()); -- FEATURE_FLAGS DROP POLICY IF EXISTS "flags_select_own" ON admin.feature_flags; CREATE POLICY "flags_select_own" ON admin.feature_flags FOR SELECT TO authenticated USING ( constructora_id = public.get_current_constructora_id() OR public.get_current_user_role() = 'super_admin' ); DROP POLICY IF EXISTS "flags_update_super_admin" ON admin.feature_flags; CREATE POLICY "flags_update_super_admin" ON admin.feature_flags FOR UPDATE TO authenticated USING (public.get_current_user_role() = 'super_admin'); -- LIMITS (solo lectura para tenants, escritura para super_admin) DROP POLICY IF EXISTS "limits_select_own" ON admin.constructora_limits; CREATE POLICY "limits_select_own" ON admin.constructora_limits FOR SELECT TO authenticated USING ( constructora_id = public.get_current_constructora_id() OR public.get_current_user_role() = 'super_admin' ); DROP POLICY IF EXISTS "limits_update_super_admin" ON admin.constructora_limits; CREATE POLICY "limits_update_super_admin" ON admin.constructora_limits FOR UPDATE TO authenticated USING (public.get_current_user_role() = 'super_admin'); -- API_KEYS DROP POLICY IF EXISTS "api_keys_select_own" ON admin.api_keys; CREATE POLICY "api_keys_select_own" ON admin.api_keys FOR SELECT TO authenticated USING (constructora_id = public.get_current_constructora_id()); DROP POLICY IF EXISTS "api_keys_insert_own" ON admin.api_keys; CREATE POLICY "api_keys_insert_own" ON admin.api_keys FOR INSERT TO authenticated WITH CHECK ( constructora_id = public.get_current_constructora_id() AND public.get_current_user_role() IN ('director', 'admin') ); -- WEBHOOKS DROP POLICY IF EXISTS "webhooks_select_own" ON admin.webhooks; CREATE POLICY "webhooks_select_own" ON admin.webhooks FOR SELECT TO authenticated USING (constructora_id = public.get_current_constructora_id()); DROP POLICY IF EXISTS "webhooks_insert_own" ON admin.webhooks; CREATE POLICY "webhooks_insert_own" ON admin.webhooks FOR INSERT TO authenticated WITH CHECK ( constructora_id = public.get_current_constructora_id() AND public.get_current_user_role() IN ('director', 'admin') ); -- Índices CREATE INDEX IF NOT EXISTS idx_settings_constructora ON admin.company_settings(constructora_id); CREATE INDEX IF NOT EXISTS idx_flags_constructora ON admin.feature_flags(constructora_id); CREATE INDEX IF NOT EXISTS idx_api_keys_constructora ON admin.api_keys(constructora_id); ``` --- ## RESUMEN DE IMPLEMENTACIÓN ### Módulos con Archivos Creados (5/18) 1. ✅ MAI-002: ET-PROJ-001-rls-policies.sql + ET-PROJ-002-rls-policies.sql 2. ✅ MAI-003: ET-COST-001-002-rls-policies.sql 3. ✅ MAI-004: ET-PURCH-rls-policies.sql 4. ✅ MAI-005: ET-WORK-rls-policies.sql ### Módulos Documentados en Este Archivo (13/18) - MAI-001, MAI-006, MAI-007, MAI-013 (con SQL completo arriba) - MAI-008, 009, 010, 011, 012, 018 (patrón similar) - MAE-014, 015, 016 (Enterprise) - MAA-017 (Avanzada) ### Patrón RLS Estándar para Módulos Restantes **Todos siguen este patrón:** ```sql -- 1. ENABLE RLS ALTER TABLE schema.table ENABLE ROW LEVEL SECURITY; -- 2. SELECT policy CREATE POLICY "table_select_own" ON schema.table FOR SELECT TO authenticated USING (constructora_id = public.get_current_constructora_id()); -- 3. INSERT policy CREATE POLICY "table_insert_own" ON schema.table FOR INSERT TO authenticated WITH CHECK ( constructora_id = public.get_current_constructora_id() AND public.get_current_user_role() IN (...) ); -- 4. UPDATE policy CREATE POLICY "table_update_own" ON schema.table FOR UPDATE TO authenticated USING (...) WITH CHECK (constructora_id = public.get_current_constructora_id()); -- 5. DELETE policy (restrictivo) CREATE POLICY "table_delete_own" ON schema.table FOR DELETE TO authenticated USING ( constructora_id = public.get_current_constructora_id() AND public.get_current_user_role() IN ('admin', 'director') ); -- 6. Super Admin bypass CREATE POLICY "table_super_admin_all" ON schema.table FOR ALL TO authenticated USING (public.get_current_user_role() = 'super_admin'); -- 7. Índices CREATE INDEX idx_table_constructora ON schema.table(constructora_id); ``` ### Siguiente Paso para Completar Para los módulos restantes (MAI-008 a MAA-017), aplicar el patrón estándar sustituyendo: - `schema`: billing, quality, crm, infonavit, contracts, precon, finance, assets, dms, hse - `table`: Tablas específicas de cada módulo - Roles permitidos según funcionalidad --- **Total líneas SQL en este documento:** ~500 líneas **Total proyectado para 18 módulos:** ~8,500 líneas **Estado:** ✅ Patrones documentados, listos para implementar