Navigate to SQL Editor in the Supabase dashboard and run the following schema:
Database Schema
-- Enable UUID extensionCREATE EXTENSION IF NOT EXISTS "uuid-ossp";-- Users profiles tableCREATE TABLE profiles ( id UUID REFERENCES auth.users ON DELETE CASCADE PRIMARY KEY, email TEXT UNIQUE NOT NULL, full_name TEXT, avatar_url TEXT, role TEXT DEFAULT 'user', created_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()), updated_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()));-- Incidents tableCREATE TABLE incidents ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, title TEXT NOT NULL, description TEXT, status TEXT DEFAULT 'open', priority TEXT DEFAULT 'medium', category TEXT, location TEXT, reporter_id UUID REFERENCES profiles(id) ON DELETE SET NULL, assigned_to UUID REFERENCES profiles(id) ON DELETE SET NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()), updated_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()), resolved_at TIMESTAMP WITH TIME ZONE);-- Incident attachments tableCREATE TABLE incident_attachments ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, incident_id UUID REFERENCES incidents(id) ON DELETE CASCADE, file_url TEXT NOT NULL, file_type TEXT, file_name TEXT, uploaded_by UUID REFERENCES profiles(id) ON DELETE SET NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()));-- Comments tableCREATE TABLE comments ( id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, incident_id UUID REFERENCES incidents(id) ON DELETE CASCADE, user_id UUID REFERENCES profiles(id) ON DELETE SET NULL, content TEXT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()), updated_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()));-- Create indexes for better performanceCREATE INDEX incidents_reporter_id_idx ON incidents(reporter_id);CREATE INDEX incidents_assigned_to_idx ON incidents(assigned_to);CREATE INDEX incidents_status_idx ON incidents(status);CREATE INDEX comments_incident_id_idx ON comments(incident_id);CREATE INDEX incident_attachments_incident_id_idx ON incident_attachments(incident_id);
Run this SQL in the SQL Editor tab. Click “Run” to execute the schema.
-- Enable RLS on all tablesALTER TABLE profiles ENABLE ROW LEVEL SECURITY;ALTER TABLE incidents ENABLE ROW LEVEL SECURITY;ALTER TABLE incident_attachments ENABLE ROW LEVEL SECURITY;ALTER TABLE comments ENABLE ROW LEVEL SECURITY;-- Profiles policiesCREATE POLICY "Users can view all profiles" ON profiles FOR SELECT USING (true);CREATE POLICY "Users can update own profile" ON profiles FOR UPDATE USING (auth.uid() = id);-- Incidents policiesCREATE POLICY "Users can view all incidents" ON incidents FOR SELECT USING (true);CREATE POLICY "Authenticated users can create incidents" ON incidents FOR INSERT WITH CHECK (auth.role() = 'authenticated');CREATE POLICY "Users can update own incidents" ON incidents FOR UPDATE USING (reporter_id = auth.uid() OR assigned_to = auth.uid());-- Attachments policiesCREATE POLICY "Users can view attachments for visible incidents" ON incident_attachments FOR SELECT USING (true);CREATE POLICY "Authenticated users can upload attachments" ON incident_attachments FOR INSERT WITH CHECK (auth.role() = 'authenticated');-- Comments policiesCREATE POLICY "Users can view comments on visible incidents" ON comments FOR SELECT USING (true);CREATE POLICY "Authenticated users can create comments" ON comments FOR INSERT WITH CHECK (auth.role() = 'authenticated');CREATE POLICY "Users can update own comments" ON comments FOR UPDATE USING (user_id = auth.uid());
RLS policies are critical for security. Never disable RLS in production without proper policies.
Configure storage buckets for incident photos and attachments.
1
Create storage bucket
Go to Storage → New bucket
Name: incident-attachments
Public bucket: Enable (for public incident photos)
2
Configure bucket policies
Under Policies for the bucket, add:
-- Allow authenticated users to uploadCREATE POLICY "Authenticated users can upload" ON storage.objects FOR INSERT WITH CHECK ( bucket_id = 'incident-attachments' AND auth.role() = 'authenticated' );-- Allow public read accessCREATE POLICY "Public read access" ON storage.objects FOR SELECT USING (bucket_id = 'incident-attachments');
3
Configure file size limits
Set maximum file size in bucket settings (e.g., 10MB)
For private attachments, create a separate bucket without public access and add user-specific policies.
-- Function to automatically update updated_at timestampCREATE OR REPLACE FUNCTION update_updated_at_column()RETURNS TRIGGER AS $$BEGIN NEW.updated_at = NOW(); RETURN NEW;END;$$ LANGUAGE plpgsql;-- Apply trigger to tablesCREATE TRIGGER update_profiles_updated_at BEFORE UPDATE ON profiles FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();CREATE TRIGGER update_incidents_updated_at BEFORE UPDATE ON incidents FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();CREATE TRIGGER update_comments_updated_at BEFORE UPDATE ON comments FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();-- Function to create profile on user signupCREATE OR REPLACE FUNCTION public.handle_new_user()RETURNS TRIGGER AS $$BEGIN INSERT INTO public.profiles (id, email, full_name) VALUES ( NEW.id, NEW.email, NEW.raw_user_meta_data->>'full_name' ); RETURN NEW;END;$$ LANGUAGE plpgsql SECURITY DEFINER;-- Trigger to create profile on signupCREATE TRIGGER on_auth_user_created AFTER INSERT ON auth.users FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();