170 lines
6.7 KiB
SQL
170 lines
6.7 KiB
SQL
-- ============================================================
|
|
-- RLS Policies — Sistema de Recolección Inteligente
|
|
-- Ejecutar en: Supabase > SQL Editor
|
|
-- Regla innegociable: el ciudadano NUNCA ve coordenadas ni datos ajenos.
|
|
-- ============================================================
|
|
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 1. Tabla public.users (espejo de auth.users con rol)
|
|
-- ------------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS public.users (
|
|
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
email TEXT,
|
|
phone TEXT,
|
|
role TEXT DEFAULT 'citizen'
|
|
CHECK (role IN ('citizen', 'driver', 'admin')),
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
ALTER TABLE public.users ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- Cada usuario ve y edita solo su propia fila
|
|
DROP POLICY IF EXISTS "users_select_own" ON public.users;
|
|
CREATE POLICY "users_select_own" ON public.users
|
|
FOR SELECT USING (auth.uid() = id);
|
|
|
|
DROP POLICY IF EXISTS "users_update_own" ON public.users;
|
|
CREATE POLICY "users_update_own" ON public.users
|
|
FOR UPDATE USING (auth.uid() = id);
|
|
|
|
-- El backend (service_role) inserta al registrar; no necesita policy
|
|
-- porque service_role bypasea RLS por diseño.
|
|
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 2. Tabla public.addresses
|
|
-- ------------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS public.addresses (
|
|
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
|
|
user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
|
|
label TEXT NOT NULL,
|
|
calle TEXT NOT NULL,
|
|
colonia TEXT NOT NULL,
|
|
route_id TEXT NOT NULL,
|
|
verified BOOLEAN DEFAULT FALSE,
|
|
verified_method TEXT,
|
|
verified_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
ALTER TABLE public.addresses ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- Ciudadano: solo lee sus domicilios; admin lee todos
|
|
DROP POLICY IF EXISTS "addresses_select" ON public.addresses;
|
|
CREATE POLICY "addresses_select" ON public.addresses
|
|
FOR SELECT USING (
|
|
auth.uid() = user_id
|
|
OR (SELECT role FROM public.users WHERE id = auth.uid()) = 'admin'
|
|
);
|
|
|
|
-- Ciudadano solo inserta domicilios propios
|
|
DROP POLICY IF EXISTS "addresses_insert" ON public.addresses;
|
|
CREATE POLICY "addresses_insert" ON public.addresses
|
|
FOR INSERT WITH CHECK (auth.uid() = user_id);
|
|
|
|
-- Ciudadano solo modifica los suyos (para verified=true tras OCR)
|
|
DROP POLICY IF EXISTS "addresses_update" ON public.addresses;
|
|
CREATE POLICY "addresses_update" ON public.addresses
|
|
FOR UPDATE USING (
|
|
auth.uid() = user_id
|
|
OR (SELECT role FROM public.users WHERE id = auth.uid()) = 'admin'
|
|
);
|
|
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 3. Tabla public.route_positions ← ÚNICA QUE TIENE LAT/LNG
|
|
-- Solo admin puede leerla. Regla innegociable #1 y #4.
|
|
-- ------------------------------------------------------------
|
|
ALTER TABLE public.route_positions ENABLE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS "route_positions_admin_only" ON public.route_positions;
|
|
CREATE POLICY "route_positions_admin_only" ON public.route_positions
|
|
FOR SELECT USING (
|
|
(SELECT role FROM public.users WHERE id = auth.uid()) = 'admin'
|
|
);
|
|
-- Sin policy para INSERT/UPDATE/DELETE → el backend usa service_role para el seed.
|
|
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 4. Tabla public.notifications
|
|
-- ------------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS public.notifications (
|
|
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
|
|
user_id UUID REFERENCES public.users(id) ON DELETE CASCADE,
|
|
route_id TEXT,
|
|
type TEXT,
|
|
payload JSONB,
|
|
sent_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
ALTER TABLE public.notifications ENABLE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS "notifications_select" ON public.notifications;
|
|
CREATE POLICY "notifications_select" ON public.notifications
|
|
FOR SELECT USING (
|
|
auth.uid() = user_id
|
|
OR (SELECT role FROM public.users WHERE id = auth.uid()) = 'admin'
|
|
);
|
|
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 5. Tabla public.feedback
|
|
-- Las quejas van a target_unit_id (unidad), NUNCA al chofer.
|
|
-- ------------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS public.feedback (
|
|
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
|
|
user_id UUID REFERENCES public.users(id) ON DELETE SET NULL,
|
|
address_id UUID REFERENCES public.addresses(id) ON DELETE SET NULL,
|
|
type TEXT,
|
|
target_unit_id INT, -- unidad (no chofer): privacidad del chofer
|
|
message TEXT,
|
|
rating SMALLINT CHECK (rating BETWEEN 1 AND 5),
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
ALTER TABLE public.feedback ENABLE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS "feedback_select" ON public.feedback;
|
|
CREATE POLICY "feedback_select" ON public.feedback
|
|
FOR SELECT USING (
|
|
auth.uid() = user_id
|
|
OR (SELECT role FROM public.users WHERE id = auth.uid()) = 'admin'
|
|
);
|
|
|
|
DROP POLICY IF EXISTS "feedback_insert" ON public.feedback;
|
|
CREATE POLICY "feedback_insert" ON public.feedback
|
|
FOR INSERT WITH CHECK (auth.uid() = user_id);
|
|
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 5b. Tabla public.incidents (reportes ciudadanos)
|
|
-- ------------------------------------------------------------
|
|
ALTER TABLE public.incidents ENABLE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS "incidents_select" ON public.incidents;
|
|
CREATE POLICY "incidents_select" ON public.incidents
|
|
FOR SELECT USING (
|
|
auth.uid() = user_id
|
|
OR (SELECT role FROM public.users WHERE id = auth.uid()) = 'admin'
|
|
);
|
|
|
|
DROP POLICY IF EXISTS "incidents_insert" ON public.incidents;
|
|
CREATE POLICY "incidents_insert" ON public.incidents
|
|
FOR INSERT WITH CHECK (auth.uid() = user_id);
|
|
|
|
DROP POLICY IF EXISTS "incidents_update_admin" ON public.incidents;
|
|
CREATE POLICY "incidents_update_admin" ON public.incidents
|
|
FOR UPDATE USING (
|
|
(SELECT role FROM public.users WHERE id = auth.uid()) = 'admin'
|
|
);
|
|
|
|
|
|
-- ------------------------------------------------------------
|
|
-- 6. Índices útiles para rendimiento
|
|
-- ------------------------------------------------------------
|
|
CREATE INDEX IF NOT EXISTS idx_addresses_user_id ON public.addresses(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_addresses_route_id ON public.addresses(route_id);
|
|
CREATE INDEX IF NOT EXISTS idx_notifications_user ON public.notifications(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_feedback_user ON public.feedback(user_id);
|