CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), username VARCHAR(32) NOT NULL UNIQUE, email VARCHAR(255) NOT NULL UNIQUE, password_hash TEXT NOT NULL, avatar_seed VARCHAR(64) NOT NULL DEFAULT '', last_seen TIMESTAMPTZ NOT NULL DEFAULT NOW(), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE friendships ( requester_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, addressee_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, status VARCHAR(16) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'accepted', 'blocked')), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (requester_id, addressee_id) ); CREATE TABLE rooms ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), name VARCHAR(64) NOT NULL, owner_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, max_players INTEGER NOT NULL DEFAULT 10, is_public BOOLEAN NOT NULL DEFAULT TRUE, password_hash TEXT, game_version VARCHAR(32) NOT NULL DEFAULT '1.20', status VARCHAR(16) NOT NULL DEFAULT 'open' CHECK (status IN ('open', 'in_game', 'closed')), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE room_members ( room_id UUID NOT NULL REFERENCES rooms(id) ON DELETE CASCADE, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, role VARCHAR(16) NOT NULL DEFAULT 'member' CHECK (role IN ('owner', 'member')), joined_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (room_id, user_id) ); CREATE TABLE refresh_tokens ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, token_hash TEXT NOT NULL UNIQUE, device_id VARCHAR(128), expires_at TIMESTAMPTZ NOT NULL, revoked_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE relay_sessions ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), room_id UUID REFERENCES rooms(id) ON DELETE SET NULL, initiator_id UUID REFERENCES users(id) ON DELETE SET NULL, peer_id UUID REFERENCES users(id) ON DELETE SET NULL, session_type VARCHAR(8) NOT NULL DEFAULT 'relay' CHECK (session_type IN ('p2p', 'relay')), bytes_transferred BIGINT NOT NULL DEFAULT 0, started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), ended_at TIMESTAMPTZ ); CREATE INDEX idx_friendships_addressee ON friendships(addressee_id); CREATE INDEX idx_room_members_user ON room_members(user_id); CREATE INDEX idx_refresh_tokens_user ON refresh_tokens(user_id); CREATE INDEX idx_relay_sessions_room ON relay_sessions(room_id);