package router import ( "backend/config" "backend/internal/controller/analytics" "backend/internal/controller/auth" "backend/internal/controller/customer" "backend/internal/controller/entitlement" "backend/internal/controller/license" "backend/internal/controller/order" "backend/internal/controller/plan" "backend/internal/controller/product" "backend/internal/controller/setting" "backend/middleware" "strings" "github.com/gin-contrib/gzip" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // register 同时注册带和不带 trailing slash 的路由 // Logan.Li func register(r gin.IRoutes, method, relativePath string, handlers ...gin.HandlerFunc) { isParamRoute := strings.Contains(relativePath, ":") switch method { case "GET": r.GET(relativePath, handlers...) if !isParamRoute { r.GET(relativePath+"/", handlers...) } case "POST": r.POST(relativePath, handlers...) if !isParamRoute { r.POST(relativePath+"/", handlers...) } case "PUT": r.PUT(relativePath, handlers...) if !isParamRoute { r.PUT(relativePath+"/", handlers...) } case "DELETE": r.DELETE(relativePath, handlers...) if !isParamRoute { r.DELETE(relativePath+"/", handlers...) } case "PATCH": r.PATCH(relativePath, handlers...) if !isParamRoute { r.PATCH(relativePath+"/", handlers...) } } } // SetupRouter 初始化路由 // Logan.Li func SetupRouter(db *gorm.DB, cfg *config.Config) *gin.Engine { gin.SetMode(cfg.Mode) r := gin.Default() r.RedirectTrailingSlash = false r.RedirectFixedPath = false // Gzip 压缩中间件 // Logan.Li r.Use(gzip.Gzip(gzip.DefaultCompression)) // CORS 中间件 // Logan.Li r.Use(middleware.CORSMiddleware(cfg)) // 存活探针(不查库) // Logan.Li r.GET("/health", func(c *gin.Context) { c.JSON(200, gin.H{"code": 0, "message": "ok", "data": nil}) }) r.GET("/healthz", func(c *gin.Context) { c.JSON(200, gin.H{"status": "alive"}) }) // 就绪探针:检查数据库可达 // Logan.Li r.GET("/readyz", func(c *gin.Context) { sqlDB, err := db.DB() if err != nil || sqlDB.Ping() != nil { c.JSON(503, gin.H{"status": "db unreachable"}) return } c.JSON(200, gin.H{"status": "ready"}) }) // 初始化控制器 // Logan.Li authController := auth.NewAuthController(db, cfg) productController := product.NewProductController(db) customerController := customer.NewCustomerController(db) licenseController := license.NewLicenseController(db, cfg) planController := plan.NewPlanController(db) orderController := order.NewOrderController(db) entitlementController := entitlement.NewEntitlementController(db) analyticsController := analytics.NewAnalyticsController(db) settingController := setting.NewSettingController(db) api := r.Group("/api") { // ============ 认证路由(无需 JWT) ============ authGroup := api.Group("/auth") { register(authGroup, "POST", "/login", middleware.RateLimit(0.2, 5), authController.Login) } // ============ 客户端授权契约(无需认证,供外部工具调用) ============ clientAPI := api.Group("/v1") { licLimit := middleware.RateLimit(2, 30) checkoutLimit := middleware.RateLimit(0.5, 10) webhookLimit := middleware.RateLimit(1, 20) // License 验证 / 激活 / 停用 / 心跳 register(clientAPI, "POST", "/license/verify", licLimit, licenseController.Verify) register(clientAPI, "POST", "/license/activate", licLimit, licenseController.ActivateDevice) register(clientAPI, "POST", "/license/deactivate", licLimit, licenseController.Deactivate) register(clientAPI, "POST", "/license/heartbeat", licLimit, licenseController.Heartbeat) register(clientAPI, "POST", "/license/devices", licLimit, licenseController.ListDevices) // 产品定价查询(展示用) register(clientAPI, "GET", "/products/code/:code", productController.GetByCode) clientAPI.GET("/products/:product_id/plans", planController.GetByProduct) // 订单与支付(客户端购买入口 + 支付回调) register(clientAPI, "POST", "/orders", checkoutLimit, orderController.CreateOrder) register(clientAPI, "POST", "/checkout", checkoutLimit, orderController.Checkout) register(clientAPI, "POST", "/purchase/claim", checkoutLimit, orderController.ClaimPurchase) register(clientAPI, "POST", "/webhooks/payment", webhookLimit, orderController.PaymentWebhook) register(clientAPI, "GET", "/webhooks/waffo", orderController.WaffoWebhookReady) register(clientAPI, "POST", "/webhooks/waffo", webhookLimit, orderController.WaffoWebhook) register(clientAPI, "GET", "/purchase/success", orderController.PurchaseSuccess) register(clientAPI, "POST", "/purchase/check", checkoutLimit, orderController.CheckDuplicatePurchase) register(clientAPI, "POST", "/purchase/status", checkoutLimit, orderController.CheckPurchaseStatus) // 客户权益查询(通过邮箱) register(clientAPI, "GET", "/entitlements/my", checkoutLimit, entitlementController.GetByEmail) } // ============ 需要认证的管理路由 ============ protected := api.Group("", middleware.AuthMiddleware(cfg, db)) { // 认证相关 register(protected, "GET", "/auth/me", authController.Me) register(protected, "PUT", "/auth/password", authController.ChangePassword) // 产品管理 products := protected.Group("/products") { register(products, "GET", "", productController.List) register(products, "GET", "/all", productController.GetAll) register(products, "POST", "", productController.Create) register(products, "GET", "/:id", productController.Get) register(products, "PUT", "/:id", productController.Update) register(products, "DELETE", "/:id", productController.Delete) register(products, "PATCH", "/:id/status", productController.UpdateStatus) } // 客户管理 customers := protected.Group("/customers") { register(customers, "GET", "", customerController.List) register(customers, "GET", "/all", customerController.GetAll) register(customers, "POST", "", customerController.Create) register(customers, "GET", "/:id", customerController.Get) register(customers, "PUT", "/:id", customerController.Update) register(customers, "DELETE", "/:id", customerController.Delete) register(customers, "PATCH", "/:id/status", customerController.UpdateStatus) } // License 管理 licenses := protected.Group("/licenses") { register(licenses, "GET", "", licenseController.List) register(licenses, "POST", "", licenseController.Create) register(licenses, "POST", "/offline", licenseController.IssueOffline) register(licenses, "GET", "/offline/public-key", licenseController.OfflinePublicKey) register(licenses, "GET", "/export", licenseController.Export) register(licenses, "POST", "/batch-delete", licenseController.BatchDelete) register(licenses, "GET", "/:id", licenseController.Get) register(licenses, "PUT", "/:id", licenseController.Update) register(licenses, "DELETE", "/:id", licenseController.Delete) register(licenses, "POST", "/:id/renew", licenseController.Renew) register(licenses, "POST", "/:id/revoke", licenseController.Revoke) register(licenses, "POST", "/:id/suspend", licenseController.Suspend) register(licenses, "POST", "/:id/activate", licenseController.Activate) register(licenses, "GET", "/:id/activations", licenseController.GetActivations) register(licenses, "POST", "/:id/activations/:activationId/offline", licenseController.ForceOffline) } // 定价计划管理 plans := protected.Group("/plans") { register(plans, "GET", "", planController.List) register(plans, "POST", "", planController.Create) register(plans, "PUT", "/:id", planController.Update) register(plans, "DELETE", "/:id", planController.Delete) register(plans, "PATCH", "/:id/status", planController.ToggleStatus) } // 订单管理 orders := protected.Group("/orders") { register(orders, "GET", "", orderController.List) register(orders, "GET", "/:id", orderController.GetDetail) register(orders, "POST", "/manual-grant", orderController.ManualGrant) } // 客户权益管理 entitlements := protected.Group("/entitlements") { register(entitlements, "GET", "", entitlementController.List) register(entitlements, "GET", "/:id", entitlementController.Get) register(entitlements, "POST", "/:id/revoke", entitlementController.Revoke) register(entitlements, "POST", "/:id/renew", entitlementController.Renew) } // 仪表板与数据分析 dashboard := protected.Group("/dashboard") { register(dashboard, "GET", "/stats", analyticsController.GetDashboardStats) register(dashboard, "GET", "/expiring", analyticsController.GetExpiringLicenses) register(dashboard, "GET", "/activities", analyticsController.GetRecentActivities) register(dashboard, "GET", "/online-stats", analyticsController.GetOnlineStats) register(dashboard, "GET", "/revenue", analyticsController.GetRevenueStats) } analyticsGroup := protected.Group("/analytics") { register(analyticsGroup, "GET", "/license-growth", analyticsController.GetLicenseGrowth) register(analyticsGroup, "GET", "/license-growth-detail", analyticsController.GetLicenseGrowthDetail) register(analyticsGroup, "GET", "/product-distribution", analyticsController.GetProductDistribution) register(analyticsGroup, "GET", "/revenue", analyticsController.GetRevenueStats) register(analyticsGroup, "GET", "/geo-distribution", analyticsController.GetGeoDistribution) register(analyticsGroup, "GET", "/platform-distribution", analyticsController.GetPlatformDistribution) } // 日志审计与系统设置 logs := protected.Group("/logs") { register(logs, "GET", "", settingController.ListAuditLogs) register(logs, "DELETE", "/clear", settingController.ClearAuditLogs) } system := protected.Group("/settings") { register(system, "GET", "", settingController.Get) register(system, "PUT", "", settingController.Update) register(system, "GET", "/waffo", settingController.GetWaffo) register(system, "PUT", "/waffo", settingController.UpdateWaffo) register(system, "POST", "/waffo/test", settingController.DebugWaffo) } // 支付调试(与 settings/waffo/test 同一 handler) // Logan.Li paymentGroup := protected.Group("/payment") { register(paymentGroup, "POST", "/waffo/debug", settingController.DebugWaffo) } } } return r }