AeThex-OS/supabase/migrations/004_calls_system.sql
MrPiglr b3c308b2c8 Add functional marketplace modules, bottom nav bar, root terminal, arcade games
- ModuleManager: Central tracking for installed marketplace modules
- DataAnalyzerWidget: Real-time CPU/RAM/Battery/Storage widget (unlocked by Data Analyzer module)
- BottomNavBar: Navigation bar for Projects/Chat/Marketplace/Settings
- RootShell: Real root command execution utility
- TerminalActivity: Full root shell with neofetch, sysinfo, real Linux commands
- Terminal Pro module: Adds aliases (ll, la, h), command history
- ArcadeActivity + SnakeGame: Pixel Arcade module unlocks retro games
- fade_in/fade_out animations for smooth transitions
2026-02-18 22:03:50 -07:00

151 lines
5.6 KiB
PL/PgSQL

-- Migration 004: Voice/Video Calls System
-- WebRTC calling infrastructure for 1-on-1 and group calls
-- ============================================================================
-- CALLS TABLE
-- ============================================================================
CREATE TABLE IF NOT EXISTS calls (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
type VARCHAR(20) NOT NULL CHECK (type IN ('voice', 'video')),
initiator_id UUID NOT NULL REFERENCES auth.users(id),
status VARCHAR(30) NOT NULL DEFAULT 'ringing' CHECK (status IN ('ringing', 'active', 'ended', 'failed', 'missed')),
sfu_room_id VARCHAR(100),
started_at TIMESTAMP WITH TIME ZONE,
ended_at TIMESTAMP WITH TIME ZONE,
duration_seconds INTEGER,
end_reason VARCHAR(50),
metadata JSONB,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_calls_conversation ON calls(conversation_id);
CREATE INDEX IF NOT EXISTS idx_calls_initiator ON calls(initiator_id);
CREATE INDEX IF NOT EXISTS idx_calls_status ON calls(status);
CREATE INDEX IF NOT EXISTS idx_calls_created ON calls(created_at DESC);
-- ============================================================================
-- CALL PARTICIPANTS
-- ============================================================================
CREATE TABLE IF NOT EXISTS call_participants (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
call_id UUID NOT NULL REFERENCES calls(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES auth.users(id),
joined_at TIMESTAMP WITH TIME ZONE,
left_at TIMESTAMP WITH TIME ZONE,
media_state JSONB DEFAULT '{"audio": true, "video": false, "screen": false}'::jsonb,
connection_quality VARCHAR(20) DEFAULT 'unknown' CHECK (connection_quality IN ('excellent', 'good', 'fair', 'poor', 'unknown')),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(call_id, user_id)
);
CREATE INDEX IF NOT EXISTS idx_call_participants_call ON call_participants(call_id);
CREATE INDEX IF NOT EXISTS idx_call_participants_user ON call_participants(user_id);
-- ============================================================================
-- TURN CREDENTIALS (for NAT traversal)
-- ============================================================================
CREATE TABLE IF NOT EXISTS turn_credentials (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
username VARCHAR(200) NOT NULL,
credential VARCHAR(500) NOT NULL,
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(user_id)
);
CREATE INDEX IF NOT EXISTS idx_turn_credentials_user ON turn_credentials(user_id);
CREATE INDEX IF NOT EXISTS idx_turn_credentials_expires ON turn_credentials(expires_at);
-- ============================================================================
-- ENABLE ROW LEVEL SECURITY
-- ============================================================================
ALTER TABLE calls ENABLE ROW LEVEL SECURITY;
ALTER TABLE call_participants ENABLE ROW LEVEL SECURITY;
ALTER TABLE turn_credentials ENABLE ROW LEVEL SECURITY;
-- ============================================================================
-- RLS POLICIES
-- ============================================================================
-- Calls: Users can see calls they're participants in
CREATE POLICY "calls_select" ON calls
FOR SELECT USING (
EXISTS (
SELECT 1 FROM call_participants
WHERE call_participants.call_id = calls.id AND call_participants.user_id = auth.uid()
)
OR initiator_id = auth.uid()
);
CREATE POLICY "calls_insert" ON calls
FOR INSERT WITH CHECK (initiator_id = auth.uid());
CREATE POLICY "calls_update" ON calls
FOR UPDATE USING (
initiator_id = auth.uid()
OR EXISTS (
SELECT 1 FROM call_participants
WHERE call_participants.call_id = calls.id AND call_participants.user_id = auth.uid()
)
);
-- Call Participants: Users can see participants in their calls
CREATE POLICY "call_participants_select" ON call_participants
FOR SELECT USING (
user_id = auth.uid()
OR EXISTS (
SELECT 1 FROM call_participants cp2
WHERE cp2.call_id = call_participants.call_id
AND cp2.user_id = auth.uid()
)
);
CREATE POLICY "call_participants_insert" ON call_participants
FOR INSERT WITH CHECK (
user_id = auth.uid()
OR EXISTS (
SELECT 1 FROM calls
WHERE id = call_id AND initiator_id = auth.uid()
)
);
CREATE POLICY "call_participants_update" ON call_participants
FOR UPDATE USING (user_id = auth.uid());
-- TURN Credentials: Users can only see their own
CREATE POLICY "turn_credentials_select" ON turn_credentials
FOR SELECT USING (user_id = auth.uid());
CREATE POLICY "turn_credentials_insert" ON turn_credentials
FOR INSERT WITH CHECK (user_id = auth.uid());
CREATE POLICY "turn_credentials_update" ON turn_credentials
FOR UPDATE USING (user_id = auth.uid());
-- ============================================================================
-- TRIGGER TO TRACK CALL DURATION
-- ============================================================================
CREATE OR REPLACE FUNCTION update_call_duration()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.status = 'ended' AND OLD.status != 'ended' THEN
NEW.ended_at = NOW();
IF NEW.started_at IS NOT NULL THEN
NEW.duration_seconds = EXTRACT(EPOCH FROM (NEW.ended_at - NEW.started_at))::INTEGER;
END IF;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trigger_call_duration ON calls;
CREATE TRIGGER trigger_call_duration
BEFORE UPDATE ON calls
FOR EACH ROW EXECUTE FUNCTION update_call_duration();