092_UI_core / migrations /001_initial_schema.sql
anotherath's picture
fix create space
16f3c9e
-- VinClassroom Database Schema
-- Run this in Supabase SQL Editor
-- Enable necessary extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- Users (extends Supabase auth.users)
CREATE TABLE profiles (
id UUID REFERENCES auth.users(id) PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
display_name TEXT NOT NULL,
avatar_url TEXT,
bio TEXT,
color TEXT,
status TEXT DEFAULT 'offline',
last_seen TIMESTAMPTZ DEFAULT NOW(),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Spaces
CREATE TABLE spaces (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
description TEXT,
icon_url TEXT,
owner_id UUID REFERENCES profiles(id),
is_private BOOLEAN DEFAULT false,
invite_code TEXT UNIQUE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Rooms
CREATE TABLE rooms (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
space_id UUID REFERENCES spaces(id) ON DELETE CASCADE,
name TEXT NOT NULL,
description TEXT,
type TEXT DEFAULT 'text',
is_private BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Space Members
CREATE TABLE space_members (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
space_id UUID REFERENCES spaces(id) ON DELETE CASCADE,
user_id UUID REFERENCES profiles(id),
role TEXT DEFAULT 'member',
joined_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(space_id, user_id)
);
-- Room Members
CREATE TABLE room_members (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
room_id UUID REFERENCES rooms(id) ON DELETE CASCADE,
user_id UUID REFERENCES profiles(id),
joined_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(room_id, user_id)
);
-- Messages
CREATE TABLE messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
room_id UUID REFERENCES rooms(id) ON DELETE CASCADE,
user_id UUID REFERENCES profiles(id),
content TEXT,
reply_to_id UUID REFERENCES messages(id),
is_pinned BOOLEAN DEFAULT false,
is_edited BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
-- Message Attachments
CREATE TABLE message_attachments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
message_id UUID REFERENCES messages(id) ON DELETE CASCADE,
file_name TEXT NOT NULL,
file_url TEXT NOT NULL,
file_type TEXT,
file_size INTEGER,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Reactions
CREATE TABLE reactions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
message_id UUID REFERENCES messages(id) ON DELETE CASCADE,
user_id UUID REFERENCES profiles(id),
emoji TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(message_id, user_id, emoji)
);
-- Direct Messages
CREATE TABLE dm_conversations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user1_id UUID REFERENCES profiles(id),
user2_id UUID REFERENCES profiles(id),
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(user1_id, user2_id)
);
CREATE TABLE dm_messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID REFERENCES dm_conversations(id) ON DELETE CASCADE,
sender_id UUID REFERENCES profiles(id),
content TEXT,
is_read BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
-- Notifications
CREATE TABLE notifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES profiles(id),
type TEXT NOT NULL,
title TEXT NOT NULL,
message TEXT,
data JSONB,
is_read BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Blocked Users
CREATE TABLE blocked_users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
blocker_id UUID REFERENCES profiles(id),
blocked_id UUID REFERENCES profiles(id),
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(blocker_id, blocked_id)
);
-- Space Invitations
CREATE TABLE space_invitations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
space_id UUID REFERENCES spaces(id) ON DELETE CASCADE,
email TEXT NOT NULL,
token TEXT UNIQUE NOT NULL,
invited_by UUID REFERENCES profiles(id),
status TEXT DEFAULT 'pending',
expires_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Files
CREATE TABLE files (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
uploader_id UUID REFERENCES profiles(id),
space_id UUID REFERENCES spaces(id),
room_id UUID REFERENCES rooms(id),
file_name TEXT NOT NULL,
file_url TEXT NOT NULL,
file_type TEXT,
file_size INTEGER,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Indexes for performance
CREATE INDEX idx_profiles_status ON profiles(status);
CREATE INDEX idx_profiles_last_seen ON profiles(last_seen);
CREATE INDEX idx_spaces_owner ON spaces(owner_id);
CREATE INDEX idx_spaces_invite_code ON spaces(invite_code);
CREATE INDEX idx_rooms_space ON rooms(space_id);
CREATE INDEX idx_space_members_space ON space_members(space_id);
CREATE INDEX idx_space_members_user ON space_members(user_id);
CREATE INDEX idx_room_members_room ON room_members(room_id);
CREATE INDEX idx_room_members_user ON room_members(user_id);
CREATE INDEX idx_messages_room ON messages(room_id);
CREATE INDEX idx_messages_user ON messages(user_id);
CREATE INDEX idx_messages_created_at ON messages(created_at);
CREATE INDEX idx_messages_reply_to ON messages(reply_to_id);
CREATE INDEX idx_reactions_message ON reactions(message_id);
CREATE INDEX idx_dm_conversations_user1 ON dm_conversations(user1_id);
CREATE INDEX idx_dm_conversations_user2 ON dm_conversations(user2_id);
CREATE INDEX idx_dm_messages_conversation ON dm_messages(conversation_id);
CREATE INDEX idx_notifications_user ON notifications(user_id);
CREATE INDEX idx_notifications_is_read ON notifications(is_read);
CREATE INDEX idx_files_space ON files(space_id);
CREATE INDEX idx_files_room ON files(room_id);
-- Enable Row Level Security
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE spaces ENABLE ROW LEVEL SECURITY;
ALTER TABLE rooms ENABLE ROW LEVEL SECURITY;
ALTER TABLE space_members ENABLE ROW LEVEL SECURITY;
ALTER TABLE room_members ENABLE ROW LEVEL SECURITY;
ALTER TABLE messages ENABLE ROW LEVEL SECURITY;
ALTER TABLE message_attachments ENABLE ROW LEVEL SECURITY;
ALTER TABLE reactions ENABLE ROW LEVEL SECURITY;
ALTER TABLE dm_conversations ENABLE ROW LEVEL SECURITY;
ALTER TABLE dm_messages ENABLE ROW LEVEL SECURITY;
ALTER TABLE notifications ENABLE ROW LEVEL SECURITY;
ALTER TABLE blocked_users ENABLE ROW LEVEL SECURITY;
ALTER TABLE space_invitations ENABLE ROW LEVEL SECURITY;
ALTER TABLE files ENABLE ROW LEVEL SECURITY;
-- RLS Policies
-- Profiles: Users can read all profiles, update only their own
CREATE POLICY "Profiles are viewable by everyone" ON profiles
FOR SELECT USING (true);
CREATE POLICY "Users can update own profile" ON profiles
FOR UPDATE USING (auth.uid() = id);
-- Spaces: Members can view, owner can update/delete
CREATE POLICY "Spaces viewable by members" ON spaces
FOR SELECT USING (
EXISTS (
SELECT 1 FROM space_members WHERE space_id = id AND user_id = auth.uid()
) OR NOT is_private
);
CREATE POLICY "Spaces insertable by authenticated users" ON spaces
FOR INSERT WITH CHECK (auth.uid() = owner_id);
CREATE POLICY "Spaces updatable by owner" ON spaces
FOR UPDATE USING (auth.uid() = owner_id);
CREATE POLICY "Spaces deletable by owner" ON spaces
FOR DELETE USING (auth.uid() = owner_id);
-- Space Members: Viewable by space members
CREATE POLICY "Space members viewable by space members" ON space_members
FOR SELECT USING (
EXISTS (
SELECT 1 FROM space_members AS sm
WHERE sm.space_id = space_id AND sm.user_id = auth.uid()
)
);
-- Rooms: Viewable by space members
CREATE POLICY "Rooms viewable by space members" ON rooms
FOR SELECT USING (
EXISTS (
SELECT 1 FROM space_members
WHERE space_id = rooms.space_id AND user_id = auth.uid()
)
);
-- Messages: Viewable by room members
CREATE POLICY "Messages viewable by room members" ON messages
FOR SELECT USING (
EXISTS (
SELECT 1 FROM room_members
WHERE room_id = messages.room_id AND user_id = auth.uid()
)
);
CREATE POLICY "Users can insert own messages" ON messages
FOR INSERT WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users can update own messages" ON messages
FOR UPDATE USING (auth.uid() = user_id);
CREATE POLICY "Users can delete own messages" ON messages
FOR DELETE USING (auth.uid() = user_id);
-- DM Conversations: Viewable by participants
CREATE POLICY "DM conversations viewable by participants" ON dm_conversations
FOR SELECT USING (auth.uid() = user1_id OR auth.uid() = user2_id);
-- DM Messages: Viewable by conversation participants
CREATE POLICY "DM messages viewable by participants" ON dm_messages
FOR SELECT USING (
EXISTS (
SELECT 1 FROM dm_conversations
WHERE id = conversation_id AND (user1_id = auth.uid() OR user2_id = auth.uid())
)
);
-- Notifications: Viewable by owner
CREATE POLICY "Notifications viewable by owner" ON notifications
FOR SELECT USING (auth.uid() = user_id);
-- Enable Realtime
ALTER PUBLICATION supabase_realtime ADD TABLE messages;
ALTER PUBLICATION supabase_realtime ADD TABLE dm_messages;
ALTER PUBLICATION supabase_realtime ADD TABLE files;
ALTER PUBLICATION supabase_realtime ADD TABLE reactions;
ALTER PUBLICATION supabase_realtime ADD TABLE notifications;
-- Functions for updated_at
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';
-- Triggers for updated_at
CREATE TRIGGER update_profiles_updated_at BEFORE UPDATE ON profiles
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_spaces_updated_at BEFORE UPDATE ON spaces
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_rooms_updated_at BEFORE UPDATE ON rooms
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_messages_updated_at BEFORE UPDATE ON messages
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();