-- Drop existing tables if they exist (safe teardown for re-creating DB) DROP TABLE IF EXISTS room_messages CASCADE; DROP TABLE IF EXISTS logs CASCADE; DROP TABLE IF EXISTS codes CASCADE; DROP TABLE IF EXISTS users CASCADE; DROP TABLE IF EXISTS rooms CASCADE; -- Enable necessary extensions (ensure gen_random_uuid is available) CREATE EXTENSION IF NOT EXISTS "pgcrypto"; CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- Rooms table (created first because other tables reference it) CREATE TABLE rooms ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR, description VARCHAR(255), status INTEGER DEFAULT 1, date_created TIMESTAMP DEFAULT NOW(), date_last_message TIMESTAMP, updated_at TIMESTAMP DEFAULT NOW(), creator_id UUID ); -- Users table -- id MUST match auth.users.id (no default) to keep auth as single source of truth CREATE TABLE users ( id UUID PRIMARY KEY, email VARCHAR UNIQUE NOT NULL, token VARCHAR UNIQUE NOT NULL DEFAULT gen_random_uuid()::text, status INTEGER DEFAULT 1, fname VARCHAR NOT NULL, sname VARCHAR NOT NULL, sex INTEGER, nickname VARCHAR, birth_date DATE, photo_url VARCHAR, lang VARCHAR DEFAULT 'cs', created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); -- Codes table (create without FK references to avoid dependency ordering issues) CREATE TABLE codes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), code VARCHAR(5) UNIQUE NOT NULL, linked_to UUID, -- will add self-FK constraint below used INTEGER, user_id UUID, -- will add FK constraint below room_id UUID, -- will add FK constraint below pin_hash VARCHAR, session_hash VARCHAR, date_first TIMESTAMP, date_last TIMESTAMP, used_count INTEGER DEFAULT 0, created_at TIMESTAMP DEFAULT NOW() ); -- Room messages table (create without FK references to avoid ordering issues) CREATE TABLE room_messages ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), room_id UUID, -- FK added below code_id UUID, -- FK added below user_id UUID, -- FK added below content TEXT NOT NULL, image_url VARCHAR, created_at TIMESTAMP DEFAULT NOW() ); -- Logs table CREATE TABLE logs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), created_at TIMESTAMP DEFAULT NOW(), lang VARCHAR, ip VARCHAR, user_agent VARCHAR, module VARCHAR, operation VARCHAR, data JSONB, error TEXT, level VARCHAR ); -- Create indexes CREATE INDEX idx_codes_code ON codes(code); CREATE INDEX idx_codes_used ON codes(used); CREATE INDEX idx_codes_room_id ON codes(room_id); CREATE INDEX idx_room_messages_room_id ON room_messages(room_id); CREATE INDEX idx_room_messages_created_at ON room_messages(created_at); CREATE INDEX idx_users_email ON users(email); CREATE INDEX idx_users_status ON users(status); CREATE INDEX idx_logs_created_at ON logs(created_at); -- Add foreign key constraints after all tables exist (avoids "relation does not exist" errors) -- Ensure profile id references auth.users(id) for consistency ALTER TABLE users ADD CONSTRAINT fk_users_auth FOREIGN KEY (id) REFERENCES auth.users(id) ON DELETE CASCADE; -- codes foreign keys ALTER TABLE codes ADD CONSTRAINT fk_codes_linked_to FOREIGN KEY (linked_to) REFERENCES codes(id); ALTER TABLE codes ADD CONSTRAINT fk_codes_user FOREIGN KEY (user_id) REFERENCES users(id); ALTER TABLE codes ADD CONSTRAINT fk_codes_room FOREIGN KEY (room_id) REFERENCES rooms(id); -- Make creator relation explicit ALTER TABLE rooms ADD CONSTRAINT fk_rooms_creator FOREIGN KEY (creator_id) REFERENCES users(id); -- room_messages foreign keys ALTER TABLE room_messages ADD CONSTRAINT fk_room_messages_room FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE; ALTER TABLE room_messages ADD CONSTRAINT fk_room_messages_code FOREIGN KEY (code_id) REFERENCES codes(id); ALTER TABLE room_messages ADD CONSTRAINT fk_room_messages_user FOREIGN KEY (user_id) REFERENCES users(id); -- Logs (no FKs) -- Enable RLS ALTER TABLE users ENABLE ROW LEVEL SECURITY; ALTER TABLE codes ENABLE ROW LEVEL SECURITY; ALTER TABLE rooms ENABLE ROW LEVEL SECURITY; ALTER TABLE room_messages ENABLE ROW LEVEL SECURITY; ALTER TABLE logs ENABLE ROW LEVEL SECURITY; -- RLS policies for users DROP POLICY IF EXISTS "Users can view own profile" ON users; CREATE POLICY "Users can view own profile" ON users FOR SELECT USING (auth.uid()::text = id::text); DROP POLICY IF EXISTS "Users can insert own profile" ON users; CREATE POLICY "Users can insert own profile" ON users FOR INSERT WITH CHECK (auth.role() = 'service_role' OR auth.uid()::text = id::text); DROP POLICY IF EXISTS "Users can update own profile" ON users; CREATE POLICY "Users can update own profile" ON users FOR UPDATE USING (auth.uid()::text = id::text) WITH CHECK (auth.uid()::text = id::text); DROP POLICY IF EXISTS "Users can delete own profile" ON users; CREATE POLICY "Users can delete own profile" ON users FOR DELETE USING (auth.uid()::text = id::text); -- Logs: allow service role only DROP POLICY IF EXISTS "Logs service role only" ON logs; CREATE POLICY "Logs service role only" ON logs USING (auth.role() = 'service_role') WITH CHECK (auth.role() = 'service_role'); -- Note: service role bypasses RLS; use service role for migrations and admin operations. -- Additional policies for other tables should reference auth.uid() similarly where needed.