diff --git a/migrations/6.1.0_enterprise_suite/down.sql b/migrations/6.1.0_enterprise_suite/down.sql index 3f951e0b..80bf153d 100644 --- a/migrations/6.1.0_enterprise_suite/down.sql +++ b/migrations/6.1.0_enterprise_suite/down.sql @@ -1,6 +1,181 @@ -- Rollback Migration: 6.1.0 Enterprise Features -- WARNING: This will delete all enterprise feature data! -- NOTE: TABLES AND INDEXES ONLY - No views, triggers, or functions per project standards +-- Includes rollback for: config ID fixes, connected accounts, bot hierarchy, monitors + +-- ============================================================================ +-- ROLLBACK: Bot Hierarchy and Monitors (from 6.1.3) +-- ============================================================================ + +-- Drop comments first +COMMENT ON TABLE public.user_organizations IS NULL; +COMMENT ON TABLE public.email_received_events IS NULL; +COMMENT ON TABLE public.folder_change_events IS NULL; +COMMENT ON TABLE public.folder_monitors IS NULL; +COMMENT ON TABLE public.email_monitors IS NULL; +COMMENT ON COLUMN public.bots.inherit_parent_config IS NULL; +COMMENT ON COLUMN public.bots.enabled_tabs_json IS NULL; +COMMENT ON COLUMN public.bots.parent_bot_id IS NULL; +COMMENT ON TABLE public.system_automations IS NULL; + +-- Drop user organizations table +DROP INDEX IF EXISTS idx_user_orgs_default; +DROP INDEX IF EXISTS idx_user_orgs_org; +DROP INDEX IF EXISTS idx_user_orgs_user; +DROP TABLE IF EXISTS public.user_organizations; + +-- Drop email received events table +DROP INDEX IF EXISTS idx_email_events_received; +DROP INDEX IF EXISTS idx_email_events_processed; +DROP INDEX IF EXISTS idx_email_events_monitor; +DROP TABLE IF EXISTS public.email_received_events; + +-- Drop folder change events table +DROP INDEX IF EXISTS idx_folder_events_created; +DROP INDEX IF EXISTS idx_folder_events_processed; +DROP INDEX IF EXISTS idx_folder_events_monitor; +DROP TABLE IF EXISTS public.folder_change_events; + +-- Drop folder monitors table +DROP INDEX IF EXISTS idx_folder_monitors_account_email; +DROP INDEX IF EXISTS idx_folder_monitors_active; +DROP INDEX IF EXISTS idx_folder_monitors_provider; +DROP INDEX IF EXISTS idx_folder_monitors_bot_id; +DROP TABLE IF EXISTS public.folder_monitors; + +-- Drop email monitors table +DROP INDEX IF EXISTS idx_email_monitors_active; +DROP INDEX IF EXISTS idx_email_monitors_email; +DROP INDEX IF EXISTS idx_email_monitors_bot_id; +DROP TABLE IF EXISTS public.email_monitors; + +-- Remove bot hierarchy columns +DROP INDEX IF EXISTS idx_bots_parent_bot_id; +ALTER TABLE public.bots DROP COLUMN IF EXISTS inherit_parent_config; +ALTER TABLE public.bots DROP COLUMN IF EXISTS enabled_tabs_json; +ALTER TABLE public.bots DROP COLUMN IF EXISTS parent_bot_id; + +-- ============================================================================ +-- ROLLBACK: Connected Accounts (from 6.1.2) +-- ============================================================================ + +DROP INDEX IF EXISTS idx_account_sync_items_unique; +DROP INDEX IF EXISTS idx_account_sync_items_embedding; +DROP INDEX IF EXISTS idx_account_sync_items_date; +DROP INDEX IF EXISTS idx_account_sync_items_type; +DROP INDEX IF EXISTS idx_account_sync_items_account; +DROP TABLE IF EXISTS account_sync_items; + +DROP INDEX IF EXISTS idx_session_account_assoc_unique; +DROP INDEX IF EXISTS idx_session_account_assoc_active; +DROP INDEX IF EXISTS idx_session_account_assoc_account; +DROP INDEX IF EXISTS idx_session_account_assoc_session; +DROP TABLE IF EXISTS session_account_associations; + +DROP INDEX IF EXISTS idx_connected_accounts_bot_email; +DROP INDEX IF EXISTS idx_connected_accounts_status; +DROP INDEX IF EXISTS idx_connected_accounts_provider; +DROP INDEX IF EXISTS idx_connected_accounts_email; +DROP INDEX IF EXISTS idx_connected_accounts_user_id; +DROP INDEX IF EXISTS idx_connected_accounts_bot_id; +DROP TABLE IF EXISTS connected_accounts; + +-- ============================================================================ +-- ROLLBACK: Config ID Type Fixes (from 6.1.1) +-- Revert UUID columns back to TEXT +-- ============================================================================ + +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'bot_configuration' + AND column_name = 'id' + AND data_type = 'uuid') THEN + ALTER TABLE bot_configuration + ALTER COLUMN id TYPE TEXT USING id::text; + END IF; +END $$; + +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'server_configuration' + AND column_name = 'id' + AND data_type = 'uuid') THEN + ALTER TABLE server_configuration + ALTER COLUMN id TYPE TEXT USING id::text; + END IF; +END $$; + +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'tenant_configuration' + AND column_name = 'id' + AND data_type = 'uuid') THEN + ALTER TABLE tenant_configuration + ALTER COLUMN id TYPE TEXT USING id::text; + END IF; +END $$; + +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'model_configurations' + AND column_name = 'id' + AND data_type = 'uuid') THEN + ALTER TABLE model_configurations + ALTER COLUMN id TYPE TEXT USING id::text; + END IF; +END $$; + +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'connection_configurations' + AND column_name = 'id' + AND data_type = 'uuid') THEN + ALTER TABLE connection_configurations + ALTER COLUMN id TYPE TEXT USING id::text; + END IF; +END $$; + +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'component_installations' + AND column_name = 'id' + AND data_type = 'uuid') THEN + ALTER TABLE component_installations + ALTER COLUMN id TYPE TEXT USING id::text; + END IF; +END $$; + +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'component_logs' + AND column_name = 'id' + AND data_type = 'uuid') THEN + ALTER TABLE component_logs + ALTER COLUMN id TYPE TEXT USING id::text; + END IF; +END $$; + +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'gbot_config_sync' + AND column_name = 'id' + AND data_type = 'uuid') THEN + ALTER TABLE gbot_config_sync + ALTER COLUMN id TYPE TEXT USING id::text; + END IF; +END $$; + +-- ============================================================================ +-- ROLLBACK: Original 6.1.0 Enterprise Features +-- ============================================================================ -- Drop test support tables DROP TABLE IF EXISTS test_execution_logs; diff --git a/migrations/6.1.0_enterprise_suite/up.sql b/migrations/6.1.0_enterprise_suite/up.sql index 62f6264e..10ce0833 100644 --- a/migrations/6.1.0_enterprise_suite/up.sql +++ b/migrations/6.1.0_enterprise_suite/up.sql @@ -1726,3 +1726,319 @@ CREATE TRIGGER external_connections_updated_at_trigger BEFORE UPDATE ON external_connections FOR EACH ROW EXECUTE FUNCTION update_external_connections_updated_at(); + +-- ============================================================================ +-- CONFIG ID TYPE FIXES (from 6.1.1) +-- Fix columns that were created as TEXT but should be UUID +-- ============================================================================ + +-- For bot_configuration +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'bot_configuration' + AND column_name = 'id' + AND data_type = 'text') THEN + ALTER TABLE bot_configuration + ALTER COLUMN id TYPE UUID USING id::uuid; + END IF; +END $$; + +-- For server_configuration +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'server_configuration' + AND column_name = 'id' + AND data_type = 'text') THEN + ALTER TABLE server_configuration + ALTER COLUMN id TYPE UUID USING id::uuid; + END IF; +END $$; + +-- For tenant_configuration +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'tenant_configuration' + AND column_name = 'id' + AND data_type = 'text') THEN + ALTER TABLE tenant_configuration + ALTER COLUMN id TYPE UUID USING id::uuid; + END IF; +END $$; + +-- For model_configurations +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'model_configurations' + AND column_name = 'id' + AND data_type = 'text') THEN + ALTER TABLE model_configurations + ALTER COLUMN id TYPE UUID USING id::uuid; + END IF; +END $$; + +-- For connection_configurations +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'connection_configurations' + AND column_name = 'id' + AND data_type = 'text') THEN + ALTER TABLE connection_configurations + ALTER COLUMN id TYPE UUID USING id::uuid; + END IF; +END $$; + +-- For component_installations +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'component_installations' + AND column_name = 'id' + AND data_type = 'text') THEN + ALTER TABLE component_installations + ALTER COLUMN id TYPE UUID USING id::uuid; + END IF; +END $$; + +-- For component_logs +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'component_logs' + AND column_name = 'id' + AND data_type = 'text') THEN + ALTER TABLE component_logs + ALTER COLUMN id TYPE UUID USING id::uuid; + END IF; +END $$; + +-- For gbot_config_sync +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'gbot_config_sync' + AND column_name = 'id' + AND data_type = 'text') THEN + ALTER TABLE gbot_config_sync + ALTER COLUMN id TYPE UUID USING id::uuid; + END IF; +END $$; + +-- ============================================================================ +-- CONNECTED ACCOUNTS (from 6.1.2) +-- OAuth connected accounts for email providers +-- ============================================================================ + +CREATE TABLE IF NOT EXISTS connected_accounts ( + id UUID PRIMARY KEY, + bot_id UUID NOT NULL REFERENCES bots(id) ON DELETE CASCADE, + user_id UUID, + email TEXT NOT NULL, + provider TEXT NOT NULL, + account_type TEXT NOT NULL DEFAULT 'email', + access_token TEXT NOT NULL, + refresh_token TEXT, + token_expires_at TIMESTAMPTZ, + scopes TEXT, + status TEXT NOT NULL DEFAULT 'active', + sync_enabled BOOLEAN NOT NULL DEFAULT true, + sync_interval_seconds INTEGER NOT NULL DEFAULT 300, + last_sync_at TIMESTAMPTZ, + last_sync_status TEXT, + last_sync_error TEXT, + metadata_json TEXT DEFAULT '{}', + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE INDEX IF NOT EXISTS idx_connected_accounts_bot_id ON connected_accounts(bot_id); +CREATE INDEX IF NOT EXISTS idx_connected_accounts_user_id ON connected_accounts(user_id); +CREATE INDEX IF NOT EXISTS idx_connected_accounts_email ON connected_accounts(email); +CREATE INDEX IF NOT EXISTS idx_connected_accounts_provider ON connected_accounts(provider); +CREATE INDEX IF NOT EXISTS idx_connected_accounts_status ON connected_accounts(status); +CREATE UNIQUE INDEX IF NOT EXISTS idx_connected_accounts_bot_email ON connected_accounts(bot_id, email); + +CREATE TABLE IF NOT EXISTS session_account_associations ( + id UUID PRIMARY KEY, + session_id UUID NOT NULL, + bot_id UUID NOT NULL REFERENCES bots(id) ON DELETE CASCADE, + account_id UUID NOT NULL REFERENCES connected_accounts(id) ON DELETE CASCADE, + email TEXT NOT NULL, + provider TEXT NOT NULL, + qdrant_collection TEXT NOT NULL, + is_active BOOLEAN NOT NULL DEFAULT true, + added_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + added_by_tool TEXT +); + +CREATE INDEX IF NOT EXISTS idx_session_account_assoc_session ON session_account_associations(session_id); +CREATE INDEX IF NOT EXISTS idx_session_account_assoc_account ON session_account_associations(account_id); +CREATE INDEX IF NOT EXISTS idx_session_account_assoc_active ON session_account_associations(session_id, is_active); +CREATE UNIQUE INDEX IF NOT EXISTS idx_session_account_assoc_unique ON session_account_associations(session_id, account_id); + +CREATE TABLE IF NOT EXISTS account_sync_items ( + id UUID PRIMARY KEY, + account_id UUID NOT NULL REFERENCES connected_accounts(id) ON DELETE CASCADE, + item_type TEXT NOT NULL, + item_id TEXT NOT NULL, + subject TEXT, + content_preview TEXT, + sender TEXT, + recipients TEXT, + item_date TIMESTAMPTZ, + folder TEXT, + labels TEXT, + has_attachments BOOLEAN DEFAULT false, + qdrant_point_id TEXT, + embedding_status TEXT DEFAULT 'pending', + metadata_json TEXT DEFAULT '{}', + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE INDEX IF NOT EXISTS idx_account_sync_items_account ON account_sync_items(account_id); +CREATE INDEX IF NOT EXISTS idx_account_sync_items_type ON account_sync_items(item_type); +CREATE INDEX IF NOT EXISTS idx_account_sync_items_date ON account_sync_items(item_date); +CREATE INDEX IF NOT EXISTS idx_account_sync_items_embedding ON account_sync_items(embedding_status); +CREATE UNIQUE INDEX IF NOT EXISTS idx_account_sync_items_unique ON account_sync_items(account_id, item_type, item_id); + +-- ============================================================================ +-- BOT HIERARCHY AND MONITORS (from 6.1.3) +-- Sub-bots, ON EMAIL triggers, ON CHANGE triggers +-- ============================================================================ + +-- Bot Hierarchy: Add parent_bot_id to support sub-bots +ALTER TABLE public.bots +ADD COLUMN IF NOT EXISTS parent_bot_id UUID REFERENCES public.bots(id) ON DELETE SET NULL; + +-- Index for efficient hierarchy queries +CREATE INDEX IF NOT EXISTS idx_bots_parent_bot_id ON public.bots(parent_bot_id); + +-- Bot enabled tabs configuration (which UI tabs are enabled for this bot) +ALTER TABLE public.bots +ADD COLUMN IF NOT EXISTS enabled_tabs_json TEXT DEFAULT '["chat"]'; + +-- Bot configuration inheritance flag +ALTER TABLE public.bots +ADD COLUMN IF NOT EXISTS inherit_parent_config BOOLEAN DEFAULT true; + +-- Email monitoring table for ON EMAIL triggers +CREATE TABLE IF NOT EXISTS public.email_monitors ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + bot_id UUID NOT NULL REFERENCES public.bots(id) ON DELETE CASCADE, + email_address VARCHAR(500) NOT NULL, + script_path VARCHAR(1000) NOT NULL, + is_active BOOLEAN DEFAULT true, + last_check_at TIMESTAMPTZ, + last_uid BIGINT DEFAULT 0, + filter_from VARCHAR(500), + filter_subject VARCHAR(500), + created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL, + updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL, + CONSTRAINT unique_bot_email UNIQUE (bot_id, email_address) +); + +CREATE INDEX IF NOT EXISTS idx_email_monitors_bot_id ON public.email_monitors(bot_id); +CREATE INDEX IF NOT EXISTS idx_email_monitors_email ON public.email_monitors(email_address); +CREATE INDEX IF NOT EXISTS idx_email_monitors_active ON public.email_monitors(is_active) WHERE is_active = true; + +-- Folder monitoring table for ON CHANGE triggers (GDrive, OneDrive, Dropbox) +-- Uses account:// syntax: account://user@gmail.com/path or gdrive:///path +CREATE TABLE IF NOT EXISTS public.folder_monitors ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + bot_id UUID NOT NULL REFERENCES public.bots(id) ON DELETE CASCADE, + provider VARCHAR(50) NOT NULL, -- 'gdrive', 'onedrive', 'dropbox', 'local' + account_email VARCHAR(500), -- Email from account:// path (e.g., user@gmail.com) + folder_path VARCHAR(2000) NOT NULL, + folder_id VARCHAR(500), -- Provider-specific folder ID + script_path VARCHAR(1000) NOT NULL, + is_active BOOLEAN DEFAULT true, + watch_subfolders BOOLEAN DEFAULT true, + last_check_at TIMESTAMPTZ, + last_change_token VARCHAR(500), -- Provider-specific change token/page token + event_types_json TEXT DEFAULT '["create", "modify", "delete"]', + created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL, + updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL, + CONSTRAINT unique_bot_folder UNIQUE (bot_id, provider, folder_path) +); + +CREATE INDEX IF NOT EXISTS idx_folder_monitors_bot_id ON public.folder_monitors(bot_id); +CREATE INDEX IF NOT EXISTS idx_folder_monitors_provider ON public.folder_monitors(provider); +CREATE INDEX IF NOT EXISTS idx_folder_monitors_active ON public.folder_monitors(is_active) WHERE is_active = true; +CREATE INDEX IF NOT EXISTS idx_folder_monitors_account_email ON public.folder_monitors(account_email); + +-- Folder change events log +CREATE TABLE IF NOT EXISTS public.folder_change_events ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + monitor_id UUID NOT NULL REFERENCES public.folder_monitors(id) ON DELETE CASCADE, + event_type VARCHAR(50) NOT NULL, -- 'create', 'modify', 'delete', 'rename', 'move' + file_path VARCHAR(2000) NOT NULL, + file_id VARCHAR(500), + file_name VARCHAR(500), + file_size BIGINT, + mime_type VARCHAR(255), + old_path VARCHAR(2000), -- For rename/move events + processed BOOLEAN DEFAULT false, + processed_at TIMESTAMPTZ, + error_message TEXT, + created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL +); + +CREATE INDEX IF NOT EXISTS idx_folder_events_monitor ON public.folder_change_events(monitor_id); +CREATE INDEX IF NOT EXISTS idx_folder_events_processed ON public.folder_change_events(processed) WHERE processed = false; +CREATE INDEX IF NOT EXISTS idx_folder_events_created ON public.folder_change_events(created_at); + +-- Email received events log +CREATE TABLE IF NOT EXISTS public.email_received_events ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + monitor_id UUID NOT NULL REFERENCES public.email_monitors(id) ON DELETE CASCADE, + message_uid BIGINT NOT NULL, + message_id VARCHAR(500), + from_address VARCHAR(500) NOT NULL, + to_addresses_json TEXT, + subject VARCHAR(1000), + received_at TIMESTAMPTZ, + has_attachments BOOLEAN DEFAULT false, + attachments_json TEXT, + processed BOOLEAN DEFAULT false, + processed_at TIMESTAMPTZ, + error_message TEXT, + created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL +); + +CREATE INDEX IF NOT EXISTS idx_email_events_monitor ON public.email_received_events(monitor_id); +CREATE INDEX IF NOT EXISTS idx_email_events_processed ON public.email_received_events(processed) WHERE processed = false; +CREATE INDEX IF NOT EXISTS idx_email_events_received ON public.email_received_events(received_at); + +-- Add new trigger kinds to system_automations +-- TriggerKind enum: 0=Scheduled, 1=TableUpdate, 2=TableInsert, 3=TableDelete, 4=Webhook, 5=EmailReceived, 6=FolderChange +COMMENT ON TABLE public.system_automations IS 'System automations with TriggerKind: 0=Scheduled, 1=TableUpdate, 2=TableInsert, 3=TableDelete, 4=Webhook, 5=EmailReceived, 6=FolderChange'; + +-- User organization memberships (users can belong to multiple orgs) +CREATE TABLE IF NOT EXISTS public.user_organizations ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID NOT NULL REFERENCES public.users(user_id) ON DELETE CASCADE, + org_id UUID NOT NULL REFERENCES public.organizations(org_id) ON DELETE CASCADE, + role VARCHAR(50) DEFAULT 'member', -- 'owner', 'admin', 'member', 'viewer' + is_default BOOLEAN DEFAULT false, + joined_at TIMESTAMPTZ DEFAULT NOW() NOT NULL, + CONSTRAINT unique_user_org UNIQUE (user_id, org_id) +); + +CREATE INDEX IF NOT EXISTS idx_user_orgs_user ON public.user_organizations(user_id); +CREATE INDEX IF NOT EXISTS idx_user_orgs_org ON public.user_organizations(org_id); +CREATE INDEX IF NOT EXISTS idx_user_orgs_default ON public.user_organizations(user_id, is_default) WHERE is_default = true; + +-- Comments for documentation +COMMENT ON COLUMN public.bots.parent_bot_id IS 'Parent bot ID for hierarchical bot structure. NULL means root bot.'; +COMMENT ON COLUMN public.bots.enabled_tabs_json IS 'JSON array of enabled UI tabs for this bot. Root bots have all tabs.'; +COMMENT ON COLUMN public.bots.inherit_parent_config IS 'If true, inherits config from parent bot for missing values.'; +COMMENT ON TABLE public.email_monitors IS 'Email monitoring configuration for ON EMAIL triggers.'; +COMMENT ON TABLE public.folder_monitors IS 'Folder monitoring configuration for ON CHANGE triggers (GDrive, OneDrive, Dropbox).'; +COMMENT ON TABLE public.folder_change_events IS 'Log of detected folder changes to be processed by scripts.'; +COMMENT ON TABLE public.email_received_events IS 'Log of received emails to be processed by scripts.'; +COMMENT ON TABLE public.user_organizations IS 'User membership in organizations with roles.'; diff --git a/migrations/6.1.1_fix_config_id_types/down.sql b/migrations/6.1.1_fix_config_id_types/down.sql deleted file mode 100644 index b76c5c47..00000000 --- a/migrations/6.1.1_fix_config_id_types/down.sql +++ /dev/null @@ -1,98 +0,0 @@ --- Rollback Migration 6.1.1: Revert UUID columns back to TEXT --- This reverts the id columns from UUID back to TEXT - --- For bot_configuration -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'bot_configuration' - AND column_name = 'id' - AND data_type = 'uuid') THEN - ALTER TABLE bot_configuration - ALTER COLUMN id TYPE TEXT USING id::text; - END IF; -END $$; - --- For server_configuration -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'server_configuration' - AND column_name = 'id' - AND data_type = 'uuid') THEN - ALTER TABLE server_configuration - ALTER COLUMN id TYPE TEXT USING id::text; - END IF; -END $$; - --- For tenant_configuration -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'tenant_configuration' - AND column_name = 'id' - AND data_type = 'uuid') THEN - ALTER TABLE tenant_configuration - ALTER COLUMN id TYPE TEXT USING id::text; - END IF; -END $$; - --- For model_configurations -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'model_configurations' - AND column_name = 'id' - AND data_type = 'uuid') THEN - ALTER TABLE model_configurations - ALTER COLUMN id TYPE TEXT USING id::text; - END IF; -END $$; - --- For connection_configurations -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'connection_configurations' - AND column_name = 'id' - AND data_type = 'uuid') THEN - ALTER TABLE connection_configurations - ALTER COLUMN id TYPE TEXT USING id::text; - END IF; -END $$; - --- For component_installations -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'component_installations' - AND column_name = 'id' - AND data_type = 'uuid') THEN - ALTER TABLE component_installations - ALTER COLUMN id TYPE TEXT USING id::text; - END IF; -END $$; - --- For component_logs -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'component_logs' - AND column_name = 'id' - AND data_type = 'uuid') THEN - ALTER TABLE component_logs - ALTER COLUMN id TYPE TEXT USING id::text; - END IF; -END $$; - --- For gbot_config_sync -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'gbot_config_sync' - AND column_name = 'id' - AND data_type = 'uuid') THEN - ALTER TABLE gbot_config_sync - ALTER COLUMN id TYPE TEXT USING id::text; - END IF; -END $$; diff --git a/migrations/6.1.1_fix_config_id_types/up.sql b/migrations/6.1.1_fix_config_id_types/up.sql deleted file mode 100644 index 353d3cb7..00000000 --- a/migrations/6.1.1_fix_config_id_types/up.sql +++ /dev/null @@ -1,99 +0,0 @@ --- Migration 6.1.1: Fix bot_configuration id column type --- The Diesel schema expects UUID but migration 6.0.4 created it as TEXT --- This migration converts the id column from TEXT to UUID - --- For bot_configuration (main table that needs fixing) -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'bot_configuration' - AND column_name = 'id' - AND data_type = 'text') THEN - ALTER TABLE bot_configuration - ALTER COLUMN id TYPE UUID USING id::uuid; - END IF; -END $$; - --- Also fix server_configuration which has the same issue -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'server_configuration' - AND column_name = 'id' - AND data_type = 'text') THEN - ALTER TABLE server_configuration - ALTER COLUMN id TYPE UUID USING id::uuid; - END IF; -END $$; - --- Also fix tenant_configuration which has the same issue -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'tenant_configuration' - AND column_name = 'id' - AND data_type = 'text') THEN - ALTER TABLE tenant_configuration - ALTER COLUMN id TYPE UUID USING id::uuid; - END IF; -END $$; - --- Fix model_configurations -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'model_configurations' - AND column_name = 'id' - AND data_type = 'text') THEN - ALTER TABLE model_configurations - ALTER COLUMN id TYPE UUID USING id::uuid; - END IF; -END $$; - --- Fix connection_configurations -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'connection_configurations' - AND column_name = 'id' - AND data_type = 'text') THEN - ALTER TABLE connection_configurations - ALTER COLUMN id TYPE UUID USING id::uuid; - END IF; -END $$; - --- Fix component_installations -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'component_installations' - AND column_name = 'id' - AND data_type = 'text') THEN - ALTER TABLE component_installations - ALTER COLUMN id TYPE UUID USING id::uuid; - END IF; -END $$; - --- Fix component_logs -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'component_logs' - AND column_name = 'id' - AND data_type = 'text') THEN - ALTER TABLE component_logs - ALTER COLUMN id TYPE UUID USING id::uuid; - END IF; -END $$; - --- Fix gbot_config_sync -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM information_schema.columns - WHERE table_name = 'gbot_config_sync' - AND column_name = 'id' - AND data_type = 'text') THEN - ALTER TABLE gbot_config_sync - ALTER COLUMN id TYPE UUID USING id::uuid; - END IF; -END $$; diff --git a/migrations/6.1.2_connected_accounts/down.sql b/migrations/6.1.2_connected_accounts/down.sql deleted file mode 100644 index 3aaf8064..00000000 --- a/migrations/6.1.2_connected_accounts/down.sql +++ /dev/null @@ -1,20 +0,0 @@ -DROP INDEX IF EXISTS idx_account_sync_items_unique; -DROP INDEX IF EXISTS idx_account_sync_items_embedding; -DROP INDEX IF EXISTS idx_account_sync_items_date; -DROP INDEX IF EXISTS idx_account_sync_items_type; -DROP INDEX IF EXISTS idx_account_sync_items_account; -DROP TABLE IF EXISTS account_sync_items; - -DROP INDEX IF EXISTS idx_session_account_assoc_unique; -DROP INDEX IF EXISTS idx_session_account_assoc_active; -DROP INDEX IF EXISTS idx_session_account_assoc_account; -DROP INDEX IF EXISTS idx_session_account_assoc_session; -DROP TABLE IF EXISTS session_account_associations; - -DROP INDEX IF EXISTS idx_connected_accounts_bot_email; -DROP INDEX IF EXISTS idx_connected_accounts_status; -DROP INDEX IF EXISTS idx_connected_accounts_provider; -DROP INDEX IF EXISTS idx_connected_accounts_email; -DROP INDEX IF EXISTS idx_connected_accounts_user_id; -DROP INDEX IF EXISTS idx_connected_accounts_bot_id; -DROP TABLE IF EXISTS connected_accounts; diff --git a/migrations/6.1.2_connected_accounts/up.sql b/migrations/6.1.2_connected_accounts/up.sql deleted file mode 100644 index bfe125e7..00000000 --- a/migrations/6.1.2_connected_accounts/up.sql +++ /dev/null @@ -1,72 +0,0 @@ -CREATE TABLE IF NOT EXISTS connected_accounts ( - id UUID PRIMARY KEY, - bot_id UUID NOT NULL REFERENCES bots(id) ON DELETE CASCADE, - user_id UUID, - email TEXT NOT NULL, - provider TEXT NOT NULL, - account_type TEXT NOT NULL DEFAULT 'email', - access_token TEXT NOT NULL, - refresh_token TEXT, - token_expires_at TIMESTAMPTZ, - scopes TEXT, - status TEXT NOT NULL DEFAULT 'active', - sync_enabled BOOLEAN NOT NULL DEFAULT true, - sync_interval_seconds INTEGER NOT NULL DEFAULT 300, - last_sync_at TIMESTAMPTZ, - last_sync_status TEXT, - last_sync_error TEXT, - metadata_json TEXT DEFAULT '{}', - created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() -); - -CREATE INDEX IF NOT EXISTS idx_connected_accounts_bot_id ON connected_accounts(bot_id); -CREATE INDEX IF NOT EXISTS idx_connected_accounts_user_id ON connected_accounts(user_id); -CREATE INDEX IF NOT EXISTS idx_connected_accounts_email ON connected_accounts(email); -CREATE INDEX IF NOT EXISTS idx_connected_accounts_provider ON connected_accounts(provider); -CREATE INDEX IF NOT EXISTS idx_connected_accounts_status ON connected_accounts(status); -CREATE UNIQUE INDEX IF NOT EXISTS idx_connected_accounts_bot_email ON connected_accounts(bot_id, email); - -CREATE TABLE IF NOT EXISTS session_account_associations ( - id UUID PRIMARY KEY, - session_id UUID NOT NULL, - bot_id UUID NOT NULL REFERENCES bots(id) ON DELETE CASCADE, - account_id UUID NOT NULL REFERENCES connected_accounts(id) ON DELETE CASCADE, - email TEXT NOT NULL, - provider TEXT NOT NULL, - qdrant_collection TEXT NOT NULL, - is_active BOOLEAN NOT NULL DEFAULT true, - added_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - added_by_tool TEXT -); - -CREATE INDEX IF NOT EXISTS idx_session_account_assoc_session ON session_account_associations(session_id); -CREATE INDEX IF NOT EXISTS idx_session_account_assoc_account ON session_account_associations(account_id); -CREATE INDEX IF NOT EXISTS idx_session_account_assoc_active ON session_account_associations(session_id, is_active); -CREATE UNIQUE INDEX IF NOT EXISTS idx_session_account_assoc_unique ON session_account_associations(session_id, account_id); - -CREATE TABLE IF NOT EXISTS account_sync_items ( - id UUID PRIMARY KEY, - account_id UUID NOT NULL REFERENCES connected_accounts(id) ON DELETE CASCADE, - item_type TEXT NOT NULL, - item_id TEXT NOT NULL, - subject TEXT, - content_preview TEXT, - sender TEXT, - recipients TEXT, - item_date TIMESTAMPTZ, - folder TEXT, - labels TEXT, - has_attachments BOOLEAN DEFAULT false, - qdrant_point_id TEXT, - embedding_status TEXT DEFAULT 'pending', - metadata_json TEXT DEFAULT '{}', - created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() -); - -CREATE INDEX IF NOT EXISTS idx_account_sync_items_account ON account_sync_items(account_id); -CREATE INDEX IF NOT EXISTS idx_account_sync_items_type ON account_sync_items(item_type); -CREATE INDEX IF NOT EXISTS idx_account_sync_items_date ON account_sync_items(item_date); -CREATE INDEX IF NOT EXISTS idx_account_sync_items_embedding ON account_sync_items(embedding_status); -CREATE UNIQUE INDEX IF NOT EXISTS idx_account_sync_items_unique ON account_sync_items(account_id, item_type, item_id); diff --git a/migrations/6.1.3_bot_hierarchy_monitors/down.sql b/migrations/6.1.3_bot_hierarchy_monitors/down.sql deleted file mode 100644 index bae3b16b..00000000 --- a/migrations/6.1.3_bot_hierarchy_monitors/down.sql +++ /dev/null @@ -1,47 +0,0 @@ --- Drop comments first -COMMENT ON TABLE public.user_organizations IS NULL; -COMMENT ON TABLE public.email_received_events IS NULL; -COMMENT ON TABLE public.folder_change_events IS NULL; -COMMENT ON TABLE public.folder_monitors IS NULL; -COMMENT ON TABLE public.email_monitors IS NULL; -COMMENT ON COLUMN public.bots.inherit_parent_config IS NULL; -COMMENT ON COLUMN public.bots.enabled_tabs_json IS NULL; -COMMENT ON COLUMN public.bots.parent_bot_id IS NULL; -COMMENT ON TABLE public.system_automations IS NULL; - --- Drop user organizations table -DROP INDEX IF EXISTS idx_user_orgs_default; -DROP INDEX IF EXISTS idx_user_orgs_org; -DROP INDEX IF EXISTS idx_user_orgs_user; -DROP TABLE IF EXISTS public.user_organizations; - --- Drop email received events table -DROP INDEX IF EXISTS idx_email_events_received; -DROP INDEX IF EXISTS idx_email_events_processed; -DROP INDEX IF EXISTS idx_email_events_monitor; -DROP TABLE IF EXISTS public.email_received_events; - --- Drop folder change events table -DROP INDEX IF EXISTS idx_folder_events_created; -DROP INDEX IF EXISTS idx_folder_events_processed; -DROP INDEX IF EXISTS idx_folder_events_monitor; -DROP TABLE IF EXISTS public.folder_change_events; - --- Drop folder monitors table -DROP INDEX IF EXISTS idx_folder_monitors_account_email; -DROP INDEX IF EXISTS idx_folder_monitors_active; -DROP INDEX IF EXISTS idx_folder_monitors_provider; -DROP INDEX IF EXISTS idx_folder_monitors_bot_id; -DROP TABLE IF EXISTS public.folder_monitors; - --- Drop email monitors table -DROP INDEX IF EXISTS idx_email_monitors_active; -DROP INDEX IF EXISTS idx_email_monitors_email; -DROP INDEX IF EXISTS idx_email_monitors_bot_id; -DROP TABLE IF EXISTS public.email_monitors; - --- Remove bot hierarchy columns -DROP INDEX IF EXISTS idx_bots_parent_bot_id; -ALTER TABLE public.bots DROP COLUMN IF EXISTS inherit_parent_config; -ALTER TABLE public.bots DROP COLUMN IF EXISTS enabled_tabs_json; -ALTER TABLE public.bots DROP COLUMN IF EXISTS parent_bot_id; diff --git a/migrations/6.1.3_bot_hierarchy_monitors/up.sql b/migrations/6.1.3_bot_hierarchy_monitors/up.sql deleted file mode 100644 index 19388826..00000000 --- a/migrations/6.1.3_bot_hierarchy_monitors/up.sql +++ /dev/null @@ -1,131 +0,0 @@ --- Bot Hierarchy: Add parent_bot_id to support sub-bots -ALTER TABLE public.bots -ADD COLUMN IF NOT EXISTS parent_bot_id UUID REFERENCES public.bots(id) ON DELETE SET NULL; - --- Index for efficient hierarchy queries -CREATE INDEX IF NOT EXISTS idx_bots_parent_bot_id ON public.bots(parent_bot_id); - --- Bot enabled tabs configuration (which UI tabs are enabled for this bot) -ALTER TABLE public.bots -ADD COLUMN IF NOT EXISTS enabled_tabs_json TEXT DEFAULT '["chat"]'; - --- Bot configuration inheritance flag -ALTER TABLE public.bots -ADD COLUMN IF NOT EXISTS inherit_parent_config BOOLEAN DEFAULT true; - --- Email monitoring table for ON EMAIL triggers -CREATE TABLE IF NOT EXISTS public.email_monitors ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - bot_id UUID NOT NULL REFERENCES public.bots(id) ON DELETE CASCADE, - email_address VARCHAR(500) NOT NULL, - script_path VARCHAR(1000) NOT NULL, - is_active BOOLEAN DEFAULT true, - last_check_at TIMESTAMPTZ, - last_uid BIGINT DEFAULT 0, - filter_from VARCHAR(500), - filter_subject VARCHAR(500), - created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL, - updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL, - CONSTRAINT unique_bot_email UNIQUE (bot_id, email_address) -); - -CREATE INDEX IF NOT EXISTS idx_email_monitors_bot_id ON public.email_monitors(bot_id); -CREATE INDEX IF NOT EXISTS idx_email_monitors_email ON public.email_monitors(email_address); -CREATE INDEX IF NOT EXISTS idx_email_monitors_active ON public.email_monitors(is_active) WHERE is_active = true; - --- Folder monitoring table for ON CHANGE triggers (GDrive, OneDrive, Dropbox) --- Uses account:// syntax: account://user@gmail.com/path or gdrive:///path -CREATE TABLE IF NOT EXISTS public.folder_monitors ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - bot_id UUID NOT NULL REFERENCES public.bots(id) ON DELETE CASCADE, - provider VARCHAR(50) NOT NULL, -- 'gdrive', 'onedrive', 'dropbox', 'local' - account_email VARCHAR(500), -- Email from account:// path (e.g., user@gmail.com) - folder_path VARCHAR(2000) NOT NULL, - folder_id VARCHAR(500), -- Provider-specific folder ID - script_path VARCHAR(1000) NOT NULL, - is_active BOOLEAN DEFAULT true, - watch_subfolders BOOLEAN DEFAULT true, - last_check_at TIMESTAMPTZ, - last_change_token VARCHAR(500), -- Provider-specific change token/page token - event_types_json TEXT DEFAULT '["create", "modify", "delete"]', - created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL, - updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL, - CONSTRAINT unique_bot_folder UNIQUE (bot_id, provider, folder_path) -); - -CREATE INDEX IF NOT EXISTS idx_folder_monitors_bot_id ON public.folder_monitors(bot_id); -CREATE INDEX IF NOT EXISTS idx_folder_monitors_provider ON public.folder_monitors(provider); -CREATE INDEX IF NOT EXISTS idx_folder_monitors_active ON public.folder_monitors(is_active) WHERE is_active = true; -CREATE INDEX IF NOT EXISTS idx_folder_monitors_account_email ON public.folder_monitors(account_email); - --- Folder change events log -CREATE TABLE IF NOT EXISTS public.folder_change_events ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - monitor_id UUID NOT NULL REFERENCES public.folder_monitors(id) ON DELETE CASCADE, - event_type VARCHAR(50) NOT NULL, -- 'create', 'modify', 'delete', 'rename', 'move' - file_path VARCHAR(2000) NOT NULL, - file_id VARCHAR(500), - file_name VARCHAR(500), - file_size BIGINT, - mime_type VARCHAR(255), - old_path VARCHAR(2000), -- For rename/move events - processed BOOLEAN DEFAULT false, - processed_at TIMESTAMPTZ, - error_message TEXT, - created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL -); - -CREATE INDEX IF NOT EXISTS idx_folder_events_monitor ON public.folder_change_events(monitor_id); -CREATE INDEX IF NOT EXISTS idx_folder_events_processed ON public.folder_change_events(processed) WHERE processed = false; -CREATE INDEX IF NOT EXISTS idx_folder_events_created ON public.folder_change_events(created_at); - --- Email received events log -CREATE TABLE IF NOT EXISTS public.email_received_events ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - monitor_id UUID NOT NULL REFERENCES public.email_monitors(id) ON DELETE CASCADE, - message_uid BIGINT NOT NULL, - message_id VARCHAR(500), - from_address VARCHAR(500) NOT NULL, - to_addresses_json TEXT, - subject VARCHAR(1000), - received_at TIMESTAMPTZ, - has_attachments BOOLEAN DEFAULT false, - attachments_json TEXT, - processed BOOLEAN DEFAULT false, - processed_at TIMESTAMPTZ, - error_message TEXT, - created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL -); - -CREATE INDEX IF NOT EXISTS idx_email_events_monitor ON public.email_received_events(monitor_id); -CREATE INDEX IF NOT EXISTS idx_email_events_processed ON public.email_received_events(processed) WHERE processed = false; -CREATE INDEX IF NOT EXISTS idx_email_events_received ON public.email_received_events(received_at); - --- Add new trigger kinds to system_automations --- TriggerKind enum: 0=Scheduled, 1=TableUpdate, 2=TableInsert, 3=TableDelete, 4=Webhook, 5=EmailReceived, 6=FolderChange -COMMENT ON TABLE public.system_automations IS 'System automations with TriggerKind: 0=Scheduled, 1=TableUpdate, 2=TableInsert, 3=TableDelete, 4=Webhook, 5=EmailReceived, 6=FolderChange'; - --- User organization memberships (users can belong to multiple orgs) -CREATE TABLE IF NOT EXISTS public.user_organizations ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - user_id UUID NOT NULL REFERENCES public.users(user_id) ON DELETE CASCADE, - org_id UUID NOT NULL REFERENCES public.organizations(org_id) ON DELETE CASCADE, - role VARCHAR(50) DEFAULT 'member', -- 'owner', 'admin', 'member', 'viewer' - is_default BOOLEAN DEFAULT false, - joined_at TIMESTAMPTZ DEFAULT NOW() NOT NULL, - CONSTRAINT unique_user_org UNIQUE (user_id, org_id) -); - -CREATE INDEX IF NOT EXISTS idx_user_orgs_user ON public.user_organizations(user_id); -CREATE INDEX IF NOT EXISTS idx_user_orgs_org ON public.user_organizations(org_id); -CREATE INDEX IF NOT EXISTS idx_user_orgs_default ON public.user_organizations(user_id, is_default) WHERE is_default = true; - --- Comments for documentation -COMMENT ON COLUMN public.bots.parent_bot_id IS 'Parent bot ID for hierarchical bot structure. NULL means root bot.'; -COMMENT ON COLUMN public.bots.enabled_tabs_json IS 'JSON array of enabled UI tabs for this bot. Root bots have all tabs.'; -COMMENT ON COLUMN public.bots.inherit_parent_config IS 'If true, inherits config from parent bot for missing values.'; -COMMENT ON TABLE public.email_monitors IS 'Email monitoring configuration for ON EMAIL triggers.'; -COMMENT ON TABLE public.folder_monitors IS 'Folder monitoring configuration for ON CHANGE triggers (GDrive, OneDrive, Dropbox).'; -COMMENT ON TABLE public.folder_change_events IS 'Log of detected folder changes to be processed by scripts.'; -COMMENT ON TABLE public.email_received_events IS 'Log of received emails to be processed by scripts.'; -COMMENT ON TABLE public.user_organizations IS 'User membership in organizations with roles.';