package web import ( "context" "fmt" "fuj-management/go/internal/config" "fuj-management/go/internal/services/membership" "fuj-management/go/internal/web/api" "fuj-management/go/internal/web/middleware" "io" "io/fs" "log/slog" "net/http" ) // BuildInfo carries the linker-injected build metadata. type BuildInfo struct { Version string Commit string BuildDate string } // ActionHandlers holds function closures for side-effectful operations that // require dependencies (fio, sheets) not present on the core API handler. type ActionHandlers struct { // BankSync runs sync+infer and writes a human-readable log to out. // nil disables the /sync-bank action (renders an error instead). BankSync func(ctx context.Context, out io.Writer) error } // Run registers routes and starts the HTTP server on addr. func Run(logger *slog.Logger, addr string, build BuildInfo, sources membership.Sources, cfg config.Config, actions ActionHandlers) error { renderer, err := NewRenderer() if err != nil { return fmt.Errorf("init templates: %w", err) } ah := &api.Handler{ BuildVersion: build.Version, BuildCommit: build.Commit, BuildDate: build.BuildDate, Sources: sources, Config: cfg, Logger: logger, } hh := NewHTMLHandler(renderer, build, ah, actions) staticSubFS, err := fs.Sub(staticFS, "static") if err != nil { return fmt.Errorf("static subfs: %w", err) } mux := http.NewServeMux() // HTML routes mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/adults", http.StatusFound) }) mux.HandleFunc("GET /adults", hh.ServeAdults) mux.HandleFunc("GET /juniors", hh.ServeJuniors) mux.HandleFunc("GET /payments", hh.ServePayments) mux.HandleFunc("GET /sync-bank", hh.ServeSync) mux.HandleFunc("GET /flush-cache", hh.ServeFlushCacheGET) mux.HandleFunc("POST /flush-cache", hh.ServeFlushCachePOST) mux.HandleFunc("GET /qr", hh.ServeQR) // Static files mux.Handle("/static/", http.StripPrefix("/static/", http.FileServerFS(staticSubFS))) // JSON API routes mux.HandleFunc("GET /api/version", ah.ServeVersion) mux.HandleFunc("GET /version", ah.ServeVersion) mux.HandleFunc("GET /api/adults", ah.ServeAdults) mux.HandleFunc("GET /api/juniors", ah.ServeJuniors) mux.HandleFunc("GET /api/payments", ah.ServePayments) logger.Info("starting server", "addr", addr) return http.ListenAndServe(addr, middleware.RequestTimer(logger, mux)) }