diff --git a/supabase/migrations/000_supabase_schemas.sql b/supabase/migrations/000_supabase_schemas.sql new file mode 100644 index 0000000..630107c --- /dev/null +++ b/supabase/migrations/000_supabase_schemas.sql @@ -0,0 +1,113 @@ +-- Monaco USA Portal - Supabase Schema Initialization +-- This MUST run before any other migrations to create required schemas for Supabase +-- The auth and storage schemas are required by GoTrue and Storage API + +-- Create extensions schema for PostgreSQL extensions +CREATE SCHEMA IF NOT EXISTS extensions; + +-- Create auth schema for GoTrue (authentication) +CREATE SCHEMA IF NOT EXISTS auth; + +-- Create storage schema for Storage API +CREATE SCHEMA IF NOT EXISTS storage; + +-- Create realtime schema for Realtime subscriptions +CREATE SCHEMA IF NOT EXISTS _realtime; + +-- Create graphql_public schema for GraphQL +CREATE SCHEMA IF NOT EXISTS graphql_public; + +-- Enable required extensions +CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA extensions; +CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA extensions; + +-- Grant necessary permissions +GRANT USAGE ON SCHEMA auth TO postgres, anon, authenticated, service_role; +GRANT USAGE ON SCHEMA storage TO postgres, anon, authenticated, service_role; +GRANT USAGE ON SCHEMA extensions TO postgres, anon, authenticated, service_role; + +-- Create the roles if they don't exist (for fresh installations) +DO $$ +BEGIN + IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'anon') THEN + CREATE ROLE anon NOLOGIN NOINHERIT; + END IF; + IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'authenticated') THEN + CREATE ROLE authenticated NOLOGIN NOINHERIT; + END IF; + IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'service_role') THEN + CREATE ROLE service_role NOLOGIN NOINHERIT BYPASSRLS; + END IF; + IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'supabase_admin') THEN + CREATE ROLE supabase_admin NOLOGIN NOINHERIT BYPASSRLS; + END IF; + IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'supabase_auth_admin') THEN + CREATE ROLE supabase_auth_admin NOLOGIN NOINHERIT; + END IF; + IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'supabase_storage_admin') THEN + CREATE ROLE supabase_storage_admin NOLOGIN NOINHERIT; + END IF; +END +$$; + +-- Grant auth schema ownership to auth admin +ALTER SCHEMA auth OWNER TO supabase_auth_admin; +GRANT ALL ON SCHEMA auth TO supabase_auth_admin; +GRANT ALL ON SCHEMA auth TO postgres; + +-- Grant storage schema ownership to storage admin +ALTER SCHEMA storage OWNER TO supabase_storage_admin; +GRANT ALL ON SCHEMA storage TO supabase_storage_admin; +GRANT ALL ON SCHEMA storage TO postgres; + +-- Create auth.users table structure needed by GoTrue +-- GoTrue will manage this table and run its own migrations +CREATE TABLE IF NOT EXISTS auth.users ( + id UUID PRIMARY KEY DEFAULT extensions.uuid_generate_v4(), + instance_id UUID, + aud VARCHAR(255), + role VARCHAR(255), + email VARCHAR(255) UNIQUE, + encrypted_password VARCHAR(255), + email_confirmed_at TIMESTAMPTZ, + invited_at TIMESTAMPTZ, + confirmation_token VARCHAR(255), + confirmation_sent_at TIMESTAMPTZ, + recovery_token VARCHAR(255), + recovery_sent_at TIMESTAMPTZ, + email_change_token_new VARCHAR(255), + email_change VARCHAR(255), + email_change_sent_at TIMESTAMPTZ, + last_sign_in_at TIMESTAMPTZ, + raw_app_meta_data JSONB, + raw_user_meta_data JSONB, + is_super_admin BOOLEAN, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + phone VARCHAR(15) UNIQUE, + phone_confirmed_at TIMESTAMPTZ, + phone_change VARCHAR(15), + phone_change_token VARCHAR(255), + phone_change_sent_at TIMESTAMPTZ, + confirmed_at TIMESTAMPTZ GENERATED ALWAYS AS (LEAST(email_confirmed_at, phone_confirmed_at)) STORED, + email_change_token_current VARCHAR(255), + email_change_confirm_status SMALLINT DEFAULT 0, + banned_until TIMESTAMPTZ, + reauthentication_token VARCHAR(255), + reauthentication_sent_at TIMESTAMPTZ, + is_sso_user BOOLEAN DEFAULT FALSE NOT NULL, + deleted_at TIMESTAMPTZ, + is_anonymous BOOLEAN DEFAULT FALSE NOT NULL +); + +-- Indexes for auth.users +CREATE INDEX IF NOT EXISTS users_instance_id_idx ON auth.users(instance_id); +CREATE INDEX IF NOT EXISTS users_email_idx ON auth.users(email); + +-- Grant permissions on auth.users +GRANT ALL ON auth.users TO supabase_auth_admin; +GRANT ALL ON auth.users TO postgres; +GRANT SELECT ON auth.users TO anon, authenticated; + +-- Set search path to include both public and auth +ALTER DATABASE postgres SET search_path TO public, extensions;