import { QueryInterface, QueryTypes } from 'sequelize'; /** * Migration to migrate from multi-provider AI to Vertex AI Gemini * * Removes: * - AI_PROVIDER * - CLAUDE_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY * - CLAUDE_MODEL, OPENAI_MODEL, GEMINI_MODEL * - VERTEX_AI_MODEL (moved to environment variable only) * - VERTEX_AI_LOCATION (moved to environment variable only) * * Note: Both VERTEX_AI_MODEL and VERTEX_AI_LOCATION are now configured via * environment variables only (not in admin settings). * * This migration is idempotent - it will only delete configs that exist. */ export async function up(queryInterface: QueryInterface): Promise { // Remove old AI provider configurations await queryInterface.sequelize.query(` DELETE FROM admin_configurations WHERE config_key IN ( 'AI_PROVIDER', 'CLAUDE_API_KEY', 'OPENAI_API_KEY', 'GEMINI_API_KEY', 'CLAUDE_MODEL', 'OPENAI_MODEL', 'GEMINI_MODEL', 'VERTEX_AI_MODEL', 'VERTEX_AI_LOCATION' ) `, { type: QueryTypes.DELETE }); } export async function down(queryInterface: QueryInterface): Promise { // This migration only removes configs, so down migration would restore them // However, we don't restore them as they're now environment-only console.log('[Migration] Down migration skipped - AI configs are now environment-only'); // Restore old configurations (for rollback) await queryInterface.sequelize.query(` INSERT INTO admin_configurations ( config_id, config_key, config_category, config_value, value_type, display_name, description, default_value, is_editable, is_sensitive, validation_rules, ui_component, options, sort_order, requires_restart, last_modified_by, last_modified_at, created_at, updated_at ) VALUES ( gen_random_uuid(), 'AI_PROVIDER', 'AI_CONFIGURATION', 'claude', 'STRING', 'AI Provider', 'Active AI provider for conclusion generation (claude, openai, or gemini)', 'claude', true, false, '{"enum": ["claude", "openai", "gemini"], "required": true}'::jsonb, 'select', '["claude", "openai", "gemini"]'::jsonb, 22, false, NULL, NULL, NOW(), NOW() ), ( gen_random_uuid(), 'CLAUDE_API_KEY', 'AI_CONFIGURATION', '', 'STRING', 'Claude API Key', 'API key for Claude (Anthropic) - Get from console.anthropic.com', '', true, true, '{"pattern": "^sk-ant-", "minLength": 40}'::jsonb, 'input', NULL, 23, false, NULL, NULL, NOW(), NOW() ), ( gen_random_uuid(), 'OPENAI_API_KEY', 'AI_CONFIGURATION', '', 'STRING', 'OpenAI API Key', 'API key for OpenAI (GPT-4) - Get from platform.openai.com', '', true, true, '{"pattern": "^sk-", "minLength": 40}'::jsonb, 'input', NULL, 24, false, NULL, NULL, NOW(), NOW() ), ( gen_random_uuid(), 'GEMINI_API_KEY', 'AI_CONFIGURATION', '', 'STRING', 'Gemini API Key', 'API key for Gemini (Google) - Get from ai.google.dev', '', true, true, '{"minLength": 20}'::jsonb, 'input', NULL, 25, false, NULL, NULL, NOW(), NOW() ), ( gen_random_uuid(), 'CLAUDE_MODEL', 'AI_CONFIGURATION', 'claude-sonnet-4-20250514', 'STRING', 'Claude Model', 'Claude (Anthropic) model to use for AI generation', 'claude-sonnet-4-20250514', true, false, '{}'::jsonb, 'input', NULL, 27, false, NULL, NULL, NOW(), NOW() ), ( gen_random_uuid(), 'OPENAI_MODEL', 'AI_CONFIGURATION', 'gpt-4o', 'STRING', 'OpenAI Model', 'OpenAI model to use for AI generation', 'gpt-4o', true, false, '{}'::jsonb, 'input', NULL, 28, false, NULL, NULL, NOW(), NOW() ), ( gen_random_uuid(), 'GEMINI_MODEL', 'AI_CONFIGURATION', 'gemini-2.0-flash-lite', 'STRING', 'Gemini Model', 'Gemini (Google) model to use for AI generation', 'gemini-2.0-flash-lite', true, false, '{}'::jsonb, 'input', NULL, 29, false, NULL, NULL, NOW(), NOW() ) ON CONFLICT (config_key) DO NOTHING `, { type: QueryTypes.INSERT }); }