Files
LWLT-AIBOT/control-plane/migrations/019_extension_host_updates.sql

78 lines
3.1 KiB
SQL

-- Bind browser accounts to Alibaba ECS Windows hosts and persist signed-in
-- browser extension releases/update orchestration. The updater remains part of
-- the control-plane process; target hosts only run one-shot Cloud Assistant
-- commands after every browser worker on that host reports an idle state.
ALTER TABLE users
ADD COLUMN IF NOT EXISTS extension_ecs_region_id text,
ADD COLUMN IF NOT EXISTS extension_ecs_instance_id text;
ALTER TABLE users
DROP CONSTRAINT IF EXISTS users_extension_ecs_binding_pair_check;
ALTER TABLE users
ADD CONSTRAINT users_extension_ecs_binding_pair_check
CHECK (
(extension_ecs_region_id IS NULL AND extension_ecs_instance_id IS NULL)
OR (
extension_ecs_region_id ~ '^[a-z0-9][a-z0-9-]{0,63}$'
AND extension_ecs_instance_id ~ '^i-[A-Za-z0-9]{6,64}$'
)
);
CREATE INDEX IF NOT EXISTS users_extension_ecs_host_idx
ON users (organization_id, extension_ecs_region_id, extension_ecs_instance_id)
WHERE extension_ecs_region_id IS NOT NULL AND extension_ecs_instance_id IS NOT NULL;
CREATE TABLE IF NOT EXISTS extension_releases (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id uuid NOT NULL REFERENCES organizations(id),
version text NOT NULL,
object_key text NOT NULL,
sha256 text NOT NULL,
byte_size integer NOT NULL,
extension_manifest jsonb NOT NULL,
is_active boolean NOT NULL DEFAULT false,
published_by uuid NOT NULL REFERENCES users(id),
created_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (organization_id, version),
UNIQUE (organization_id, object_key),
CHECK (version ~ '^[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?$'),
CHECK (sha256 ~ '^[a-f0-9]{64}$'),
CHECK (byte_size BETWEEN 1 AND 50000000),
CHECK (char_length(object_key) BETWEEN 1 AND 500)
);
CREATE UNIQUE INDEX IF NOT EXISTS extension_releases_one_active_idx
ON extension_releases (organization_id)
WHERE is_active = true;
CREATE INDEX IF NOT EXISTS extension_releases_created_idx
ON extension_releases (organization_id, created_at DESC);
CREATE TABLE IF NOT EXISTS extension_host_updates (
organization_id uuid NOT NULL REFERENCES organizations(id),
ecs_region_id text NOT NULL,
ecs_instance_id text NOT NULL,
release_id uuid NOT NULL REFERENCES extension_releases(id),
status text NOT NULL,
attempt_count integer NOT NULL DEFAULT 0,
invocation_id text,
error_code text,
error_message text,
started_at timestamptz,
deployed_at timestamptz,
verified_at timestamptz,
updated_at timestamptz NOT NULL DEFAULT now(),
PRIMARY KEY (organization_id, ecs_region_id, ecs_instance_id),
CHECK (status IN ('waiting_for_idle', 'running', 'deployed', 'verified', 'failed')),
CHECK (attempt_count BETWEEN 0 AND 3),
CHECK (ecs_region_id ~ '^[a-z0-9][a-z0-9-]{0,63}$'),
CHECK (ecs_instance_id ~ '^i-[A-Za-z0-9]{6,64}$'),
CHECK (error_code IS NULL OR char_length(error_code) <= 120),
CHECK (error_message IS NULL OR char_length(error_message) <= 2000)
);
CREATE INDEX IF NOT EXISTS extension_host_updates_release_status_idx
ON extension_host_updates (organization_id, release_id, status, updated_at DESC);