Files
crank/crates/crank-registry/src/migrations.rs
T
github-ops 1cf1efadfe
Deploy / deploy (push) Successful in 33s
CI / Rust Checks (push) Successful in 5m12s
CI / UI Checks (push) Successful in 5s
CI / Deployment Manifests (push) Successful in 3s
CI / Frontend E2E (push) Successful in 3m56s
chore: publish clean community baseline
2026-06-16 23:26:28 +00:00

600 lines
19 KiB
Rust

use sqlx::{PgPool, query};
pub async fn apply_postgres(pool: &PgPool) -> Result<(), sqlx::Error> {
query(
"create table if not exists workspaces (
id text primary key,
slug text not null unique,
display_name text not null,
status text not null,
settings_json jsonb not null default '{}'::jsonb,
created_at timestamptz not null,
updated_at timestamptz not null
)",
)
.execute(pool)
.await?;
query(
"create table if not exists users (
id text primary key,
email text not null unique,
display_name text not null,
password_hash text null,
status text not null,
created_at timestamptz not null
)",
)
.execute(pool)
.await?;
query("alter table users add column if not exists password_hash text null")
.execute(pool)
.await?;
query(
"insert into users (
id,
email,
display_name,
status,
created_at
) values (
'user_default_owner',
'owner@crank.local',
'Workspace Owner',
'active',
now()
)
on conflict (id) do nothing",
)
.execute(pool)
.await?;
query(
"create table if not exists memberships (
workspace_id text not null references workspaces(id) on delete cascade,
user_id text not null references users(id) on delete cascade,
role text not null,
created_at timestamptz not null,
primary key (workspace_id, user_id)
)",
)
.execute(pool)
.await?;
query(
"create table if not exists user_sessions (
id text primary key,
user_id text not null references users(id) on delete cascade,
current_workspace_id text null references workspaces(id) on delete set null,
secret_hash text not null,
status text not null,
expires_at timestamptz not null,
last_seen_at timestamptz null,
created_at timestamptz not null
)",
)
.execute(pool)
.await?;
query(
"alter table user_sessions
add column if not exists current_workspace_id text null references workspaces(id) on delete set null",
)
.execute(pool)
.await?;
query(
"insert into workspaces (
id,
slug,
display_name,
status,
settings_json,
created_at,
updated_at
) values (
'ws_default',
'default',
'Default Workspace',
'active',
'{}'::jsonb,
now(),
now()
)
on conflict (id) do nothing",
)
.execute(pool)
.await?;
query(
"insert into memberships (
workspace_id,
user_id,
role,
created_at
) values (
'ws_default',
'user_default_owner',
'owner',
now()
)
on conflict (workspace_id, user_id) do nothing",
)
.execute(pool)
.await?;
query(
"create table if not exists invitation_tokens (
id text primary key,
workspace_id text not null references workspaces(id) on delete cascade,
email text not null,
role text not null,
status text not null,
token_hash text not null,
expires_at timestamptz not null,
created_at timestamptz not null
)",
)
.execute(pool)
.await?;
query(
"create table if not exists platform_api_keys (
id text primary key,
workspace_id text not null references workspaces(id) on delete cascade,
agent_id text null,
name text not null,
prefix text not null,
secret_hash text not null,
scopes_json jsonb not null,
status text not null,
created_at timestamptz not null,
last_used_at timestamptz null,
revoked_at timestamptz null
)",
)
.execute(pool)
.await?;
query(
"create unique index if not exists platform_api_keys_workspace_name_idx on platform_api_keys(workspace_id, name)",
)
.execute(pool)
.await?;
query("alter table platform_api_keys add column if not exists agent_id text null")
.execute(pool)
.await?;
query(
"insert into workspaces (
id,
slug,
display_name,
status,
settings_json,
created_at,
updated_at
) values (
'ws_default',
'default',
'Default Workspace',
'active',
'{}'::jsonb,
now(),
now()
)
on conflict (id) do nothing",
)
.execute(pool)
.await?;
query(
"create table if not exists operations (
id text primary key,
workspace_id text null references workspaces(id) on delete cascade,
name text not null,
display_name text not null,
category text not null default 'general',
protocol text not null,
security_level text not null default 'standard',
status text not null,
current_draft_version integer not null default 1,
latest_published_version integer null,
created_at timestamptz not null,
updated_at timestamptz not null,
published_at timestamptz null
)",
)
.execute(pool)
.await?;
query("alter table operations add column if not exists workspace_id text null references workspaces(id) on delete cascade")
.execute(pool)
.await?;
query(
"alter table operations add column if not exists category text not null default 'general'",
)
.execute(pool)
.await?;
query(
"alter table operations add column if not exists security_level text not null default 'standard'",
)
.execute(pool)
.await?;
query("update operations set workspace_id = 'ws_default' where workspace_id is null")
.execute(pool)
.await?;
query("alter table operations alter column workspace_id set not null")
.execute(pool)
.await?;
query("alter table operations drop constraint if exists operations_name_key")
.execute(pool)
.await?;
query(
"create unique index if not exists operations_workspace_name_idx on operations(workspace_id, name)",
)
.execute(pool)
.await?;
query(
"create table if not exists operation_versions (
operation_id text not null references operations(id) on delete cascade,
version integer not null,
status text not null,
target_json jsonb not null,
input_schema_json jsonb not null,
output_schema_json jsonb not null,
input_mapping_json jsonb not null,
output_mapping_json jsonb not null,
execution_config_json jsonb not null,
tool_description_json jsonb not null,
samples_json jsonb null,
generated_draft_json jsonb null,
config_export_json jsonb null,
change_note text null,
created_at timestamptz not null,
created_by text null,
primary key (operation_id, version)
)",
)
.execute(pool)
.await?;
query(
"create table if not exists published_operations (
operation_id text primary key references operations(id) on delete cascade,
version integer not null,
published_at timestamptz not null,
published_by text null,
foreign key (operation_id, version) references operation_versions(operation_id, version) on delete cascade
)",
)
.execute(pool)
.await?;
query(
"create table if not exists operation_samples (
id text primary key,
operation_id text not null references operations(id) on delete cascade,
version integer not null,
sample_kind text not null,
storage_ref text not null,
content_type text not null,
file_name text null,
created_at timestamptz not null,
foreign key (operation_id, version) references operation_versions(operation_id, version) on delete cascade
)",
)
.execute(pool)
.await?;
query(
"create table if not exists descriptors (
id text primary key,
operation_id text null references operations(id) on delete cascade,
version integer null,
descriptor_kind text not null,
storage_ref text not null,
source_name text null,
package_index_json jsonb null,
created_at timestamptz not null,
foreign key (operation_id, version) references operation_versions(operation_id, version) on delete cascade
)",
)
.execute(pool)
.await?;
query(
"create table if not exists auth_profiles (
id text primary key,
workspace_id text null references workspaces(id) on delete cascade,
name text not null,
kind text not null,
config_json jsonb not null,
created_at timestamptz not null,
updated_at timestamptz not null
)",
)
.execute(pool)
.await?;
query("alter table auth_profiles add column if not exists workspace_id text null references workspaces(id) on delete cascade")
.execute(pool)
.await?;
query("update auth_profiles set workspace_id = 'ws_default' where workspace_id is null")
.execute(pool)
.await?;
query("alter table auth_profiles alter column workspace_id set not null")
.execute(pool)
.await?;
query("alter table auth_profiles drop constraint if exists auth_profiles_name_key")
.execute(pool)
.await?;
query(
"create unique index if not exists auth_profiles_workspace_name_idx on auth_profiles(workspace_id, name)",
)
.execute(pool)
.await?;
query(
"create table if not exists secrets (
id text primary key,
workspace_id text not null references workspaces(id) on delete cascade,
name text not null,
kind text not null,
status text not null,
current_version integer not null,
last_used_at timestamptz null,
created_at timestamptz not null,
updated_at timestamptz not null
)",
)
.execute(pool)
.await?;
query(
"create unique index if not exists secrets_workspace_name_idx on secrets(workspace_id, name)",
)
.execute(pool)
.await?;
query(
"create table if not exists secret_versions (
secret_id text not null references secrets(id) on delete cascade,
version integer not null,
ciphertext text not null,
key_version text not null,
created_at timestamptz not null,
created_by text null references users(id) on delete set null,
primary key (secret_id, version)
)",
)
.execute(pool)
.await?;
query(
"create table if not exists yaml_import_jobs (
id text primary key,
source_sample_id text null references operation_samples(id) on delete set null,
status text not null,
format_version text not null,
mode text not null,
result_operation_id text null references operations(id) on delete set null,
result_version integer null,
error_text text null,
created_at timestamptz not null,
finished_at timestamptz null
)",
)
.execute(pool)
.await?;
query(
"create table if not exists agents (
id text primary key,
workspace_id text not null references workspaces(id) on delete cascade,
slug text not null,
display_name text not null,
description text not null,
status text not null,
current_draft_version integer not null default 1,
latest_published_version integer null,
created_at timestamptz not null,
updated_at timestamptz not null,
published_at timestamptz null
)",
)
.execute(pool)
.await?;
query(
"create unique index if not exists agents_workspace_slug_idx on agents(workspace_id, slug)",
)
.execute(pool)
.await?;
query(
"create table if not exists agent_versions (
agent_id text not null references agents(id) on delete cascade,
version integer not null,
status text not null,
instructions_json jsonb not null,
tool_selection_policy_json jsonb not null,
created_at timestamptz not null,
primary key (agent_id, version)
)",
)
.execute(pool)
.await?;
query(
"create table if not exists agent_operation_bindings (
agent_id text not null references agents(id) on delete cascade,
agent_version integer not null,
operation_id text not null references operations(id) on delete cascade,
operation_version integer not null,
tool_name text not null,
tool_title text not null,
tool_description_override text null,
enabled boolean not null default true,
foreign key (agent_id, agent_version) references agent_versions(agent_id, version) on delete cascade,
foreign key (operation_id, operation_version) references operation_versions(operation_id, version) on delete cascade
)",
)
.execute(pool)
.await?;
query(
"create unique index if not exists agent_bindings_tool_name_idx on agent_operation_bindings(agent_id, agent_version, tool_name)",
)
.execute(pool)
.await?;
query(
"create table if not exists published_agents (
agent_id text primary key references agents(id) on delete cascade,
version integer not null,
published_at timestamptz not null,
published_by text null,
foreign key (agent_id, version) references agent_versions(agent_id, version) on delete cascade
)",
)
.execute(pool)
.await?;
query(
"create table if not exists invocation_logs (
id text primary key,
workspace_id text not null references workspaces(id) on delete cascade,
agent_id text null references agents(id) on delete set null,
operation_id text not null references operations(id) on delete cascade,
source text not null,
level text not null,
status text not null,
tool_name text not null,
message text not null,
request_id text null,
status_code integer null,
duration_ms bigint not null,
error_kind text null,
request_preview_json jsonb not null,
response_preview_json jsonb not null,
created_at timestamptz not null
)",
)
.execute(pool)
.await?;
query(
"create index if not exists invocation_logs_workspace_created_idx on invocation_logs(workspace_id, created_at desc)",
)
.execute(pool)
.await?;
query(
"create index if not exists invocation_logs_workspace_operation_created_idx on invocation_logs(workspace_id, operation_id, created_at desc)",
)
.execute(pool)
.await?;
query(
"create index if not exists invocation_logs_workspace_agent_created_idx on invocation_logs(workspace_id, agent_id, created_at desc)",
)
.execute(pool)
.await?;
query(
"create table if not exists usage_rollups (
workspace_id text not null references workspaces(id) on delete cascade,
agent_id text null references agents(id) on delete cascade,
operation_id text null references operations(id) on delete cascade,
period text not null,
calls_total bigint not null,
calls_ok bigint not null,
calls_error bigint not null,
p50_ms bigint not null,
p95_ms bigint not null,
p99_ms bigint not null,
updated_at timestamptz not null
)",
)
.execute(pool)
.await?;
query(
"create table if not exists stream_sessions (
id text primary key,
workspace_id text not null references workspaces(id) on delete cascade,
agent_id text null references agents(id) on delete set null,
operation_id text not null references operations(id) on delete cascade,
protocol text not null,
mode text not null,
status text not null,
cursor_json jsonb null,
state_json jsonb not null,
expires_at timestamptz not null,
last_poll_at timestamptz null,
created_at timestamptz not null,
closed_at timestamptz null
)",
)
.execute(pool)
.await?;
query(
"create index if not exists stream_sessions_workspace_status_idx
on stream_sessions(workspace_id, status, created_at desc)",
)
.execute(pool)
.await?;
query(
"create index if not exists stream_sessions_expires_at_idx
on stream_sessions(expires_at)",
)
.execute(pool)
.await?;
query(
"create table if not exists async_jobs (
id text primary key,
workspace_id text not null references workspaces(id) on delete cascade,
agent_id text null references agents(id) on delete set null,
operation_id text not null references operations(id) on delete cascade,
status text not null,
progress_json jsonb not null,
result_json jsonb null,
error_json jsonb null,
expires_at timestamptz null,
last_poll_at timestamptz null,
created_at timestamptz not null,
updated_at timestamptz not null,
finished_at timestamptz null
)",
)
.execute(pool)
.await?;
query("alter table async_jobs add column if not exists last_poll_at timestamptz null")
.execute(pool)
.await?;
query(
"create index if not exists async_jobs_workspace_status_idx
on async_jobs(workspace_id, status, updated_at desc)",
)
.execute(pool)
.await?;
query(
"create index if not exists async_jobs_expires_at_idx
on async_jobs(expires_at)",
)
.execute(pool)
.await?;
Ok(())
}