package main import ( "bufio" "fmt" "log" "net/http" "os" "strings" "time" "archi_folio/internal/app" "archi_folio/internal/store" ) func main() { if err := loadDotEnv(".env"); err != nil { log.Fatal(err) } cfg := app.Config{ Addr: requiredEnv("ADDR"), DatabasePath: requiredEnv("DATABASE_PATH"), SessionSecret: requiredEnv("SESSION_SECRET"), AdminUsername: requiredEnv("ADMIN_USERNAME"), AdminPassword: requiredEnv("ADMIN_PASSWORD"), UploadDir: requiredEnv("UPLOAD_DIR"), } db, err := store.Open(cfg.DatabasePath) if err != nil { log.Fatal(err) } defer db.Close() if err := db.Migrate(cfg.AdminUsername, cfg.AdminPassword); err != nil { log.Fatal(err) } srv, err := app.New(cfg, db) if err != nil { log.Fatal(err) } server := &http.Server{ Addr: cfg.Addr, Handler: srv.Routes(), ReadHeaderTimeout: 5 * time.Second, } log.Printf("serving on http://localhost%s", cfg.Addr) log.Fatal(server.ListenAndServe()) } func loadDotEnv(path string) error { file, err := os.Open(path) if os.IsNotExist(err) { return nil } if err != nil { return err } defer file.Close() scanner := bufio.NewScanner(file) for lineNumber := 1; scanner.Scan(); lineNumber++ { line := strings.TrimSpace(scanner.Text()) if line == "" || strings.HasPrefix(line, "#") { continue } key, value, ok := strings.Cut(line, "=") if !ok { return fmt.Errorf("%s:%d: expected KEY=value", path, lineNumber) } key = strings.TrimSpace(key) value = strings.TrimSpace(value) value = strings.Trim(value, `"'`) if key == "" { return fmt.Errorf("%s:%d: empty key", path, lineNumber) } if _, exists := os.LookupEnv(key); !exists { if err := os.Setenv(key, value); err != nil { return err } } } return scanner.Err() } func requiredEnv(key string) string { value, ok := os.LookupEnv(key) if !ok || strings.TrimSpace(value) == "" { log.Fatalf("missing required environment variable %s", key) } return value }