// seed_e2e_user creates or updates a deterministic test user for Playwright e2e. // Usage: go run ./backend/cmd/seed_e2e_user --db apps/kanban/operations.db // // Idempotent: safe to run repeatedly. The user "e2e_user" / password "e2e_test_pw_2026" // is intentional and used by apps/kanban/frontend/e2e/*.spec.ts when env vars are not set. package main import ( "database/sql" "errors" "flag" "fmt" "os" "time" _ "github.com/mattn/go-sqlite3" "golang.org/x/crypto/bcrypt" ) func main() { dbPath := flag.String("db", "operations.db", "path to kanban operations.db") username := flag.String("username", "e2e_user", "username") password := flag.String("password", "e2e_test_pw_2026", "password") displayName := flag.String("display", "E2E Test", "display name") flag.Parse() db, err := sql.Open("sqlite3", *dbPath) if err != nil { fail(err) } defer db.Close() hash, err := bcrypt.GenerateFromPassword([]byte(*password), bcrypt.DefaultCost) if err != nil { fail(err) } now := time.Now().UTC().Format(time.RFC3339Nano) id := "e2etest" + fmt.Sprintf("%x", time.Now().UnixNano())[:9] // Try update first res, err := db.Exec( `UPDATE users SET password_hash=?, display_name=? WHERE username=?`, string(hash), *displayName, *username, ) if err != nil { fail(err) } n, _ := res.RowsAffected() if n > 0 { fmt.Printf("updated existing user %q\n", *username) return } _, err = db.Exec( `INSERT INTO users (id, username, password_hash, display_name, created_at) VALUES (?, ?, ?, ?, ?)`, id, *username, string(hash), *displayName, now, ) if err != nil { if errors.Is(err, sql.ErrNoRows) { fail(err) } fail(err) } fmt.Printf("created user %q (id=%s)\n", *username, id) } func fail(err error) { fmt.Fprintln(os.Stderr, "seed_e2e_user:", err) os.Exit(1) }