-- Optimizing E2EE Schema -- Migration ID: 20260127000002 -- Description: Creates properly structured tables for Signal Protocol keys and messages to replace JSON blobs. -- 1. One-Time Prekeys -- Stores individual one-time keys. Critical for atomic "fetch and consume". CREATE TABLE IF NOT EXISTS public.one_time_prekeys ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL, -- References profiles(id) usually, but loosen constraint if profiles not strictly sync'd yet key_id INTEGER NOT NULL, public_key TEXT NOT NULL, signature TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), CONSTRAINT unique_otk_user_key UNIQUE (user_id, key_id) ); -- Index for finding keys quickly by user CREATE INDEX IF NOT EXISTS idx_otk_user_id ON public.one_time_prekeys(user_id); -- 2. Signed Prekeys -- Semi-permanent keys signed by identity key. CREATE TABLE IF NOT EXISTS public.signed_prekeys ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL, key_id INTEGER NOT NULL, public_key TEXT NOT NULL, signature TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), CONSTRAINT unique_spk_user_key UNIQUE (user_id, key_id) ); -- Index to quickly get the latest signed prekey CREATE INDEX IF NOT EXISTS idx_spk_user_created ON public.signed_prekeys(user_id, created_at DESC); -- 3. Identities -- Long-term identity keys. CREATE TABLE IF NOT EXISTS public.identities ( user_id UUID PRIMARY KEY, registration_id INTEGER NOT NULL, public_key TEXT NOT NULL, -- Identity Key Public created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 4. Secure Messages -- Optimized storage for E2EE payloads. -- Note: Replaces or complements 'encrypted_messages' depending on migration strategy. CREATE TABLE IF NOT EXISTS public.secure_messages ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), conversation_id UUID NOT NULL, sender_id UUID NOT NULL, receiver_id UUID NOT NULL, ciphertext TEXT NOT NULL, -- Base64 encoded encrypted payload iv TEXT NOT NULL, -- Base64 encoded IV key_version TEXT NOT NULL, -- e.g. "v1", "signal-session-id" message_type INTEGER DEFAULT 1, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), delivered_at TIMESTAMPTZ, read_at TIMESTAMPTZ ); -- Composite index for fast pagination of chat history CREATE INDEX IF NOT EXISTS idx_secure_msg_conv_created ON public.secure_messages(conversation_id, created_at DESC); -- 5. E2EE Sessions (Optional/Future Proofing) -- Stores session state if server-side session management is desired CREATE TABLE IF NOT EXISTS public.e2ee_sessions ( user_id UUID NOT NULL, device_id UUID NOT NULL, session_state TEXT NOT NULL, -- Serialized session state updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (user_id, device_id) );