Row Level Security (RLS) is a PostgreSQL feature that restricts which rows users can access in database tables. RLS is critical for data security in Portal Ciudadano Manta.
Without RLS enabled, any authenticated user could access ALL data in your database, including other users’ personal information and reports.
Reportes (citizen reports) have strict policies ensuring users can only manage their own reports while admins can manage all reports.Location: sql/reportes_rls.sql
CREATE POLICY "Administradores pueden ver todos los reportes"ON public.reportesFOR SELECTTO authenticatedUSING ( EXISTS ( SELECT 1 FROM public.usuarios WHERE usuarios.id = auth.uid() AND usuarios.tipo = 'administrador' ));
Allows administrators to view all reports for management.
CREATE POLICY "Usuarios pueden actualizar sus propios reportes"ON public.reportesFOR UPDATETO authenticatedUSING ( auth.uid() = usuario_id AND estado = 'pendiente')WITH CHECK ( auth.uid() = usuario_id AND estado = 'pendiente');
Users can only edit their reports while still pendiente (not yet reviewed).
CREATE POLICY "noticias_select_authenticated"ON public.noticiasFOR SELECTTO authenticatedUSING ( parroquia_destino IS NULL OR EXISTS ( SELECT 1 FROM public.usuarios WHERE usuarios.id = auth.uid() AND ( usuarios.parroquia = noticias.parroquia_destino AND (noticias.barrio_destino IS NULL OR usuarios.barrio = noticias.barrio_destino) ) ));
Logic:
Global news (parroquia_destino IS NULL) visible to all
Parroquia-specific news visible to users in that parroquia
Barrio-specific news visible only to users in that barrio
-- Set session to simulate a specific userSET request.jwt.claims = '{"sub": "user-uuid-here"}'::json;-- Try to querySELECT * FROM reportes;-- Should only see that user's reports
-- Set session as admin userSET request.jwt.claims = '{"sub": "admin-uuid-here"}'::json;-- Try to querySELECT * FROM reportes;-- Should see all reports
RLS policies can impact query performance. Ensure indexes exist:
-- Index on usuario_id for reportes queriesCREATE INDEX IF NOT EXISTS idx_reportes_usuario_id ON reportes(usuario_id);-- Index on administrador_id for noticias queriesCREATE INDEX IF NOT EXISTS idx_noticias_administrador_id ON noticias(administrador_id);-- Index on parroquia/barrio for geotargetingCREATE INDEX IF NOT EXISTS idx_usuarios_parroquia_barrio ON usuarios(parroquia, barrio);