- Port design tokens, sidebar, topbar, and icons to inline SVG set - Rewrite each page (Home/Team/Work/Chat/Files/Approvals/Social/Settings) to drive real snapshot data and match the bento, kanban, three-pane chat, file tree + pinned cards, approval queue, social schedule + calendar, and settings sub-nav layouts - Split Chat and Settings into per-concern subcomponents so every file stays under 500 lines - Add schema v4 for pinned files and scheduled posts plus IPC + service wiring; cover new behavior in unit tests - Update onboarding labels and Hire form to remove ambiguity for the expanded e2e suite (all settings tabs + 8 routes at 1280 and 980)
489 lines
17 KiB
TypeScript
489 lines
17 KiB
TypeScript
import type { DatabaseSync } from "node:sqlite";
|
|
|
|
const SCHEMA_VERSION = 4;
|
|
|
|
export function installSchema(db: DatabaseSync): void {
|
|
db.exec(`
|
|
create table if not exists schema_migrations (
|
|
version integer primary key,
|
|
name text not null,
|
|
applied_at text not null
|
|
);
|
|
`);
|
|
|
|
const row = db.prepare("select coalesce(max(version), 0) as version from schema_migrations").get() as { version: number };
|
|
let currentVersion = row.version;
|
|
if (currentVersion > SCHEMA_VERSION) {
|
|
throw new Error(`Database schema ${currentVersion} is newer than supported schema ${SCHEMA_VERSION}.`);
|
|
}
|
|
if (currentVersion === SCHEMA_VERSION) return;
|
|
|
|
if (currentVersion < 1) {
|
|
db.exec(`
|
|
create table if not exists organizations (
|
|
id text primary key,
|
|
name text not null,
|
|
mission text not null,
|
|
goal text not null,
|
|
created_at text not null
|
|
);
|
|
|
|
create table if not exists employees (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
display_name text not null,
|
|
role text not null,
|
|
created_at text not null
|
|
);
|
|
|
|
create table if not exists agents (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
name text not null,
|
|
role text not null,
|
|
department text not null,
|
|
model_provider_id text,
|
|
model_id text,
|
|
budget_cents integer not null,
|
|
manager_agent_id text references agents(id) on delete set null,
|
|
lifecycle text not null,
|
|
created_at text not null
|
|
);
|
|
|
|
create table if not exists tasks (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
title text not null,
|
|
description text not null,
|
|
status text not null,
|
|
assignee_agent_id text references agents(id) on delete set null,
|
|
risk text not null,
|
|
created_at text not null,
|
|
updated_at text not null
|
|
);
|
|
|
|
create table if not exists approvals (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
kind text not null,
|
|
title text not null,
|
|
details text not null,
|
|
risk text not null,
|
|
requested_by_type text not null,
|
|
requested_by_id text,
|
|
state text not null,
|
|
decided_by_employee_id text references employees(id) on delete set null,
|
|
created_at text not null,
|
|
decided_at text
|
|
);
|
|
|
|
create table if not exists chat_spaces (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
space_type text not null,
|
|
name text not null,
|
|
topic text not null,
|
|
visibility text not null,
|
|
created_at text not null
|
|
);
|
|
|
|
create table if not exists chat_memberships (
|
|
space_id text not null references chat_spaces(id) on delete cascade,
|
|
principal_type text not null,
|
|
principal_id text not null,
|
|
role text not null,
|
|
mute_state text not null,
|
|
primary key (space_id, principal_type, principal_id)
|
|
);
|
|
|
|
create table if not exists chat_messages (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
space_id text not null references chat_spaces(id) on delete cascade,
|
|
thread_id text,
|
|
sender_type text not null,
|
|
sender_id text,
|
|
body_md text not null,
|
|
created_at text not null,
|
|
edited_at text,
|
|
deleted_at text
|
|
);
|
|
|
|
create table if not exists file_objects (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
name text not null,
|
|
kind text not null,
|
|
size_bytes integer not null,
|
|
sha256 text not null,
|
|
storage_path text not null,
|
|
owner_type text not null,
|
|
owner_id text,
|
|
created_at text not null
|
|
);
|
|
|
|
create table if not exists providers (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
provider_key text not null,
|
|
label text not null,
|
|
auth_type text not null,
|
|
model text,
|
|
credential_id text,
|
|
enabled integer not null,
|
|
created_at text not null,
|
|
unique(org_id, provider_key)
|
|
);
|
|
|
|
create table if not exists credentials (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
provider_key text not null,
|
|
kind text not null,
|
|
ciphertext blob not null,
|
|
display_hint text not null,
|
|
created_at text not null
|
|
);
|
|
|
|
create table if not exists skill_definitions (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
slug text not null,
|
|
name text not null,
|
|
owner_type text not null,
|
|
status text not null,
|
|
created_at text not null,
|
|
unique(org_id, slug)
|
|
);
|
|
|
|
create table if not exists skill_revisions (
|
|
id text primary key,
|
|
skill_id text not null references skill_definitions(id) on delete cascade,
|
|
version_semver text not null,
|
|
manifest_json text not null,
|
|
source_type text not null,
|
|
source_ref text not null,
|
|
published_at text not null,
|
|
immutable_checksum text not null,
|
|
unique(skill_id, version_semver)
|
|
);
|
|
|
|
create table if not exists skill_artifacts (
|
|
id text primary key,
|
|
revision_id text not null references skill_revisions(id) on delete cascade,
|
|
artifact_type text not null,
|
|
object_key text not null,
|
|
sha256 text not null,
|
|
size_bytes integer not null
|
|
);
|
|
|
|
create table if not exists skill_tests (
|
|
id text primary key,
|
|
revision_id text not null references skill_revisions(id) on delete cascade,
|
|
test_type text not null,
|
|
expected_output_ref text not null,
|
|
last_result text,
|
|
last_run_at text
|
|
);
|
|
|
|
create table if not exists skill_bindings (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
agent_id text not null references agents(id) on delete cascade,
|
|
skill_id text not null references skill_definitions(id) on delete cascade,
|
|
pinned_revision_id text not null references skill_revisions(id) on delete cascade,
|
|
binding_mode text not null,
|
|
priority integer not null,
|
|
enabled integer not null,
|
|
unique(agent_id, skill_id)
|
|
);
|
|
|
|
create table if not exists social_accounts (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
platform text not null,
|
|
handle text not null,
|
|
display_name text not null,
|
|
authorized_employee_id text references employees(id) on delete set null,
|
|
created_at text not null
|
|
);
|
|
|
|
create table if not exists social_account_grants (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
social_account_id text not null references social_accounts(id) on delete cascade,
|
|
employee_id text not null references employees(id) on delete cascade,
|
|
role text not null,
|
|
scope_json text not null,
|
|
created_at text not null
|
|
);
|
|
|
|
create table if not exists browser_actions (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
social_account_id text not null references social_accounts(id) on delete cascade,
|
|
action_type text not null,
|
|
policy_decision text not null,
|
|
evidence_file_id text references file_objects(id) on delete set null,
|
|
created_at text not null
|
|
);
|
|
|
|
create table if not exists migration_reports (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
source_ref text not null,
|
|
report_json text not null,
|
|
created_at text not null
|
|
);
|
|
|
|
create table if not exists audit_events (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
entity_type text not null,
|
|
entity_id text not null,
|
|
actor_type text not null,
|
|
actor_id text,
|
|
action text not null,
|
|
payload_json text not null,
|
|
created_at text not null
|
|
);
|
|
|
|
create index if not exists idx_tasks_org_status on tasks(org_id, status);
|
|
create index if not exists idx_messages_space_created on chat_messages(space_id, created_at);
|
|
create index if not exists idx_audit_org_created on audit_events(org_id, created_at);
|
|
insert into schema_migrations(version, name, applied_at)
|
|
values (1, 'initial_enterprise_schema', datetime('now'));
|
|
`);
|
|
currentVersion = 1;
|
|
}
|
|
|
|
if (currentVersion < 2) {
|
|
db.exec(`
|
|
create table if not exists skill_dependencies (
|
|
revision_id text not null references skill_revisions(id) on delete cascade,
|
|
depends_on_revision_id text not null references skill_revisions(id) on delete cascade,
|
|
dependency_kind text not null,
|
|
optional integer not null,
|
|
primary key (revision_id, depends_on_revision_id)
|
|
);
|
|
|
|
create table if not exists skill_runtime_snapshots (
|
|
id text primary key,
|
|
agent_id text not null references agents(id) on delete cascade,
|
|
run_id text not null,
|
|
compiled_prompt text not null,
|
|
tools_manifest text not null,
|
|
source_revision_ids text not null,
|
|
created_at text not null
|
|
);
|
|
|
|
create table if not exists skill_catalog_tags (
|
|
skill_id text not null references skill_definitions(id) on delete cascade,
|
|
tag text not null,
|
|
tag_type text not null,
|
|
primary key (skill_id, tag, tag_type)
|
|
);
|
|
|
|
create table if not exists chat_threads (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
space_id text not null references chat_spaces(id) on delete cascade,
|
|
root_message_id text references chat_messages(id) on delete set null,
|
|
title text not null,
|
|
state text not null,
|
|
created_at text not null,
|
|
updated_at text not null
|
|
);
|
|
|
|
create table if not exists chat_mentions (
|
|
message_id text not null references chat_messages(id) on delete cascade,
|
|
target_type text not null,
|
|
target_id text not null,
|
|
offset_start integer not null,
|
|
offset_end integer not null
|
|
);
|
|
|
|
create table if not exists chat_attachments (
|
|
message_id text not null references chat_messages(id) on delete cascade,
|
|
file_id text not null references file_objects(id) on delete cascade,
|
|
transfer_type text not null,
|
|
checksum text not null,
|
|
preview_key text
|
|
);
|
|
|
|
create table if not exists chat_presence (
|
|
principal_type text not null,
|
|
principal_id text not null,
|
|
status text not null,
|
|
status_text text not null,
|
|
last_seen_at text not null,
|
|
primary key (principal_type, principal_id)
|
|
);
|
|
|
|
create table if not exists chat_slash_invocations (
|
|
id text primary key,
|
|
message_id text not null references chat_messages(id) on delete cascade,
|
|
command text not null,
|
|
args_json text not null,
|
|
result_ref text,
|
|
created_at text not null
|
|
);
|
|
|
|
create table if not exists provider_requests (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
provider_id text not null references providers(id) on delete cascade,
|
|
provider_key text not null,
|
|
model text not null,
|
|
prompt_sha256 text not null,
|
|
response_text text,
|
|
raw_response_json text,
|
|
state text not null,
|
|
error_message text,
|
|
created_at text not null,
|
|
completed_at text
|
|
);
|
|
|
|
create table if not exists policy_rules (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
subject_type text not null,
|
|
subject_id text,
|
|
action text not null,
|
|
effect text not null,
|
|
risk_ceiling text not null,
|
|
created_at text not null
|
|
);
|
|
|
|
create index if not exists idx_provider_requests_org_created on provider_requests(org_id, created_at);
|
|
create index if not exists idx_chat_threads_space_updated on chat_threads(space_id, updated_at);
|
|
insert into policy_rules(id, org_id, subject_type, subject_id, action, effect, risk_ceiling, created_at)
|
|
select
|
|
'pol_' || lower(hex(randomblob(16))),
|
|
id,
|
|
'organization',
|
|
id,
|
|
'task_create',
|
|
'require_approval',
|
|
'medium',
|
|
datetime('now')
|
|
from organizations
|
|
where not exists (
|
|
select 1 from policy_rules
|
|
where policy_rules.org_id = organizations.id and policy_rules.action = 'task_create'
|
|
);
|
|
insert into schema_migrations(version, name, applied_at)
|
|
values (2, 'collaboration_provider_policy_schema', datetime('now'));
|
|
`);
|
|
currentVersion = 2;
|
|
}
|
|
|
|
if (currentVersion < 3) {
|
|
db.exec(`
|
|
alter table organizations add column description text not null default '';
|
|
alter table organizations add column execution_mode text not null default 'ai_ceo';
|
|
alter table organizations add column auto_approve_hires integer not null default 1;
|
|
alter table organizations add column review_deliverables integer not null default 0;
|
|
|
|
alter table agents add column title text not null default '';
|
|
alter table agents add column role_level text not null default 'staff';
|
|
alter table agents add column model_strategy text not null default 'pooled';
|
|
alter table agents add column workspace_id text;
|
|
alter table agents add column heartbeat_enabled integer not null default 0;
|
|
alter table agents add column heartbeat_interval_sec integer not null default 0;
|
|
|
|
alter table tasks add column project_id text;
|
|
alter table tasks add column goal_id text;
|
|
alter table tasks add column workspace_id text;
|
|
alter table tasks add column priority text not null default 'normal';
|
|
alter table tasks add column requires_filesystem integer not null default 0;
|
|
|
|
create table if not exists workspaces (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
name text not null,
|
|
local_path text not null,
|
|
repo_url text not null,
|
|
repo_ref text not null,
|
|
project_id text,
|
|
is_primary integer not null,
|
|
created_at text not null,
|
|
updated_at text not null
|
|
);
|
|
|
|
create table if not exists goals (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
title text not null,
|
|
description text not null,
|
|
status text not null,
|
|
owner_agent_id text references agents(id) on delete set null,
|
|
created_at text not null,
|
|
updated_at text not null
|
|
);
|
|
|
|
create table if not exists projects (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
goal_id text references goals(id) on delete set null,
|
|
name text not null,
|
|
description text not null,
|
|
lead_agent_id text references agents(id) on delete set null,
|
|
status text not null,
|
|
created_at text not null,
|
|
updated_at text not null
|
|
);
|
|
|
|
create table if not exists task_runs (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
task_id text not null references tasks(id) on delete cascade,
|
|
agent_id text references agents(id) on delete set null,
|
|
provider_id text references providers(id) on delete set null,
|
|
trigger text not null,
|
|
state text not null,
|
|
created_at text not null,
|
|
started_at text,
|
|
completed_at text,
|
|
error_message text
|
|
);
|
|
|
|
create index if not exists idx_workspaces_org_primary on workspaces(org_id, is_primary);
|
|
create index if not exists idx_goals_org_status on goals(org_id, status);
|
|
create index if not exists idx_projects_org_status on projects(org_id, status);
|
|
create index if not exists idx_task_runs_task_created on task_runs(task_id, created_at);
|
|
insert into schema_migrations(version, name, applied_at)
|
|
values (3, 'onboarding_execution_schema', datetime('now'));
|
|
`);
|
|
currentVersion = 3;
|
|
}
|
|
|
|
if (currentVersion < 4) {
|
|
db.exec(`
|
|
alter table file_objects add column pinned integer not null default 0;
|
|
alter table file_objects add column space_id text;
|
|
alter table file_objects add column updated_at text;
|
|
|
|
create table if not exists scheduled_posts (
|
|
id text primary key,
|
|
org_id text not null references organizations(id) on delete cascade,
|
|
social_account_id text not null references social_accounts(id) on delete cascade,
|
|
body_md text not null,
|
|
scheduled_for text not null,
|
|
state text not null,
|
|
approval_id text references approvals(id) on delete set null,
|
|
created_by_employee_id text references employees(id) on delete set null,
|
|
created_at text not null,
|
|
updated_at text not null
|
|
);
|
|
|
|
create index if not exists idx_files_org_pinned on file_objects(org_id, pinned);
|
|
create index if not exists idx_scheduled_posts_org_state on scheduled_posts(org_id, state);
|
|
create index if not exists idx_scheduled_posts_account_date on scheduled_posts(social_account_id, scheduled_for);
|
|
|
|
insert into schema_migrations(version, name, applied_at)
|
|
values (4, 'files_pinned_and_scheduled_posts', datetime('now'));
|
|
`);
|
|
}
|
|
}
|