package db import ( "database/sql" "fmt" ) // Migrate runs all database migrations func Migrate(db *sql.DB) error { migrations := []string{ createUsersTable, createEntriesTable, createAccessTable, createSessionsTable, createAuditLogTable, createIndexes, } for i, migration := range migrations { if _, err := db.Exec(migration); err != nil { return fmt.Errorf("migration %d failed: %w", i+1, err) } } return nil } const createUsersTable = ` CREATE TABLE IF NOT EXISTS users ( id TEXT PRIMARY KEY, email TEXT UNIQUE NOT NULL, name TEXT NOT NULL, role TEXT NOT NULL CHECK (role IN ('admin', 'user')), avatar_url TEXT, created_at INTEGER NOT NULL, last_login INTEGER, is_active BOOLEAN NOT NULL DEFAULT 1 );` const createEntriesTable = ` CREATE TABLE IF NOT EXISTS entries ( id TEXT PRIMARY KEY, parent_id TEXT, deal_room_id TEXT NOT NULL, entry_type TEXT NOT NULL CHECK (entry_type IN ('deal_room', 'document', 'note', 'message', 'analysis')), title TEXT NOT NULL, content TEXT NOT NULL, file_path TEXT, file_size INTEGER, file_hash TEXT, embedding BLOB, created_by TEXT NOT NULL, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, FOREIGN KEY (created_by) REFERENCES users(id), FOREIGN KEY (parent_id) REFERENCES entries(id), FOREIGN KEY (deal_room_id) REFERENCES entries(id) );` const createAccessTable = ` CREATE TABLE IF NOT EXISTS access ( id TEXT PRIMARY KEY, entry_id TEXT NOT NULL, user_id TEXT NOT NULL, permissions INTEGER NOT NULL DEFAULT 1, granted_by TEXT NOT NULL, granted_at INTEGER NOT NULL, FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, FOREIGN KEY (granted_by) REFERENCES users(id), UNIQUE(entry_id, user_id) );` const createSessionsTable = ` CREATE TABLE IF NOT EXISTS sessions ( token TEXT PRIMARY KEY, user_id TEXT NOT NULL, expires_at INTEGER NOT NULL, created_at INTEGER NOT NULL, last_used INTEGER NOT NULL, user_agent TEXT, ip_address TEXT, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE );` const createAuditLogTable = ` CREATE TABLE IF NOT EXISTS audit_log ( id TEXT PRIMARY KEY, user_id TEXT, entry_id TEXT, action TEXT NOT NULL, details TEXT, ip_address TEXT, user_agent TEXT, created_at INTEGER NOT NULL, FOREIGN KEY (user_id) REFERENCES users(id), FOREIGN KEY (entry_id) REFERENCES entries(id) );` const createIndexes = ` CREATE INDEX IF NOT EXISTS idx_users_email ON users(email); CREATE INDEX IF NOT EXISTS idx_users_active ON users(is_active); CREATE INDEX IF NOT EXISTS idx_entries_deal_room ON entries(deal_room_id); CREATE INDEX IF NOT EXISTS idx_entries_type ON entries(entry_type); CREATE INDEX IF NOT EXISTS idx_entries_parent ON entries(parent_id); CREATE INDEX IF NOT EXISTS idx_entries_created ON entries(created_at); CREATE INDEX IF NOT EXISTS idx_entries_creator ON entries(created_by); CREATE INDEX IF NOT EXISTS idx_access_entry ON access(entry_id); CREATE INDEX IF NOT EXISTS idx_access_user ON access(user_id); CREATE INDEX IF NOT EXISTS idx_access_permissions ON access(permissions); CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_id); CREATE INDEX IF NOT EXISTS idx_sessions_expires ON sessions(expires_at); CREATE INDEX IF NOT EXISTS idx_audit_user ON audit_log(user_id); CREATE INDEX IF NOT EXISTS idx_audit_entry ON audit_log(entry_id); CREATE INDEX IF NOT EXISTS idx_audit_action ON audit_log(action); CREATE INDEX IF NOT EXISTS idx_audit_created ON audit_log(created_at);`