package main import ( "log" "net/http" "os" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" "github.com/daniil/homelab-api/internal/config" "github.com/daniil/homelab-api/internal/handler" customMiddleware "github.com/daniil/homelab-api/internal/middleware" "github.com/daniil/homelab-api/internal/repository" "github.com/daniil/homelab-api/internal/service" ) func main() { cfg := config.Load() // Initialize database db, err := repository.NewDB(cfg.DatabaseURL) if err != nil { log.Fatalf("Failed to connect to database: %v", err) } defer db.Close() // Run migrations if err := repository.RunMigrations(db); err != nil { log.Fatalf("Failed to run migrations: %v", err) } // Initialize repositories userRepo := repository.NewUserRepository(db) habitRepo := repository.NewHabitRepository(db) taskRepo := repository.NewTaskRepository(db) emailTokenRepo := repository.NewEmailTokenRepository(db) // Initialize services emailService := service.NewEmailService(cfg.ResendAPIKey, cfg.FromEmail, cfg.FromName, cfg.AppURL) authService := service.NewAuthService(userRepo, emailTokenRepo, emailService, cfg.JWTSecret) habitService := service.NewHabitService(habitRepo) taskService := service.NewTaskService(taskRepo) // Initialize handlers authHandler := handler.NewAuthHandler(authService) habitHandler := handler.NewHabitHandler(habitService) taskHandler := handler.NewTaskHandler(taskService) healthHandler := handler.NewHealthHandler() // Initialize middleware authMiddleware := customMiddleware.NewAuthMiddleware(cfg.JWTSecret) // Setup router r := chi.NewRouter() // Global middleware r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Use(middleware.RequestID) r.Use(cors.Handler(cors.Options{ AllowedOrigins: []string{"https://*", "http://*"}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-Request-ID"}, ExposedHeaders: []string{"Link"}, AllowCredentials: true, MaxAge: 300, })) // Public routes r.Get("/health", healthHandler.Health) // Auth routes (public) r.Post("/auth/register", authHandler.Register) r.Post("/auth/login", authHandler.Login) r.Post("/auth/refresh", authHandler.Refresh) r.Post("/auth/verify-email", authHandler.VerifyEmail) r.Post("/auth/resend-verification", authHandler.ResendVerification) r.Post("/auth/forgot-password", authHandler.ForgotPassword) r.Post("/auth/reset-password", authHandler.ResetPassword) // Protected routes r.Group(func(r chi.Router) { r.Use(authMiddleware.Authenticate) // User routes r.Get("/auth/me", authHandler.Me) r.Put("/auth/me", authHandler.UpdateProfile) r.Put("/auth/password", authHandler.ChangePassword) // Habits routes r.Get("/habits", habitHandler.List) r.Post("/habits", habitHandler.Create) r.Get("/habits/{id}", habitHandler.Get) r.Put("/habits/{id}", habitHandler.Update) r.Delete("/habits/{id}", habitHandler.Delete) // Habit logs r.Post("/habits/{id}/log", habitHandler.Log) r.Get("/habits/{id}/logs", habitHandler.GetLogs) r.Delete("/habits/{id}/logs/{logId}", habitHandler.DeleteLog) // Stats r.Get("/habits/stats", habitHandler.Stats) r.Get("/habits/{id}/stats", habitHandler.HabitStats) // Tasks routes r.Get("/tasks", taskHandler.List) r.Get("/tasks/today", taskHandler.Today) r.Post("/tasks", taskHandler.Create) r.Get("/tasks/{id}", taskHandler.Get) r.Put("/tasks/{id}", taskHandler.Update) r.Delete("/tasks/{id}", taskHandler.Delete) r.Post("/tasks/{id}/complete", taskHandler.Complete) r.Post("/tasks/{id}/uncomplete", taskHandler.Uncomplete) }) port := os.Getenv("PORT") if port == "" { port = "8080" } log.Printf("Server starting on :%s", port) if err := http.ListenAndServe(":"+port, r); err != nil { log.Fatalf("Server failed: %v", err) } }