package main import ( "crussell/auth" "crussell/internal/dav" "fmt" "log" "net/http" "os" "time" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "crussell/db" "crussell/mw" authHandlers "crussell/handlers/auth" "crussell/handlers/scheduling" "crussell/handlers/user" ) func init() { // 1. Read the environment variable jwtSecret := os.Getenv("JWT_SECRET_KEY") // 2. Add a check to ensure the secret is set if jwtSecret == "" { log.Fatal("FATAL: JWT_SECRET_KEY environment variable not set. Application cannot start.") } // 3. Use the environment variable for initialization auth.InitJWT(jwtSecret) } func initDB() { if err := db.Connect(); err != nil { log.Fatal("Failed to connect to DB:", err) } fmt.Println("Connected to DB successfully") } func initDav() { if dav.Service == nil { log.Fatal("Failed to initialize DAV service") } fmt.Println("DAV Service connected successfully") } func main() { initDB() initDav() r := chi.NewRouter() // --- Middleware --- r.Use(middleware.RequestID) // Add X-Request-ID header r.Use(middleware.RealIP) // Get real IP from headers r.Use(middleware.Logger) // Basic logging r.Use(middleware.Recoverer) // Panic recovery r.Use(middleware.Timeout(15 * time.Second)) // Request timeout r.Use(func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("X-Frame-Options", "DENY") w.Header().Set("X-XSS-Protection", "1; mode=block") next.ServeHTTP(w, r) }) }) // --- Public auth routes --- r.Post("/api/register", authHandlers.RegisterHandler) r.Post("/api/login", authHandlers.LoginHandler) // --- Protected routes - any authenticated user --- r.Group(func(r chi.Router) { r.Use(mw.RequireAuth) // User profile r.Get("/api/user/profile", user.GetProfileHandler) r.Put("/api/user/profile", user.UpdateProfileHandler) r.Delete("/api/user/account", user.DeleteAccountHandler) // Loyalty r.Get("/api/user/loyalty", user.GetLoyaltyHandler) }) // --- Scheduling routes --- r.Route("/api/scheduling", func(r chi.Router) { // Default hours r.Get("/default-hours", scheduling.GetDefaultHours) r.Group(func(r chi.Router) { r.Use(mw.RequireAuth) r.Use(mw.RequireAdmin) r.Put("/default-hours", scheduling.UpdateDefaultHours) }) // Exceptional groups r.Get("/exceptional-groups", scheduling.ListExceptionalGroups) r.Group(func(r chi.Router) { r.Use(mw.RequireAuth) r.Use(mw.RequireAdmin) r.Post("/exceptional-groups", scheduling.CreateExceptionalGroup) }) // Exceptional applications (assign groups to weeks) r.Get("/exceptional-applications", scheduling.ListExceptionalApplications) r.Group(func(r chi.Router) { r.Use(mw.RequireAuth) r.Use(mw.RequireAdmin) r.Post("/exceptional-applications", scheduling.CreateExceptionalApplication) }) // Merged working hours (default + exceptional) r.Get("/working-hours", scheduling.GetWorkingHours) // Fully calculated available hours (default + exceptional + bookings + lunch breaks) r.Get("/available-hours", scheduling.GetAvailableHours) }) fmt.Println("Server is listening on :8080") http.ListenAndServe(":8080", r) }