Replace Alembic with plain SQL schema

- Fix scalar_first() bug in persistent_conversation.py (use scalars().first())
- Add schema.sql with all 7 tables (users, user_preferences, user_facts, guilds, guild_members, conversations, messages)
- Update database.py to run schema.sql on startup
- Remove Alembic directory and configuration
- Remove alembic from requirements.txt
This commit is contained in:
2026-01-12 18:30:55 +01:00
parent 707410e2ce
commit 94abdca2f7
8 changed files with 139 additions and 389 deletions

119
schema.sql Normal file
View File

@@ -0,0 +1,119 @@
-- Daemon Boyfriend Database Schema
-- Run with: psql -U postgres -d daemon_boyfriend -f schema.sql
-- Users table
CREATE TABLE IF NOT EXISTS users (
id BIGSERIAL PRIMARY KEY,
discord_id BIGINT NOT NULL UNIQUE,
discord_username VARCHAR(255) NOT NULL,
discord_display_name VARCHAR(255),
custom_name VARCHAR(255),
first_seen_at TIMESTAMPTZ DEFAULT NOW(),
last_seen_at TIMESTAMPTZ DEFAULT NOW(),
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS ix_users_discord_id ON users(discord_id);
CREATE INDEX IF NOT EXISTS ix_users_last_seen_at ON users(last_seen_at);
-- User preferences table
CREATE TABLE IF NOT EXISTS user_preferences (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
preference_key VARCHAR(100) NOT NULL,
preference_value TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(user_id, preference_key)
);
CREATE INDEX IF NOT EXISTS ix_user_preferences_user_id ON user_preferences(user_id);
-- User facts table
CREATE TABLE IF NOT EXISTS user_facts (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
fact_type VARCHAR(50) NOT NULL,
fact_content TEXT NOT NULL,
confidence FLOAT DEFAULT 1.0,
source VARCHAR(50) DEFAULT 'conversation',
is_active BOOLEAN NOT NULL DEFAULT TRUE,
learned_at TIMESTAMPTZ DEFAULT NOW(),
last_referenced_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS ix_user_facts_user_id ON user_facts(user_id);
CREATE INDEX IF NOT EXISTS ix_user_facts_fact_type ON user_facts(fact_type);
CREATE INDEX IF NOT EXISTS ix_user_facts_is_active ON user_facts(is_active);
-- Guilds table
CREATE TABLE IF NOT EXISTS guilds (
id BIGSERIAL PRIMARY KEY,
discord_id BIGINT NOT NULL UNIQUE,
name VARCHAR(255) NOT NULL,
joined_at TIMESTAMPTZ DEFAULT NOW(),
is_active BOOLEAN NOT NULL DEFAULT TRUE,
settings JSONB DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS ix_guilds_discord_id ON guilds(discord_id);
-- Guild members table
CREATE TABLE IF NOT EXISTS guild_members (
id BIGSERIAL PRIMARY KEY,
guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE,
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
guild_nickname VARCHAR(255),
roles TEXT[],
joined_guild_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(guild_id, user_id)
);
CREATE INDEX IF NOT EXISTS ix_guild_members_guild_id ON guild_members(guild_id);
CREATE INDEX IF NOT EXISTS ix_guild_members_user_id ON guild_members(user_id);
-- Conversations table
CREATE TABLE IF NOT EXISTS conversations (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
guild_id BIGINT,
channel_id BIGINT,
started_at TIMESTAMPTZ DEFAULT NOW(),
last_message_at TIMESTAMPTZ DEFAULT NOW(),
message_count INTEGER DEFAULT 0,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS ix_conversations_user_id ON conversations(user_id);
CREATE INDEX IF NOT EXISTS ix_conversations_channel_id ON conversations(channel_id);
CREATE INDEX IF NOT EXISTS ix_conversations_last_message_at ON conversations(last_message_at);
CREATE INDEX IF NOT EXISTS ix_conversations_is_active ON conversations(is_active);
-- Messages table
CREATE TABLE IF NOT EXISTS messages (
id BIGSERIAL PRIMARY KEY,
conversation_id BIGINT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
discord_message_id BIGINT,
role VARCHAR(20) NOT NULL,
content TEXT NOT NULL,
has_images BOOLEAN NOT NULL DEFAULT FALSE,
image_urls TEXT[],
token_count INTEGER,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS ix_messages_conversation_id ON messages(conversation_id);
CREATE INDEX IF NOT EXISTS ix_messages_user_id ON messages(user_id);
CREATE INDEX IF NOT EXISTS ix_messages_created_at ON messages(created_at);