package main import ( "log" "net/http" "os" "github.com/jmoiron/sqlx" "github.com/joho/godotenv" "golang.org/x/crypto/bcrypt" "workorders/internal/api" "workorders/internal/config" "workorders/internal/repository" ) func main() { if _, err := os.Stat(".env"); err == nil { if err := godotenv.Load(); err != nil { log.Printf("warning: could not load .env: %v", err) } } cfg := config.Load() log.Printf("connecting to database...") db, err := repository.Connect(cfg.DBDSN) if err != nil { log.Fatalf("database connect: %v", err) } defer db.Close() log.Printf("running migrations...") if err := repository.RunMigrations(db); err != nil { log.Fatalf("migrations: %v", err) } log.Printf("seeding default admin...") if err := seedAdmin(db, cfg.AdminPassword); err != nil { log.Printf("warning: seed admin: %v", err) } r := api.NewRouter(cfg, db) log.Printf("listening on %s", cfg.Addr) if err := http.ListenAndServe(cfg.Addr, r); err != nil { log.Fatal(err) } } func seedAdmin(db *sqlx.DB, password string) error { var count int if err := db.Get(&count, "SELECT COUNT(*) FROM users"); err != nil { return err } if count > 0 { return nil } hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return err } _, err = db.Exec(` INSERT INTO users (username, email, display_name, password_hash, role) VALUES (@p1, @p2, @p3, @p4, 'admin')`, "admin", "admin@workorders.local", "Admin User", string(hash)) return err }