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:
whm
2026-07-31 17:54:14 +08:00
parent 632057c857
commit 76cdcd760e
39 changed files with 3302 additions and 199 deletions

View 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 审计",
})
}
}