feat(api): add admin master key listing/revoke

Add admin endpoints to list and revoke child keys under a master.
Standardize OpenAPI responses to use ResponseEnvelope with MapData
for error payloads, and regenerate swagger specs accordingly.
This commit is contained in:
zenfun
2026-01-10 01:10:36 +08:00
parent ac6a1858cf
commit 5349c9c833
27 changed files with 9407 additions and 1134 deletions

View File

@@ -30,9 +30,9 @@ type UpdateAccessRequest struct {
// @Security AdminAuth
// @Param id path int true "Master ID"
// @Success 200 {object} ResponseEnvelope{data=AccessResponse}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/masters/{id}/access [get]
func (h *Handler) GetMasterAccess(c *gin.Context) {
id, ok := parseUintParam(c, "id")
@@ -62,9 +62,9 @@ func (h *Handler) GetMasterAccess(c *gin.Context) {
// @Param id path int true "Master ID"
// @Param request body UpdateAccessRequest true "Access settings"
// @Success 200 {object} ResponseEnvelope{data=AccessResponse}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/masters/{id}/access [put]
func (h *Handler) UpdateMasterAccess(c *gin.Context) {
id, ok := parseUintParam(c, "id")
@@ -145,9 +145,9 @@ func (h *Handler) UpdateMasterAccess(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "Key ID"
// @Success 200 {object} ResponseEnvelope{data=AccessResponse}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/keys/{id}/access [get]
func (h *Handler) GetKeyAccess(c *gin.Context) {
id, ok := parseUintParam(c, "id")
@@ -175,9 +175,9 @@ func (h *Handler) GetKeyAccess(c *gin.Context) {
// @Param id path int true "Key ID"
// @Param request body UpdateAccessRequest true "Access settings"
// @Success 200 {object} ResponseEnvelope{data=AccessResponse}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/keys/{id}/access [put]
func (h *Handler) UpdateKeyAccess(c *gin.Context) {
id, ok := parseUintParam(c, "id")

View File

@@ -54,9 +54,9 @@ type CreateMasterRequest struct {
// @Produce json
// @Security AdminAuth
// @Param master body CreateMasterRequest true "Master Info"
// @Success 201 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 201 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/masters [post]
func (h *AdminHandler) CreateMaster(c *gin.Context) {
var req CreateMasterRequest
@@ -136,7 +136,7 @@ func toMasterView(m model.Master) MasterView {
// @Param limit query int false "limit (default 50, max 200)"
// @Param search query string false "search by name/group"
// @Success 200 {object} ResponseEnvelope{data=[]MasterView}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/masters [get]
func (h *AdminHandler) ListMasters(c *gin.Context) {
var masters []model.Master
@@ -163,9 +163,9 @@ func (h *AdminHandler) ListMasters(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "Master ID"
// @Success 200 {object} ResponseEnvelope{data=MasterView}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/masters/{id} [get]
func (h *AdminHandler) GetMaster(c *gin.Context) {
idRaw := strings.TrimSpace(c.Param("id"))
@@ -209,9 +209,9 @@ type UpdateMasterRequest struct {
// @Param id path int true "Master ID"
// @Param request body UpdateMasterRequest true "Update payload"
// @Success 200 {object} ResponseEnvelope{data=MasterView}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/masters/{id} [put]
func (h *AdminHandler) UpdateMaster(c *gin.Context) {
idRaw := strings.TrimSpace(c.Param("id"))
@@ -314,9 +314,9 @@ type ManageMasterRequest struct {
// @Param id path int true "Master ID"
// @Param request body ManageMasterRequest true "Action"
// @Success 200 {object} ResponseEnvelope{data=MasterView}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/masters/{id}/manage [post]
func (h *AdminHandler) ManageMaster(c *gin.Context) {
idRaw := strings.TrimSpace(c.Param("id"))
@@ -370,10 +370,10 @@ func (h *AdminHandler) ManageMaster(c *gin.Context) {
// @Produce json
// @Security AdminAuth
// @Param id path int true "Master ID"
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/masters/{id} [delete]
func (h *AdminHandler) DeleteMaster(c *gin.Context) {
idRaw := strings.TrimSpace(c.Param("id"))
@@ -404,11 +404,11 @@ func (h *AdminHandler) DeleteMaster(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "Master ID"
// @Param request body IssueChildKeyRequest true "Key Request"
// @Success 201 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 403 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 201 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 403 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/masters/{id}/keys [post]
func (h *AdminHandler) IssueChildKeyForMaster(c *gin.Context) {
idRaw := strings.TrimSpace(c.Param("id"))
@@ -477,3 +477,89 @@ func (h *AdminHandler) IssueChildKeyForMaster(c *gin.Context) {
"issued_by": key.IssuedBy,
})
}
// ListKeysForMaster godoc
// @Summary List child keys for a master
// @Description List child keys issued under a master (admin view)
// @Tags admin
// @Produce json
// @Security AdminAuth
// @Param id path int true "Master ID"
// @Param page query int false "page (1-based)"
// @Param limit query int false "limit (default 50, max 200)"
// @Param search query string false "search by group/scopes/namespaces/status"
// @Success 200 {object} ResponseEnvelope{data=[]TokenView}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Router /admin/masters/{id}/keys [get]
func (h *AdminHandler) ListKeysForMaster(c *gin.Context) {
masterID, ok := parseUintParam(c, "id")
if !ok {
return
}
var keys []model.Key
q := h.db.Model(&model.Key{}).Where("master_id = ?", masterID).Order("id desc")
query := parseListQuery(c)
q = applyListSearch(q, query.Search, `"group"`, "scopes", "default_namespace", "namespaces", "status")
q = applyListPagination(q, query)
if err := q.Find(&keys).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list tokens", "details": err.Error()})
return
}
out := make([]TokenView, 0, len(keys))
for _, k := range keys {
out = append(out, toTokenView(k))
}
c.JSON(http.StatusOK, out)
}
// DeleteKeyForMaster godoc
// @Summary Delete (revoke) child key
// @Description Suspends a child key under the specified master
// @Tags admin
// @Produce json
// @Security AdminAuth
// @Param id path int true "Master ID"
// @Param key_id path int true "Token ID"
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Router /admin/masters/{id}/keys/{key_id} [delete]
func (h *AdminHandler) DeleteKeyForMaster(c *gin.Context) {
masterID, ok := parseUintParam(c, "id")
if !ok {
return
}
keyID, ok := parseUintParam(c, "key_id")
if !ok {
return
}
var k model.Key
if err := h.db.Where("master_id = ? AND id = ?", masterID, keyID).First(&k).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
c.JSON(http.StatusNotFound, gin.H{"error": "token not found"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load token", "details": err.Error()})
return
}
if err := h.db.Model(&k).Update("status", "suspended").Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to revoke token", "details": err.Error()})
return
}
if err := h.db.Where("master_id = ? AND id = ?", masterID, keyID).First(&k).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to reload token", "details": err.Error()})
return
}
if err := h.syncService.SyncKey(&k); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to sync token", "details": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"status": "revoked"})
}

View File

@@ -91,7 +91,7 @@ type ListAlertsResponse struct {
// @Param severity query string false "filter by severity (info, warning, critical)"
// @Param type query string false "filter by type (rate_limit, error_spike, quota_exceeded, key_disabled, key_expired, provider_down, traffic_spike)"
// @Success 200 {object} ResponseEnvelope{data=ListAlertsResponse}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/alerts [get]
func (h *AlertHandler) ListAlerts(c *gin.Context) {
limit, offset := parseLimitOffset(c)
@@ -141,8 +141,8 @@ func (h *AlertHandler) ListAlerts(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "Alert ID"
// @Success 200 {object} ResponseEnvelope{data=AlertView}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Router /admin/alerts/{id} [get]
func (h *AlertHandler) GetAlert(c *gin.Context) {
id, ok := parseUintParam(c, "id")
@@ -181,8 +181,8 @@ type CreateAlertRequest struct {
// @Security AdminAuth
// @Param request body CreateAlertRequest true "Alert data"
// @Success 201 {object} ResponseEnvelope{data=AlertView}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/alerts [post]
func (h *AlertHandler) CreateAlert(c *gin.Context) {
var req CreateAlertRequest
@@ -248,9 +248,9 @@ type AckAlertRequest struct {
// @Param id path int true "Alert ID"
// @Param request body AckAlertRequest false "Ack data"
// @Success 200 {object} ResponseEnvelope{data=AlertView}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/alerts/{id}/ack [post]
func (h *AlertHandler) AcknowledgeAlert(c *gin.Context) {
id, ok := parseUintParam(c, "id")
@@ -295,9 +295,9 @@ func (h *AlertHandler) AcknowledgeAlert(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "Alert ID"
// @Success 200 {object} ResponseEnvelope{data=AlertView}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/alerts/{id}/resolve [post]
func (h *AlertHandler) ResolveAlert(c *gin.Context) {
id, ok := parseUintParam(c, "id")
@@ -337,10 +337,10 @@ func (h *AlertHandler) ResolveAlert(c *gin.Context) {
// @Produce json
// @Security AdminAuth
// @Param id path int true "Alert ID"
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/alerts/{id} [delete]
func (h *AlertHandler) DismissAlert(c *gin.Context) {
id, ok := parseUintParam(c, "id")
@@ -380,7 +380,7 @@ type AlertStats struct {
// @Produce json
// @Security AdminAuth
// @Success 200 {object} ResponseEnvelope{data=AlertStats}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/alerts/stats [get]
func (h *AlertHandler) GetAlertStats(c *gin.Context) {
var total, active, acknowledged, resolved, critical, warning, info int64
@@ -436,7 +436,7 @@ func toAlertThresholdView(cfg model.AlertThresholdConfig) AlertThresholdView {
// @Produce json
// @Security AdminAuth
// @Success 200 {object} ResponseEnvelope{data=AlertThresholdView}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/alerts/thresholds [get]
func (h *AlertHandler) GetAlertThresholds(c *gin.Context) {
cfg, err := h.loadThresholdConfig()
@@ -467,8 +467,8 @@ type UpdateAlertThresholdsRequest struct {
// @Security AdminAuth
// @Param request body UpdateAlertThresholdsRequest true "Threshold configuration"
// @Success 200 {object} ResponseEnvelope{data=AlertThresholdView}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/alerts/thresholds [put]
func (h *AlertHandler) UpdateAlertThresholds(c *gin.Context) {
var req UpdateAlertThresholdsRequest

View File

@@ -18,8 +18,8 @@ import (
// @Security AdminAuth
// @Param key body dto.APIKeyDTO true "API key payload"
// @Success 201 {object} ResponseEnvelope{data=model.APIKey}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/api-keys [post]
func (h *Handler) CreateAPIKey(c *gin.Context) {
var req dto.APIKeyDTO
@@ -101,7 +101,7 @@ func (h *Handler) CreateAPIKey(c *gin.Context) {
// @Param group_id query int false "filter by group_id"
// @Param status query string false "filter by status (active, suspended, auto_disabled, manual_disabled)"
// @Success 200 {object} ResponseEnvelope{data=[]model.APIKey}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/api-keys [get]
func (h *Handler) ListAPIKeys(c *gin.Context) {
var keys []model.APIKey
@@ -129,9 +129,9 @@ func (h *Handler) ListAPIKeys(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "APIKey ID"
// @Success 200 {object} ResponseEnvelope{data=model.APIKey}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/api-keys/{id} [get]
func (h *Handler) GetAPIKey(c *gin.Context) {
id, ok := parseUintParam(c, "id")
@@ -156,9 +156,9 @@ func (h *Handler) GetAPIKey(c *gin.Context) {
// @Param id path int true "APIKey ID"
// @Param key body dto.APIKeyDTO true "API key payload"
// @Success 200 {object} ResponseEnvelope{data=model.APIKey}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/api-keys/{id} [put]
func (h *Handler) UpdateAPIKey(c *gin.Context) {
id, ok := parseUintParam(c, "id")
@@ -275,10 +275,10 @@ func (h *Handler) UpdateAPIKey(c *gin.Context) {
// @Produce json
// @Security AdminAuth
// @Param id path int true "APIKey ID"
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/api-keys/{id} [delete]
func (h *Handler) DeleteAPIKey(c *gin.Context) {
id, ok := parseUintParam(c, "id")

View File

@@ -26,7 +26,7 @@ type APIKeyStatsSummaryResponse struct {
// @Param since query int false "Start time (unix seconds)"
// @Param until query int false "End time (unix seconds)"
// @Success 200 {object} ResponseEnvelope{data=APIKeyStatsSummaryResponse}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/apikey-stats/summary [get]
func (h *AdminHandler) GetAPIKeyStatsSummary(c *gin.Context) {
if h == nil || h.db == nil {

View File

@@ -172,7 +172,7 @@ type WhoamiResponse struct {
// @Security AdminAuth
// @Security MasterAuth
// @Success 200 {object} ResponseEnvelope{data=WhoamiResponse}
// @Failure 401 {object} ResponseEnvelope{data=gin.H} "Invalid or missing token"
// @Failure 401 {object} ResponseEnvelope{data=MapData} "Invalid or missing token"
// @Router /auth/whoami [get]
func (h *AuthHandler) Whoami(c *gin.Context) {
authHeader := c.GetHeader("Authorization")

View File

@@ -58,8 +58,8 @@ func isAllowedStatus(raw string, allowed ...string) bool {
// @Security AdminAuth
// @Param request body BatchActionRequest true "Batch payload"
// @Success 200 {object} ResponseEnvelope{data=BatchResponse}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/masters/batch [post]
func (h *AdminHandler) BatchMasters(c *gin.Context) {
var req BatchActionRequest
@@ -113,8 +113,8 @@ func (h *AdminHandler) BatchMasters(c *gin.Context) {
// @Security AdminAuth
// @Param request body BatchActionRequest true "Batch payload"
// @Success 200 {object} ResponseEnvelope{data=BatchResponse}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/api-keys/batch [post]
func (h *Handler) BatchAPIKeys(c *gin.Context) {
var req BatchActionRequest
@@ -197,8 +197,8 @@ func (h *Handler) BatchAPIKeys(c *gin.Context) {
// @Security AdminAuth
// @Param request body BatchActionRequest true "Batch payload"
// @Success 200 {object} ResponseEnvelope{data=BatchResponse}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/models/batch [post]
func (h *Handler) BatchModels(c *gin.Context) {
var req BatchActionRequest
@@ -249,8 +249,8 @@ func (h *Handler) BatchModels(c *gin.Context) {
// @Security AdminAuth
// @Param request body BatchActionRequest true "Batch payload"
// @Success 200 {object} ResponseEnvelope{data=BatchResponse}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/bindings/batch [post]
func (h *Handler) BatchBindings(c *gin.Context) {
var req BatchActionRequest

View File

@@ -20,8 +20,8 @@ import (
// @Security AdminAuth
// @Param binding body dto.BindingDTO true "Binding Info"
// @Success 201 {object} ResponseEnvelope{data=model.Binding}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/bindings [post]
func (h *Handler) CreateBinding(c *gin.Context) {
var req dto.BindingDTO
@@ -85,7 +85,7 @@ func (h *Handler) CreateBinding(c *gin.Context) {
// @Param limit query int false "limit (default 50, max 200)"
// @Param search query string false "search by namespace/public_model"
// @Success 200 {object} ResponseEnvelope{data=[]model.Binding}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/bindings [get]
func (h *Handler) ListBindings(c *gin.Context) {
var out []model.Binding
@@ -110,9 +110,9 @@ func (h *Handler) ListBindings(c *gin.Context) {
// @Param id path int true "Binding ID"
// @Param binding body dto.BindingDTO true "Binding Info"
// @Success 200 {object} ResponseEnvelope{data=model.Binding}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/bindings/{id} [put]
func (h *Handler) UpdateBinding(c *gin.Context) {
idParam := c.Param("id")
@@ -181,9 +181,9 @@ func (h *Handler) UpdateBinding(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "Binding ID"
// @Success 200 {object} ResponseEnvelope{data=model.Binding}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/bindings/{id} [get]
func (h *Handler) GetBinding(c *gin.Context) {
idParam := c.Param("id")
@@ -207,10 +207,10 @@ func (h *Handler) GetBinding(c *gin.Context) {
// @Produce json
// @Security AdminAuth
// @Param id path int true "Binding ID"
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/bindings/{id} [delete]
func (h *Handler) DeleteBinding(c *gin.Context) {
idParam := c.Param("id")

View File

@@ -188,8 +188,8 @@ type DashboardSummaryResponse struct {
// @Param until query int false "unix seconds"
// @Param include_trends query bool false "include trend data comparing to previous period"
// @Success 200 {object} ResponseEnvelope{data=DashboardSummaryResponse}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/dashboard/summary [get]
func (h *DashboardHandler) GetSummary(c *gin.Context) {
rng, err := parseStatsRange(c)

View File

@@ -37,8 +37,8 @@ func NewFeatureHandler(rdb *redis.Client) *FeatureHandler {
// @Tags admin
// @Produce json
// @Security AdminAuth
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/features [get]
func (h *FeatureHandler) ListFeatures(c *gin.Context) {
if h.rdb == nil {
@@ -75,9 +75,9 @@ type UpdateFeaturesRequest map[string]any
// @Produce json
// @Security AdminAuth
// @Param request body object true "Feature map"
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/features [put]
func (h *FeatureHandler) UpdateFeatures(c *gin.Context) {
if h.rdb == nil {

View File

@@ -63,8 +63,8 @@ func (h *Handler) logBaseQuery() *gorm.DB {
// @Security AdminAuth
// @Param model body dto.ModelDTO true "Model Info"
// @Success 201 {object} ResponseEnvelope{data=model.Model}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/models [post]
func (h *Handler) CreateModel(c *gin.Context) {
var req dto.ModelDTO
@@ -124,7 +124,7 @@ func (h *Handler) CreateModel(c *gin.Context) {
// @Param limit query int false "limit (default 50, max 200)"
// @Param search query string false "search by name/kind"
// @Success 200 {object} ResponseEnvelope{data=[]model.Model}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/models [get]
func (h *Handler) ListModels(c *gin.Context) {
var models []model.Model
@@ -149,9 +149,9 @@ func (h *Handler) ListModels(c *gin.Context) {
// @Param id path int true "Model ID"
// @Param model body dto.ModelDTO true "Model Info"
// @Success 200 {object} ResponseEnvelope{data=model.Model}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/models/{id} [put]
func (h *Handler) UpdateModel(c *gin.Context) {
idParam := c.Param("id")
@@ -222,10 +222,10 @@ func (h *Handler) UpdateModel(c *gin.Context) {
// @Produce json
// @Security AdminAuth
// @Param id path int true "Model ID"
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/models/{id} [delete]
func (h *Handler) DeleteModel(c *gin.Context) {
idParam := c.Param("id")
@@ -260,8 +260,8 @@ func (h *Handler) DeleteModel(c *gin.Context) {
// @Tags admin
// @Produce json
// @Security AdminAuth
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/sync/snapshot [post]
func (h *Handler) SyncSnapshot(c *gin.Context) {
if err := h.sync.SyncAll(h.db); err != nil {
@@ -278,8 +278,8 @@ func (h *Handler) SyncSnapshot(c *gin.Context) {
// @Accept json
// @Produce json
// @Param log body model.LogRecord true "Log Record"
// @Success 202 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Success 202 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Router /logs [post]
func (h *Handler) IngestLog(c *gin.Context) {
var rec model.LogRecord

View File

@@ -47,9 +47,9 @@ type apiKeyStatsFlushEntry struct {
// @Accept json
// @Produce json
// @Param request body statsFlushRequest true "Stats to flush"
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /internal/stats/flush [post]
func (h *InternalHandler) FlushStats(c *gin.Context) {
if h == nil || h.db == nil {
@@ -124,9 +124,9 @@ func (h *InternalHandler) FlushStats(c *gin.Context) {
// @Accept json
// @Produce json
// @Param request body apiKeyStatsFlushRequest true "Stats to flush"
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /internal/apikey-stats/flush [post]
func (h *InternalHandler) FlushAPIKeyStats(c *gin.Context) {
if h == nil || h.db == nil {
@@ -288,8 +288,8 @@ const alertDeduplicationCooldown = 5 * time.Minute
// @Produce json
// @Param request body reportAlertsRequest true "Alerts to report"
// @Success 200 {object} ResponseEnvelope{data=reportAlertsResponse}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /internal/alerts/report [post]
func (h *InternalHandler) ReportAlerts(c *gin.Context) {
if h == nil || h.db == nil {

View File

@@ -90,9 +90,9 @@ func toIPBanView(ban *model.IPBan) IPBanView {
// @Security AdminAuth
// @Param ban body CreateIPBanRequest true "IP Ban Info"
// @Success 201 {object} ResponseEnvelope{data=IPBanView}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 409 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 409 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/ip-bans [post]
func (h *IPBanHandler) Create(c *gin.Context) {
var req CreateIPBanRequest
@@ -140,7 +140,7 @@ func (h *IPBanHandler) Create(c *gin.Context) {
// @Security AdminAuth
// @Param status query string false "Filter by status (active, expired)"
// @Success 200 {object} ResponseEnvelope{data=[]IPBanView}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/ip-bans [get]
func (h *IPBanHandler) List(c *gin.Context) {
status := c.Query("status")
@@ -168,8 +168,8 @@ func (h *IPBanHandler) List(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "IP Ban ID"
// @Success 200 {object} ResponseEnvelope{data=IPBanView}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/ip-bans/{id} [get]
func (h *IPBanHandler) Get(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
@@ -201,10 +201,10 @@ func (h *IPBanHandler) Get(c *gin.Context) {
// @Param id path int true "IP Ban ID"
// @Param ban body UpdateIPBanRequest true "IP Ban Update"
// @Success 200 {object} ResponseEnvelope{data=IPBanView}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 409 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 409 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/ip-bans/{id} [put]
func (h *IPBanHandler) Update(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
@@ -250,8 +250,8 @@ func (h *IPBanHandler) Update(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "IP Ban ID"
// @Success 204
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/ip-bans/{id} [delete]
func (h *IPBanHandler) Delete(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)

View File

@@ -168,7 +168,7 @@ func (h *MasterHandler) masterLogBase(masterID uint) (*gorm.DB, error) {
// @Param model query string false "model"
// @Param status_code query int false "status code"
// @Success 200 {object} ResponseEnvelope{data=ListLogsResponse}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/logs [get]
func (h *Handler) ListLogs(c *gin.Context) {
limit, offset := parseLimitOffset(c)
@@ -268,8 +268,8 @@ type DeleteLogsResponse struct {
// @Security AdminAuth
// @Param request body DeleteLogsRequest true "Delete filters"
// @Success 200 {object} ResponseEnvelope{data=DeleteLogsResponse}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/logs [delete]
func (h *Handler) DeleteLogs(c *gin.Context) {
var req DeleteLogsRequest
@@ -359,8 +359,8 @@ func (h *Handler) deleteLogsBefore(cutoff time.Time, keyID uint, modelName strin
// @Param group_by query string false "group by dimension: model, day, month, hour, minute. Returns GroupedStatsResponse when specified." Enums(model, day, month, hour, minute)
// @Success 200 {object} ResponseEnvelope{data=LogStatsResponse} "Default aggregated stats (when group_by is not specified)"
// @Success 200 {object} ResponseEnvelope{data=GroupedStatsResponse} "Grouped stats (when group_by is specified)"
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/logs/stats [get]
func (h *Handler) LogStats(c *gin.Context) {
q := h.logBaseQuery()
@@ -768,8 +768,8 @@ func buildTrafficChartSeriesResponse(rows []trafficBucketRow, topN int, granular
// @Param until query int false "End time (unix seconds), defaults to now"
// @Param top_n query int false "Number of top models to return (1-20), defaults to 5"
// @Success 200 {object} ResponseEnvelope{data=TrafficChartResponse}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/logs/stats/traffic-chart [get]
func (h *Handler) GetTrafficChart(c *gin.Context) {
// Parse granularity
@@ -870,8 +870,8 @@ func (h *Handler) GetTrafficChart(c *gin.Context) {
// @Param model query string false "model"
// @Param status_code query int false "status code"
// @Success 200 {object} ResponseEnvelope{data=ListMasterLogsResponse}
// @Failure 401 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 401 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /v1/logs [get]
func (h *MasterHandler) ListSelfLogs(c *gin.Context) {
master, exists := c.Get("master")
@@ -929,8 +929,8 @@ func (h *MasterHandler) ListSelfLogs(c *gin.Context) {
// @Param since query int false "unix seconds"
// @Param until query int false "unix seconds"
// @Success 200 {object} ResponseEnvelope{data=LogStatsResponse}
// @Failure 401 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 401 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /v1/logs/stats [get]
func (h *MasterHandler) GetSelfLogStats(c *gin.Context) {
master, exists := c.Get("master")

View File

@@ -14,7 +14,7 @@ import (
// @Produce json
// @Security AdminAuth
// @Success 200 {object} ResponseEnvelope{data=service.LogWebhookConfig}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/logs/webhook [get]
func (h *Handler) GetLogWebhookConfig(c *gin.Context) {
if h == nil || h.logWebhook == nil {
@@ -38,8 +38,8 @@ func (h *Handler) GetLogWebhookConfig(c *gin.Context) {
// @Security AdminAuth
// @Param request body service.LogWebhookConfig true "Webhook config"
// @Success 200 {object} ResponseEnvelope{data=service.LogWebhookConfig}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/logs/webhook [put]
func (h *Handler) UpdateLogWebhookConfig(c *gin.Context) {
if h == nil || h.logWebhook == nil {

View File

@@ -58,11 +58,11 @@ type IssueChildKeyRequest struct {
// @Produce json
// @Security MasterAuth
// @Param request body IssueChildKeyRequest true "Key Request"
// @Success 201 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 401 {object} ResponseEnvelope{data=gin.H}
// @Failure 403 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 201 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 401 {object} ResponseEnvelope{data=MapData}
// @Failure 403 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /v1/tokens [post]
func (h *MasterHandler) IssueChildKey(c *gin.Context) {
master, exists := c.Get("master")
@@ -146,7 +146,7 @@ func (h *MasterHandler) IssueChildKey(c *gin.Context) {
// @Produce json
// @Security MasterAuth
// @Success 200 {object} ResponseEnvelope{data=MasterView}
// @Failure 401 {object} ResponseEnvelope{data=gin.H}
// @Failure 401 {object} ResponseEnvelope{data=MapData}
// @Router /v1/self [get]
func (h *MasterHandler) GetSelf(c *gin.Context) {
master, exists := c.Get("master")
@@ -220,8 +220,8 @@ func toTokenView(k model.Key) TokenView {
// @Param limit query int false "limit (default 50, max 200)"
// @Param search query string false "search by group/scopes/namespaces/status"
// @Success 200 {object} ResponseEnvelope{data=[]TokenView}
// @Failure 401 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 401 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /v1/tokens [get]
func (h *MasterHandler) ListTokens(c *gin.Context) {
master, exists := c.Get("master")
@@ -255,10 +255,10 @@ func (h *MasterHandler) ListTokens(c *gin.Context) {
// @Security MasterAuth
// @Param id path int true "Token ID"
// @Success 200 {object} ResponseEnvelope{data=TokenView}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 401 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 401 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /v1/tokens/{id} [get]
func (h *MasterHandler) GetToken(c *gin.Context) {
master, exists := c.Get("master")
@@ -303,10 +303,10 @@ type UpdateTokenRequest struct {
// @Param id path int true "Token ID"
// @Param request body UpdateTokenRequest true "Update payload"
// @Success 200 {object} ResponseEnvelope{data=TokenView}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 401 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 401 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /v1/tokens/{id} [put]
func (h *MasterHandler) UpdateToken(c *gin.Context) {
master, exists := c.Get("master")
@@ -398,11 +398,11 @@ func (h *MasterHandler) UpdateToken(c *gin.Context) {
// @Produce json
// @Security MasterAuth
// @Param id path int true "Token ID"
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 401 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 401 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /v1/tokens/{id} [delete]
func (h *MasterHandler) DeleteToken(c *gin.Context) {
master, exists := c.Get("master")

View File

@@ -23,7 +23,7 @@ func NewModelRegistryHandler(reg *service.ModelRegistryService) *ModelRegistryHa
// @Produce json
// @Security AdminAuth
// @Success 200 {object} ResponseEnvelope{data=service.ModelRegistryStatus}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/model-registry/status [get]
func (h *ModelRegistryHandler) GetStatus(c *gin.Context) {
if h == nil || h.reg == nil {
@@ -51,8 +51,8 @@ type refreshModelRegistryRequest struct {
// @Security AdminAuth
// @Param body body refreshModelRegistryRequest false "optional override ref"
// @Success 200 {object} ResponseEnvelope{data=service.ModelRegistryCheckResult}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/model-registry/check [post]
func (h *ModelRegistryHandler) Check(c *gin.Context) {
if h == nil || h.reg == nil {
@@ -78,9 +78,9 @@ func (h *ModelRegistryHandler) Check(c *gin.Context) {
// @Produce json
// @Security AdminAuth
// @Param body body refreshModelRegistryRequest false "optional override ref"
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/model-registry/refresh [post]
func (h *ModelRegistryHandler) Refresh(c *gin.Context) {
if h == nil || h.reg == nil {
@@ -103,8 +103,8 @@ func (h *ModelRegistryHandler) Refresh(c *gin.Context) {
// @Tags admin
// @Produce json
// @Security AdminAuth
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/model-registry/rollback [post]
func (h *ModelRegistryHandler) Rollback(c *gin.Context) {
if h == nil || h.reg == nil {

View File

@@ -23,8 +23,8 @@ type NamespaceRequest struct {
// @Security AdminAuth
// @Param namespace body NamespaceRequest true "Namespace payload"
// @Success 201 {object} ResponseEnvelope{data=model.Namespace}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/namespaces [post]
func (h *Handler) CreateNamespace(c *gin.Context) {
var req NamespaceRequest
@@ -65,7 +65,7 @@ func (h *Handler) CreateNamespace(c *gin.Context) {
// @Param limit query int false "limit (default 50, max 200)"
// @Param search query string false "search by name/description"
// @Success 200 {object} ResponseEnvelope{data=[]model.Namespace}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/namespaces [get]
func (h *Handler) ListNamespaces(c *gin.Context) {
var out []model.Namespace
@@ -88,9 +88,9 @@ func (h *Handler) ListNamespaces(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "Namespace ID"
// @Success 200 {object} ResponseEnvelope{data=model.Namespace}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/namespaces/{id} [get]
func (h *Handler) GetNamespace(c *gin.Context) {
id, ok := parseUintParam(c, "id")
@@ -121,9 +121,9 @@ type UpdateNamespaceRequest struct {
// @Param id path int true "Namespace ID"
// @Param namespace body UpdateNamespaceRequest true "Update payload"
// @Success 200 {object} ResponseEnvelope{data=model.Namespace}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/namespaces/{id} [put]
func (h *Handler) UpdateNamespace(c *gin.Context) {
id, ok := parseUintParam(c, "id")
@@ -185,10 +185,10 @@ func (h *Handler) UpdateNamespace(c *gin.Context) {
// @Produce json
// @Security AdminAuth
// @Param id path int true "Namespace ID"
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/namespaces/{id} [delete]
func (h *Handler) DeleteNamespace(c *gin.Context) {
id, ok := parseUintParam(c, "id")

View File

@@ -49,7 +49,7 @@ func toOperationLogView(l model.OperationLog) OperationLogView {
// @Param limit query int false "limit (default 50, max 200)"
// @Param search query string false "search by actor/method/path"
// @Success 200 {object} ResponseEnvelope{data=[]OperationLogView}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/operation-logs [get]
func (h *AdminHandler) ListOperationLogs(c *gin.Context) {
var rows []model.OperationLog

View File

@@ -20,8 +20,8 @@ import (
// @Security AdminAuth
// @Param group body dto.ProviderGroupDTO true "Provider group payload"
// @Success 201 {object} ResponseEnvelope{data=model.ProviderGroup}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/provider-groups [post]
func (h *Handler) CreateProviderGroup(c *gin.Context) {
var req dto.ProviderGroupDTO
@@ -79,7 +79,7 @@ func (h *Handler) CreateProviderGroup(c *gin.Context) {
// @Param limit query int false "limit (default 50, max 200)"
// @Param search query string false "search by name/type"
// @Success 200 {object} ResponseEnvelope{data=[]model.ProviderGroup}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/provider-groups [get]
func (h *Handler) ListProviderGroups(c *gin.Context) {
var groups []model.ProviderGroup
@@ -102,9 +102,9 @@ func (h *Handler) ListProviderGroups(c *gin.Context) {
// @Security AdminAuth
// @Param id path int true "ProviderGroup ID"
// @Success 200 {object} ResponseEnvelope{data=model.ProviderGroup}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/provider-groups/{id} [get]
func (h *Handler) GetProviderGroup(c *gin.Context) {
id, ok := parseUintParam(c, "id")
@@ -129,9 +129,9 @@ func (h *Handler) GetProviderGroup(c *gin.Context) {
// @Param id path int true "ProviderGroup ID"
// @Param group body dto.ProviderGroupDTO true "Provider group payload"
// @Success 200 {object} ResponseEnvelope{data=model.ProviderGroup}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/provider-groups/{id} [put]
func (h *Handler) UpdateProviderGroup(c *gin.Context) {
idParam := c.Param("id")
@@ -221,10 +221,10 @@ func (h *Handler) UpdateProviderGroup(c *gin.Context) {
// @Produce json
// @Security AdminAuth
// @Param id path int true "ProviderGroup ID"
// @Success 200 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Success 200 {object} ResponseEnvelope{data=MapData}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/provider-groups/{id} [delete]
func (h *Handler) DeleteProviderGroup(c *gin.Context) {
id, ok := parseUintParam(c, "id")

View File

@@ -45,9 +45,9 @@ func toMasterRealtimeView(stats service.MasterRealtimeSnapshot) *MasterRealtimeV
// @Security AdminAuth
// @Param id path int true "Master ID"
// @Success 200 {object} ResponseEnvelope{data=MasterRealtimeView}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 404 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 404 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/masters/{id}/realtime [get]
func (h *AdminHandler) GetMasterRealtime(c *gin.Context) {
idRaw := strings.TrimSpace(c.Param("id"))
@@ -88,8 +88,8 @@ func (h *AdminHandler) GetMasterRealtime(c *gin.Context) {
// @Produce json
// @Security MasterAuth
// @Success 200 {object} ResponseEnvelope{data=MasterRealtimeView}
// @Failure 401 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 401 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /v1/realtime [get]
func (h *MasterHandler) GetSelfRealtime(c *gin.Context) {
master, exists := c.Get("master")
@@ -136,7 +136,7 @@ type MasterRealtimeSummaryView struct {
// @Produce json
// @Security AdminAuth
// @Success 200 {object} ResponseEnvelope{data=SystemRealtimeView}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/realtime [get]
func (h *AdminHandler) GetAdminRealtime(c *gin.Context) {
if h.statsService == nil {

View File

@@ -14,3 +14,6 @@ type ResponseEnvelope struct {
TraceID string `json:"trace_id" example:"a1b2c3d4e5f6g7h8"`
Details any `json:"details,omitempty" swaggertype:"object"`
}
// MapData represents a generic JSON object for documentation purposes.
type MapData map[string]any

View File

@@ -42,9 +42,9 @@ type MasterUsageStatsResponse struct {
// @Param since query int false "unix seconds"
// @Param until query int false "unix seconds"
// @Success 200 {object} ResponseEnvelope{data=MasterUsageStatsResponse}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 401 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 401 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /v1/stats [get]
func (h *MasterHandler) GetSelfStats(c *gin.Context) {
master, exists := c.Get("master")
@@ -148,8 +148,8 @@ type AdminUsageStatsResponse struct {
// @Param since query int false "unix seconds"
// @Param until query int false "unix seconds"
// @Success 200 {object} ResponseEnvelope{data=AdminUsageStatsResponse}
// @Failure 400 {object} ResponseEnvelope{data=gin.H}
// @Failure 500 {object} ResponseEnvelope{data=gin.H}
// @Failure 400 {object} ResponseEnvelope{data=MapData}
// @Failure 500 {object} ResponseEnvelope{data=MapData}
// @Router /admin/stats [get]
func (h *AdminHandler) GetAdminStats(c *gin.Context) {
rng, err := parseStatsRange(c)