package server import ( "net/http" "time" "github.com/go-chi/chi/v5" chimw "github.com/go-chi/chi/v5/middleware" "github.com/prometheus/client_golang/prometheus/promhttp" "git.eeqj.de/sneak/upaas/static" ) // requestTimeout is the maximum duration for handling a request. const requestTimeout = 60 * time.Second // SetupRoutes configures all HTTP routes. // //nolint:funlen // route configuration is inherently long but straightforward func (s *Server) SetupRoutes() { s.router = chi.NewRouter() // Global middleware s.router.Use(chimw.Recoverer) s.router.Use(chimw.RequestID) s.router.Use(s.mw.Logging()) s.router.Use(s.mw.CORS()) s.router.Use(chimw.Timeout(requestTimeout)) s.router.Use(s.mw.SetupRequired()) // Health check (no auth required) s.router.Get("/health", s.handlers.HandleHealthCheck()) // Static files s.router.Handle("/s/*", http.StripPrefix( "/s/", http.FileServer(http.FS(static.Static)), )) // Public routes s.router.Get("/login", s.handlers.HandleLoginGET()) s.router.With(s.mw.LoginRateLimit()).Post("/login", s.handlers.HandleLoginPOST()) s.router.Get("/setup", s.handlers.HandleSetupGET()) s.router.Post("/setup", s.handlers.HandleSetupPOST()) // Webhook endpoint (uses secret for auth, not session) s.router.Post("/webhook/{secret}", s.handlers.HandleWebhook()) // Protected routes (require session auth) s.router.Group(func(r chi.Router) { r.Use(s.mw.SessionAuth()) // Dashboard r.Get("/", s.handlers.HandleDashboard()) // Logout r.Post("/logout", s.handlers.HandleLogout()) // App routes r.Get("/apps/new", s.handlers.HandleAppNew()) r.Post("/apps", s.handlers.HandleAppCreate()) r.Get("/apps/{id}", s.handlers.HandleAppDetail()) r.Get("/apps/{id}/edit", s.handlers.HandleAppEdit()) r.Post("/apps/{id}", s.handlers.HandleAppUpdate()) r.Post("/apps/{id}/delete", s.handlers.HandleAppDelete()) r.Post("/apps/{id}/deploy", s.handlers.HandleAppDeploy()) r.Get("/apps/{id}/deployments", s.handlers.HandleAppDeployments()) r.Get("/apps/{id}/deployments/{deploymentID}/logs", s.handlers.HandleDeploymentLogsAPI()) r.Get("/apps/{id}/deployments/{deploymentID}/download", s.handlers.HandleDeploymentLogDownload()) r.Get("/apps/{id}/logs", s.handlers.HandleAppLogs()) r.Get("/apps/{id}/container-logs", s.handlers.HandleContainerLogsAPI()) r.Get("/apps/{id}/status", s.handlers.HandleAppStatusAPI()) r.Get("/apps/{id}/recent-deployments", s.handlers.HandleRecentDeploymentsAPI()) r.Post("/apps/{id}/restart", s.handlers.HandleAppRestart()) r.Post("/apps/{id}/stop", s.handlers.HandleAppStop()) r.Post("/apps/{id}/start", s.handlers.HandleAppStart()) // Environment variables r.Post("/apps/{id}/env-vars", s.handlers.HandleEnvVarAdd()) r.Post("/apps/{id}/env-vars/{varID}/delete", s.handlers.HandleEnvVarDelete()) // Labels r.Post("/apps/{id}/labels", s.handlers.HandleLabelAdd()) r.Post("/apps/{id}/labels/{labelID}/delete", s.handlers.HandleLabelDelete()) // Volumes r.Post("/apps/{id}/volumes", s.handlers.HandleVolumeAdd()) r.Post("/apps/{id}/volumes/{volumeID}/delete", s.handlers.HandleVolumeDelete()) // Ports r.Post("/apps/{id}/ports", s.handlers.HandlePortAdd()) r.Post("/apps/{id}/ports/{portID}/delete", s.handlers.HandlePortDelete()) }) // Metrics endpoint (optional, with basic auth) if s.params.Config.MetricsUsername != "" { s.router.Group(func(r chi.Router) { r.Use(s.mw.MetricsAuth()) r.Get("/metrics", promhttp.Handler().ServeHTTP) }) } }