feat: ship loose-offline dbsync (validate, agent push, LWW audit)
Add UUID/FK channel checks, agent whitelist/push APIs, bindings, super-admin LWW audit with rollback, reconcile rate limits, and sync docs. Default customers stay opt-in; company conflict UI is removed. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
68
platform/internal/handler/platform_dbsync.go
Normal file
68
platform/internal/handler/platform_dbsync.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"aijianzhan/platform/internal/authx"
|
||||
"aijianzhan/platform/internal/dbsync"
|
||||
"aijianzhan/platform/internal/svc"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||
)
|
||||
|
||||
// GET /api/v1/platform/dbsync/lww-overrides — 仅平台超级管理员。
|
||||
func platformLwwOverridesHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if svcCtx.DBSync == nil {
|
||||
authx.WriteError(w, http.StatusServiceUnavailable, "dbsync not enabled")
|
||||
return
|
||||
}
|
||||
q := r.URL.Query()
|
||||
var tenantID int64
|
||||
if s := q.Get("tenant_id"); s != "" {
|
||||
tenantID, _ = strconv.ParseInt(s, 10, 64)
|
||||
}
|
||||
channelID := q.Get("channel_id")
|
||||
limit := 200
|
||||
if s := q.Get("limit"); s != "" {
|
||||
if n, err := strconv.Atoi(s); err == nil && n > 0 {
|
||||
limit = n
|
||||
if limit > 1000 {
|
||||
limit = 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
list, err := svcCtx.DBSync.Store().ListLwwOverrides(tenantID, channelID, limit)
|
||||
if err != nil {
|
||||
authx.WriteError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
httpx.OkJson(w, map[string]any{
|
||||
"items": list,
|
||||
"hint": "LWW 自动覆盖审计;公司管理员不可见;默认 TTL 90 天;可对 applied_source 回滚单行",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// POST /api/v1/platform/dbsync/lww-overrides/:id/rollback — 按落败快照回滚线上单行。
|
||||
func platformLwwRollbackHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if svcCtx.DBSync == nil {
|
||||
authx.WriteError(w, http.StatusServiceUnavailable, "dbsync not enabled")
|
||||
return
|
||||
}
|
||||
id := pathvar.Vars(r)["id"]
|
||||
rec, err := dbsync.RollbackLwwOverride(r.Context(), svcCtx.DBSync.Store(), id)
|
||||
if err != nil {
|
||||
authx.WriteError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
httpx.OkJson(w, map[string]any{
|
||||
"ok": true,
|
||||
"record": rec,
|
||||
"hint": "已按落败快照写回线上 A,并追加一条 rollback 审计",
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user