247 lines
12 KiB
SQL
247 lines
12 KiB
SQL
-- Validate that a pre-MVP-1 Gemini template or model has not been configured without
|
|
-- the explicit capability that MVP-1 requires. The guard remains only after a failed run.
|
|
CREATE TABLE IF NOT EXISTS chorus_mvp1_routing_up_guard (
|
|
id TINYINT NOT NULL,
|
|
CONSTRAINT chk_chorus_mvp1_routing_up_guard CHECK (id = 0)
|
|
) ENGINE=InnoDB;
|
|
|
|
DELETE FROM chorus_mvp1_routing_up_guard;
|
|
INSERT INTO chorus_mvp1_routing_up_guard (id)
|
|
SELECT 1
|
|
WHERE EXISTS (SELECT 1 FROM provider_models WHERE api_type = 'gemini')
|
|
OR EXISTS (SELECT 1 FROM prompt_templates WHERE api_type = 'gemini');
|
|
DROP TABLE chorus_mvp1_routing_up_guard;
|
|
|
|
CREATE TABLE provider_credentials (
|
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
provider_id BIGINT UNSIGNED NOT NULL,
|
|
credential_version INT UNSIGNED NOT NULL,
|
|
api_key_enc JSON NOT NULL,
|
|
key_id VARCHAR(128) NOT NULL,
|
|
status VARCHAR(16) NOT NULL,
|
|
created_by BIGINT NULL,
|
|
updated_by BIGINT NULL,
|
|
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
|
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
|
retired_at DATETIME(6) NULL,
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY uq_provider_credentials_version (provider_id, credential_version),
|
|
KEY idx_provider_credentials_status (provider_id, status, created_at),
|
|
CONSTRAINT fk_provider_credentials_provider FOREIGN KEY (provider_id) REFERENCES providers (id) ON DELETE RESTRICT,
|
|
CONSTRAINT chk_provider_credentials_status CHECK (status IN ('active', 'retired')),
|
|
CONSTRAINT chk_provider_credentials_envelope CHECK (
|
|
JSON_TYPE(api_key_enc) = 'OBJECT' AND
|
|
JSON_CONTAINS_PATH(api_key_enc, 'all', '$.version', '$.key_id', '$.nonce', '$.ciphertext')
|
|
)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
CREATE TABLE provider_model_capabilities (
|
|
provider_model_id BIGINT UNSIGNED NOT NULL,
|
|
capability VARCHAR(32) NOT NULL,
|
|
PRIMARY KEY (provider_model_id, capability),
|
|
CONSTRAINT fk_provider_model_capabilities_model FOREIGN KEY (provider_model_id) REFERENCES provider_models (id) ON DELETE CASCADE,
|
|
CONSTRAINT chk_provider_model_capabilities_capability CHECK (capability IN ('text', 'image_generate', 'image_edit'))
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
CREATE TABLE route_pools (
|
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
slug VARCHAR(80) NOT NULL,
|
|
name VARCHAR(120) NOT NULL,
|
|
capability VARCHAR(32) NOT NULL,
|
|
prompt_template_id BIGINT UNSIGNED NOT NULL,
|
|
max_failover SMALLINT UNSIGNED NOT NULL DEFAULT 0,
|
|
version INT UNSIGNED NOT NULL DEFAULT 1,
|
|
enabled BOOLEAN NOT NULL DEFAULT FALSE,
|
|
created_by BIGINT NULL,
|
|
updated_by BIGINT NULL,
|
|
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
|
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY uq_route_pools_slug (slug),
|
|
KEY idx_route_pools_capability_enabled (capability, enabled),
|
|
KEY idx_route_pools_prompt_template (prompt_template_id),
|
|
CONSTRAINT fk_route_pools_template FOREIGN KEY (prompt_template_id) REFERENCES prompt_templates (id) ON DELETE RESTRICT,
|
|
CONSTRAINT chk_route_pools_capability CHECK (capability IN ('text', 'image_generate', 'image_edit')),
|
|
CONSTRAINT chk_route_pools_version CHECK (version > 0)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
CREATE TABLE active_routes (
|
|
capability VARCHAR(32) NOT NULL,
|
|
route_pool_id BIGINT UNSIGNED NOT NULL,
|
|
operator_id BIGINT NULL,
|
|
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
|
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
|
PRIMARY KEY (capability),
|
|
KEY idx_active_routes_pool (route_pool_id),
|
|
CONSTRAINT fk_active_routes_pool FOREIGN KEY (route_pool_id) REFERENCES route_pools (id) ON DELETE RESTRICT,
|
|
CONSTRAINT chk_active_routes_capability CHECK (capability IN ('text', 'image_generate', 'image_edit'))
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
CREATE TABLE route_pool_members (
|
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
route_pool_id BIGINT UNSIGNED NOT NULL,
|
|
provider_model_id BIGINT UNSIGNED NOT NULL,
|
|
weight SMALLINT UNSIGNED NOT NULL,
|
|
failure_threshold SMALLINT UNSIGNED NOT NULL DEFAULT 3,
|
|
open_seconds INT UNSIGNED NOT NULL DEFAULT 60,
|
|
half_open_max SMALLINT UNSIGNED NOT NULL DEFAULT 1,
|
|
enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
|
position SMALLINT UNSIGNED NOT NULL DEFAULT 0,
|
|
created_by BIGINT NULL,
|
|
updated_by BIGINT NULL,
|
|
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
|
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY uq_route_pool_members_model (route_pool_id, provider_model_id),
|
|
KEY idx_route_pool_members_list (route_pool_id, enabled, position),
|
|
CONSTRAINT fk_route_pool_members_pool FOREIGN KEY (route_pool_id) REFERENCES route_pools (id) ON DELETE CASCADE,
|
|
CONSTRAINT fk_route_pool_members_model FOREIGN KEY (provider_model_id) REFERENCES provider_models (id) ON DELETE RESTRICT,
|
|
CONSTRAINT chk_route_pool_members_weight CHECK (weight > 0),
|
|
CONSTRAINT chk_route_pool_members_failure_threshold CHECK (failure_threshold > 0),
|
|
CONSTRAINT chk_route_pool_members_open_seconds CHECK (open_seconds > 0),
|
|
CONSTRAINT chk_route_pool_members_half_open CHECK (half_open_max > 0)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
CREATE TABLE route_member_runtime (
|
|
route_pool_member_id BIGINT UNSIGNED NOT NULL,
|
|
state VARCHAR(16) NOT NULL DEFAULT 'closed',
|
|
consecutive_failures INT UNSIGNED NOT NULL DEFAULT 0,
|
|
open_until DATETIME(6) NULL,
|
|
probe_owner VARCHAR(128) NULL,
|
|
probe_token CHAR(36) NULL,
|
|
probe_until DATETIME(6) NULL,
|
|
last_error_code VARCHAR(64) NULL,
|
|
last_error_message VARCHAR(1024) NULL,
|
|
last_observed_at DATETIME(6) NULL,
|
|
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
|
PRIMARY KEY (route_pool_member_id),
|
|
KEY idx_route_member_runtime_state (state, open_until),
|
|
CONSTRAINT fk_route_member_runtime_member FOREIGN KEY (route_pool_member_id) REFERENCES route_pool_members (id) ON DELETE CASCADE,
|
|
CONSTRAINT chk_route_member_runtime_state CHECK (state IN ('closed', 'open', 'half_open')),
|
|
CONSTRAINT chk_route_member_runtime_probe CHECK (
|
|
(probe_owner IS NULL AND probe_token IS NULL AND probe_until IS NULL) OR
|
|
(probe_owner IS NOT NULL AND probe_token IS NOT NULL AND probe_until IS NOT NULL)
|
|
)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
CREATE TABLE provider_connectivity_checks (
|
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
provider_model_id BIGINT UNSIGNED NOT NULL,
|
|
operator_id BIGINT NULL,
|
|
status VARCHAR(16) NOT NULL,
|
|
error_code VARCHAR(64) NULL,
|
|
error_message VARCHAR(1024) NULL,
|
|
latency_ms INT UNSIGNED NULL,
|
|
started_at DATETIME(6) NOT NULL,
|
|
completed_at DATETIME(6) NULL,
|
|
cooldown_until DATETIME(6) NOT NULL,
|
|
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
|
PRIMARY KEY (id),
|
|
KEY idx_provider_connectivity_checks_model (provider_model_id, started_at DESC),
|
|
KEY idx_provider_connectivity_checks_status (status, started_at),
|
|
CONSTRAINT fk_provider_connectivity_checks_model FOREIGN KEY (provider_model_id) REFERENCES provider_models (id) ON DELETE RESTRICT,
|
|
CONSTRAINT chk_provider_connectivity_checks_status CHECK (status IN ('running', 'succeeded', 'failed'))
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
CREATE TABLE admin_audit_events (
|
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
operator_id BIGINT NULL,
|
|
action VARCHAR(128) NOT NULL,
|
|
target_type VARCHAR(64) NOT NULL,
|
|
target_id VARCHAR(128) NOT NULL,
|
|
result VARCHAR(16) NOT NULL,
|
|
request_id VARCHAR(128) NOT NULL,
|
|
summary JSON NOT NULL,
|
|
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY uq_admin_audit_events_request_action (request_id, action),
|
|
KEY idx_admin_audit_events_target (target_type, target_id, created_at),
|
|
KEY idx_admin_audit_events_operator (operator_id, created_at),
|
|
CONSTRAINT chk_admin_audit_events_result CHECK (result IN ('succeeded', 'failed')),
|
|
CONSTRAINT chk_admin_audit_events_summary CHECK (JSON_TYPE(summary) = 'OBJECT')
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
-- Backfill only envelopes that already passed the MVP-0 provider check constraint.
|
|
INSERT INTO provider_credentials (provider_id, credential_version, api_key_enc, key_id, status, created_at, updated_at)
|
|
SELECT id,
|
|
1,
|
|
api_key_enc,
|
|
JSON_UNQUOTE(JSON_EXTRACT(api_key_enc, '$.key_id')),
|
|
'active',
|
|
created_at,
|
|
updated_at
|
|
FROM providers
|
|
WHERE api_key_enc IS NOT NULL;
|
|
|
|
INSERT INTO provider_model_capabilities (provider_model_id, capability)
|
|
SELECT id,
|
|
CASE api_type
|
|
WHEN 'chat' THEN 'text'
|
|
WHEN 'images' THEN 'image_generate'
|
|
WHEN 'images_edits' THEN 'image_edit'
|
|
END
|
|
FROM provider_models;
|
|
|
|
ALTER TABLE providers
|
|
ADD COLUMN active_credential_id BIGINT UNSIGNED NULL,
|
|
ADD UNIQUE KEY uq_providers_active_credential (active_credential_id);
|
|
|
|
UPDATE providers p
|
|
JOIN provider_credentials c ON c.provider_id = p.id AND c.status = 'active'
|
|
SET p.active_credential_id = c.id;
|
|
|
|
ALTER TABLE providers
|
|
DROP CHECK chk_providers_auth,
|
|
ADD CONSTRAINT fk_providers_active_credential FOREIGN KEY (active_credential_id) REFERENCES provider_credentials (id) ON DELETE RESTRICT;
|
|
|
|
UPDATE providers SET api_key_enc = NULL WHERE active_credential_id IS NOT NULL;
|
|
|
|
ALTER TABLE providers
|
|
ADD CONSTRAINT chk_providers_auth_mvp1 CHECK (
|
|
auth_type IN ('none', 'bearer', 'x-goog-api-key') AND
|
|
((auth_type = 'none' AND active_credential_id IS NULL AND api_key_enc IS NULL) OR
|
|
(auth_type IN ('bearer', 'x-goog-api-key') AND active_credential_id IS NOT NULL AND api_key_enc IS NULL))
|
|
);
|
|
|
|
ALTER TABLE provider_models
|
|
DROP FOREIGN KEY fk_provider_models_provider,
|
|
ADD CONSTRAINT fk_provider_models_provider_mvp1 FOREIGN KEY (provider_id) REFERENCES providers (id) ON DELETE RESTRICT;
|
|
|
|
ALTER TABLE prompt_templates
|
|
ADD COLUMN capability VARCHAR(32) NULL,
|
|
ADD COLUMN default_role_rule TEXT NULL;
|
|
|
|
UPDATE prompt_templates
|
|
SET capability = CASE api_type
|
|
WHEN 'chat' THEN 'text'
|
|
WHEN 'images' THEN 'image_generate'
|
|
WHEN 'images_edits' THEN 'image_edit'
|
|
END,
|
|
default_role_rule = '';
|
|
|
|
ALTER TABLE prompt_templates
|
|
MODIFY COLUMN capability VARCHAR(32) NOT NULL,
|
|
MODIFY COLUMN default_role_rule TEXT NOT NULL,
|
|
ADD CONSTRAINT chk_prompt_templates_capability CHECK (capability IN ('text', 'image_generate', 'image_edit'));
|
|
|
|
ALTER TABLE generations
|
|
ADD COLUMN route_pool_id BIGINT UNSIGNED NULL,
|
|
ADD COLUMN route_pool_version INT UNSIGNED NULL,
|
|
ADD COLUMN prompt_template_id BIGINT UNSIGNED NULL,
|
|
ADD COLUMN route_snapshot JSON NULL,
|
|
ADD COLUMN role_rule TEXT NULL,
|
|
ADD COLUMN provider_attempt_count INT UNSIGNED NOT NULL DEFAULT 0,
|
|
ADD KEY idx_generations_route_pool (route_pool_id),
|
|
ADD KEY idx_generations_prompt_template (prompt_template_id),
|
|
ADD CONSTRAINT fk_generations_route_pool FOREIGN KEY (route_pool_id) REFERENCES route_pools (id) ON DELETE RESTRICT,
|
|
ADD CONSTRAINT fk_generations_prompt_template FOREIGN KEY (prompt_template_id) REFERENCES prompt_templates (id) ON DELETE RESTRICT,
|
|
ADD CONSTRAINT chk_generations_route_snapshot CHECK (
|
|
(route_pool_id IS NULL AND route_pool_version IS NULL AND prompt_template_id IS NULL AND route_snapshot IS NULL) OR
|
|
(route_pool_id IS NOT NULL AND route_pool_version IS NOT NULL AND prompt_template_id IS NOT NULL AND route_snapshot IS NOT NULL AND JSON_TYPE(route_snapshot) = 'OBJECT')
|
|
),
|
|
ADD CONSTRAINT chk_generations_provider_attempt_count CHECK (provider_attempt_count <= attempt_count);
|
|
|
|
ALTER TABLE generation_inputs
|
|
ADD COLUMN note VARCHAR(500) NULL,
|
|
ADD CONSTRAINT chk_generation_inputs_note CHECK (note IS NULL OR CHAR_LENGTH(note) <= 500);
|