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>
4.3 KiB
4.3 KiB
跨库数据同步中间件
支持 SQLite ↔ MySQL ↔ Postgres。平台侧 worker 可轮询两端 outbox;形态 B(本机 agent) 下由终端 agent 经平台 push 写线上 A,平台不直连用户本机 SQLite。
冲突策略默认 自动 LWW(源端覆盖);落败写入平台超级管理员覆盖日志。公司管理员无冲突台。
权限与隔离
| 项 | 说明 |
|---|---|
| 谁可配通道 | 公司顶级权限(管理员),「数据同步」 |
| Agent push / 拉白名单 | JWT 含「数据同步」(人类管理员或智能体凭证) |
| LWW 覆盖审计 | 仅平台超级管理员;公司 top → 403 |
| 数据隔离 | 通道带 tenant_id;公司 A 看不到公司 B |
推荐场景(松离线 B→A)
| 端 | 角色 |
|---|---|
| B | 本机正式库(UUID 主键);开通且白名单表本地可见 |
| A | 线上库;agent 经平台 push 幂等写入 |
| Agent | 读本机 outbox → POST /api/v1/agent/sync/channels/:id/push |
推荐配置:
- 通道:
local描述本机表名单,remote= A 的 DSN;方向local_to_remote;策略lww_source。 - 表白名单须 UUID TEXT PK + FK 闭包(保存时校验)。
- 客户端显式
local_dbsync(见开通说明);未开通用户零感。 - 怀疑漏数时点 同步修复(对账)(有最小间隔限流);双向通道自动对账约 15 分钟 一次。
如何保证不漏、不多:
| 手段 | 防什么 |
|---|---|
| 触发器 / 本机 outbox → agent push | 漏 |
WithApplying / 远端应用不回写 outbox |
多(回声) |
| 目标 meta 同 version 跳过 | 多(重复投递) |
| LWW + 超管覆盖日志 | 并发同 PK |
| 主键对账 reconcile | 漏(存量差) |
能力一览
| 项 | 说明 |
|---|---|
| 方言 | sqlite / mysql / postgres |
| 方向 | 本地→线上(推荐)/ 线上→本地 / 双向 |
| 冲突 | 默认 lww_source;lww_target;queue 仅调试(租户不可见) |
| Agent | GET .../agent/sync/.../whitelist;POST .../push |
| Binding | GET/POST /api/v1/admin/sync/bindings |
| 对账 | POST .../reconcile(默认最少间隔 300s) |
| 审计 | GET /api/v1/platform/dbsync/lww-overrides(超管) |
持久化:data/dbsync/channels.json、lww_overrides.json(及遗留 conflicts.json)。
控制台用法
- 数据同步 → 新建通道(UUID 表白名单)→ 测试 → 保存 → 启动
- 默认策略选 源端覆盖;方向首期用 本地 → 线上
- 点 同步修复 做主键对账(勿连续狂点,有限流)
- LWW 明细在 平台工作台(超管),不在公司同步页
开通与迁移:见 数据同步-开通说明.md、数据同步-迁移手册.md。
API
公司管理员(「数据同步」)
| 方法 | 路径 |
|---|---|
| GET/POST | /api/v1/admin/sync/channels |
| GET/PUT/DELETE | /api/v1/admin/sync/channels/{id} |
| POST | /api/v1/admin/sync/test |
| POST | /api/v1/admin/sync/channels/{id}/prepare|start|stop |
| POST | /api/v1/admin/sync/channels/{id}/reconcile |
| POST | /api/v1/admin/sync/channels/{id}/ingest(写通道 local,偏形态 A) |
| GET/POST | /api/v1/admin/sync/bindings |
| GET/POST | /api/v1/admin/sync/conflicts* → 403(已迁超管审计) |
本机 Agent
| 方法 | 路径 |
|---|---|
| GET | /api/v1/agent/sync/channels/{id}/whitelist |
| POST | /api/v1/agent/sync/channels/{id}/push |
| POST | /api/v1/agent/sync/channels/{id}/push/batch |
平台超级管理员
| 方法 | 路径 |
|---|---|
| GET | /api/v1/platform/dbsync/lww-overrides |
| POST | /api/v1/platform/dbsync/lww-overrides/{id}/rollback |
push 示例
POST /api/v1/agent/sync/channels/{id}/push
{
"table": "orders",
"op": "insert",
"row_pk": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"row": { "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "title": "x" },
"version": 1710000000000000000,
"client_outbox_id": "..."
}