CREATE EXTENSION IF NOT EXISTS pgcrypto; CREATE TABLE IF NOT EXISTS model_catalog_providers ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), provider_key text NOT NULL UNIQUE, display_name text NOT NULL, provider_type text NOT NULL DEFAULT 'openai_compatible', capability_schema jsonb NOT NULL DEFAULT '{}'::jsonb, default_rate_limit_policy jsonb NOT NULL DEFAULT '{}'::jsonb, status text NOT NULL DEFAULT 'active', metadata jsonb NOT NULL DEFAULT '{}'::jsonb, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS base_model_catalog ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), provider_id uuid REFERENCES model_catalog_providers(id) ON DELETE SET NULL, provider_key text NOT NULL, canonical_model_key text NOT NULL UNIQUE, provider_model_name text NOT NULL, model_type text NOT NULL, display_name text NOT NULL, capabilities jsonb NOT NULL DEFAULT '{}'::jsonb, base_billing_config jsonb NOT NULL DEFAULT '{}'::jsonb, default_rate_limit_policy jsonb NOT NULL DEFAULT '{}'::jsonb, pricing_version integer NOT NULL DEFAULT 1, status text NOT NULL DEFAULT 'active', metadata jsonb NOT NULL DEFAULT '{}'::jsonb, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS integration_platforms ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), provider text NOT NULL, platform_key text NOT NULL UNIQUE DEFAULT ('platform_' || replace(gen_random_uuid()::text, '-', '')), name text NOT NULL, base_url text, auth_type text NOT NULL DEFAULT 'bearer', credentials jsonb NOT NULL DEFAULT '{}'::jsonb, config jsonb NOT NULL DEFAULT '{}'::jsonb, visibility_scope text NOT NULL DEFAULT 'global', tenant_id text, tenant_key text, default_pricing_mode text NOT NULL DEFAULT 'inherit_discount', default_discount_factor numeric NOT NULL DEFAULT 1, retry_policy jsonb NOT NULL DEFAULT '{}'::jsonb, rate_limit_policy jsonb NOT NULL DEFAULT '{}'::jsonb, priority integer NOT NULL DEFAULT 100, dynamic_priority integer, status text NOT NULL DEFAULT 'enabled', disabled_reason text, cooldown_until timestamptz, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), deleted_at timestamptz ); ALTER TABLE IF EXISTS integration_platforms ADD COLUMN IF NOT EXISTS platform_key text, ADD COLUMN IF NOT EXISTS visibility_scope text NOT NULL DEFAULT 'global', ADD COLUMN IF NOT EXISTS tenant_id text, ADD COLUMN IF NOT EXISTS tenant_key text, ADD COLUMN IF NOT EXISTS default_pricing_mode text NOT NULL DEFAULT 'inherit_discount', ADD COLUMN IF NOT EXISTS default_discount_factor numeric NOT NULL DEFAULT 1, ADD COLUMN IF NOT EXISTS retry_policy jsonb NOT NULL DEFAULT '{}'::jsonb, ADD COLUMN IF NOT EXISTS rate_limit_policy jsonb NOT NULL DEFAULT '{}'::jsonb, ADD COLUMN IF NOT EXISTS dynamic_priority integer, ADD COLUMN IF NOT EXISTS disabled_reason text, ADD COLUMN IF NOT EXISTS cooldown_until timestamptz, ADD COLUMN IF NOT EXISTS deleted_at timestamptz; UPDATE integration_platforms SET platform_key = 'platform_' || replace(id::text, '-', '') WHERE platform_key IS NULL OR platform_key = ''; ALTER TABLE IF EXISTS integration_platforms ALTER COLUMN platform_key SET DEFAULT ('platform_' || replace(gen_random_uuid()::text, '-', '')), ALTER COLUMN platform_key SET NOT NULL; CREATE TABLE IF NOT EXISTS model_pricing_rules ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), scope_type text NOT NULL, scope_id uuid, resource_type text NOT NULL, unit text NOT NULL, base_price numeric NOT NULL, currency text NOT NULL DEFAULT 'resource', base_weight jsonb NOT NULL DEFAULT '{}'::jsonb, dynamic_weight jsonb NOT NULL DEFAULT '{}'::jsonb, effective_from timestamptz, effective_to timestamptz, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS gateway_user_groups ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), group_key text NOT NULL UNIQUE, name text NOT NULL, description text, source text NOT NULL DEFAULT 'gateway', priority integer NOT NULL DEFAULT 100, recharge_discount_policy jsonb NOT NULL DEFAULT '{}'::jsonb, billing_discount_policy jsonb NOT NULL DEFAULT '{}'::jsonb, rate_limit_policy jsonb NOT NULL DEFAULT '{}'::jsonb, quota_policy jsonb NOT NULL DEFAULT '{}'::jsonb, metadata jsonb NOT NULL DEFAULT '{}'::jsonb, status text NOT NULL DEFAULT 'active', created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS gateway_tenants ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), tenant_key text NOT NULL UNIQUE, source text NOT NULL DEFAULT 'gateway', external_tenant_id text, name text NOT NULL, description text, default_user_group_id uuid REFERENCES gateway_user_groups(id) ON DELETE SET NULL, plan_key text, billing_profile jsonb NOT NULL DEFAULT '{}'::jsonb, rate_limit_policy jsonb NOT NULL DEFAULT '{}'::jsonb, auth_policy jsonb NOT NULL DEFAULT '{}'::jsonb, metadata jsonb NOT NULL DEFAULT '{}'::jsonb, status text NOT NULL DEFAULT 'active', synced_at timestamptz, source_updated_at timestamptz, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), deleted_at timestamptz, UNIQUE(source, external_tenant_id) ); CREATE TABLE IF NOT EXISTS gateway_users ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), user_key text NOT NULL UNIQUE, source text NOT NULL DEFAULT 'gateway', external_user_id text, username text NOT NULL, display_name text, email text, phone text, avatar_url text, password_hash text, gateway_tenant_id uuid REFERENCES gateway_tenants(id) ON DELETE SET NULL, tenant_id text, tenant_key text, default_user_group_id uuid REFERENCES gateway_user_groups(id) ON DELETE SET NULL, roles jsonb NOT NULL DEFAULT '[]'::jsonb, auth_profile jsonb NOT NULL DEFAULT '{}'::jsonb, metadata jsonb NOT NULL DEFAULT '{}'::jsonb, status text NOT NULL DEFAULT 'active', last_login_at timestamptz, synced_at timestamptz, source_updated_at timestamptz, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), deleted_at timestamptz, UNIQUE(source, external_user_id) ); CREATE TABLE IF NOT EXISTS gateway_user_group_memberships ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), group_id uuid NOT NULL REFERENCES gateway_user_groups(id) ON DELETE CASCADE, principal_type text NOT NULL, principal_id text NOT NULL, source text NOT NULL DEFAULT 'gateway', priority integer NOT NULL DEFAULT 100, effective_from timestamptz, effective_to timestamptz, status text NOT NULL DEFAULT 'active', metadata jsonb NOT NULL DEFAULT '{}'::jsonb, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), UNIQUE(group_id, principal_type, principal_id) ); DO $$ BEGIN IF to_regclass('public.gateway_tenant_invitations') IS NOT NULL AND to_regclass('public.gateway_invitations') IS NULL THEN ALTER TABLE gateway_tenant_invitations RENAME TO gateway_invitations; END IF; END $$; DROP INDEX IF EXISTS idx_gateway_invitations_tenant; CREATE TABLE IF NOT EXISTS gateway_invitations ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), invite_code text NOT NULL UNIQUE, max_uses integer, used_count integer NOT NULL DEFAULT 0, expires_at timestamptz, status text NOT NULL DEFAULT 'active', metadata jsonb NOT NULL DEFAULT '{}'::jsonb, created_by uuid REFERENCES gateway_users(id) ON DELETE SET NULL, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() ); ALTER TABLE IF EXISTS gateway_invitations DROP COLUMN IF EXISTS tenant_id, DROP COLUMN IF EXISTS role, DROP COLUMN IF EXISTS user_group_id; CREATE TABLE IF NOT EXISTS gateway_api_keys ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), gateway_tenant_id uuid REFERENCES gateway_tenants(id) ON DELETE SET NULL, gateway_user_id uuid REFERENCES gateway_users(id) ON DELETE CASCADE, tenant_id text, tenant_key text, user_id text, key_prefix text NOT NULL, key_hash text NOT NULL UNIQUE, name text NOT NULL, scopes jsonb NOT NULL DEFAULT '[]'::jsonb, user_group_id uuid REFERENCES gateway_user_groups(id) ON DELETE SET NULL, rate_limit_policy jsonb NOT NULL DEFAULT '{}'::jsonb, quota_policy jsonb NOT NULL DEFAULT '{}'::jsonb, status text NOT NULL DEFAULT 'active', expires_at timestamptz, last_used_at timestamptz, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), deleted_at timestamptz ); CREATE TABLE IF NOT EXISTS gateway_wallet_accounts ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), gateway_tenant_id uuid REFERENCES gateway_tenants(id) ON DELETE SET NULL, gateway_user_id uuid REFERENCES gateway_users(id) ON DELETE CASCADE, tenant_id text, tenant_key text, user_id text, currency text NOT NULL DEFAULT 'resource', balance numeric NOT NULL DEFAULT 0, frozen_balance numeric NOT NULL DEFAULT 0, metadata jsonb NOT NULL DEFAULT '{}'::jsonb, status text NOT NULL DEFAULT 'active', created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), UNIQUE(gateway_user_id, currency) ); CREATE TABLE IF NOT EXISTS gateway_wallet_transactions ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), wallet_account_id uuid REFERENCES gateway_wallet_accounts(id) ON DELETE SET NULL, gateway_tenant_id uuid REFERENCES gateway_tenants(id) ON DELETE SET NULL, gateway_user_id uuid REFERENCES gateway_users(id) ON DELETE SET NULL, transaction_type text NOT NULL, amount numeric NOT NULL, balance_after numeric NOT NULL, reference_type text, reference_id text, metadata jsonb NOT NULL DEFAULT '{}'::jsonb, created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS gateway_recharge_orders ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), gateway_tenant_id uuid REFERENCES gateway_tenants(id) ON DELETE SET NULL, gateway_user_id uuid REFERENCES gateway_users(id) ON DELETE SET NULL, tenant_id text, tenant_key text, user_id text, order_no text NOT NULL UNIQUE, amount numeric NOT NULL, bonus_amount numeric NOT NULL DEFAULT 0, currency text NOT NULL DEFAULT 'resource', payment_provider text, payment_payload jsonb NOT NULL DEFAULT '{}'::jsonb, status text NOT NULL DEFAULT 'pending', paid_at timestamptz, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS platform_models ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), platform_id uuid REFERENCES integration_platforms(id) ON DELETE CASCADE, base_model_id uuid REFERENCES base_model_catalog(id) ON DELETE SET NULL, model_name text NOT NULL, model_alias text, model_type text NOT NULL, display_name text NOT NULL DEFAULT '', capability_override jsonb NOT NULL DEFAULT '{}'::jsonb, capabilities jsonb NOT NULL DEFAULT '{}'::jsonb, pricing_mode text NOT NULL DEFAULT 'inherit_discount', discount_factor numeric, billing_config_override jsonb NOT NULL DEFAULT '{}'::jsonb, billing_config jsonb NOT NULL DEFAULT '{}'::jsonb, permission_config jsonb NOT NULL DEFAULT '{}'::jsonb, retry_policy jsonb NOT NULL DEFAULT '{}'::jsonb, rate_limit_policy jsonb NOT NULL DEFAULT '{}'::jsonb, enabled boolean NOT NULL DEFAULT true, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), UNIQUE(platform_id, model_name, model_type) ); ALTER TABLE IF EXISTS platform_models ADD COLUMN IF NOT EXISTS base_model_id uuid REFERENCES base_model_catalog(id) ON DELETE SET NULL, ADD COLUMN IF NOT EXISTS model_alias text, ADD COLUMN IF NOT EXISTS capability_override jsonb NOT NULL DEFAULT '{}'::jsonb, ADD COLUMN IF NOT EXISTS pricing_mode text NOT NULL DEFAULT 'inherit_discount', ADD COLUMN IF NOT EXISTS discount_factor numeric, ADD COLUMN IF NOT EXISTS billing_config_override jsonb NOT NULL DEFAULT '{}'::jsonb, ADD COLUMN IF NOT EXISTS permission_config jsonb NOT NULL DEFAULT '{}'::jsonb, ADD COLUMN IF NOT EXISTS retry_policy jsonb NOT NULL DEFAULT '{}'::jsonb, ADD COLUMN IF NOT EXISTS rate_limit_policy jsonb NOT NULL DEFAULT '{}'::jsonb; CREATE TABLE IF NOT EXISTS gateway_tasks ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), external_task_id text, kind text NOT NULL, run_mode text NOT NULL DEFAULT 'production', user_id text NOT NULL, gateway_user_id uuid REFERENCES gateway_users(id) ON DELETE SET NULL, user_source text NOT NULL DEFAULT 'gateway', gateway_tenant_id uuid REFERENCES gateway_tenants(id) ON DELETE SET NULL, tenant_id text, tenant_key text, api_key_id text, user_group_id uuid REFERENCES gateway_user_groups(id) ON DELETE SET NULL, user_group_key text, user_group_policy_snapshot jsonb NOT NULL DEFAULT '{}'::jsonb, model text NOT NULL, model_type text, request jsonb NOT NULL DEFAULT '{}'::jsonb, normalized_request jsonb NOT NULL DEFAULT '{}'::jsonb, status text NOT NULL DEFAULT 'queued', queue_key text NOT NULL DEFAULT 'default', priority integer NOT NULL DEFAULT 100, idempotency_key text, remote_task_id text, remote_task_payload jsonb, simulation_profile jsonb, simulation_seed text, locked_by text, locked_at timestamptz, heartbeat_at timestamptz, next_run_at timestamptz NOT NULL DEFAULT now(), attempt_count integer NOT NULL DEFAULT 0, max_attempts integer NOT NULL DEFAULT 1, result jsonb, billings jsonb, error text, error_code text, error_message text, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), finished_at timestamptz ); ALTER TABLE IF EXISTS gateway_tasks ADD COLUMN IF NOT EXISTS external_task_id text, ADD COLUMN IF NOT EXISTS run_mode text NOT NULL DEFAULT 'production', ADD COLUMN IF NOT EXISTS gateway_user_id uuid REFERENCES gateway_users(id) ON DELETE SET NULL, ADD COLUMN IF NOT EXISTS user_source text NOT NULL DEFAULT 'gateway', ADD COLUMN IF NOT EXISTS gateway_tenant_id uuid REFERENCES gateway_tenants(id) ON DELETE SET NULL, ADD COLUMN IF NOT EXISTS tenant_key text, ADD COLUMN IF NOT EXISTS api_key_id text, ADD COLUMN IF NOT EXISTS user_group_id uuid REFERENCES gateway_user_groups(id) ON DELETE SET NULL, ADD COLUMN IF NOT EXISTS user_group_key text, ADD COLUMN IF NOT EXISTS user_group_policy_snapshot jsonb NOT NULL DEFAULT '{}'::jsonb, ADD COLUMN IF NOT EXISTS model_type text, ADD COLUMN IF NOT EXISTS normalized_request jsonb NOT NULL DEFAULT '{}'::jsonb, ADD COLUMN IF NOT EXISTS queue_key text NOT NULL DEFAULT 'default', ADD COLUMN IF NOT EXISTS priority integer NOT NULL DEFAULT 100, ADD COLUMN IF NOT EXISTS idempotency_key text, ADD COLUMN IF NOT EXISTS remote_task_id text, ADD COLUMN IF NOT EXISTS remote_task_payload jsonb, ADD COLUMN IF NOT EXISTS simulation_profile jsonb, ADD COLUMN IF NOT EXISTS simulation_seed text, ADD COLUMN IF NOT EXISTS locked_by text, ADD COLUMN IF NOT EXISTS locked_at timestamptz, ADD COLUMN IF NOT EXISTS heartbeat_at timestamptz, ADD COLUMN IF NOT EXISTS next_run_at timestamptz NOT NULL DEFAULT now(), ADD COLUMN IF NOT EXISTS attempt_count integer NOT NULL DEFAULT 0, ADD COLUMN IF NOT EXISTS max_attempts integer NOT NULL DEFAULT 1, ADD COLUMN IF NOT EXISTS error_code text, ADD COLUMN IF NOT EXISTS error_message text, ADD COLUMN IF NOT EXISTS finished_at timestamptz; CREATE TABLE IF NOT EXISTS gateway_task_attempts ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), task_id uuid NOT NULL REFERENCES gateway_tasks(id) ON DELETE CASCADE, attempt_no integer NOT NULL, platform_id uuid REFERENCES integration_platforms(id) ON DELETE SET NULL, platform_model_id uuid REFERENCES platform_models(id) ON DELETE SET NULL, client_id text, queue_key text NOT NULL, status text NOT NULL, retryable boolean NOT NULL DEFAULT false, simulated boolean NOT NULL DEFAULT false, remote_task_id text, request_snapshot jsonb NOT NULL DEFAULT '{}'::jsonb, response_snapshot jsonb, error_code text, error_message text, started_at timestamptz NOT NULL DEFAULT now(), finished_at timestamptz, UNIQUE(task_id, attempt_no) ); CREATE TABLE IF NOT EXISTS gateway_task_events ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), task_id uuid NOT NULL REFERENCES gateway_tasks(id) ON DELETE CASCADE, seq bigint NOT NULL, event_type text NOT NULL, status text, phase text, progress numeric, message text, payload jsonb NOT NULL DEFAULT '{}'::jsonb, simulated boolean NOT NULL DEFAULT false, created_at timestamptz NOT NULL DEFAULT now(), UNIQUE(task_id, seq) ); CREATE TABLE IF NOT EXISTS gateway_task_callback_outbox ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), task_id uuid NOT NULL REFERENCES gateway_tasks(id) ON DELETE CASCADE, event_id uuid REFERENCES gateway_task_events(id) ON DELETE SET NULL, seq bigint NOT NULL, callback_url text NOT NULL, payload jsonb NOT NULL, status text NOT NULL DEFAULT 'pending', attempts integer NOT NULL DEFAULT 0, next_attempt_at timestamptz NOT NULL DEFAULT now(), last_error text, delivered_at timestamptz, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), UNIQUE(task_id, seq, callback_url) ); CREATE TABLE IF NOT EXISTS runtime_client_states ( client_id text PRIMARY KEY, platform_id uuid REFERENCES integration_platforms(id) ON DELETE SET NULL, provider text NOT NULL, method_name text NOT NULL, queue_key text NOT NULL, running_count integer NOT NULL DEFAULT 0, waiting_count integer NOT NULL DEFAULT 0, limiter_ratio numeric NOT NULL DEFAULT 0, cooldown_until timestamptz, last_assigned_at timestamptz, last_error text, updated_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS gateway_upload_assets ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), task_id uuid REFERENCES gateway_tasks(id) ON DELETE SET NULL, source text NOT NULL, server_main_file_id text, url text NOT NULL, object_key text, content_type text, size bigint, checksum text, metadata jsonb NOT NULL DEFAULT '{}'::jsonb, created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS gateway_retry_policies ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), scope_type text NOT NULL, scope_key text NOT NULL, enabled boolean NOT NULL DEFAULT true, policy jsonb NOT NULL DEFAULT '{}'::jsonb, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), UNIQUE(scope_type, scope_key) ); CREATE TABLE IF NOT EXISTS gateway_rate_limit_policies ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), scope_type text NOT NULL, scope_key text NOT NULL, policy jsonb NOT NULL DEFAULT '{}'::jsonb, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), UNIQUE(scope_type, scope_key) ); CREATE TABLE IF NOT EXISTS gateway_rate_limit_counters ( scope_type text NOT NULL, scope_key text NOT NULL, metric text NOT NULL, window_start timestamptz NOT NULL, limit_value numeric NOT NULL, used_value numeric NOT NULL DEFAULT 0, reserved_value numeric NOT NULL DEFAULT 0, reset_at timestamptz NOT NULL, updated_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY(scope_type, scope_key, metric, window_start) ); CREATE TABLE IF NOT EXISTS gateway_concurrency_leases ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), task_id uuid NOT NULL REFERENCES gateway_tasks(id) ON DELETE CASCADE, attempt_id uuid REFERENCES gateway_task_attempts(id) ON DELETE SET NULL, scope_type text NOT NULL, scope_key text NOT NULL, lease_value numeric NOT NULL DEFAULT 1, acquired_at timestamptz NOT NULL DEFAULT now(), expires_at timestamptz NOT NULL, released_at timestamptz ); ALTER TABLE IF EXISTS settlement_outbox ADD COLUMN IF NOT EXISTS event_type text NOT NULL DEFAULT 'task.settlement.requested', ADD COLUMN IF NOT EXISTS payload jsonb NOT NULL DEFAULT '{}'::jsonb, ADD COLUMN IF NOT EXISTS status text NOT NULL DEFAULT 'pending', ADD COLUMN IF NOT EXISTS attempts integer NOT NULL DEFAULT 0, ADD COLUMN IF NOT EXISTS next_attempt_at timestamptz NOT NULL DEFAULT now(), ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now(); CREATE TABLE IF NOT EXISTS settlement_outbox ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), task_id uuid NOT NULL REFERENCES gateway_tasks(id) ON DELETE CASCADE, event_type text NOT NULL DEFAULT 'task.settlement.requested', payload jsonb NOT NULL, status text NOT NULL DEFAULT 'pending', attempts integer NOT NULL DEFAULT 0, next_attempt_at timestamptz NOT NULL DEFAULT now(), created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), UNIQUE(task_id, event_type) ); CREATE UNIQUE INDEX IF NOT EXISTS uniq_integration_platforms_platform_key ON integration_platforms(platform_key); CREATE INDEX IF NOT EXISTS idx_model_catalog_provider_status ON model_catalog_providers(status); CREATE INDEX IF NOT EXISTS idx_base_model_catalog_provider ON base_model_catalog(provider_key, model_type, status); CREATE INDEX IF NOT EXISTS idx_base_model_catalog_capabilities ON base_model_catalog USING gin(capabilities); CREATE INDEX IF NOT EXISTS idx_integration_platforms_provider_status ON integration_platforms(provider, status); CREATE INDEX IF NOT EXISTS idx_integration_platforms_status_priority ON integration_platforms(status, priority, dynamic_priority); CREATE INDEX IF NOT EXISTS idx_integration_platforms_cooldown ON integration_platforms(cooldown_until); CREATE INDEX IF NOT EXISTS idx_integration_platforms_tenant_scope ON integration_platforms(visibility_scope, tenant_id, tenant_key, status); CREATE INDEX IF NOT EXISTS idx_model_pricing_scope ON model_pricing_rules(scope_type, scope_id, resource_type); CREATE INDEX IF NOT EXISTS idx_model_pricing_effective ON model_pricing_rules(effective_from, effective_to); CREATE INDEX IF NOT EXISTS idx_gateway_user_groups_status_priority ON gateway_user_groups(status, priority); CREATE INDEX IF NOT EXISTS idx_gateway_tenants_source_external ON gateway_tenants(source, external_tenant_id) WHERE external_tenant_id IS NOT NULL; CREATE INDEX IF NOT EXISTS idx_gateway_tenants_status ON gateway_tenants(status, created_at DESC); CREATE INDEX IF NOT EXISTS idx_gateway_users_source_external ON gateway_users(source, external_user_id) WHERE external_user_id IS NOT NULL; CREATE INDEX IF NOT EXISTS idx_gateway_users_status ON gateway_users(status, created_at DESC); CREATE INDEX IF NOT EXISTS idx_gateway_users_tenant ON gateway_users(tenant_id, tenant_key, status); CREATE INDEX IF NOT EXISTS idx_user_group_membership_principal ON gateway_user_group_memberships(principal_type, principal_id, status); CREATE INDEX IF NOT EXISTS idx_user_group_membership_effective ON gateway_user_group_memberships(effective_from, effective_to); CREATE INDEX IF NOT EXISTS idx_gateway_invitations_status ON gateway_invitations(status, created_at DESC); CREATE INDEX IF NOT EXISTS idx_gateway_invitations_expiry ON gateway_invitations(expires_at); CREATE INDEX IF NOT EXISTS idx_gateway_api_keys_prefix ON gateway_api_keys(key_prefix, status); CREATE INDEX IF NOT EXISTS idx_gateway_api_keys_user ON gateway_api_keys(gateway_user_id, status); CREATE INDEX IF NOT EXISTS idx_gateway_wallet_accounts_tenant ON gateway_wallet_accounts(gateway_tenant_id, status); CREATE INDEX IF NOT EXISTS idx_gateway_wallet_transactions_user ON gateway_wallet_transactions(gateway_user_id, created_at DESC); CREATE INDEX IF NOT EXISTS idx_gateway_recharge_orders_user ON gateway_recharge_orders(gateway_user_id, created_at DESC); CREATE INDEX IF NOT EXISTS idx_platform_models_base ON platform_models(base_model_id); CREATE INDEX IF NOT EXISTS idx_platform_models_lookup ON platform_models(model_type, model_name, enabled); CREATE INDEX IF NOT EXISTS idx_platform_models_alias ON platform_models(model_alias); CREATE INDEX IF NOT EXISTS idx_platform_models_capabilities ON platform_models USING gin(capabilities); CREATE UNIQUE INDEX IF NOT EXISTS uniq_platform_models_model ON platform_models(platform_id, model_name, model_type); CREATE INDEX IF NOT EXISTS idx_gateway_tasks_queue ON gateway_tasks(status, next_run_at, priority, created_at); CREATE INDEX IF NOT EXISTS idx_gateway_tasks_lease ON gateway_tasks(status, heartbeat_at); CREATE INDEX IF NOT EXISTS idx_gateway_tasks_user_created ON gateway_tasks(user_id, created_at DESC); CREATE INDEX IF NOT EXISTS idx_gateway_tasks_external ON gateway_tasks(external_task_id); CREATE UNIQUE INDEX IF NOT EXISTS uniq_gateway_tasks_idempotency ON gateway_tasks(user_id, idempotency_key) WHERE idempotency_key IS NOT NULL; CREATE INDEX IF NOT EXISTS idx_gateway_attempts_task ON gateway_task_attempts(task_id); CREATE INDEX IF NOT EXISTS idx_gateway_attempts_client ON gateway_task_attempts(client_id, started_at DESC); CREATE INDEX IF NOT EXISTS idx_gateway_events_task_created ON gateway_task_events(task_id, created_at); CREATE INDEX IF NOT EXISTS idx_task_callback_outbox_pending ON gateway_task_callback_outbox(status, next_attempt_at); CREATE INDEX IF NOT EXISTS idx_task_callback_outbox_task ON gateway_task_callback_outbox(task_id, seq); CREATE INDEX IF NOT EXISTS idx_runtime_client_queue ON runtime_client_states(queue_key, cooldown_until); CREATE INDEX IF NOT EXISTS idx_runtime_client_platform ON runtime_client_states(platform_id); CREATE INDEX IF NOT EXISTS idx_gateway_upload_task ON gateway_upload_assets(task_id); CREATE INDEX IF NOT EXISTS idx_gateway_upload_file ON gateway_upload_assets(server_main_file_id); CREATE INDEX IF NOT EXISTS idx_concurrency_leases_active ON gateway_concurrency_leases(scope_type, scope_key, released_at, expires_at); CREATE INDEX IF NOT EXISTS idx_concurrency_leases_task ON gateway_concurrency_leases(task_id); CREATE UNIQUE INDEX IF NOT EXISTS uniq_settlement_outbox_task_event ON settlement_outbox(task_id, event_type);