package server import ( "encoding/json" "net/http" "github.com/food-ai/backend/internal/auth" "github.com/food-ai/backend/internal/diary" "github.com/food-ai/backend/internal/ingredient" "github.com/food-ai/backend/internal/menu" "github.com/food-ai/backend/internal/middleware" "github.com/food-ai/backend/internal/product" "github.com/food-ai/backend/internal/recognition" "github.com/food-ai/backend/internal/recommendation" "github.com/food-ai/backend/internal/savedrecipe" "github.com/food-ai/backend/internal/user" "github.com/go-chi/chi/v5" "github.com/jackc/pgx/v5/pgxpool" ) func NewRouter( pool *pgxpool.Pool, authHandler *auth.Handler, userHandler *user.Handler, recommendationHandler *recommendation.Handler, savedRecipeHandler *savedrecipe.Handler, ingredientHandler *ingredient.Handler, productHandler *product.Handler, recognitionHandler *recognition.Handler, menuHandler *menu.Handler, diaryHandler *diary.Handler, authMiddleware func(http.Handler) http.Handler, allowedOrigins []string, ) *chi.Mux { r := chi.NewRouter() // Global middleware r.Use(middleware.RequestID) r.Use(middleware.Logging) r.Use(middleware.Recovery) r.Use(middleware.CORS(allowedOrigins)) // Public r.Get("/health", healthCheck(pool)) r.Route("/auth", func(r chi.Router) { r.Post("/login", authHandler.Login) r.Post("/refresh", authHandler.Refresh) r.Post("/logout", authHandler.Logout) }) // Protected r.Group(func(r chi.Router) { r.Use(authMiddleware) r.Get("/ingredients/search", ingredientHandler.Search) r.Get("/profile", userHandler.Get) r.Put("/profile", userHandler.Update) r.Get("/recommendations", recommendationHandler.GetRecommendations) r.Route("/saved-recipes", func(r chi.Router) { r.Post("/", savedRecipeHandler.Save) r.Get("/", savedRecipeHandler.List) r.Get("/{id}", savedRecipeHandler.GetByID) r.Delete("/{id}", savedRecipeHandler.Delete) }) r.Route("/products", func(r chi.Router) { r.Get("/", productHandler.List) r.Post("/", productHandler.Create) r.Post("/batch", productHandler.BatchCreate) r.Put("/{id}", productHandler.Update) r.Delete("/{id}", productHandler.Delete) }) r.Route("/menu", func(r chi.Router) { r.Get("/", menuHandler.GetMenu) r.Put("/items/{id}", menuHandler.UpdateMenuItem) r.Delete("/items/{id}", menuHandler.DeleteMenuItem) }) r.Route("/shopping-list", func(r chi.Router) { r.Get("/", menuHandler.GetShoppingList) r.Post("/generate", menuHandler.GenerateShoppingList) r.Patch("/items/{index}/check", menuHandler.ToggleShoppingItem) }) r.Route("/diary", func(r chi.Router) { r.Get("/", diaryHandler.GetByDate) r.Post("/", diaryHandler.Create) r.Delete("/{id}", diaryHandler.Delete) }) r.Route("/ai", func(r chi.Router) { r.Post("/recognize-receipt", recognitionHandler.RecognizeReceipt) r.Post("/recognize-products", recognitionHandler.RecognizeProducts) r.Post("/recognize-dish", recognitionHandler.RecognizeDish) r.Post("/generate-menu", menuHandler.GenerateMenu) }) }) return r } func healthCheck(pool *pgxpool.Pool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { dbStatus := "connected" if err := pool.Ping(r.Context()); err != nil { dbStatus = "disconnected" } w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(map[string]string{ "status": "ok", "version": "0.1.0", "db": dbStatus, }) } }