test(persistence): verify tagged 4.10.11 upgrades on sqlite and postgres

This commit is contained in:
RockChinQ
2026-10-13 13:28:03 +00:00
parent 48c6a1f536
commit 0ed2a513f9
3 changed files with 419 additions and 0 deletions
@@ -0,0 +1,39 @@
# v4.10.11 database upgrade audit
Baseline: `v4.10.11`, commit `273b8839b91cb74dfd083644efea18849a3fcee1`.
Audited target: `48c6a1f536bab421cbaab98a1e880fe767034463`.
## Changes covered
- Agent definitions, run ledger, interactions/delivery results, event logs and transcripts.
- Bot legacy pipeline routing to event bindings, followed by legacy-column removal; plugin processors.
- Workspace tenancy/ownership repairs and migration branch merges.
- Unified runner state, assistant conversations and pipeline migration snapshots.
- Passkey and TOTP credentials.
- Knowledge-base initialization/drafts and engine document identity.
- Operation traceability, monitoring links/tool calls, execution host leases and metadata text storage.
The existing migration chain covers the audited ORM changes. No additional runtime migration was required by the exercised upgrade paths.
## Added regression
`release_4_10_11_schema.json` contains immutable dialect-specific DDL exported from the tagged release ORM, rather than current metadata. The test applies historical migrations through `0023_bot_scoped_sessions` to include migration-owned objects such as pgvector, seeds representative legacy records, then runs the current persistence schema initialization twice.
Assertions cover legacy bot/pipeline preservation, converted bot event bindings, default plugin processors, initialized knowledge bases, SQLite foreign-key consistency, and missing tables/columns/indexes/constraints or column type/nullability differences against current metadata. Equivalent existing index/constraint column sets are accepted; extra migration-owned objects and removed-object diffs are not treated as missing schema. This is representative upgrade coverage, not an exhaustive test of every possible historical data value.
## Executed verification
Disposable SQLite files and an isolated PostgreSQL/pgvector container were used; no business database was changed.
- New tagged-release upgrade test: **2 passed** (SQLite and PostgreSQL), including repeated initialization.
- Existing PostgreSQL migration / release-migration / RAG identity suite: **85 passed, 4 failed** on the first completed run. The four failures were release configuration validation because the test URL omitted the required port.
- Release-migration suite rerun with explicit `:5432`: **5 passed**.
- Ruff check and format: passed for the new regression test.
Reproduce the new regression with `TEST_POSTGRES_URL` pointing to a disposable PostgreSQL/pgvector instance whose test role can create/drop databases:
```sh
pytest tests/integration/persistence/test_release_41011_upgrade.py -q
```
Without `TEST_POSTGRES_URL`, PostgreSQL is explicitly skipped rather than reported as tested.
@@ -0,0 +1,250 @@
{
"source_commit": "273b8839b91cb74dfd083644efea18849a3fcee1",
"revision": "0023_bot_scoped_sessions",
"dialects": {
"sqlite": [
"\nCREATE TABLE directory_projection_inbox (\n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tevent_uuid VARCHAR(36) NOT NULL, \n\tcursor BIGINT NOT NULL, \n\tevent_type VARCHAR(128) NOT NULL, \n\trevision BIGINT NOT NULL, \n\tfingerprint TEXT NOT NULL, \n\treceived_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tapplied_at DATETIME, \n\tPRIMARY KEY (instance_uuid, event_uuid), \n\tCONSTRAINT uq_directory_projection_inbox_cursor UNIQUE (instance_uuid, cursor), \n\tCONSTRAINT ck_directory_projection_inbox_cursor CHECK (cursor > 0), \n\tCONSTRAINT ck_directory_projection_inbox_revision CHECK (revision > 0), \n\tCONSTRAINT ck_directory_projection_inbox_fingerprint CHECK (length(fingerprint) = 64)\n)\n\n",
"CREATE INDEX ix_directory_projection_inbox_pending ON directory_projection_inbox (instance_uuid, applied_at, cursor)",
"\nCREATE TABLE directory_projection_states (\n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tcursor BIGINT DEFAULT '0' NOT NULL, \n\tsnapshot_coverage_cursor BIGINT DEFAULT '0' NOT NULL, \n\tsnapshot_fingerprint TEXT NOT NULL, \n\tlast_applied_at DATETIME NOT NULL, \n\tlease_expires_at DATETIME, \n\tPRIMARY KEY (instance_uuid), \n\tCONSTRAINT ck_directory_projection_state_cursor CHECK (cursor >= 0), \n\tCONSTRAINT ck_directory_projection_state_snapshot_coverage CHECK (snapshot_coverage_cursor >= 0 AND snapshot_coverage_cursor <= cursor), \n\tCONSTRAINT ck_directory_projection_state_fingerprint CHECK (length(snapshot_fingerprint) = 64)\n)\n\n",
"\nCREATE TABLE metadata (\n\t\"key\" VARCHAR(255) NOT NULL, \n\tvalue VARCHAR(255), \n\tPRIMARY KEY (\"key\")\n)\n\n",
"\nCREATE TABLE users (\n\tid INTEGER NOT NULL, \n\tuuid VARCHAR(36) NOT NULL, \n\tuser VARCHAR(255) NOT NULL, \n\tnormalized_email VARCHAR(320) NOT NULL, \n\tpassword VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tprojection_revision BIGINT DEFAULT '0' NOT NULL, \n\taccount_type VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tspace_account_uuid VARCHAR(255), \n\tspace_access_token TEXT, \n\tspace_refresh_token TEXT, \n\tspace_access_token_expires_at DATETIME, \n\tspace_api_key VARCHAR(255), \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (id), \n\tCONSTRAINT ck_users_normalized_email CHECK (normalized_email = trim(normalized_email) AND length(normalized_email) > 0 AND length(normalized_email) <= 320), \n\tCONSTRAINT ck_users_status CHECK (status IN ('active', 'disabled', 'deleted')), \n\tCONSTRAINT ck_users_source CHECK (source IN ('local', 'cloud_projection'))\n)\n\n",
"CREATE UNIQUE INDEX uq_users_normalized_email ON users (normalized_email)",
"CREATE UNIQUE INDEX uq_users_uuid ON users (uuid)",
"\nCREATE TABLE workspaces (\n\tuuid VARCHAR(36) NOT NULL, \n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tslug VARCHAR(255) NOT NULL, \n\ttype VARCHAR(32) DEFAULT 'team' NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\tcreated_by_account_uuid VARCHAR(36), \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tprojection_revision BIGINT DEFAULT '0' NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_workspaces_instance_slug UNIQUE (instance_uuid, slug), \n\tCONSTRAINT ck_workspaces_type CHECK (type IN ('personal', 'team')), \n\tCONSTRAINT ck_workspaces_status CHECK (status IN ('provisioning', 'active', 'suspended', 'archived', 'deleted')), \n\tCONSTRAINT ck_workspaces_source CHECK (source IN ('local', 'cloud_projection')), \n\tFOREIGN KEY(created_by_account_uuid) REFERENCES users (uuid) ON DELETE SET NULL\n)\n\n",
"CREATE INDEX ix_workspaces_instance_status ON workspaces (instance_uuid, status)",
"CREATE UNIQUE INDEX uq_workspaces_local_instance ON workspaces (instance_uuid) WHERE source = 'local'",
"\nCREATE TABLE api_keys (\n\tid INTEGER NOT NULL, \n\tuuid VARCHAR(36) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tcreated_by_account_uuid VARCHAR(36), \n\tname VARCHAR(255) NOT NULL, \n\tkey_hash VARCHAR(64) NOT NULL, \n\tscopes JSON DEFAULT '[]' NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\texpires_at DATETIME, \n\tlast_used_at DATETIME, \n\tdescription VARCHAR(512), \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (id), \n\tCONSTRAINT ck_api_keys_status CHECK (status IN ('active', 'revoked')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(created_by_account_uuid) REFERENCES users (uuid) ON DELETE SET NULL\n)\n\n",
"CREATE INDEX ix_api_keys_workspace_name ON api_keys (workspace_uuid, name)",
"CREATE INDEX ix_api_keys_workspace_status ON api_keys (workspace_uuid, status)",
"CREATE UNIQUE INDEX uq_api_keys_key_hash ON api_keys (key_hash)",
"CREATE UNIQUE INDEX uq_api_keys_uuid ON api_keys (uuid)",
"\nCREATE TABLE binary_storages (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tunique_key VARCHAR(255) NOT NULL, \n\t\"key\" VARCHAR(255) NOT NULL, \n\towner_type VARCHAR(255) NOT NULL, \n\towner VARCHAR(255) NOT NULL, \n\tvalue BLOB NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (workspace_uuid, unique_key), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_binary_storages_workspace_owner ON binary_storages (workspace_uuid, owner_type, owner)",
"\nCREATE TABLE bots (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tdescription VARCHAR(255) NOT NULL, \n\tadapter VARCHAR(255) NOT NULL, \n\tadapter_config JSON NOT NULL, \n\tenable BOOLEAN NOT NULL, \n\tuse_pipeline_name VARCHAR(255), \n\tuse_pipeline_uuid VARCHAR(255), \n\tpipeline_routing_rules JSON DEFAULT '[]' NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_bots_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_bots_workspace_name ON bots (workspace_uuid, name)",
"\nCREATE TABLE knowledge_bases (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR, \n\tdescription TEXT, \n\temoji VARCHAR(10), \n\tcreated_at DATETIME, \n\tupdated_at DATETIME, \n\tknowledge_engine_plugin_id VARCHAR, \n\tcollection_id VARCHAR, \n\tlegacy_vector_collection BOOLEAN DEFAULT 0 NOT NULL, \n\tcreation_settings JSON, \n\tretrieval_settings JSON, \n\tembedding_dimension INTEGER, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_knowledge_bases_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tCONSTRAINT ck_knowledge_bases_embedding_dimension_positive CHECK (embedding_dimension IS NULL OR embedding_dimension > 0), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_knowledge_bases_name ON knowledge_bases (name)",
"CREATE INDEX ix_knowledge_bases_workspace_name ON knowledge_bases (workspace_uuid, name)",
"CREATE UNIQUE INDEX uq_knowledge_bases_workspace_collection ON knowledge_bases (workspace_uuid, collection_id) WHERE collection_id IS NOT NULL",
"\nCREATE TABLE legacy_pipelines (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tdescription VARCHAR(255) NOT NULL, \n\temoji VARCHAR(10), \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tfor_version VARCHAR(255) NOT NULL, \n\tis_default BOOLEAN NOT NULL, \n\tstages JSON NOT NULL, \n\tconfig JSON NOT NULL, \n\textensions_preferences JSON NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_legacy_pipelines_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_legacy_pipelines_workspace_default ON legacy_pipelines (workspace_uuid, is_default)",
"CREATE INDEX ix_legacy_pipelines_workspace_name ON legacy_pipelines (workspace_uuid, name)",
"\nCREATE TABLE mcp_servers (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tenable BOOLEAN NOT NULL, \n\tmode VARCHAR(255) NOT NULL, \n\textra_args JSON NOT NULL, \n\treadme TEXT DEFAULT '' NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_mcp_servers_workspace_name UNIQUE (workspace_uuid, name), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_mcp_servers_workspace_enable ON mcp_servers (workspace_uuid, enable)",
"\nCREATE TABLE model_providers (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\trequester VARCHAR(255) NOT NULL, \n\tbase_url VARCHAR(512) NOT NULL, \n\tapi_keys JSON NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_model_providers_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_model_providers_workspace_name ON model_providers (workspace_uuid, name)",
"CREATE INDEX ix_model_providers_workspace_requester ON model_providers (workspace_uuid, requester)",
"\nCREATE TABLE monitoring_embedding_calls (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp DATETIME NOT NULL, \n\tmodel_name VARCHAR(255) NOT NULL, \n\tprompt_tokens INTEGER NOT NULL, \n\ttotal_tokens INTEGER NOT NULL, \n\tduration INTEGER NOT NULL, \n\tinput_count INTEGER NOT NULL, \n\tstatus VARCHAR(50) NOT NULL, \n\terror_message TEXT, \n\tknowledge_base_id VARCHAR(255), \n\tquery_text TEXT, \n\tsession_id VARCHAR(255), \n\tmessage_id VARCHAR(255), \n\tcall_type VARCHAR(50), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_monitoring_embedding_calls_knowledge_base_id ON monitoring_embedding_calls (knowledge_base_id)",
"CREATE INDEX ix_monitoring_embedding_calls_message_id ON monitoring_embedding_calls (message_id)",
"CREATE INDEX ix_monitoring_embedding_calls_session_id ON monitoring_embedding_calls (session_id)",
"CREATE INDEX ix_monitoring_embedding_calls_timestamp ON monitoring_embedding_calls (timestamp)",
"CREATE INDEX ix_monitoring_embedding_calls_workspace_kb ON monitoring_embedding_calls (workspace_uuid, knowledge_base_id)",
"CREATE INDEX ix_monitoring_embedding_calls_workspace_timestamp ON monitoring_embedding_calls (workspace_uuid, timestamp)",
"\nCREATE TABLE monitoring_errors (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp DATETIME NOT NULL, \n\terror_type VARCHAR(255) NOT NULL, \n\terror_message TEXT NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255), \n\tstack_trace TEXT, \n\tmessage_id VARCHAR(255), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_monitoring_errors_bot_id ON monitoring_errors (bot_id)",
"CREATE INDEX ix_monitoring_errors_message_id ON monitoring_errors (message_id)",
"CREATE INDEX ix_monitoring_errors_pipeline_id ON monitoring_errors (pipeline_id)",
"CREATE INDEX ix_monitoring_errors_timestamp ON monitoring_errors (timestamp)",
"CREATE INDEX ix_monitoring_errors_workspace_session ON monitoring_errors (workspace_uuid, session_id)",
"CREATE INDEX ix_monitoring_errors_workspace_timestamp ON monitoring_errors (workspace_uuid, timestamp)",
"\nCREATE TABLE monitoring_feedback (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp DATETIME NOT NULL, \n\tfeedback_id VARCHAR(255) NOT NULL, \n\tfeedback_type INTEGER NOT NULL, \n\tfeedback_content TEXT, \n\tinaccurate_reasons TEXT, \n\tbot_id VARCHAR(255), \n\tbot_name VARCHAR(255), \n\tpipeline_id VARCHAR(255), \n\tpipeline_name VARCHAR(255), \n\tsession_id VARCHAR(255), \n\tmessage_id VARCHAR(255), \n\tstream_id VARCHAR(255), \n\tuser_id VARCHAR(255), \n\tplatform VARCHAR(255), \n\tPRIMARY KEY (id), \n\tCONSTRAINT uq_monitoring_feedback_workspace_feedback_id UNIQUE (workspace_uuid, feedback_id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_monitoring_feedback_bot_id ON monitoring_feedback (bot_id)",
"CREATE INDEX ix_monitoring_feedback_feedback_id ON monitoring_feedback (feedback_id)",
"CREATE INDEX ix_monitoring_feedback_message_id ON monitoring_feedback (message_id)",
"CREATE INDEX ix_monitoring_feedback_pipeline_id ON monitoring_feedback (pipeline_id)",
"CREATE INDEX ix_monitoring_feedback_session_id ON monitoring_feedback (session_id)",
"CREATE INDEX ix_monitoring_feedback_stream_id ON monitoring_feedback (stream_id)",
"CREATE INDEX ix_monitoring_feedback_timestamp ON monitoring_feedback (timestamp)",
"CREATE INDEX ix_monitoring_feedback_workspace_session ON monitoring_feedback (workspace_uuid, session_id)",
"CREATE INDEX ix_monitoring_feedback_workspace_timestamp ON monitoring_feedback (workspace_uuid, timestamp)",
"\nCREATE TABLE monitoring_llm_calls (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp DATETIME NOT NULL, \n\tmodel_name VARCHAR(255) NOT NULL, \n\tinput_tokens INTEGER NOT NULL, \n\toutput_tokens INTEGER NOT NULL, \n\ttotal_tokens INTEGER NOT NULL, \n\tduration INTEGER NOT NULL, \n\tcost FLOAT, \n\tstatus VARCHAR(50) NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255) NOT NULL, \n\terror_message TEXT, \n\tmessage_id VARCHAR(255), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_monitoring_llm_calls_bot_id ON monitoring_llm_calls (bot_id)",
"CREATE INDEX ix_monitoring_llm_calls_message_id ON monitoring_llm_calls (message_id)",
"CREATE INDEX ix_monitoring_llm_calls_pipeline_id ON monitoring_llm_calls (pipeline_id)",
"CREATE INDEX ix_monitoring_llm_calls_timestamp ON monitoring_llm_calls (timestamp)",
"CREATE INDEX ix_monitoring_llm_calls_workspace_session ON monitoring_llm_calls (workspace_uuid, session_id)",
"CREATE INDEX ix_monitoring_llm_calls_workspace_timestamp ON monitoring_llm_calls (workspace_uuid, timestamp)",
"\nCREATE TABLE monitoring_messages (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp DATETIME NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tmessage_content TEXT NOT NULL, \n\tsession_id VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(50) NOT NULL, \n\tlevel VARCHAR(50) NOT NULL, \n\tplatform VARCHAR(255), \n\tuser_id VARCHAR(255), \n\tuser_name VARCHAR(255), \n\trunner_name VARCHAR(255), \n\tvariables TEXT, \n\trole VARCHAR(50), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_monitoring_messages_bot_id ON monitoring_messages (bot_id)",
"CREATE INDEX ix_monitoring_messages_pipeline_id ON monitoring_messages (pipeline_id)",
"CREATE INDEX ix_monitoring_messages_session_id ON monitoring_messages (session_id)",
"CREATE INDEX ix_monitoring_messages_timestamp ON monitoring_messages (timestamp)",
"CREATE INDEX ix_monitoring_messages_workspace_session ON monitoring_messages (workspace_uuid, session_id)",
"CREATE INDEX ix_monitoring_messages_workspace_timestamp ON monitoring_messages (workspace_uuid, timestamp)",
"\nCREATE TABLE monitoring_sessions (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tmessage_count INTEGER NOT NULL, \n\tstart_time DATETIME NOT NULL, \n\tlast_activity DATETIME NOT NULL, \n\tis_active BOOLEAN NOT NULL, \n\tplatform VARCHAR(255), \n\tuser_id VARCHAR(255), \n\tuser_name VARCHAR(255), \n\tPRIMARY KEY (workspace_uuid, bot_id, session_id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_monitoring_sessions_bot_id ON monitoring_sessions (bot_id)",
"CREATE INDEX ix_monitoring_sessions_is_active ON monitoring_sessions (is_active)",
"CREATE INDEX ix_monitoring_sessions_last_activity ON monitoring_sessions (last_activity)",
"CREATE INDEX ix_monitoring_sessions_pipeline_id ON monitoring_sessions (pipeline_id)",
"CREATE INDEX ix_monitoring_sessions_start_time ON monitoring_sessions (start_time)",
"CREATE INDEX ix_monitoring_sessions_workspace_active ON monitoring_sessions (workspace_uuid, is_active)",
"CREATE INDEX ix_monitoring_sessions_workspace_activity ON monitoring_sessions (workspace_uuid, last_activity)",
"\nCREATE TABLE monitoring_tool_calls (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp DATETIME NOT NULL, \n\ttool_name VARCHAR(255) NOT NULL, \n\ttool_source VARCHAR(50) NOT NULL, \n\tduration INTEGER NOT NULL, \n\tstatus VARCHAR(50) NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255), \n\tmessage_id VARCHAR(255), \n\targuments TEXT, \n\tresult TEXT, \n\terror_message TEXT, \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_monitoring_tool_calls_bot_id ON monitoring_tool_calls (bot_id)",
"CREATE INDEX ix_monitoring_tool_calls_message_id ON monitoring_tool_calls (message_id)",
"CREATE INDEX ix_monitoring_tool_calls_pipeline_id ON monitoring_tool_calls (pipeline_id)",
"CREATE INDEX ix_monitoring_tool_calls_session_id ON monitoring_tool_calls (session_id)",
"CREATE INDEX ix_monitoring_tool_calls_timestamp ON monitoring_tool_calls (timestamp)",
"CREATE INDEX ix_monitoring_tool_calls_workspace_session ON monitoring_tool_calls (workspace_uuid, session_id)",
"CREATE INDEX ix_monitoring_tool_calls_workspace_timestamp ON monitoring_tool_calls (workspace_uuid, timestamp)",
"\nCREATE TABLE plugin_settings (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tplugin_author VARCHAR(255) NOT NULL, \n\tplugin_name VARCHAR(255) NOT NULL, \n\tinstallation_uuid VARCHAR(36) NOT NULL, \n\tartifact_digest VARCHAR(64) NOT NULL, \n\truntime_revision INTEGER NOT NULL, \n\tenabled BOOLEAN NOT NULL, \n\tpriority INTEGER NOT NULL, \n\tconfig JSON NOT NULL, \n\tinstall_source VARCHAR(255) NOT NULL, \n\tinstall_info JSON NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (workspace_uuid, plugin_author, plugin_name), \n\tCONSTRAINT uq_plugin_settings_installation_uuid UNIQUE (installation_uuid), \n\tCONSTRAINT ck_plugin_settings_runtime_revision_positive CHECK (runtime_revision >= 1), \n\tCONSTRAINT ck_plugin_settings_artifact_digest_length CHECK (length(artifact_digest) = 64), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_plugin_settings_workspace_enabled ON plugin_settings (workspace_uuid, enabled)",
"CREATE UNIQUE INDEX ix_plugin_settings_workspace_installation ON plugin_settings (workspace_uuid, installation_uuid)",
"\nCREATE TABLE support_admin_temporary_sessions (\n\tgrant_jti_hash VARCHAR(64) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tactor_account_uuid VARCHAR(36) NOT NULL, \n\tissued_at DATETIME NOT NULL, \n\texpires_at DATETIME NOT NULL, \n\trevoked_at DATETIME, \n\tlast_used_at DATETIME, \n\tPRIMARY KEY (grant_jti_hash), \n\tCONSTRAINT ck_support_admin_sessions_grant_jti_hash CHECK (length(grant_jti_hash) = 64), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_support_admin_sessions_workspace_expiry ON support_admin_temporary_sessions (workspace_uuid, expires_at)",
"\nCREATE TABLE webhooks (\n\tid INTEGER NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\turl VARCHAR(1024) NOT NULL, \n\tdescription VARCHAR(512), \n\tenabled BOOLEAN NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_webhooks_workspace_name ON webhooks (workspace_uuid, name)",
"\nCREATE TABLE workspace_execution_states (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tactive_generation BIGINT DEFAULT '1' NOT NULL, \n\tstate VARCHAR(32) DEFAULT 'active' NOT NULL, \n\twrite_fenced BOOLEAN DEFAULT 0 NOT NULL, \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tdesired_state_revision BIGINT DEFAULT '0' NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (workspace_uuid), \n\tCONSTRAINT ck_workspace_execution_generation CHECK (active_generation > 0), \n\tCONSTRAINT ck_workspace_execution_state CHECK (state IN ('provisioning', 'active', 'migrating', 'draining', 'inactive')), \n\tCONSTRAINT ck_workspace_execution_source CHECK (source IN ('local', 'cloud')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_workspace_execution_states_instance_state ON workspace_execution_states (instance_uuid, state)",
"\nCREATE TABLE workspace_invitations (\n\tuuid VARCHAR(36) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tnormalized_email VARCHAR(320) NOT NULL, \n\trole VARCHAR(32) NOT NULL, \n\ttoken_hash VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'pending' NOT NULL, \n\texpires_at DATETIME NOT NULL, \n\taccepted_at DATETIME, \n\trevoked_at DATETIME, \n\tcreated_by_account_uuid VARCHAR(36) NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT ck_workspace_invitations_role CHECK (role IN ('admin', 'developer', 'operator', 'viewer')), \n\tCONSTRAINT ck_workspace_invitations_status CHECK (status IN ('pending', 'accepted', 'revoked', 'expired')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(created_by_account_uuid) REFERENCES users (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE UNIQUE INDEX uq_workspace_invitations_pending_email ON workspace_invitations (workspace_uuid, normalized_email) WHERE status = 'pending'",
"CREATE UNIQUE INDEX uq_workspace_invitations_token_hash ON workspace_invitations (token_hash)",
"\nCREATE TABLE workspace_memberships (\n\tuuid VARCHAR(36) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\taccount_uuid VARCHAR(36) NOT NULL, \n\trole VARCHAR(32) NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\tinvited_by_account_uuid VARCHAR(36), \n\tjoined_at DATETIME, \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tprojection_revision BIGINT DEFAULT '0' NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_workspace_membership_account UNIQUE (workspace_uuid, account_uuid), \n\tCONSTRAINT ck_workspace_memberships_role CHECK (role IN ('owner', 'admin', 'developer', 'operator', 'viewer')), \n\tCONSTRAINT ck_workspace_memberships_status CHECK (status IN ('active', 'disabled', 'removed')), \n\tCONSTRAINT ck_workspace_memberships_source CHECK (source IN ('local', 'cloud_projection')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(account_uuid) REFERENCES users (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(invited_by_account_uuid) REFERENCES users (uuid) ON DELETE SET NULL\n)\n\n",
"CREATE INDEX ix_workspace_memberships_account_status ON workspace_memberships (account_uuid, status)",
"CREATE UNIQUE INDEX uq_workspace_memberships_one_active_owner ON workspace_memberships (workspace_uuid) WHERE role = 'owner' AND status = 'active'",
"\nCREATE TABLE workspace_metadata (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\t\"key\" VARCHAR(255) NOT NULL, \n\tvalue VARCHAR(255), \n\tPRIMARY KEY (workspace_uuid, \"key\"), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"\nCREATE TABLE bot_admins (\n\tid INTEGER NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tbot_uuid VARCHAR(255) NOT NULL, \n\tlauncher_type VARCHAR(64) NOT NULL, \n\tlauncher_id VARCHAR(255) NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (id), \n\tCONSTRAINT uq_bot_admin UNIQUE (workspace_uuid, bot_uuid, launcher_type, launcher_id), \n\tCONSTRAINT fk_bot_admins_workspace_bot FOREIGN KEY(workspace_uuid, bot_uuid) REFERENCES bots (workspace_uuid, uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"\nCREATE TABLE codex_credentials (\n\tprovider_uuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tpayload JSON NOT NULL, \n\tversion INTEGER NOT NULL, \n\tlease_owner VARCHAR(64), \n\tlease_until FLOAT NOT NULL, \n\tPRIMARY KEY (provider_uuid), \n\tCONSTRAINT fk_codex_credentials_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_codex_credentials_workspace ON codex_credentials (workspace_uuid)",
"\nCREATE TABLE embedding_models (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tprovider_uuid VARCHAR(255) NOT NULL, \n\textra_args JSON NOT NULL, \n\tprefered_ranking INTEGER NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_embedding_models_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_embedding_models_workspace_name ON embedding_models (workspace_uuid, name)",
"CREATE INDEX ix_embedding_models_workspace_provider ON embedding_models (workspace_uuid, provider_uuid)",
"\nCREATE TABLE knowledge_base_files (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tkb_id VARCHAR(255), \n\tfile_name VARCHAR, \n\textension VARCHAR, \n\tcreated_at DATETIME, \n\tstatus VARCHAR, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_knowledge_base_files_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tCONSTRAINT fk_knowledge_base_files_workspace_kb FOREIGN KEY(workspace_uuid, kb_id) REFERENCES knowledge_bases (workspace_uuid, uuid) ON DELETE CASCADE, \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_knowledge_base_files_workspace_kb ON knowledge_base_files (workspace_uuid, kb_id)",
"\nCREATE TABLE llm_models (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tprovider_uuid VARCHAR(255) NOT NULL, \n\tabilities JSON NOT NULL, \n\tcontext_length INTEGER, \n\treasoning_config JSON DEFAULT '{\"level\":\"provider_default\"}' NOT NULL, \n\textra_args JSON NOT NULL, \n\tprefered_ranking INTEGER NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_llm_models_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_llm_models_workspace_name ON llm_models (workspace_uuid, name)",
"CREATE INDEX ix_llm_models_workspace_provider ON llm_models (workspace_uuid, provider_uuid)",
"\nCREATE TABLE pipeline_run_records (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tpipeline_uuid VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(255) NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tstarted_at DATETIME NOT NULL, \n\tfinished_at DATETIME NOT NULL, \n\tresult JSON NOT NULL, \n\tknowledge_base_uuid VARCHAR(255), \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_pipeline_run_records_workspace_pipeline FOREIGN KEY(workspace_uuid, pipeline_uuid) REFERENCES legacy_pipelines (workspace_uuid, uuid) ON DELETE CASCADE, \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_pipeline_run_records_workspace_created ON pipeline_run_records (workspace_uuid, created_at)",
"CREATE INDEX ix_pipeline_run_records_workspace_pipeline ON pipeline_run_records (workspace_uuid, pipeline_uuid)",
"\nCREATE TABLE rerank_models (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tprovider_uuid VARCHAR(255) NOT NULL, \n\textra_args JSON NOT NULL, \n\tprefered_ranking INTEGER NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_rerank_models_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_rerank_models_workspace_name ON rerank_models (workspace_uuid, name)",
"CREATE INDEX ix_rerank_models_workspace_provider ON rerank_models (workspace_uuid, provider_uuid)",
"\nCREATE TABLE knowledge_base_chunks (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tfile_id VARCHAR(255), \n\ttext TEXT, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_knowledge_base_chunks_workspace_file FOREIGN KEY(workspace_uuid, file_id) REFERENCES knowledge_base_files (workspace_uuid, uuid) ON DELETE CASCADE, \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_knowledge_base_chunks_workspace_file ON knowledge_base_chunks (workspace_uuid, file_id)"
],
"postgresql": [
"\nCREATE TABLE directory_projection_inbox (\n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tevent_uuid VARCHAR(36) NOT NULL, \n\tcursor BIGINT NOT NULL, \n\tevent_type VARCHAR(128) NOT NULL, \n\trevision BIGINT NOT NULL, \n\tfingerprint TEXT NOT NULL, \n\treceived_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, \n\tapplied_at TIMESTAMP WITH TIME ZONE, \n\tPRIMARY KEY (instance_uuid, event_uuid), \n\tCONSTRAINT uq_directory_projection_inbox_cursor UNIQUE (instance_uuid, cursor), \n\tCONSTRAINT ck_directory_projection_inbox_cursor CHECK (cursor > 0), \n\tCONSTRAINT ck_directory_projection_inbox_revision CHECK (revision > 0), \n\tCONSTRAINT ck_directory_projection_inbox_fingerprint CHECK (length(fingerprint) = 64)\n)\n\n",
"CREATE INDEX ix_directory_projection_inbox_pending ON directory_projection_inbox (instance_uuid, applied_at, cursor)",
"\nCREATE TABLE directory_projection_states (\n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tcursor BIGINT DEFAULT '0' NOT NULL, \n\tsnapshot_coverage_cursor BIGINT DEFAULT '0' NOT NULL, \n\tsnapshot_fingerprint TEXT NOT NULL, \n\tlast_applied_at TIMESTAMP WITH TIME ZONE NOT NULL, \n\tlease_expires_at TIMESTAMP WITH TIME ZONE, \n\tPRIMARY KEY (instance_uuid), \n\tCONSTRAINT ck_directory_projection_state_cursor CHECK (cursor >= 0), \n\tCONSTRAINT ck_directory_projection_state_snapshot_coverage CHECK (snapshot_coverage_cursor >= 0 AND snapshot_coverage_cursor <= cursor), \n\tCONSTRAINT ck_directory_projection_state_fingerprint CHECK (length(snapshot_fingerprint) = 64)\n)\n\n",
"\nCREATE TABLE metadata (\n\tkey VARCHAR(255) NOT NULL, \n\tvalue VARCHAR(255), \n\tPRIMARY KEY (key)\n)\n\n",
"\nCREATE TABLE users (\n\tid SERIAL NOT NULL, \n\tuuid VARCHAR(36) NOT NULL, \n\t\"user\" VARCHAR(255) NOT NULL, \n\tnormalized_email VARCHAR(320) NOT NULL, \n\tpassword VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tprojection_revision BIGINT DEFAULT '0' NOT NULL, \n\taccount_type VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tspace_account_uuid VARCHAR(255), \n\tspace_access_token TEXT, \n\tspace_refresh_token TEXT, \n\tspace_access_token_expires_at TIMESTAMP WITHOUT TIME ZONE, \n\tspace_api_key VARCHAR(255), \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (id), \n\tCONSTRAINT ck_users_normalized_email CHECK (normalized_email = trim(normalized_email) AND length(normalized_email) > 0 AND length(normalized_email) <= 320), \n\tCONSTRAINT ck_users_status CHECK (status IN ('active', 'disabled', 'deleted')), \n\tCONSTRAINT ck_users_source CHECK (source IN ('local', 'cloud_projection'))\n)\n\n",
"CREATE UNIQUE INDEX uq_users_normalized_email ON users (normalized_email)",
"CREATE UNIQUE INDEX uq_users_uuid ON users (uuid)",
"\nCREATE TABLE workspaces (\n\tuuid VARCHAR(36) NOT NULL, \n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tslug VARCHAR(255) NOT NULL, \n\ttype VARCHAR(32) DEFAULT 'team' NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\tcreated_by_account_uuid VARCHAR(36), \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tprojection_revision BIGINT DEFAULT '0' NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_workspaces_instance_slug UNIQUE (instance_uuid, slug), \n\tCONSTRAINT ck_workspaces_type CHECK (type IN ('personal', 'team')), \n\tCONSTRAINT ck_workspaces_status CHECK (status IN ('provisioning', 'active', 'suspended', 'archived', 'deleted')), \n\tCONSTRAINT ck_workspaces_source CHECK (source IN ('local', 'cloud_projection')), \n\tFOREIGN KEY(created_by_account_uuid) REFERENCES users (uuid) ON DELETE SET NULL\n)\n\n",
"CREATE INDEX ix_workspaces_instance_status ON workspaces (instance_uuid, status)",
"CREATE UNIQUE INDEX uq_workspaces_local_instance ON workspaces (instance_uuid) WHERE source = 'local'",
"\nCREATE TABLE api_keys (\n\tid SERIAL NOT NULL, \n\tuuid VARCHAR(36) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tcreated_by_account_uuid VARCHAR(36), \n\tname VARCHAR(255) NOT NULL, \n\tkey_hash VARCHAR(64) NOT NULL, \n\tscopes JSON DEFAULT '[]' NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\texpires_at TIMESTAMP WITHOUT TIME ZONE, \n\tlast_used_at TIMESTAMP WITHOUT TIME ZONE, \n\tdescription VARCHAR(512), \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (id), \n\tCONSTRAINT ck_api_keys_status CHECK (status IN ('active', 'revoked')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(created_by_account_uuid) REFERENCES users (uuid) ON DELETE SET NULL\n)\n\n",
"CREATE INDEX ix_api_keys_workspace_name ON api_keys (workspace_uuid, name)",
"CREATE INDEX ix_api_keys_workspace_status ON api_keys (workspace_uuid, status)",
"CREATE UNIQUE INDEX uq_api_keys_key_hash ON api_keys (key_hash)",
"CREATE UNIQUE INDEX uq_api_keys_uuid ON api_keys (uuid)",
"\nCREATE TABLE binary_storages (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tunique_key VARCHAR(255) NOT NULL, \n\tkey VARCHAR(255) NOT NULL, \n\towner_type VARCHAR(255) NOT NULL, \n\towner VARCHAR(255) NOT NULL, \n\tvalue BYTEA NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (workspace_uuid, unique_key), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_binary_storages_workspace_owner ON binary_storages (workspace_uuid, owner_type, owner)",
"\nCREATE TABLE bots (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tdescription VARCHAR(255) NOT NULL, \n\tadapter VARCHAR(255) NOT NULL, \n\tadapter_config JSON NOT NULL, \n\tenable BOOLEAN NOT NULL, \n\tuse_pipeline_name VARCHAR(255), \n\tuse_pipeline_uuid VARCHAR(255), \n\tpipeline_routing_rules JSON DEFAULT '[]' NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_bots_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_bots_workspace_name ON bots (workspace_uuid, name)",
"\nCREATE TABLE knowledge_bases (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR, \n\tdescription TEXT, \n\temoji VARCHAR(10), \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE, \n\tknowledge_engine_plugin_id VARCHAR, \n\tcollection_id VARCHAR, \n\tlegacy_vector_collection BOOLEAN DEFAULT false NOT NULL, \n\tcreation_settings JSON, \n\tretrieval_settings JSON, \n\tembedding_dimension INTEGER, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_knowledge_bases_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tCONSTRAINT ck_knowledge_bases_embedding_dimension_positive CHECK (embedding_dimension IS NULL OR embedding_dimension > 0), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_knowledge_bases_name ON knowledge_bases (name)",
"CREATE INDEX ix_knowledge_bases_workspace_name ON knowledge_bases (workspace_uuid, name)",
"CREATE UNIQUE INDEX uq_knowledge_bases_workspace_collection ON knowledge_bases (workspace_uuid, collection_id) WHERE collection_id IS NOT NULL",
"\nCREATE TABLE legacy_pipelines (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tdescription VARCHAR(255) NOT NULL, \n\temoji VARCHAR(10), \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tfor_version VARCHAR(255) NOT NULL, \n\tis_default BOOLEAN NOT NULL, \n\tstages JSON NOT NULL, \n\tconfig JSON NOT NULL, \n\textensions_preferences JSON NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_legacy_pipelines_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_legacy_pipelines_workspace_default ON legacy_pipelines (workspace_uuid, is_default)",
"CREATE INDEX ix_legacy_pipelines_workspace_name ON legacy_pipelines (workspace_uuid, name)",
"\nCREATE TABLE mcp_servers (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tenable BOOLEAN NOT NULL, \n\tmode VARCHAR(255) NOT NULL, \n\textra_args JSON NOT NULL, \n\treadme TEXT DEFAULT '' NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_mcp_servers_workspace_name UNIQUE (workspace_uuid, name), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_mcp_servers_workspace_enable ON mcp_servers (workspace_uuid, enable)",
"\nCREATE TABLE model_providers (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\trequester VARCHAR(255) NOT NULL, \n\tbase_url VARCHAR(512) NOT NULL, \n\tapi_keys JSON NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_model_providers_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_model_providers_workspace_name ON model_providers (workspace_uuid, name)",
"CREATE INDEX ix_model_providers_workspace_requester ON model_providers (workspace_uuid, requester)",
"\nCREATE TABLE monitoring_embedding_calls (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tmodel_name VARCHAR(255) NOT NULL, \n\tprompt_tokens INTEGER NOT NULL, \n\ttotal_tokens INTEGER NOT NULL, \n\tduration INTEGER NOT NULL, \n\tinput_count INTEGER NOT NULL, \n\tstatus VARCHAR(50) NOT NULL, \n\terror_message TEXT, \n\tknowledge_base_id VARCHAR(255), \n\tquery_text TEXT, \n\tsession_id VARCHAR(255), \n\tmessage_id VARCHAR(255), \n\tcall_type VARCHAR(50), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_monitoring_embedding_calls_knowledge_base_id ON monitoring_embedding_calls (knowledge_base_id)",
"CREATE INDEX ix_monitoring_embedding_calls_message_id ON monitoring_embedding_calls (message_id)",
"CREATE INDEX ix_monitoring_embedding_calls_session_id ON monitoring_embedding_calls (session_id)",
"CREATE INDEX ix_monitoring_embedding_calls_timestamp ON monitoring_embedding_calls (timestamp)",
"CREATE INDEX ix_monitoring_embedding_calls_workspace_kb ON monitoring_embedding_calls (workspace_uuid, knowledge_base_id)",
"CREATE INDEX ix_monitoring_embedding_calls_workspace_timestamp ON monitoring_embedding_calls (workspace_uuid, timestamp)",
"\nCREATE TABLE monitoring_errors (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\terror_type VARCHAR(255) NOT NULL, \n\terror_message TEXT NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255), \n\tstack_trace TEXT, \n\tmessage_id VARCHAR(255), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_monitoring_errors_bot_id ON monitoring_errors (bot_id)",
"CREATE INDEX ix_monitoring_errors_message_id ON monitoring_errors (message_id)",
"CREATE INDEX ix_monitoring_errors_pipeline_id ON monitoring_errors (pipeline_id)",
"CREATE INDEX ix_monitoring_errors_timestamp ON monitoring_errors (timestamp)",
"CREATE INDEX ix_monitoring_errors_workspace_session ON monitoring_errors (workspace_uuid, session_id)",
"CREATE INDEX ix_monitoring_errors_workspace_timestamp ON monitoring_errors (workspace_uuid, timestamp)",
"\nCREATE TABLE monitoring_feedback (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tfeedback_id VARCHAR(255) NOT NULL, \n\tfeedback_type INTEGER NOT NULL, \n\tfeedback_content TEXT, \n\tinaccurate_reasons TEXT, \n\tbot_id VARCHAR(255), \n\tbot_name VARCHAR(255), \n\tpipeline_id VARCHAR(255), \n\tpipeline_name VARCHAR(255), \n\tsession_id VARCHAR(255), \n\tmessage_id VARCHAR(255), \n\tstream_id VARCHAR(255), \n\tuser_id VARCHAR(255), \n\tplatform VARCHAR(255), \n\tPRIMARY KEY (id), \n\tCONSTRAINT uq_monitoring_feedback_workspace_feedback_id UNIQUE (workspace_uuid, feedback_id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_monitoring_feedback_bot_id ON monitoring_feedback (bot_id)",
"CREATE INDEX ix_monitoring_feedback_feedback_id ON monitoring_feedback (feedback_id)",
"CREATE INDEX ix_monitoring_feedback_message_id ON monitoring_feedback (message_id)",
"CREATE INDEX ix_monitoring_feedback_pipeline_id ON monitoring_feedback (pipeline_id)",
"CREATE INDEX ix_monitoring_feedback_session_id ON monitoring_feedback (session_id)",
"CREATE INDEX ix_monitoring_feedback_stream_id ON monitoring_feedback (stream_id)",
"CREATE INDEX ix_monitoring_feedback_timestamp ON monitoring_feedback (timestamp)",
"CREATE INDEX ix_monitoring_feedback_workspace_session ON monitoring_feedback (workspace_uuid, session_id)",
"CREATE INDEX ix_monitoring_feedback_workspace_timestamp ON monitoring_feedback (workspace_uuid, timestamp)",
"\nCREATE TABLE monitoring_llm_calls (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tmodel_name VARCHAR(255) NOT NULL, \n\tinput_tokens INTEGER NOT NULL, \n\toutput_tokens INTEGER NOT NULL, \n\ttotal_tokens INTEGER NOT NULL, \n\tduration INTEGER NOT NULL, \n\tcost FLOAT, \n\tstatus VARCHAR(50) NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255) NOT NULL, \n\terror_message TEXT, \n\tmessage_id VARCHAR(255), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_monitoring_llm_calls_bot_id ON monitoring_llm_calls (bot_id)",
"CREATE INDEX ix_monitoring_llm_calls_message_id ON monitoring_llm_calls (message_id)",
"CREATE INDEX ix_monitoring_llm_calls_pipeline_id ON monitoring_llm_calls (pipeline_id)",
"CREATE INDEX ix_monitoring_llm_calls_timestamp ON monitoring_llm_calls (timestamp)",
"CREATE INDEX ix_monitoring_llm_calls_workspace_session ON monitoring_llm_calls (workspace_uuid, session_id)",
"CREATE INDEX ix_monitoring_llm_calls_workspace_timestamp ON monitoring_llm_calls (workspace_uuid, timestamp)",
"\nCREATE TABLE monitoring_messages (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tmessage_content TEXT NOT NULL, \n\tsession_id VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(50) NOT NULL, \n\tlevel VARCHAR(50) NOT NULL, \n\tplatform VARCHAR(255), \n\tuser_id VARCHAR(255), \n\tuser_name VARCHAR(255), \n\trunner_name VARCHAR(255), \n\tvariables TEXT, \n\trole VARCHAR(50), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_monitoring_messages_bot_id ON monitoring_messages (bot_id)",
"CREATE INDEX ix_monitoring_messages_pipeline_id ON monitoring_messages (pipeline_id)",
"CREATE INDEX ix_monitoring_messages_session_id ON monitoring_messages (session_id)",
"CREATE INDEX ix_monitoring_messages_timestamp ON monitoring_messages (timestamp)",
"CREATE INDEX ix_monitoring_messages_workspace_session ON monitoring_messages (workspace_uuid, session_id)",
"CREATE INDEX ix_monitoring_messages_workspace_timestamp ON monitoring_messages (workspace_uuid, timestamp)",
"\nCREATE TABLE monitoring_sessions (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tmessage_count INTEGER NOT NULL, \n\tstart_time TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tlast_activity TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tis_active BOOLEAN NOT NULL, \n\tplatform VARCHAR(255), \n\tuser_id VARCHAR(255), \n\tuser_name VARCHAR(255), \n\tPRIMARY KEY (workspace_uuid, bot_id, session_id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_monitoring_sessions_bot_id ON monitoring_sessions (bot_id)",
"CREATE INDEX ix_monitoring_sessions_is_active ON monitoring_sessions (is_active)",
"CREATE INDEX ix_monitoring_sessions_last_activity ON monitoring_sessions (last_activity)",
"CREATE INDEX ix_monitoring_sessions_pipeline_id ON monitoring_sessions (pipeline_id)",
"CREATE INDEX ix_monitoring_sessions_start_time ON monitoring_sessions (start_time)",
"CREATE INDEX ix_monitoring_sessions_workspace_active ON monitoring_sessions (workspace_uuid, is_active)",
"CREATE INDEX ix_monitoring_sessions_workspace_activity ON monitoring_sessions (workspace_uuid, last_activity)",
"\nCREATE TABLE monitoring_tool_calls (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\ttool_name VARCHAR(255) NOT NULL, \n\ttool_source VARCHAR(50) NOT NULL, \n\tduration INTEGER NOT NULL, \n\tstatus VARCHAR(50) NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255), \n\tmessage_id VARCHAR(255), \n\targuments TEXT, \n\tresult TEXT, \n\terror_message TEXT, \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_monitoring_tool_calls_bot_id ON monitoring_tool_calls (bot_id)",
"CREATE INDEX ix_monitoring_tool_calls_message_id ON monitoring_tool_calls (message_id)",
"CREATE INDEX ix_monitoring_tool_calls_pipeline_id ON monitoring_tool_calls (pipeline_id)",
"CREATE INDEX ix_monitoring_tool_calls_session_id ON monitoring_tool_calls (session_id)",
"CREATE INDEX ix_monitoring_tool_calls_timestamp ON monitoring_tool_calls (timestamp)",
"CREATE INDEX ix_monitoring_tool_calls_workspace_session ON monitoring_tool_calls (workspace_uuid, session_id)",
"CREATE INDEX ix_monitoring_tool_calls_workspace_timestamp ON monitoring_tool_calls (workspace_uuid, timestamp)",
"\nCREATE TABLE plugin_settings (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tplugin_author VARCHAR(255) NOT NULL, \n\tplugin_name VARCHAR(255) NOT NULL, \n\tinstallation_uuid VARCHAR(36) NOT NULL, \n\tartifact_digest VARCHAR(64) NOT NULL, \n\truntime_revision INTEGER NOT NULL, \n\tenabled BOOLEAN NOT NULL, \n\tpriority INTEGER NOT NULL, \n\tconfig JSON NOT NULL, \n\tinstall_source VARCHAR(255) NOT NULL, \n\tinstall_info JSON NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (workspace_uuid, plugin_author, plugin_name), \n\tCONSTRAINT uq_plugin_settings_installation_uuid UNIQUE (installation_uuid), \n\tCONSTRAINT ck_plugin_settings_runtime_revision_positive CHECK (runtime_revision >= 1), \n\tCONSTRAINT ck_plugin_settings_artifact_digest_length CHECK (length(artifact_digest) = 64), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_plugin_settings_workspace_enabled ON plugin_settings (workspace_uuid, enabled)",
"CREATE UNIQUE INDEX ix_plugin_settings_workspace_installation ON plugin_settings (workspace_uuid, installation_uuid)",
"\nCREATE TABLE support_admin_temporary_sessions (\n\tgrant_jti_hash VARCHAR(64) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tactor_account_uuid VARCHAR(36) NOT NULL, \n\tissued_at TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\texpires_at TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\trevoked_at TIMESTAMP WITHOUT TIME ZONE, \n\tlast_used_at TIMESTAMP WITHOUT TIME ZONE, \n\tPRIMARY KEY (grant_jti_hash), \n\tCONSTRAINT ck_support_admin_sessions_grant_jti_hash CHECK (length(grant_jti_hash) = 64), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_support_admin_sessions_workspace_expiry ON support_admin_temporary_sessions (workspace_uuid, expires_at)",
"\nCREATE TABLE webhooks (\n\tid SERIAL NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\turl VARCHAR(1024) NOT NULL, \n\tdescription VARCHAR(512), \n\tenabled BOOLEAN NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_webhooks_workspace_name ON webhooks (workspace_uuid, name)",
"\nCREATE TABLE workspace_execution_states (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tactive_generation BIGINT DEFAULT '1' NOT NULL, \n\tstate VARCHAR(32) DEFAULT 'active' NOT NULL, \n\twrite_fenced BOOLEAN DEFAULT false NOT NULL, \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tdesired_state_revision BIGINT DEFAULT '0' NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (workspace_uuid), \n\tCONSTRAINT ck_workspace_execution_generation CHECK (active_generation > 0), \n\tCONSTRAINT ck_workspace_execution_state CHECK (state IN ('provisioning', 'active', 'migrating', 'draining', 'inactive')), \n\tCONSTRAINT ck_workspace_execution_source CHECK (source IN ('local', 'cloud')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_workspace_execution_states_instance_state ON workspace_execution_states (instance_uuid, state)",
"\nCREATE TABLE workspace_invitations (\n\tuuid VARCHAR(36) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tnormalized_email VARCHAR(320) NOT NULL, \n\trole VARCHAR(32) NOT NULL, \n\ttoken_hash VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'pending' NOT NULL, \n\texpires_at TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\taccepted_at TIMESTAMP WITHOUT TIME ZONE, \n\trevoked_at TIMESTAMP WITHOUT TIME ZONE, \n\tcreated_by_account_uuid VARCHAR(36) NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT ck_workspace_invitations_role CHECK (role IN ('admin', 'developer', 'operator', 'viewer')), \n\tCONSTRAINT ck_workspace_invitations_status CHECK (status IN ('pending', 'accepted', 'revoked', 'expired')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(created_by_account_uuid) REFERENCES users (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE UNIQUE INDEX uq_workspace_invitations_pending_email ON workspace_invitations (workspace_uuid, normalized_email) WHERE status = 'pending'",
"CREATE UNIQUE INDEX uq_workspace_invitations_token_hash ON workspace_invitations (token_hash)",
"\nCREATE TABLE workspace_memberships (\n\tuuid VARCHAR(36) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\taccount_uuid VARCHAR(36) NOT NULL, \n\trole VARCHAR(32) NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\tinvited_by_account_uuid VARCHAR(36), \n\tjoined_at TIMESTAMP WITHOUT TIME ZONE, \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tprojection_revision BIGINT DEFAULT '0' NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_workspace_membership_account UNIQUE (workspace_uuid, account_uuid), \n\tCONSTRAINT ck_workspace_memberships_role CHECK (role IN ('owner', 'admin', 'developer', 'operator', 'viewer')), \n\tCONSTRAINT ck_workspace_memberships_status CHECK (status IN ('active', 'disabled', 'removed')), \n\tCONSTRAINT ck_workspace_memberships_source CHECK (source IN ('local', 'cloud_projection')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(account_uuid) REFERENCES users (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(invited_by_account_uuid) REFERENCES users (uuid) ON DELETE SET NULL\n)\n\n",
"CREATE INDEX ix_workspace_memberships_account_status ON workspace_memberships (account_uuid, status)",
"CREATE UNIQUE INDEX uq_workspace_memberships_one_active_owner ON workspace_memberships (workspace_uuid) WHERE role = 'owner' AND status = 'active'",
"\nCREATE TABLE workspace_metadata (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tkey VARCHAR(255) NOT NULL, \n\tvalue VARCHAR(255), \n\tPRIMARY KEY (workspace_uuid, key), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"\nCREATE TABLE bot_admins (\n\tid SERIAL NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tbot_uuid VARCHAR(255) NOT NULL, \n\tlauncher_type VARCHAR(64) NOT NULL, \n\tlauncher_id VARCHAR(255) NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (id), \n\tCONSTRAINT uq_bot_admin UNIQUE (workspace_uuid, bot_uuid, launcher_type, launcher_id), \n\tCONSTRAINT fk_bot_admins_workspace_bot FOREIGN KEY(workspace_uuid, bot_uuid) REFERENCES bots (workspace_uuid, uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"\nCREATE TABLE codex_credentials (\n\tprovider_uuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tpayload JSON NOT NULL, \n\tversion INTEGER NOT NULL, \n\tlease_owner VARCHAR(64), \n\tlease_until FLOAT NOT NULL, \n\tPRIMARY KEY (provider_uuid), \n\tCONSTRAINT fk_codex_credentials_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_codex_credentials_workspace ON codex_credentials (workspace_uuid)",
"\nCREATE TABLE embedding_models (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tprovider_uuid VARCHAR(255) NOT NULL, \n\textra_args JSON NOT NULL, \n\tprefered_ranking INTEGER NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_embedding_models_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_embedding_models_workspace_name ON embedding_models (workspace_uuid, name)",
"CREATE INDEX ix_embedding_models_workspace_provider ON embedding_models (workspace_uuid, provider_uuid)",
"\nCREATE TABLE knowledge_base_files (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tkb_id VARCHAR(255), \n\tfile_name VARCHAR, \n\textension VARCHAR, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE, \n\tstatus VARCHAR, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_knowledge_base_files_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tCONSTRAINT fk_knowledge_base_files_workspace_kb FOREIGN KEY(workspace_uuid, kb_id) REFERENCES knowledge_bases (workspace_uuid, uuid) ON DELETE CASCADE, \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_knowledge_base_files_workspace_kb ON knowledge_base_files (workspace_uuid, kb_id)",
"\nCREATE TABLE llm_models (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tprovider_uuid VARCHAR(255) NOT NULL, \n\tabilities JSON NOT NULL, \n\tcontext_length INTEGER, \n\treasoning_config JSON DEFAULT '{\"level\":\"provider_default\"}' NOT NULL, \n\textra_args JSON NOT NULL, \n\tprefered_ranking INTEGER NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_llm_models_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_llm_models_workspace_name ON llm_models (workspace_uuid, name)",
"CREATE INDEX ix_llm_models_workspace_provider ON llm_models (workspace_uuid, provider_uuid)",
"\nCREATE TABLE pipeline_run_records (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tpipeline_uuid VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(255) NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tstarted_at TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tfinished_at TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tresult JSON NOT NULL, \n\tknowledge_base_uuid VARCHAR(255), \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_pipeline_run_records_workspace_pipeline FOREIGN KEY(workspace_uuid, pipeline_uuid) REFERENCES legacy_pipelines (workspace_uuid, uuid) ON DELETE CASCADE, \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_pipeline_run_records_workspace_created ON pipeline_run_records (workspace_uuid, created_at)",
"CREATE INDEX ix_pipeline_run_records_workspace_pipeline ON pipeline_run_records (workspace_uuid, pipeline_uuid)",
"\nCREATE TABLE rerank_models (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tprovider_uuid VARCHAR(255) NOT NULL, \n\textra_args JSON NOT NULL, \n\tprefered_ranking INTEGER NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_rerank_models_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_rerank_models_workspace_name ON rerank_models (workspace_uuid, name)",
"CREATE INDEX ix_rerank_models_workspace_provider ON rerank_models (workspace_uuid, provider_uuid)",
"\nCREATE TABLE knowledge_base_chunks (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tfile_id VARCHAR(255), \n\ttext TEXT, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_knowledge_base_chunks_workspace_file FOREIGN KEY(workspace_uuid, file_id) REFERENCES knowledge_base_files (workspace_uuid, uuid) ON DELETE CASCADE, \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n",
"CREATE INDEX ix_knowledge_base_chunks_workspace_file ON knowledge_base_chunks (workspace_uuid, file_id)"
]
}
}
@@ -0,0 +1,130 @@
"""Upgrade the immutable v4.10.11 ORM schema, not current metadata."""
import json
import pytest
import sqlalchemy as sa
from alembic.autogenerate import compare_metadata
from alembic.migration import MigrationContext
from langbot.pkg.entity.persistence.base import Base
from langbot.pkg.persistence.alembic_runner import run_alembic_upgrade
from tests.integration.persistence.test_migration_branch_convergence import (
FIXTURES,
_seed_common,
)
@pytest.fixture(params=['sqlite', 'postgresql'])
async def convergence_engine(request, tmp_path):
import os
import uuid
from sqlalchemy.ext.asyncio import create_async_engine
if request.param == 'sqlite':
engine = create_async_engine(f'sqlite+aiosqlite:///{tmp_path / "release.db"}')
try:
yield engine
finally:
await engine.dispose()
return
url = os.environ.get('TEST_POSTGRES_URL')
if not url:
pytest.skip('TEST_POSTGRES_URL required for disposable PostgreSQL')
name = 'release_audit_' + uuid.uuid4().hex
admin = create_async_engine(url, isolation_level='AUTOCOMMIT')
async with admin.connect() as conn:
await conn.exec_driver_sql(f'CREATE DATABASE {name}')
engine = create_async_engine(sa.engine.make_url(url).set(database=name))
try:
yield engine
finally:
await engine.dispose()
async with admin.connect() as conn:
await conn.exec_driver_sql(f'DROP DATABASE {name}')
await admin.dispose()
@pytest.mark.asyncio
async def test_release_41011_upgrade(convergence_engine, monkeypatch):
from langbot.pkg.utils import constants
monkeypatch.setattr(constants, 'instance_id', 'migration-convergence')
engine = convergence_engine
fixture = json.loads((FIXTURES / 'release_4_10_11_schema.json').read_text())
async with engine.begin() as conn:
for statement in fixture['dialects'][engine.dialect.name]:
await conn.exec_driver_sql(statement)
# Apply the historical migrations too: pgvector is migration-owned,
# not represented in ORM metadata.
await run_alembic_upgrade(engine, fixture['revision'])
await _seed_common(engine)
async with engine.begin() as conn:
await conn.execute(sa.text("DELETE FROM metadata WHERE key='oss_workspace_uuid'"))
await conn.execute(
sa.text(
"INSERT INTO metadata (key,value) VALUES ('oss_workspace_uuid', '41100000-0000-4000-8000-000000000001')"
)
)
from types import SimpleNamespace
from unittest.mock import MagicMock
from langbot.pkg.persistence.mgr import PersistenceManager
manager = PersistenceManager(SimpleNamespace(logger=MagicMock(), instance_uuid='migration-convergence'))
manager.db = SimpleNamespace(engine=engine, get_engine=lambda: engine)
await manager._initialize_managed_schema()
async with engine.connect() as conn:
assert await conn.scalar(sa.text('SELECT name FROM bots')) == 'Fixture bot'
assert await conn.scalar(sa.text('SELECT name FROM legacy_pipelines')) == 'Fixture pipeline'
bot = await conn.run_sync(lambda sync: sa.Table('bots', sa.MetaData(), autoload_with=sync))
bindings = await conn.scalar(sa.select(bot.c.event_bindings))
assert any(binding['target_uuid'] == 'pipeline-1' for binding in bindings)
assert await conn.scalar(sa.select(bot.c.plugin_processors)) == []
kb = await conn.run_sync(lambda sync: sa.Table('knowledge_bases', sa.MetaData(), autoload_with=sync))
assert all(await conn.scalars(sa.select(kb.c.initialized)))
if engine.dialect.name == 'sqlite':
assert (await conn.exec_driver_sql('PRAGMA foreign_key_check')).all() == []
async with engine.connect() as conn:
def differences(sync):
context = MigrationContext.configure(sync, opts={'compare_type': True})
return compare_metadata(context, Base.metadata)
diffs = await conn.run_sync(differences)
def substantive(sync, diff):
if isinstance(diff, list):
return True
if diff[0] not in ('add_table', 'add_column', 'add_index', 'add_constraint'):
return False
if diff[0] in ('add_index', 'add_constraint'):
obj = diff[1]
inspector = sa.inspect(sync)
columns = [c.name for c in obj.columns]
existing = inspector.get_indexes(obj.table.name) + inspector.get_unique_constraints(obj.table.name)
if any(
item['column_names'] == columns and (diff[0] != 'add_constraint' or item.get('unique', True))
for item in existing
):
return False
if (
diff[0] == 'add_constraint'
and inspector.get_pk_constraint(obj.table.name)['constrained_columns'] == columns
):
return False
return True
actionable = await conn.run_sync(lambda sync: [d for d in diffs if substantive(sync, d)])
assert not actionable, repr(actionable)
await manager._initialize_managed_schema()
async with engine.connect() as conn:
assert await conn.scalar(sa.text('SELECT name FROM bots')) == 'Fixture bot'
assert await conn.scalar(sa.text('SELECT name FROM legacy_pipelines')) == 'Fixture pipeline'
bot = await conn.run_sync(lambda sync: sa.Table('bots', sa.MetaData(), autoload_with=sync))
bindings = await conn.scalar(sa.select(bot.c.event_bindings))
assert any(binding['target_uuid'] == 'pipeline-1' for binding in bindings)
assert await conn.scalar(sa.select(bot.c.plugin_processors)) == []
kb = await conn.run_sync(lambda sync: sa.Table('knowledge_bases', sa.MetaData(), autoload_with=sync))
assert all(await conn.scalars(sa.select(kb.c.initialized)))
if engine.dialect.name == 'sqlite':
assert (await conn.exec_driver_sql('PRAGMA foreign_key_check')).all() == []