Changeset 0.28.0 (#172)
This commit is contained in:
@@ -1,28 +1,24 @@
|
||||
-- ==========================================
|
||||
-- Chat Switchboard — 001 Core (SQLite)
|
||||
-- ==========================================
|
||||
-- Users, authentication, platform policies, global settings.
|
||||
-- v0.22.8: Domain-grouped migration
|
||||
-- ==========================================
|
||||
-- Consolidated v0.28.0
|
||||
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA foreign_keys = ON;
|
||||
|
||||
-- =========================================
|
||||
-- USERS
|
||||
-- =========================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id TEXT PRIMARY KEY,
|
||||
username TEXT NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
password_hash TEXT,
|
||||
display_name TEXT,
|
||||
avatar_url TEXT,
|
||||
role TEXT DEFAULT 'user'
|
||||
CHECK (role IN ('user', 'admin')),
|
||||
role TEXT DEFAULT 'user' CHECK (role IN ('user', 'admin')),
|
||||
is_active INTEGER DEFAULT 1,
|
||||
settings TEXT DEFAULT '{}',
|
||||
auth_source TEXT NOT NULL DEFAULT 'builtin',
|
||||
external_id TEXT,
|
||||
handle TEXT NOT NULL,
|
||||
encrypted_uek BLOB,
|
||||
uek_salt BLOB,
|
||||
uek_nonce BLOB,
|
||||
@@ -34,6 +30,8 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS users_username_ci ON users (username COLLATE NOCASE);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS users_email_ci ON users (email COLLATE NOCASE);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_handle ON users(handle COLLATE NOCASE);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_external_id ON users(auth_source, external_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
||||
|
||||
@@ -41,11 +39,6 @@ CREATE TRIGGER IF NOT EXISTS users_updated_at AFTER UPDATE ON users
|
||||
FOR EACH ROW WHEN NEW.updated_at = OLD.updated_at
|
||||
BEGIN UPDATE users SET updated_at = datetime('now') WHERE id = NEW.id; END;
|
||||
|
||||
|
||||
-- =========================================
|
||||
-- AUTH — REFRESH TOKENS
|
||||
-- =========================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS refresh_tokens (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
@@ -58,11 +51,6 @@ CREATE TABLE IF NOT EXISTS refresh_tokens (
|
||||
CREATE INDEX IF NOT EXISTS idx_refresh_tokens_user ON refresh_tokens(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_refresh_tokens_hash ON refresh_tokens(token_hash);
|
||||
|
||||
|
||||
-- =========================================
|
||||
-- PLATFORM POLICIES
|
||||
-- =========================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS platform_policies (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL,
|
||||
@@ -79,11 +67,6 @@ INSERT OR IGNORE INTO platform_policies (key, value) VALUES
|
||||
('allow_team_providers', 'true'),
|
||||
('kb_direct_access', 'true');
|
||||
|
||||
|
||||
-- =========================================
|
||||
-- GLOBAL SETTINGS
|
||||
-- =========================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS global_settings (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL DEFAULT '{}',
|
||||
@@ -95,4 +78,12 @@ INSERT OR IGNORE INTO global_settings (key, value) VALUES
|
||||
('registration', '{"enabled": true}'),
|
||||
('site', '{"name": "Chat Switchboard", "tagline": "Multi-Model AI Chat"}'),
|
||||
('banner', '{"enabled": false, "text": "", "bg": "#007a33", "fg": "#ffffff"}'),
|
||||
('model_roles', '{"utility": {"primary": null, "fallback": null}, "embedding": {"primary": null, "fallback": null}, "generation": {"primary": null, "fallback": null}}');
|
||||
('model_roles', '{"utility":{"primary":null,"fallback":null},"embedding":{"primary":null,"fallback":null},"generation":{"primary":null,"fallback":null}}');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_presence (
|
||||
user_id TEXT PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
|
||||
last_seen TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
status TEXT NOT NULL DEFAULT 'online'
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_user_presence_last_seen ON user_presence(last_seen DESC);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
-- Chat Switchboard — 002 Teams & Access Control (SQLite)
|
||||
-- Consolidated v0.28.0
|
||||
|
||||
CREATE TABLE IF NOT EXISTS teams (
|
||||
id TEXT PRIMARY KEY,
|
||||
@@ -17,8 +18,7 @@ CREATE TABLE IF NOT EXISTS team_members (
|
||||
id TEXT PRIMARY KEY,
|
||||
team_id TEXT NOT NULL REFERENCES teams(id) ON DELETE CASCADE,
|
||||
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
role TEXT NOT NULL DEFAULT 'member'
|
||||
CHECK (role IN ('admin', 'member')),
|
||||
role TEXT NOT NULL DEFAULT 'member' CHECK (role IN ('admin', 'member')),
|
||||
joined_at TEXT DEFAULT (datetime('now')),
|
||||
UNIQUE(team_id, user_id)
|
||||
);
|
||||
@@ -30,22 +30,18 @@ CREATE TABLE IF NOT EXISTS groups (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
scope TEXT NOT NULL DEFAULT 'global'
|
||||
CHECK (scope IN ('global', 'team')),
|
||||
scope TEXT NOT NULL DEFAULT 'global' CHECK (scope IN ('global', 'team')),
|
||||
team_id TEXT REFERENCES teams(id) ON DELETE CASCADE,
|
||||
created_by TEXT NOT NULL REFERENCES users(id),
|
||||
created_by TEXT REFERENCES users(id),
|
||||
source TEXT NOT NULL DEFAULT 'manual' CHECK (source IN ('manual', 'oidc', 'system')),
|
||||
permissions TEXT NOT NULL DEFAULT '[]',
|
||||
token_budget_daily INTEGER,
|
||||
token_budget_monthly INTEGER,
|
||||
allowed_models TEXT,
|
||||
created_at TEXT DEFAULT (datetime('now')),
|
||||
updated_at TEXT DEFAULT (datetime('now')),
|
||||
|
||||
CHECK (
|
||||
(scope = 'global' AND team_id IS NULL) OR
|
||||
(scope = 'team' AND team_id IS NOT NULL)
|
||||
)
|
||||
updated_at TEXT DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_groups_name_scope
|
||||
ON groups(name, COALESCE(team_id, ''));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS group_members (
|
||||
id TEXT PRIMARY KEY,
|
||||
group_id TEXT NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
|
||||
@@ -57,3 +53,14 @@ CREATE TABLE IF NOT EXISTS group_members (
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_group_members_group ON group_members(group_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_group_members_user ON group_members(user_id);
|
||||
|
||||
INSERT OR IGNORE INTO groups
|
||||
(id, name, description, scope, created_by, source, permissions, created_at, updated_at)
|
||||
VALUES (
|
||||
'00000000-0000-0000-0000-000000000001',
|
||||
'Everyone',
|
||||
'Implicit group — all authenticated users receive these permissions.',
|
||||
'global', NULL, 'system',
|
||||
'["model.use","kb.read","channel.create"]',
|
||||
datetime('now'), datetime('now')
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
-- Chat Switchboard — 003 Providers & Routing (SQLite)
|
||||
-- Consolidated v0.28.0: adds capability_match policy type
|
||||
|
||||
CREATE TABLE IF NOT EXISTS provider_configs (
|
||||
id TEXT PRIMARY KEY,
|
||||
@@ -19,8 +20,7 @@ CREATE TABLE IF NOT EXISTS provider_configs (
|
||||
proxy_mode TEXT NOT NULL DEFAULT 'system' CHECK (proxy_mode IN ('system', 'direct', 'custom')),
|
||||
proxy_url TEXT,
|
||||
created_at TEXT DEFAULT (datetime('now')),
|
||||
updated_at TEXT DEFAULT (datetime('now')),
|
||||
CHECK (proxy_mode != 'custom' OR proxy_url IS NOT NULL)
|
||||
updated_at TEXT DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_provider_configs_scope ON provider_configs(scope);
|
||||
@@ -77,7 +77,8 @@ CREATE TABLE IF NOT EXISTS provider_health (
|
||||
UNIQUE (provider_config_id, window_start)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_provider_health_window ON provider_health(provider_config_id, window_start);
|
||||
CREATE INDEX IF NOT EXISTS idx_provider_health_window
|
||||
ON provider_health (provider_config_id, window_start DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS capability_overrides (
|
||||
id TEXT PRIMARY KEY,
|
||||
@@ -98,7 +99,8 @@ CREATE TABLE IF NOT EXISTS routing_policies (
|
||||
scope TEXT NOT NULL DEFAULT 'global' CHECK (scope IN ('global', 'team')),
|
||||
team_id TEXT REFERENCES teams(id) ON DELETE CASCADE,
|
||||
priority INTEGER NOT NULL DEFAULT 100,
|
||||
policy_type TEXT NOT NULL CHECK (policy_type IN ('provider_prefer', 'team_route', 'cost_limit', 'model_alias')),
|
||||
policy_type TEXT NOT NULL
|
||||
CHECK (policy_type IN ('provider_prefer', 'team_route', 'cost_limit', 'model_alias', 'capability_match')),
|
||||
config TEXT NOT NULL DEFAULT '{}',
|
||||
is_active INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
@@ -106,4 +108,3 @@ CREATE TABLE IF NOT EXISTS routing_policies (
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_routing_policies_active ON routing_policies(is_active, priority);
|
||||
CREATE INDEX IF NOT EXISTS idx_routing_policies_team ON routing_policies(team_id);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
-- Chat Switchboard — 005 Channels & Conversations (SQLite)
|
||||
-- Consolidated v0.28.0
|
||||
|
||||
CREATE TABLE IF NOT EXISTS folders (
|
||||
id TEXT PRIMARY KEY,
|
||||
@@ -19,7 +20,8 @@ CREATE TABLE IF NOT EXISTS channels (
|
||||
user_id TEXT REFERENCES users(id) ON DELETE CASCADE,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
type TEXT DEFAULT 'direct' CHECK (type IN ('direct', 'group', 'workflow')),
|
||||
type TEXT DEFAULT 'direct'
|
||||
CHECK (type IN ('direct', 'dm', 'group', 'channel', 'workflow', 'service')),
|
||||
model TEXT,
|
||||
system_prompt TEXT,
|
||||
provider_config_id TEXT REFERENCES provider_configs(id) ON DELETE SET NULL,
|
||||
@@ -30,6 +32,17 @@ CREATE TABLE IF NOT EXISTS channels (
|
||||
team_id TEXT REFERENCES teams(id) ON DELETE SET NULL,
|
||||
settings TEXT DEFAULT '{}',
|
||||
tags TEXT DEFAULT '[]',
|
||||
ai_mode TEXT NOT NULL DEFAULT 'auto',
|
||||
topic TEXT,
|
||||
allow_anonymous INTEGER NOT NULL DEFAULT 0,
|
||||
workflow_id TEXT,
|
||||
workflow_version INTEGER,
|
||||
current_stage INTEGER DEFAULT 0,
|
||||
stage_data TEXT DEFAULT '{}',
|
||||
workflow_status TEXT DEFAULT 'active'
|
||||
CHECK (workflow_status IN ('active', 'completed', 'stale', 'cancelled')),
|
||||
last_activity_at TEXT DEFAULT (datetime('now')),
|
||||
kb_auto_inject INTEGER NOT NULL DEFAULT 0,
|
||||
project_id TEXT,
|
||||
workspace_id TEXT,
|
||||
created_at TEXT DEFAULT (datetime('now')),
|
||||
@@ -43,6 +56,7 @@ CREATE INDEX IF NOT EXISTS idx_channels_team ON channels(team_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_channels_folder ON channels(folder_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_channels_project ON channels(project_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_channels_workspace ON channels(workspace_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_channels_workflow ON channels(workflow_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS messages (
|
||||
id TEXT PRIMARY KEY,
|
||||
@@ -77,6 +91,7 @@ CREATE TABLE IF NOT EXISTS channel_participants (
|
||||
avatar_url TEXT,
|
||||
joined_at TEXT DEFAULT (datetime('now')),
|
||||
last_read_at TEXT DEFAULT (datetime('now')),
|
||||
last_read_message_id TEXT,
|
||||
UNIQUE(channel_id, participant_type, participant_id)
|
||||
);
|
||||
|
||||
@@ -96,13 +111,10 @@ CREATE TABLE IF NOT EXISTS channel_models (
|
||||
added_at TEXT DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
-- Raw model entries (no persona): unique per channel+model+provider
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_channel_models_raw
|
||||
ON channel_models(channel_id, model_id, provider_config_id) WHERE persona_id IS NULL;
|
||||
-- Persona entries: one per persona per channel
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_channel_models_persona
|
||||
ON channel_models(channel_id, persona_id) WHERE persona_id IS NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_channel_models_channel ON channel_models(channel_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS channel_cursors (
|
||||
@@ -132,3 +144,15 @@ CREATE TABLE IF NOT EXISTS user_model_settings (
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_user_model_settings_user ON user_model_settings(user_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS session_participants (
|
||||
id TEXT PRIMARY KEY,
|
||||
session_token TEXT NOT NULL UNIQUE,
|
||||
channel_id TEXT NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
|
||||
display_name TEXT NOT NULL DEFAULT 'Visitor',
|
||||
fingerprint TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_session_participants_channel ON session_participants(channel_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_session_participants_token ON session_participants(session_token);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
-- Chat Switchboard — 008 Memory (SQLite)
|
||||
-- Consolidated v0.28.0: adds last_compacted_at + decay_rate
|
||||
|
||||
CREATE TABLE IF NOT EXISTS memories (
|
||||
id TEXT PRIMARY KEY,
|
||||
@@ -11,24 +12,33 @@ CREATE TABLE IF NOT EXISTS memories (
|
||||
confidence REAL NOT NULL DEFAULT 1.0,
|
||||
status TEXT NOT NULL DEFAULT 'active'
|
||||
CHECK (status IN ('active', 'pending_review', 'archived')),
|
||||
last_compacted_at TEXT,
|
||||
decay_rate REAL NOT NULL DEFAULT 0.0,
|
||||
created_at TEXT DEFAULT (datetime('now')),
|
||||
updated_at TEXT DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_memories_scope_owner ON memories(scope, owner_id, status);
|
||||
CREATE INDEX IF NOT EXISTS idx_memories_persona_user ON memories(owner_id, user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_memories_scope_owner
|
||||
ON memories(scope, owner_id, status);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_memories_persona_user
|
||||
ON memories(owner_id, user_id);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_memories_unique_key
|
||||
ON memories(scope, owner_id, COALESCE(user_id, '00000000-0000-0000-0000-000000000000'), key);
|
||||
CREATE INDEX IF NOT EXISTS idx_memories_source_channel ON memories(source_channel_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_memories_source_channel
|
||||
ON memories(source_channel_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS memory_extraction_log (
|
||||
id TEXT PRIMARY KEY,
|
||||
channel_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
id TEXT PRIMARY KEY,
|
||||
channel_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
last_message_id TEXT NOT NULL,
|
||||
extracted_at TEXT DEFAULT (datetime('now')),
|
||||
memory_count INTEGER NOT NULL DEFAULT 0,
|
||||
extracted_at TEXT DEFAULT (datetime('now')),
|
||||
memory_count INTEGER NOT NULL DEFAULT 0,
|
||||
UNIQUE(channel_id, user_id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_mem_extract_log_channel ON memory_extraction_log(channel_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_mem_extract_log_channel
|
||||
ON memory_extraction_log(channel_id);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
-- Chat Switchboard — 013 Files (SQLite)
|
||||
-- Unified files table replacing attachments.
|
||||
-- Handles both upgrade (attachments exists) and fresh install.
|
||||
-- Consolidated v0.28.0: clean install, no legacy attachments migration
|
||||
|
||||
CREATE TABLE IF NOT EXISTS files (
|
||||
id TEXT PRIMARY KEY,
|
||||
@@ -22,40 +21,8 @@ CREATE TABLE IF NOT EXISTS files (
|
||||
updated_at TEXT DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
-- Ensure attachments table exists so the INSERT is always valid.
|
||||
-- Upgrade: no-op (table already has data). Fresh install: empty table.
|
||||
CREATE TABLE IF NOT EXISTS attachments (
|
||||
id TEXT PRIMARY KEY, channel_id TEXT, user_id TEXT, message_id TEXT,
|
||||
project_id TEXT, filename TEXT, content_type TEXT, size_bytes INTEGER,
|
||||
storage_key TEXT, extracted_text TEXT, metadata TEXT, created_at TEXT
|
||||
);
|
||||
|
||||
INSERT OR IGNORE INTO files (
|
||||
id, channel_id, message_id, user_id, project_id,
|
||||
origin, filename, content_type, size_bytes, storage_key,
|
||||
display_hint, extracted_text, metadata, created_at, updated_at
|
||||
)
|
||||
SELECT
|
||||
id, channel_id, message_id, user_id, project_id,
|
||||
'user_upload',
|
||||
filename, content_type, size_bytes, storage_key,
|
||||
CASE
|
||||
WHEN content_type LIKE 'image/%' THEN 'inline'
|
||||
WHEN content_type LIKE 'video/%' THEN 'inline'
|
||||
WHEN content_type LIKE 'audio/%' THEN 'inline'
|
||||
WHEN content_type = 'application/pdf' THEN 'thumbnail'
|
||||
WHEN content_type LIKE 'text/%' THEN 'inline'
|
||||
ELSE 'download'
|
||||
END,
|
||||
extracted_text, metadata, created_at, created_at
|
||||
FROM attachments;
|
||||
|
||||
DROP TABLE IF EXISTS attachments;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_files_channel ON files(channel_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_files_message ON files(message_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_files_user ON files(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_files_project ON files(project_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_files_origin ON files(origin);
|
||||
CREATE INDEX IF NOT EXISTS idx_files_orphan ON files(created_at)
|
||||
WHERE message_id IS NULL AND origin = 'user_upload';
|
||||
|
||||
12
server/database/migrations/sqlite/016_surfaces.sql
Normal file
12
server/database/migrations/sqlite/016_surfaces.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
-- Chat Switchboard — 016 Surfaces (SQLite)
|
||||
-- Consolidated v0.28.0: was missing from SQLite entirely
|
||||
|
||||
CREATE TABLE IF NOT EXISTS surface_registry (
|
||||
id TEXT PRIMARY KEY,
|
||||
title TEXT NOT NULL,
|
||||
manifest TEXT NOT NULL DEFAULT '{}',
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
source TEXT NOT NULL DEFAULT 'core',
|
||||
installed_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
11
server/database/migrations/sqlite/017_auth.sql
Normal file
11
server/database/migrations/sqlite/017_auth.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
-- Chat Switchboard — 017 Auth Providers (SQLite)
|
||||
-- Consolidated v0.28.0
|
||||
|
||||
CREATE TABLE IF NOT EXISTS oidc_auth_state (
|
||||
state TEXT PRIMARY KEY,
|
||||
nonce TEXT NOT NULL,
|
||||
redirect_to TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_oidc_state_created ON oidc_auth_state(created_at);
|
||||
75
server/database/migrations/sqlite/018_workflows.sql
Normal file
75
server/database/migrations/sqlite/018_workflows.sql
Normal file
@@ -0,0 +1,75 @@
|
||||
-- Chat Switchboard — 018 Workflows (SQLite)
|
||||
-- Consolidated v0.28.0: merges 023 + 025 + 027
|
||||
|
||||
CREATE TABLE IF NOT EXISTS workflows (
|
||||
id TEXT PRIMARY KEY,
|
||||
team_id TEXT REFERENCES teams(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
slug TEXT NOT NULL,
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
branding TEXT NOT NULL DEFAULT '{}',
|
||||
entry_mode TEXT NOT NULL DEFAULT 'public_link'
|
||||
CHECK (entry_mode IN ('public_link', 'team_only')),
|
||||
is_active INTEGER NOT NULL DEFAULT 0,
|
||||
version INTEGER NOT NULL DEFAULT 1,
|
||||
on_complete TEXT,
|
||||
retention TEXT NOT NULL DEFAULT '{"mode": "archive"}',
|
||||
webhook_url TEXT,
|
||||
webhook_secret TEXT,
|
||||
created_by TEXT NOT NULL REFERENCES users(id),
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_workflows_team_slug
|
||||
ON workflows(team_id, slug) WHERE team_id IS NOT NULL;
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_workflows_global_slug
|
||||
ON workflows(slug) WHERE team_id IS NULL;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS workflow_stages (
|
||||
id TEXT PRIMARY KEY,
|
||||
workflow_id TEXT NOT NULL REFERENCES workflows(id) ON DELETE CASCADE,
|
||||
ordinal INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
persona_id TEXT REFERENCES personas(id) ON DELETE SET NULL,
|
||||
assignment_team_id TEXT REFERENCES teams(id) ON DELETE SET NULL,
|
||||
form_template TEXT NOT NULL DEFAULT '{}',
|
||||
history_mode TEXT NOT NULL DEFAULT 'full'
|
||||
CHECK (history_mode IN ('full', 'summary', 'fresh')),
|
||||
auto_transition INTEGER NOT NULL DEFAULT 0,
|
||||
transition_rules TEXT NOT NULL DEFAULT '{}',
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_workflow_stages_workflow
|
||||
ON workflow_stages(workflow_id, ordinal);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS workflow_versions (
|
||||
id TEXT PRIMARY KEY,
|
||||
workflow_id TEXT NOT NULL REFERENCES workflows(id) ON DELETE CASCADE,
|
||||
version_number INTEGER NOT NULL,
|
||||
snapshot TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
UNIQUE (workflow_id, version_number)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_workflow_versions_workflow
|
||||
ON workflow_versions(workflow_id, version_number);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS workflow_assignments (
|
||||
id TEXT PRIMARY KEY,
|
||||
channel_id TEXT NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
|
||||
stage INTEGER NOT NULL,
|
||||
team_id TEXT NOT NULL REFERENCES teams(id) ON DELETE CASCADE,
|
||||
assigned_to TEXT REFERENCES users(id) ON DELETE SET NULL,
|
||||
status TEXT NOT NULL DEFAULT 'unassigned'
|
||||
CHECK (status IN ('unassigned', 'claimed', 'completed')),
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
claimed_at TEXT,
|
||||
completed_at TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_workflow_assignments_channel
|
||||
ON workflow_assignments(channel_id, stage);
|
||||
CREATE INDEX IF NOT EXISTS idx_workflow_assignments_team_status
|
||||
ON workflow_assignments(team_id, status);
|
||||
55
server/database/migrations/sqlite/019_tasks.sql
Normal file
55
server/database/migrations/sqlite/019_tasks.sql
Normal file
@@ -0,0 +1,55 @@
|
||||
-- Chat Switchboard — 019 Tasks (SQLite)
|
||||
-- Consolidated v0.28.0: merges 026 + 027
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tasks (
|
||||
id TEXT PRIMARY KEY,
|
||||
owner_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
team_id TEXT REFERENCES teams(id) ON DELETE SET NULL,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT DEFAULT '',
|
||||
scope TEXT NOT NULL DEFAULT 'personal',
|
||||
task_type TEXT NOT NULL DEFAULT 'prompt',
|
||||
persona_id TEXT REFERENCES personas(id) ON DELETE SET NULL,
|
||||
model_id TEXT,
|
||||
system_prompt TEXT DEFAULT '',
|
||||
user_prompt TEXT DEFAULT '',
|
||||
workflow_id TEXT REFERENCES workflows(id) ON DELETE SET NULL,
|
||||
tool_grants TEXT,
|
||||
schedule TEXT NOT NULL,
|
||||
timezone TEXT NOT NULL DEFAULT 'UTC',
|
||||
is_active INTEGER NOT NULL DEFAULT 1,
|
||||
max_tokens INTEGER NOT NULL DEFAULT 4096,
|
||||
max_tool_calls INTEGER NOT NULL DEFAULT 10,
|
||||
max_wall_clock INTEGER NOT NULL DEFAULT 300,
|
||||
output_mode TEXT NOT NULL DEFAULT 'channel',
|
||||
output_channel_id TEXT REFERENCES channels(id) ON DELETE SET NULL,
|
||||
webhook_url TEXT,
|
||||
webhook_secret TEXT,
|
||||
provider_config_id TEXT REFERENCES provider_configs(id) ON DELETE SET NULL,
|
||||
notify_on_complete INTEGER NOT NULL DEFAULT 0,
|
||||
notify_on_failure INTEGER NOT NULL DEFAULT 1,
|
||||
last_run_at TEXT,
|
||||
next_run_at TEXT,
|
||||
run_count INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_next_run ON tasks (next_run_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_owner ON tasks (owner_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_tasks_team ON tasks (team_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS task_runs (
|
||||
id TEXT PRIMARY KEY,
|
||||
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
||||
channel_id TEXT REFERENCES channels(id) ON DELETE SET NULL,
|
||||
status TEXT NOT NULL DEFAULT 'running',
|
||||
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
completed_at TEXT,
|
||||
tokens_used INTEGER DEFAULT 0,
|
||||
tool_calls INTEGER DEFAULT 0,
|
||||
wall_clock INTEGER DEFAULT 0,
|
||||
error TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_task_runs_task ON task_runs (task_id);
|
||||
Reference in New Issue
Block a user