feat(server): API relay gateway backend M0-M4

Gin + GORM + pure-Go SQLite. Users/auth (JWT), API key management with
quotas, proxy gateway with weighted channel failover and health checks,
usage/billing ledger, cross-protocol conversion (Anthropic Messages /
OpenAI Chat Completions / OpenAI Responses), and channel/model admin API.
Channels declare native API formats and auto-convert the rest.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Sakurasan
2026-08-15 21:05:02 +08:00
co-authored by Claude Sonnet 5
parent b0c7439c01
commit d0e31b198f
45 changed files with 6222 additions and 0 deletions
+57
View File
@@ -0,0 +1,57 @@
package admin
import (
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"gorm.io/gorm"
"openteam/server/internal/billing"
"openteam/server/internal/channel"
"openteam/server/internal/user"
)
// Register wires the admin routes onto a gin group.
func Register(g *gin.RouterGroup, db *gorm.DB, ch *channel.Service, bill *billing.Service, log *zap.Logger) {
// Handler instances.
chHandler := &channelHandler{db: db, ch: ch, log: log}
modelHandler := &modelHandler{db: db, log: log}
userHandler := &userHandler{db: db, bill: bill, log: log}
usageHandler := &usageHandler{db: db, bill: bill, log: log}
configHandler := &configHandler{db: db, log: log}
g = g.Group("", user.RequireAdmin())
// Channels.
g.GET("/channels", chHandler.List)
g.POST("/channels", chHandler.Create)
g.PUT("/channels/:id", chHandler.Update)
g.DELETE("/channels/:id", chHandler.Delete)
g.POST("/channels/:id/test", chHandler.Test)
g.POST("/channels/:id/import-models", chHandler.ImportModels)
g.GET("/channels/:id/bindings", chHandler.ListBindings)
g.PUT("/channels/:id/bindings", chHandler.SaveBindings)
// Models.
g.GET("/models", modelHandler.List)
g.POST("/models", modelHandler.Create)
g.PUT("/models/:id", modelHandler.Update)
g.PUT("/models/:id/price", modelHandler.UpdatePrice)
// Users.
g.GET("/users", userHandler.List)
g.PATCH("/users/:id", userHandler.Update)
g.POST("/users/:id/balance", userHandler.AdjustBalance)
// Recharges (reserved; approve/reject wire the paused state machine).
g.GET("/recharges", usageHandler.Recharges)
g.POST("/recharges/:id/approve", usageHandler.ApproveRecharge)
g.POST("/recharges/:id/reject", usageHandler.RejectRecharge)
// Usage & stats.
g.GET("/usage", usageHandler.Usage)
g.GET("/stats/overview", usageHandler.Overview)
// System config.
g.GET("/config", configHandler.Get)
g.PUT("/config", configHandler.Put)
}