package db import ( "context" "database/sql" "golang.org/x/crypto/bcrypt" "log" ) // MigrateAndSeed performs a very small migration set and seeds an admin user func MigrateAndSeed(ctx context.Context, db *sql.DB) error { tx, err := db.Begin() if err != nil { return err } defer tx.Rollback() stmts := []string{ `CREATE TABLE IF NOT EXISTS users (id TEXT PRIMARY KEY, username TEXT NOT NULL UNIQUE, password_hash TEXT, role TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP);`, `CREATE TABLE IF NOT EXISTS pools (name TEXT PRIMARY KEY, guid TEXT, health TEXT, capacity TEXT);`, `CREATE TABLE IF NOT EXISTS jobs (id TEXT PRIMARY KEY, type TEXT, status TEXT, progress INTEGER DEFAULT 0, owner TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME);`, } for _, s := range stmts { if _, err := tx.ExecContext(ctx, s); err != nil { return err } } // Seed a default admin user if not exists var count int if err := tx.QueryRowContext(ctx, `SELECT COUNT(1) FROM users WHERE username = 'admin'`).Scan(&count); err != nil { log.Printf("seed check failed: %v", err) } if count == 0 { // note: simple seeded password: admin (do not use in prod) pwHash, _ := bcrypt.GenerateFromPassword([]byte("admin"), bcrypt.DefaultCost) if _, err := tx.ExecContext(ctx, `INSERT INTO users (id, username, password_hash, role) VALUES (?, 'admin', ?, 'admin')`, "admin", string(pwHash)); err != nil { return err } } if err := tx.Commit(); err != nil { return err } return nil }