feat: add database schema migrations and seed data
8 SQL migration files covering all 10 tables, RLS policies with SECURITY DEFINER helpers, and seed data for SCW1 site + 3 zones. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWxyMibCuGGtSQSqfajDQ7
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
-- supabase/migrations/20260709000007_rls_policies.sql
|
||||
|
||||
-- Enable RLS on all application tables
|
||||
ALTER TABLE sites ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE zones ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE incidents ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE evidence_files ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE investigations ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE capa_actions ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE dosh_reports ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE notifications_log ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE audit_log ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Helper functions (SECURITY DEFINER avoids recursion through RLS)
|
||||
CREATE OR REPLACE FUNCTION public.auth_user_role()
|
||||
RETURNS user_role
|
||||
LANGUAGE sql
|
||||
SECURITY DEFINER
|
||||
STABLE
|
||||
AS $$ SELECT role FROM public.users WHERE id = auth.uid() $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.auth_user_site_id()
|
||||
RETURNS UUID
|
||||
LANGUAGE sql
|
||||
SECURITY DEFINER
|
||||
STABLE
|
||||
AS $$ SELECT site_id FROM public.users WHERE id = auth.uid() $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.auth_user_department()
|
||||
RETURNS TEXT
|
||||
LANGUAGE sql
|
||||
SECURITY DEFINER
|
||||
STABLE
|
||||
AS $$ SELECT department FROM public.users WHERE id = auth.uid() $$;
|
||||
|
||||
-- sites: everyone reads active sites; only admin manages
|
||||
CREATE POLICY "sites_read" ON sites FOR SELECT USING (active = true);
|
||||
CREATE POLICY "sites_admin_all" ON sites FOR ALL USING (auth_user_role() = 'admin');
|
||||
|
||||
-- zones: everyone reads; only admin manages
|
||||
CREATE POLICY "zones_read" ON zones FOR SELECT USING (true);
|
||||
CREATE POLICY "zones_admin_all" ON zones FOR ALL USING (auth_user_role() = 'admin');
|
||||
|
||||
-- users: own profile always readable; elevated roles see all; admin manages
|
||||
CREATE POLICY "users_read_own" ON users FOR SELECT USING (id = auth.uid());
|
||||
CREATE POLICY "users_read_elevated" ON users FOR SELECT
|
||||
USING (auth_user_role() IN ('hse', 'admin', 'management', 'supervisor'));
|
||||
CREATE POLICY "users_update_own" ON users FOR UPDATE USING (id = auth.uid());
|
||||
CREATE POLICY "users_admin_all" ON users FOR ALL USING (auth_user_role() = 'admin');
|
||||
|
||||
-- incidents: reporter sees own; supervisor sees own site; elevated sees all
|
||||
CREATE POLICY "incidents_insert" ON incidents FOR INSERT
|
||||
WITH CHECK (reported_by = auth.uid());
|
||||
CREATE POLICY "incidents_read_reporter" ON incidents FOR SELECT
|
||||
USING (reported_by = auth.uid());
|
||||
CREATE POLICY "incidents_read_supervisor" ON incidents FOR SELECT
|
||||
USING (auth_user_role() = 'supervisor' AND site_id = auth_user_site_id());
|
||||
CREATE POLICY "incidents_read_elevated" ON incidents FOR SELECT
|
||||
USING (auth_user_role() IN ('hse', 'admin', 'management'));
|
||||
CREATE POLICY "incidents_update_elevated" ON incidents FOR UPDATE
|
||||
USING (auth_user_role() IN ('hse', 'admin', 'supervisor'));
|
||||
|
||||
-- evidence_files: inserter or incident owner sees own; elevated sees all; no delete
|
||||
CREATE POLICY "evidence_insert" ON evidence_files FOR INSERT
|
||||
WITH CHECK (uploaded_by = auth.uid());
|
||||
CREATE POLICY "evidence_read_uploader" ON evidence_files FOR SELECT
|
||||
USING (uploaded_by = auth.uid());
|
||||
CREATE POLICY "evidence_read_elevated" ON evidence_files FOR SELECT
|
||||
USING (auth_user_role() IN ('hse', 'admin', 'management', 'supervisor'));
|
||||
-- No DELETE policy -- files are never deleted (soft-delete only via `deleted` flag)
|
||||
|
||||
-- investigations: hse/admin full access; supervisor read-only
|
||||
CREATE POLICY "investigations_hse_admin" ON investigations FOR ALL
|
||||
USING (auth_user_role() IN ('hse', 'admin'));
|
||||
CREATE POLICY "investigations_read_supervisor" ON investigations FOR SELECT
|
||||
USING (auth_user_role() = 'supervisor');
|
||||
|
||||
-- capa_actions: owner/dept reads and updates own; elevated reads all; hse/admin manages
|
||||
CREATE POLICY "capa_read_owner" ON capa_actions FOR SELECT
|
||||
USING (owner_user_id = auth.uid() OR department = auth_user_department());
|
||||
CREATE POLICY "capa_update_owner" ON capa_actions FOR UPDATE
|
||||
USING (owner_user_id = auth.uid() OR department = auth_user_department());
|
||||
CREATE POLICY "capa_read_elevated" ON capa_actions FOR SELECT
|
||||
USING (auth_user_role() IN ('hse', 'admin', 'management', 'supervisor'));
|
||||
CREATE POLICY "capa_hse_admin_all" ON capa_actions FOR ALL
|
||||
USING (auth_user_role() IN ('hse', 'admin'));
|
||||
|
||||
-- dosh_reports: hse/admin only
|
||||
CREATE POLICY "dosh_hse_admin" ON dosh_reports FOR ALL
|
||||
USING (auth_user_role() IN ('hse', 'admin'));
|
||||
|
||||
-- notifications_log: hse/admin read
|
||||
CREATE POLICY "notifications_read_elevated" ON notifications_log FOR SELECT
|
||||
USING (auth_user_role() IN ('hse', 'admin'));
|
||||
|
||||
-- audit_log: hse/admin read only -- no writes from app (writes via SECURITY DEFINER functions)
|
||||
CREATE POLICY "audit_read_elevated" ON audit_log FOR SELECT
|
||||
USING (auth_user_role() IN ('hse', 'admin'));
|
||||
Reference in New Issue
Block a user