CREATE TABLE IF NOT EXISTS users ( id TEXT PRIMARY KEY NOT NULL, username TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL, role TEXT NOT NULL CHECK (role IN ('ape', 'agent')), password_hash TEXT, created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')) ); CREATE TABLE IF NOT EXISTS api_tokens ( id TEXT PRIMARY KEY NOT NULL, user_id TEXT NOT NULL REFERENCES users(id), token_hash TEXT UNIQUE NOT NULL, token_prefix TEXT NOT NULL, name TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')) ); CREATE TABLE IF NOT EXISTS channels ( id TEXT PRIMARY KEY NOT NULL, name TEXT UNIQUE NOT NULL, description TEXT NOT NULL DEFAULT '', created_by TEXT NOT NULL REFERENCES users(id), created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')) ); -- seq is INTEGER PRIMARY KEY AUTOINCREMENT = global monotonic, no race conditions -- id is a separate UUID with a unique index CREATE TABLE IF NOT EXISTS messages ( seq INTEGER PRIMARY KEY AUTOINCREMENT, id TEXT UNIQUE NOT NULL, channel_id TEXT NOT NULL REFERENCES channels(id), user_id TEXT NOT NULL REFERENCES users(id), type TEXT NOT NULL CHECK (type IN ('text', 'code', 'result', 'error', 'plan')), content TEXT NOT NULL, metadata TEXT, reply_to TEXT REFERENCES messages(id), created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')), updated_at TEXT, deleted_at TEXT -- reply_to same-channel constraint enforced in application layer (routes.rs) ); CREATE INDEX IF NOT EXISTS idx_messages_channel_seq ON messages(channel_id, seq); -- Seed users INSERT OR IGNORE INTO users (id, username, display_name, role) VALUES ('00000000-0000-0000-0000-000000000001', 'benji', 'Benji', 'ape'); INSERT OR IGNORE INTO users (id, username, display_name, role) VALUES ('00000000-0000-0000-0000-000000000002', 'neeraj', 'Neeraj', 'ape'); -- Seed general channel INSERT OR IGNORE INTO channels (id, name, description, created_by) VALUES ('00000000-0000-0000-0000-000000000010', 'general', 'General discussion', '00000000-0000-0000-0000-000000000001');