// Path: /cmd/api // File: main.go // // Purpose // Application entrypoint. Wires the bootstrapped App into HTTP runtime concerns: // - Initializes template helpers with session + site meta // - Mounts global middleware that require *App (Auth, Remember) // - Registers all route groups outside of bootstrap // - Starts the HTTP server and performs graceful shutdown on SIGINT/SIGTERM // // Responsibilities (as implemented here) // 1) Build the application kernel via bootstrap.Load(configPath). // 2) Initialize template helpers with SessionManager and site metadata. // 3) Attach global middleware that depend on App (Auth first, then Remember). // 4) Register route groups (Home, Account, Admin, Syndicate, Statistics). // 5) Start http.Server in a goroutine and log the bound address. // 6) Block on OS signals and perform a 10s graceful shutdown. // // Notes (code-accurate) // - Config path uses a backslash; consider using forward slashes or filepath.Join // to be OS-neutral (Go accepts forward slashes cross-platform). // - Middleware order matters and matches the master reference: Auth → Remember // (CSRF is already applied inside bootstrap handler wrapping). // - ListenAndServe error handling correctly ignores http.ErrServerClosed. // - Shutdown uses a fixed 10s timeout; consider making this configurable. // // TODOs // - Replace panic on bootstrap/startup with structured logging and exit codes. // - Move config path to env/flag for deploy-time configurability. // - If background workers are added, coordinate their shutdown with the same context. package main import ( "context" "fmt" "net/http" "os" "os/signal" "syscall" "time" templateHelpers "synlotto-website/internal/helpers/template" "synlotto-website/internal/http/middleware" "synlotto-website/internal/http/routes" "synlotto-website/internal/platform/bootstrap" ) func main() { // Build application kernel (config → DB → schema → sessions → router → CSRF → server) app, err := bootstrap.Load("internal\\platform\\config\\config.json") if err != nil { panic(fmt.Errorf("bootstrap: %w", err)) } // Initialize template helpers that require session + site metadata templateHelpers.InitSessionManager(app.SessionManager) templateHelpers.InitSiteMeta(app.Config.Site.SiteName, app.Config.Site.CopyrightYearStart, 0) // Global middleware that depends on *App // Order is important: AuthMiddleware (idle timeout/last activity) → RememberMiddleware (optional) app.Router.Use(middleware.AuthMiddleware()) app.Router.Use(middleware.RememberMiddleware(app)) // rotation optional; security hardening TBD // Route registration lives OUTSIDE bootstrap (keeps bootstrap infra-only) routes.RegisterHomeRoutes(app) routes.RegisterAccountRoutes(app) routes.RegisterAdminRoutes(app) routes.RegisterSyndicateRoutes(app) routes.RegisterStatisticsRoutes(app) // Start the HTTP server srv := app.Server go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { panic(err) } }() fmt.Printf("Server running on http://%s\n", srv.Addr) // Graceful shutdown on SIGINT/SIGTERM stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt, syscall.SIGTERM) <-stop fmt.Println("Shutting down...") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() _ = srv.Shutdown(ctx) // best-effort; log if needed }