dashboard-nanobot/scripts/sql/create-tables.sql

229 lines
10 KiB
PL/PgSQL

\set ON_ERROR_STOP on
BEGIN;
CREATE TABLE IF NOT EXISTS bot_instance (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
access_password TEXT NOT NULL DEFAULT '',
workspace_dir TEXT NOT NULL UNIQUE,
docker_status TEXT NOT NULL DEFAULT 'STOPPED',
current_state TEXT DEFAULT 'IDLE',
last_action TEXT,
image_tag TEXT NOT NULL DEFAULT 'nanobot-base:v0.1.4',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS bot_image (
tag TEXT PRIMARY KEY,
image_id TEXT,
version TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'READY',
source_dir TEXT,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS bot_message (
id SERIAL PRIMARY KEY,
bot_id TEXT NOT NULL REFERENCES bot_instance(id),
role TEXT NOT NULL,
text TEXT NOT NULL,
media_json TEXT,
feedback TEXT,
feedback_at TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS sys_login_log (
id SERIAL PRIMARY KEY,
auth_type TEXT NOT NULL,
token_hash TEXT NOT NULL,
subject_id TEXT NOT NULL,
bot_id TEXT,
auth_source TEXT NOT NULL DEFAULT '',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP NOT NULL,
last_seen_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
revoked_at TIMESTAMP,
revoke_reason TEXT,
client_ip TEXT,
user_agent TEXT,
device_info TEXT
);
CREATE TABLE IF NOT EXISTS sys_setting (
key VARCHAR(120) PRIMARY KEY,
name VARCHAR(200) NOT NULL DEFAULT '',
category VARCHAR(64) NOT NULL DEFAULT 'general',
description TEXT NOT NULL DEFAULT '',
value_type VARCHAR(32) NOT NULL DEFAULT 'json',
value_json TEXT NOT NULL DEFAULT '{}',
is_public BOOLEAN NOT NULL DEFAULT FALSE,
sort_order INTEGER NOT NULL DEFAULT 100,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS bot_request_usage (
id SERIAL PRIMARY KEY,
bot_id TEXT NOT NULL REFERENCES bot_instance(id),
message_id INTEGER,
request_id VARCHAR(120) NOT NULL,
channel VARCHAR(64) NOT NULL DEFAULT 'dashboard',
status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
provider VARCHAR(120),
model VARCHAR(255),
token_source VARCHAR(32) NOT NULL DEFAULT 'estimated',
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
total_tokens INTEGER NOT NULL DEFAULT 0,
input_text_preview TEXT,
output_text_preview TEXT,
attachments_json TEXT,
error_text TEXT,
metadata_json TEXT,
started_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
completed_at TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS bot_activity_event (
id SERIAL PRIMARY KEY,
bot_id TEXT NOT NULL REFERENCES bot_instance(id),
request_id VARCHAR(120),
event_type VARCHAR(64) NOT NULL,
channel VARCHAR(64) NOT NULL DEFAULT 'dashboard',
detail TEXT,
metadata_json TEXT,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS skill_market_item (
id SERIAL PRIMARY KEY,
skill_key VARCHAR(120) NOT NULL,
display_name VARCHAR(255) NOT NULL DEFAULT '',
description TEXT NOT NULL DEFAULT '',
zip_filename VARCHAR(255) NOT NULL,
zip_size_bytes INTEGER NOT NULL DEFAULT 0,
entry_names_json TEXT NOT NULL DEFAULT '[]',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uq_skill_market_item_skill_key UNIQUE (skill_key),
CONSTRAINT uq_skill_market_item_zip_filename UNIQUE (zip_filename)
);
CREATE TABLE IF NOT EXISTS bot_skill_install (
id SERIAL PRIMARY KEY,
bot_id TEXT NOT NULL REFERENCES bot_instance(id),
skill_market_item_id INTEGER NOT NULL REFERENCES skill_market_item(id),
installed_entries_json TEXT NOT NULL DEFAULT '[]',
source_zip_filename VARCHAR(255) NOT NULL DEFAULT '',
status VARCHAR(32) NOT NULL DEFAULT 'INSTALLED',
last_error TEXT,
installed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uq_bot_skill_install_bot_market UNIQUE (bot_id, skill_market_item_id)
);
CREATE TABLE IF NOT EXISTS topic_topic (
id SERIAL PRIMARY KEY,
bot_id TEXT NOT NULL REFERENCES bot_instance(id),
topic_key TEXT NOT NULL,
name TEXT NOT NULL DEFAULT '',
description TEXT NOT NULL DEFAULT '',
is_active BOOLEAN NOT NULL DEFAULT TRUE,
is_default_fallback BOOLEAN NOT NULL DEFAULT FALSE,
routing_json TEXT NOT NULL DEFAULT '{}',
view_schema_json TEXT NOT NULL DEFAULT '{}',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uq_topic_topic_bot_topic_key UNIQUE (bot_id, topic_key)
);
CREATE TABLE IF NOT EXISTS topic_item (
id SERIAL PRIMARY KEY,
bot_id TEXT NOT NULL REFERENCES bot_instance(id),
topic_key TEXT NOT NULL,
title TEXT NOT NULL DEFAULT '',
content TEXT NOT NULL DEFAULT '',
level TEXT NOT NULL DEFAULT 'info',
tags_json TEXT,
view_json TEXT,
source TEXT NOT NULL DEFAULT 'mcp',
dedupe_key TEXT,
is_read BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_bot_instance_enabled ON bot_instance (enabled);
CREATE INDEX IF NOT EXISTS idx_bot_instance_docker_status ON bot_instance (docker_status);
CREATE INDEX IF NOT EXISTS idx_bot_message_bot_id ON bot_message (bot_id);
CREATE INDEX IF NOT EXISTS idx_bot_message_role ON bot_message (role);
CREATE INDEX IF NOT EXISTS idx_bot_message_feedback ON bot_message (feedback);
CREATE INDEX IF NOT EXISTS idx_bot_message_created_at ON bot_message (created_at);
CREATE UNIQUE INDEX IF NOT EXISTS idx_sys_login_log_token_hash ON sys_login_log (token_hash);
CREATE INDEX IF NOT EXISTS idx_sys_login_log_auth_type ON sys_login_log (auth_type);
CREATE INDEX IF NOT EXISTS idx_sys_login_log_subject_id ON sys_login_log (subject_id);
CREATE INDEX IF NOT EXISTS idx_sys_login_log_bot_id ON sys_login_log (bot_id);
CREATE INDEX IF NOT EXISTS idx_sys_login_log_auth_source ON sys_login_log (auth_source);
CREATE INDEX IF NOT EXISTS idx_sys_login_log_created_at ON sys_login_log (created_at);
CREATE INDEX IF NOT EXISTS idx_sys_login_log_expires_at ON sys_login_log (expires_at);
CREATE INDEX IF NOT EXISTS idx_sys_login_log_last_seen_at ON sys_login_log (last_seen_at);
CREATE INDEX IF NOT EXISTS idx_sys_login_log_revoked_at ON sys_login_log (revoked_at);
CREATE INDEX IF NOT EXISTS idx_sys_setting_category ON sys_setting (category);
CREATE INDEX IF NOT EXISTS idx_sys_setting_is_public ON sys_setting (is_public);
CREATE INDEX IF NOT EXISTS idx_sys_setting_sort_order ON sys_setting (sort_order);
CREATE INDEX IF NOT EXISTS idx_sys_setting_updated_at ON sys_setting (updated_at);
CREATE INDEX IF NOT EXISTS idx_bot_request_usage_bot_id ON bot_request_usage (bot_id);
CREATE INDEX IF NOT EXISTS idx_bot_request_usage_message_id ON bot_request_usage (message_id);
CREATE INDEX IF NOT EXISTS idx_bot_request_usage_request_id ON bot_request_usage (request_id);
CREATE INDEX IF NOT EXISTS idx_bot_request_usage_channel ON bot_request_usage (channel);
CREATE INDEX IF NOT EXISTS idx_bot_request_usage_status ON bot_request_usage (status);
CREATE INDEX IF NOT EXISTS idx_bot_request_usage_started_at ON bot_request_usage (started_at);
CREATE INDEX IF NOT EXISTS idx_bot_request_usage_completed_at ON bot_request_usage (completed_at);
CREATE INDEX IF NOT EXISTS idx_bot_request_usage_created_at ON bot_request_usage (created_at);
CREATE INDEX IF NOT EXISTS idx_bot_request_usage_updated_at ON bot_request_usage (updated_at);
CREATE INDEX IF NOT EXISTS idx_bot_request_usage_started_at_bot_id ON bot_request_usage (started_at, bot_id);
CREATE INDEX IF NOT EXISTS idx_bot_activity_event_bot_id ON bot_activity_event (bot_id);
CREATE INDEX IF NOT EXISTS idx_bot_activity_event_request_id ON bot_activity_event (request_id);
CREATE INDEX IF NOT EXISTS idx_bot_activity_event_event_type ON bot_activity_event (event_type);
CREATE INDEX IF NOT EXISTS idx_bot_activity_event_channel ON bot_activity_event (channel);
CREATE INDEX IF NOT EXISTS idx_bot_activity_event_created_at ON bot_activity_event (created_at);
CREATE INDEX IF NOT EXISTS idx_bot_activity_event_bot_id_request_present
ON bot_activity_event (bot_id)
WHERE request_id IS NOT NULL AND request_id <> '';
CREATE INDEX IF NOT EXISTS idx_skill_market_item_created_at ON skill_market_item (created_at);
CREATE INDEX IF NOT EXISTS idx_skill_market_item_updated_at ON skill_market_item (updated_at);
CREATE INDEX IF NOT EXISTS idx_bot_skill_install_bot_id ON bot_skill_install (bot_id);
CREATE INDEX IF NOT EXISTS idx_bot_skill_install_skill_market_item_id ON bot_skill_install (skill_market_item_id);
CREATE INDEX IF NOT EXISTS idx_bot_skill_install_status ON bot_skill_install (status);
CREATE INDEX IF NOT EXISTS idx_bot_skill_install_installed_at ON bot_skill_install (installed_at);
CREATE INDEX IF NOT EXISTS idx_bot_skill_install_updated_at ON bot_skill_install (updated_at);
CREATE INDEX IF NOT EXISTS idx_topic_topic_bot_id ON topic_topic (bot_id);
CREATE INDEX IF NOT EXISTS idx_topic_topic_topic_key ON topic_topic (topic_key);
CREATE INDEX IF NOT EXISTS idx_topic_topic_created_at ON topic_topic (created_at);
CREATE INDEX IF NOT EXISTS idx_topic_topic_updated_at ON topic_topic (updated_at);
CREATE INDEX IF NOT EXISTS idx_topic_topic_bot_fallback ON topic_topic (bot_id, is_default_fallback);
CREATE INDEX IF NOT EXISTS idx_topic_item_bot_id ON topic_item (bot_id);
CREATE INDEX IF NOT EXISTS idx_topic_item_topic_key ON topic_item (topic_key);
CREATE INDEX IF NOT EXISTS idx_topic_item_level ON topic_item (level);
CREATE INDEX IF NOT EXISTS idx_topic_item_source ON topic_item (source);
CREATE INDEX IF NOT EXISTS idx_topic_item_is_read ON topic_item (is_read);
CREATE INDEX IF NOT EXISTS idx_topic_item_created_at ON topic_item (created_at);
CREATE INDEX IF NOT EXISTS idx_topic_item_bot_topic_created_at ON topic_item (bot_id, topic_key, created_at);
CREATE INDEX IF NOT EXISTS idx_topic_item_bot_dedupe ON topic_item (bot_id, dedupe_key);
COMMIT;