package router import ( "hfb_sys/backend/internal/config" "hfb_sys/backend/internal/handler" "hfb_sys/backend/internal/middleware" "hfb_sys/backend/internal/modules/adminaudit" "hfb_sys/backend/internal/modules/adminauth" "hfb_sys/backend/internal/modules/admindashboard" "hfb_sys/backend/internal/modules/adminuser" "hfb_sys/backend/internal/modules/auth" "hfb_sys/backend/internal/modules/dispute" filemodule "hfb_sys/backend/internal/modules/file" "hfb_sys/backend/internal/modules/listing" "hfb_sys/backend/internal/modules/notification" "hfb_sys/backend/internal/modules/order" "hfb_sys/backend/internal/modules/realname" "hfb_sys/backend/internal/modules/systemconfig" "hfb_sys/backend/internal/modules/user" "hfb_sys/backend/internal/modules/wallet" "github.com/gin-gonic/gin" "go.uber.org/zap" ) func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine { if cfg.AppEnv == "production" { gin.SetMode(gin.ReleaseMode) } engine := gin.New() engine.Use(gin.Recovery()) engine.Use(middleware.RequestLogger(logger)) health := handler.NewHealthHandler() engine.GET("/health", health.Check) jwtManager := auth.NewJWTManager(cfg.JWTSecret) var userRepo *auth.UserRepository if deps.DB != nil { userRepo = auth.NewUserRepository(deps.DB) } authService := auth.NewService(userRepo, deps.Redis, jwtManager, logger) authHandler := auth.NewHandler(authService) var adminAuthRepo *adminauth.Repository if deps.DB != nil { adminAuthRepo = adminauth.NewRepository(deps.DB, deps.Redis, jwtManager) } adminAuthService := adminauth.NewService(adminAuthRepo, jwtManager) adminAuthHandler := adminauth.NewHandler(adminAuthService) var adminDashboardRepo *admindashboard.Repository if deps.DB != nil { adminDashboardRepo = admindashboard.NewRepository(deps.DB) } adminDashboardService := admindashboard.NewService(adminDashboardRepo) adminDashboardHandler := admindashboard.NewHandler(adminDashboardService) var adminUserRepo *adminuser.Repository if deps.DB != nil { adminUserRepo = adminuser.NewRepository(deps.DB) } adminUserService := adminuser.NewService(adminUserRepo) adminUserHandler := adminuser.NewHandler(adminUserService) var adminAuditRepo *adminaudit.Repository if deps.DB != nil { adminAuditRepo = adminaudit.NewRepository(deps.DB) } adminAuditService := adminaudit.NewService(adminAuditRepo) adminAuditHandler := adminaudit.NewHandler(adminAuditService) userHandler := user.NewHandler(userRepo) var realnameRepo *realname.Repository if deps.DB != nil { realnameRepo = realname.NewRepository(deps.DB) } realnameService := realname.NewService(realnameRepo, realname.NewMockProvider()) realnameHandler := realname.NewHandler(realnameService) var listingRepo *listing.Repository if deps.DB != nil { listingRepo = listing.NewRepository(deps.DB) } var orderRepo *order.Repository if deps.DB != nil { orderRepo = order.NewRepository(deps.DB) } orderService := order.NewService(orderRepo) orderHandler := order.NewHandler(orderService) var walletRepo *wallet.Repository if deps.DB != nil { walletRepo = wallet.NewRepository(deps.DB) } walletService := wallet.NewService(walletRepo) walletHandler := wallet.NewHandler(walletService) var notificationRepo *notification.Repository if deps.DB != nil { notificationRepo = notification.NewRepository(deps.DB) } notificationService := notification.NewService(notificationRepo) notificationHandler := notification.NewHandler(notificationService) var disputeRepo *dispute.Repository if deps.DB != nil { disputeRepo = dispute.NewRepository(deps.DB) } disputeService := dispute.NewService(disputeRepo) disputeHandler := dispute.NewHandler(disputeService) var systemConfigRepo *systemconfig.Repository if deps.DB != nil { systemConfigRepo = systemconfig.NewRepository(deps.DB) } systemConfigService := systemconfig.NewService(systemConfigRepo) systemConfigHandler := systemconfig.NewHandler(systemConfigService) var fileStorage *filemodule.Storage if cfg.Storage.Endpoint != "" && cfg.Storage.Bucket != "" { var err error fileStorage, err = filemodule.NewStorage(cfg.Storage) if err != nil { logger.Warn("file storage unavailable; file APIs will return 503", zap.Error(err)) } } fileService := filemodule.NewService(fileStorage) fileHandler := filemodule.NewHandler(fileService, fileStorage) listingService := listing.NewService(listingRepo, systemConfigRepo) listingHandler := listing.NewHandler(listingService, fileStorage) requireAuth := middleware.Auth(jwtManager) requireAdmin := middleware.AdminAuth(jwtManager) requireRealname := middleware.RequireRealname(userRepo) api := engine.Group("/api") { api.GET("/health", health.Check) api.GET("/listing-publish-options", systemConfigHandler.PublishOptions) api.GET("/listing-sale-price-config", systemConfigHandler.SalePriceConfig) api.GET("/home-announcements", systemConfigHandler.HomeAnnouncements) api.GET("/mobile-home-config", systemConfigHandler.HomeConfig) api.GET("/public/files/object", fileHandler.PublicObject) authRoutes := api.Group("/auth") { authRoutes.POST("/sms/send", authHandler.SendSMS) authRoutes.POST("/sms/login", authHandler.Login) authRoutes.POST("/refresh", authHandler.Refresh) authRoutes.POST("/logout", authHandler.Logout) } api.GET("/me", requireAuth, userHandler.Me) api.PUT("/me", requireAuth, userHandler.UpdateMe) listingRoutes := api.Group("/listings") { listingRoutes.GET("", listingHandler.ListPublic) listingRoutes.GET("/:id/cover", listingHandler.Cover) listingRoutes.GET("/:id/screenshots/:index", listingHandler.Screenshot) listingRoutes.GET("/:id", listingHandler.FindPublic) listingRoutes.POST("", requireAuth, requireRealname, listingHandler.Create) listingRoutes.PUT("/:id", requireAuth, requireRealname, listingHandler.Update) listingRoutes.POST("/:id/submit-review", requireAuth, requireRealname, listingHandler.SubmitReview) listingRoutes.DELETE("/:id", requireAuth, requireRealname, listingHandler.Offline) } sellerRoutes := api.Group("/seller", requireAuth, requireRealname) { sellerRoutes.GET("/listings", listingHandler.ListMine) sellerRoutes.GET("/listings/:id", listingHandler.FindMine) } orderRoutes := api.Group("/orders", requireAuth) { orderRoutes.POST("", orderHandler.Create) orderRoutes.GET("", orderHandler.List) orderRoutes.GET("/:id", orderHandler.Detail) orderRoutes.POST("/:id/cancel", orderHandler.Cancel) orderRoutes.POST("/:id/handoff", orderHandler.SubmitHandoff) orderRoutes.GET("/:id/handoff-records", orderHandler.HandoffRecords) orderRoutes.POST("/:id/confirm-receive", orderHandler.ConfirmReceive) orderRoutes.POST("/:id/checkout", orderHandler.SubmitCheckout) orderRoutes.POST("/:id/checkout/confirm", orderHandler.ConfirmCheckout) orderRoutes.POST("/:id/checkout/counter", orderHandler.CounterCheckout) orderRoutes.POST("/:id/checkout/accept", orderHandler.AcceptCheckout) orderRoutes.POST("/:id/dispute", disputeHandler.Create) } disputeRoutes := api.Group("/disputes", requireAuth) { disputeRoutes.GET("", disputeHandler.List) disputeRoutes.GET("/:id", disputeHandler.Detail) } walletRoutes := api.Group("/wallet", requireAuth) { walletRoutes.GET("/balance", walletHandler.Balance) walletRoutes.GET("/ledger", walletHandler.Ledger) } fileRoutes := api.Group("/files", requireAuth) { fileRoutes.POST("/upload", fileHandler.Upload) fileRoutes.GET("/object", fileHandler.Object) } notificationRoutes := api.Group("/notifications", requireAuth) { notificationRoutes.GET("", notificationHandler.List) notificationRoutes.POST("/:id/read", notificationHandler.MarkRead) } realnameRoutes := api.Group("/realname", requireAuth) { realnameRoutes.POST("/start", realnameHandler.Start) realnameRoutes.GET("/status", realnameHandler.Status) } adminAuthRoutes := api.Group("/admin/auth") { adminAuthRoutes.GET("/captcha", adminAuthHandler.Captcha) adminAuthRoutes.POST("/login", adminAuthHandler.Login) adminAuthRoutes.POST("/refresh", adminAuthHandler.Refresh) } adminRoutes := api.Group("/admin", requireAdmin) { adminRoutes.GET("/me", adminAuthHandler.Me) adminRoutes.POST("/auth/logout", adminAuthHandler.Logout) adminRoutes.POST("/files/upload", fileHandler.Upload) adminRoutes.GET("/dashboard", adminDashboardHandler.Summary) adminRoutes.GET("/files/object", fileHandler.Object) adminRoutes.GET("/users", adminUserHandler.List) adminRoutes.POST("/users/:id/freeze", adminUserHandler.Freeze) adminRoutes.POST("/users/:id/unfreeze", adminUserHandler.Unfreeze) adminRoutes.GET("/orders", orderHandler.AdminList) adminRoutes.GET("/orders/:id", orderHandler.AdminDetail) adminRoutes.GET("/orders/:id/handoff-records", orderHandler.AdminHandoffRecords) adminRoutes.POST("/orders/:id/close", orderHandler.AdminClose) adminRoutes.POST("/orders/:id/mark-abnormal", orderHandler.AdminMarkAbnormal) adminRoutes.GET("/listings", listingHandler.ListAdmin) adminRoutes.GET("/listings/pending", listingHandler.ListPendingReview) adminRoutes.GET("/listings/:id", listingHandler.FindAdmin) adminRoutes.POST("/listings/:id/approve", listingHandler.Approve) adminRoutes.POST("/listings/:id/reject", listingHandler.Reject) adminRoutes.POST("/listings/:id/offline", listingHandler.AdminOffline) adminRoutes.POST("/listings/:id/mark-abnormal", listingHandler.AdminMarkAbnormal) adminRoutes.GET("/disputes", disputeHandler.AdminList) adminRoutes.POST("/disputes/:id/arbitrate", disputeHandler.AdminArbitrate) adminRoutes.GET("/wallet/ledger", walletHandler.AdminLedger) adminRoutes.GET("/system-configs", systemConfigHandler.List) adminRoutes.PUT("/system-configs/:key", systemConfigHandler.Update) adminRoutes.GET("/audit-logs", adminAuditHandler.List) } } return engine }