311 lines
12 KiB
PL/PgSQL
311 lines
12 KiB
PL/PgSQL
-- =============================================================================
|
|
-- RuvBot - Database Initialization Script
|
|
-- =============================================================================
|
|
-- PostgreSQL schema for multi-tenant RuvBot deployment
|
|
-- Supports: Sessions, Memory, Skills, Events, Metrics
|
|
-- =============================================================================
|
|
|
|
-- Enable required extensions
|
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
|
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
|
CREATE EXTENSION IF NOT EXISTS "pg_trgm"; -- For text search
|
|
|
|
-- =============================================================================
|
|
-- Tenants (Multi-tenancy support)
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS tenants (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
name VARCHAR(255) NOT NULL,
|
|
slug VARCHAR(100) UNIQUE NOT NULL,
|
|
settings JSONB DEFAULT '{}',
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Enable Row-Level Security
|
|
ALTER TABLE tenants ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- =============================================================================
|
|
-- Users
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
tenant_id UUID REFERENCES tenants(id) ON DELETE CASCADE,
|
|
external_id VARCHAR(255), -- Slack user ID, Discord ID, etc.
|
|
username VARCHAR(255),
|
|
email VARCHAR(255),
|
|
avatar_url TEXT,
|
|
metadata JSONB DEFAULT '{}',
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(tenant_id, external_id)
|
|
);
|
|
|
|
CREATE INDEX idx_users_tenant ON users(tenant_id);
|
|
CREATE INDEX idx_users_external ON users(external_id);
|
|
|
|
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- =============================================================================
|
|
-- Agents
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS agents (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
tenant_id UUID REFERENCES tenants(id) ON DELETE CASCADE,
|
|
name VARCHAR(255) NOT NULL,
|
|
type VARCHAR(50) DEFAULT 'assistant',
|
|
model VARCHAR(100) DEFAULT 'claude-3-5-sonnet',
|
|
system_prompt TEXT,
|
|
config JSONB DEFAULT '{}',
|
|
status VARCHAR(20) DEFAULT 'active',
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_agents_tenant ON agents(tenant_id);
|
|
|
|
ALTER TABLE agents ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- =============================================================================
|
|
-- Sessions
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
tenant_id UUID REFERENCES tenants(id) ON DELETE CASCADE,
|
|
agent_id UUID REFERENCES agents(id) ON DELETE CASCADE,
|
|
user_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
|
channel_type VARCHAR(50), -- slack, discord, telegram, web
|
|
channel_id VARCHAR(255), -- Channel/room ID
|
|
thread_id VARCHAR(255), -- Thread ID if applicable
|
|
status VARCHAR(20) DEFAULT 'active',
|
|
metadata JSONB DEFAULT '{}',
|
|
started_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
ended_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_sessions_tenant ON sessions(tenant_id);
|
|
CREATE INDEX idx_sessions_agent ON sessions(agent_id);
|
|
CREATE INDEX idx_sessions_user ON sessions(user_id);
|
|
CREATE INDEX idx_sessions_channel ON sessions(channel_type, channel_id);
|
|
CREATE INDEX idx_sessions_status ON sessions(status) WHERE status = 'active';
|
|
|
|
ALTER TABLE sessions ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- =============================================================================
|
|
-- Turns (Conversation Messages)
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS turns (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
session_id UUID REFERENCES sessions(id) ON DELETE CASCADE,
|
|
role VARCHAR(20) NOT NULL, -- user, assistant, system
|
|
content TEXT NOT NULL,
|
|
tokens_input INTEGER DEFAULT 0,
|
|
tokens_output INTEGER DEFAULT 0,
|
|
latency_ms INTEGER,
|
|
tool_calls JSONB,
|
|
metadata JSONB DEFAULT '{}',
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_turns_session ON turns(session_id);
|
|
CREATE INDEX idx_turns_created ON turns(created_at DESC);
|
|
|
|
-- =============================================================================
|
|
-- Memory (Long-term storage with vector search)
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS memories (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
tenant_id UUID REFERENCES tenants(id) ON DELETE CASCADE,
|
|
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
|
|
type VARCHAR(50) NOT NULL, -- fact, preference, episode, semantic
|
|
content TEXT NOT NULL,
|
|
embedding FLOAT8[], -- Vector embedding (1536 dimensions for OpenAI, 768 for local)
|
|
importance FLOAT DEFAULT 0.5,
|
|
access_count INTEGER DEFAULT 0,
|
|
last_accessed TIMESTAMPTZ,
|
|
expires_at TIMESTAMPTZ,
|
|
metadata JSONB DEFAULT '{}',
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_memories_tenant ON memories(tenant_id);
|
|
CREATE INDEX idx_memories_user ON memories(user_id);
|
|
CREATE INDEX idx_memories_type ON memories(type);
|
|
CREATE INDEX idx_memories_importance ON memories(importance DESC);
|
|
|
|
-- Full-text search index
|
|
CREATE INDEX idx_memories_content_trgm ON memories USING gin(content gin_trgm_ops);
|
|
|
|
ALTER TABLE memories ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- =============================================================================
|
|
-- Skills
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS skills (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
tenant_id UUID REFERENCES tenants(id) ON DELETE CASCADE,
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
category VARCHAR(100),
|
|
version VARCHAR(20) DEFAULT '1.0.0',
|
|
schema JSONB NOT NULL, -- Input/output schema
|
|
implementation JSONB, -- Skill configuration
|
|
enabled BOOLEAN DEFAULT true,
|
|
usage_count INTEGER DEFAULT 0,
|
|
success_rate FLOAT DEFAULT 1.0,
|
|
metadata JSONB DEFAULT '{}',
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(tenant_id, name, version)
|
|
);
|
|
|
|
CREATE INDEX idx_skills_tenant ON skills(tenant_id);
|
|
CREATE INDEX idx_skills_category ON skills(category);
|
|
CREATE INDEX idx_skills_enabled ON skills(enabled) WHERE enabled = true;
|
|
|
|
ALTER TABLE skills ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- =============================================================================
|
|
-- Events (Event Sourcing)
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS events (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
tenant_id UUID REFERENCES tenants(id) ON DELETE CASCADE,
|
|
aggregate_type VARCHAR(100) NOT NULL,
|
|
aggregate_id UUID NOT NULL,
|
|
event_type VARCHAR(100) NOT NULL,
|
|
event_version INTEGER DEFAULT 1,
|
|
payload JSONB NOT NULL,
|
|
metadata JSONB DEFAULT '{}',
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_events_aggregate ON events(aggregate_type, aggregate_id);
|
|
CREATE INDEX idx_events_type ON events(event_type);
|
|
CREATE INDEX idx_events_created ON events(created_at DESC);
|
|
|
|
-- =============================================================================
|
|
-- Metrics (Usage tracking)
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS metrics (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
tenant_id UUID REFERENCES tenants(id) ON DELETE CASCADE,
|
|
metric_name VARCHAR(100) NOT NULL,
|
|
metric_value FLOAT NOT NULL,
|
|
dimensions JSONB DEFAULT '{}',
|
|
recorded_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_metrics_tenant ON metrics(tenant_id);
|
|
CREATE INDEX idx_metrics_name ON metrics(metric_name);
|
|
CREATE INDEX idx_metrics_recorded ON metrics(recorded_at DESC);
|
|
|
|
-- Partition by time for better performance
|
|
-- (In production, consider using TimescaleDB or partitioning)
|
|
|
|
-- =============================================================================
|
|
-- Patterns (Learning patterns from interactions)
|
|
-- =============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS patterns (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
tenant_id UUID REFERENCES tenants(id) ON DELETE CASCADE,
|
|
pattern_type VARCHAR(50) NOT NULL, -- intent, response, workflow
|
|
pattern_key VARCHAR(255) NOT NULL,
|
|
pattern_value JSONB NOT NULL,
|
|
confidence FLOAT DEFAULT 0.5,
|
|
usage_count INTEGER DEFAULT 0,
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(tenant_id, pattern_type, pattern_key)
|
|
);
|
|
|
|
CREATE INDEX idx_patterns_tenant ON patterns(tenant_id);
|
|
CREATE INDEX idx_patterns_type ON patterns(pattern_type);
|
|
CREATE INDEX idx_patterns_confidence ON patterns(confidence DESC);
|
|
|
|
ALTER TABLE patterns ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- =============================================================================
|
|
-- Functions
|
|
-- =============================================================================
|
|
|
|
-- Update timestamp trigger
|
|
CREATE OR REPLACE FUNCTION update_updated_at()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = CURRENT_TIMESTAMP;
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Apply to all tables with updated_at
|
|
DO $$
|
|
DECLARE
|
|
t text;
|
|
BEGIN
|
|
FOR t IN
|
|
SELECT table_name
|
|
FROM information_schema.columns
|
|
WHERE column_name = 'updated_at'
|
|
AND table_schema = 'public'
|
|
LOOP
|
|
EXECUTE format('
|
|
DROP TRIGGER IF EXISTS update_%I_updated_at ON %I;
|
|
CREATE TRIGGER update_%I_updated_at
|
|
BEFORE UPDATE ON %I
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION update_updated_at();
|
|
', t, t, t, t);
|
|
END LOOP;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- =============================================================================
|
|
-- Default Data
|
|
-- =============================================================================
|
|
|
|
-- Default tenant for development
|
|
INSERT INTO tenants (id, name, slug, settings)
|
|
VALUES (
|
|
'00000000-0000-0000-0000-000000000001',
|
|
'Default Tenant',
|
|
'default',
|
|
'{"plan": "free", "features": ["basic_chat", "memory", "skills"]}'
|
|
)
|
|
ON CONFLICT (slug) DO NOTHING;
|
|
|
|
-- Default agent
|
|
INSERT INTO agents (id, tenant_id, name, type, model, system_prompt, config)
|
|
VALUES (
|
|
'00000000-0000-0000-0000-000000000001',
|
|
'00000000-0000-0000-0000-000000000001',
|
|
'RuvBot',
|
|
'assistant',
|
|
'claude-3-5-sonnet',
|
|
'You are RuvBot, a helpful AI assistant with long-term memory and learning capabilities.',
|
|
'{"temperature": 0.7, "maxTokens": 4096}'
|
|
)
|
|
ON CONFLICT DO NOTHING;
|
|
|
|
-- =============================================================================
|
|
-- Grants (for application user)
|
|
-- =============================================================================
|
|
|
|
-- Note: Run these after creating the application user
|
|
-- GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO ruvbot;
|
|
-- GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO ruvbot;
|
|
-- GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO ruvbot;
|