package main import ( "context" "fmt" "log" "net/http" "os" "strings" "github.com/joho/godotenv" "github.com/rede5/gohorsejobs/backend/docs" "github.com/rede5/gohorsejobs/backend/internal/database" "github.com/rede5/gohorsejobs/backend/internal/router" "github.com/rede5/gohorsejobs/backend/internal/services" ) // @title GoHorseJobs API // @version 1.0 // @description API for GoHorseJobs recruitment platform. // @BasePath / // @securityDefinitions.apikey BearerAuth // @in header // @name Authorization func main() { // Load .env file if err := godotenv.Load(); err != nil { log.Println("No .env file found or error loading it") } // Validate JWT_SECRET strength (must be at least 32 characters / 256 bits) if err := ValidateJWT(os.Getenv("JWT_SECRET"), os.Getenv("ENV")); err != nil { if strings.HasPrefix(err.Error(), "FATAL") { log.Fatal(err) } log.Println(err) } database.InitDB() database.RunMigrations() // Configure Swagger Host dynamically apiHost := os.Getenv("BACKEND_HOST") if apiHost == "" { apiHost = "localhost:8521" } finalHost, schemes := ConfigureSwagger(apiHost) docs.SwaggerInfo.Host = finalHost docs.SwaggerInfo.Schemes = schemes apiHost = finalHost // Update for logging // Bootstrap Credentials from Env to DB // This ensures smooth migration from .env to Database configuration go func() { // Initialize temporary credentials service for bootstrapping credService := services.NewCredentialsService(database.DB) ctx := context.Background() if err := credService.BootstrapCredentials(ctx); err != nil { // Log error but don't crash, it might be transient DB issue fmt.Printf("Error bootstrapping credentials: %v\n", err) } }() handler := router.NewRouter() port := os.Getenv("BACKEND_PORT") if port == "" { port = "8521" } log.Println("Starting server on :" + port) log.Println("API Host configured to:", apiHost) if err := http.ListenAndServe(":"+port, handler); err != nil { log.Fatalf("Server failed to start: %v", err) } } func ValidateJWT(secret, env string) error { if secret == "" || len(secret) < 32 { msg := "⚠️ WARNING: JWT_SECRET is empty or too short (< 32 chars). Use a strong secret in production!" if env == "production" { return fmt.Errorf("FATAL: Cannot start in production without strong JWT_SECRET") } // Logic was: log warning. Here we return error with message to be logged/handled. // To match exact logic: // warning is always returned if short. // fatal error is returned if production. // Caller handles logging. return fmt.Errorf("%s", msg) } return nil } func ConfigureSwagger(apiHost string) (string, []string) { schemes := []string{"http", "https"} // default to both if strings.HasPrefix(apiHost, "https://") { schemes = []string{"https"} } else if strings.HasPrefix(apiHost, "http://") { schemes = []string{"http"} } // Strip protocol schemes to ensure clean host for Swagger apiHost = strings.TrimPrefix(apiHost, "http://") apiHost = strings.TrimPrefix(apiHost, "https://") return apiHost, schemes }