package main import ( "github.com/jackc/pgx/v5/pgxpool" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" "osdb/internal/handler" "osdb/internal/repository" ) // New creates and configures the Echo instance with all routes registered. func New(pool *pgxpool.Pool) *echo.Echo { e := echo.New() e.HideBanner = true e.Use(middleware.Logger()) e.Use(middleware.Recover()) health := handler.NewHealthHandler() // Root health — used by docker healthcheck + ops tooling e.GET("/health", health.Health) // Versioned API group api := e.Group("/api/v1") api.GET("/health", health.Health) // Fruits (story #02) fruitRepo := repository.NewFruitRepo(pool) fruits := handler.NewFruitHandler(fruitRepo) g := api.Group("/fruits") g.GET("", fruits.List) g.POST("", fruits.Create) g.GET("/:id", fruits.Get) g.PUT("/:id", fruits.Update) g.DELETE("/:id", fruits.Delete) g.GET("/:id/images", fruits.ListImages) g.POST("/:id/images", fruits.UploadImage, middleware.BodyLimit("5M")) g.GET("/:id/images/:imageId", fruits.ServeImage) g.GET("/:id/images/:imageId/thumbnail", fruits.ServeThumbnail) g.DELETE("/:id/images/:imageId", fruits.DeleteImage) // Publications (story #04) pubRepo := repository.NewPublicationRepo(pool) pubs := handler.NewPublicationHandler(pubRepo) // Fruit-scoped publication reads g.GET("/:id/descriptions", pubs.GetFruitDescriptions) g.GET("/:id/publication-images", pubs.GetFruitPublicationImages) p := api.Group("/publications") p.GET("", pubs.List) p.POST("", pubs.Create) p.GET("/:id", pubs.Get) p.PUT("/:id", pubs.Update) p.DELETE("/:id", pubs.Delete) p.POST("/:id/image", pubs.UploadCoverImage, middleware.BodyLimit("5M")) p.GET("/:id/image", pubs.ServeCoverImage) p.DELETE("/:id/image", pubs.DeleteCoverImage) p.GET("/:id/fruits", pubs.ListFruits) p.POST("/:id/fruits", pubs.LinkFruit) p.DELETE("/:id/fruits/:fruitId", pubs.UnlinkFruit) p.GET("/:id/descriptions", pubs.ListDescriptions) p.POST("/:id/descriptions", pubs.UploadDescription, middleware.BodyLimit("5M")) p.GET("/:id/descriptions/:descId", pubs.ServeDescription) p.DELETE("/:id/descriptions/:descId", pubs.DeleteDescription) p.GET("/:id/fruit-images", pubs.ListFruitImages) p.POST("/:id/fruit-images", pubs.UploadFruitImage, middleware.BodyLimit("5M")) p.GET("/:id/fruit-images/:imgId", pubs.ServeFruitImage) p.GET("/:id/fruit-images/:imgId/thumbnail", pubs.ServeFruitImageThumbnail) p.DELETE("/:id/fruit-images/:imgId", pubs.DeleteFruitImage) // Admin (story #07) admin := handler.NewAdminHandler(fruitRepo, pubRepo) adminGroup := api.Group("/admin") adminGroup.POST("/backfill-thumbnails", admin.BackfillThumbnails) return e }