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>
30 KiB
方案稿:松离线 + 接法①(dbsync)
状态:已冻结 → 请以
松离线-dbsync方案-最终版.md为准开工
本文保留为过程稿(正文草稿 + 双方审评 + 协商记录),口径以最终版为准。
日期:2026-07-31
配套:智建修改意见.md、docs/数据同步-中间件.md、宇恒db_write_gateway.py
1. 一句话
离线在本地正式库按最终 UUID 落库;联网靠 dbsync 通道把本地 B 与线上 A 同主键幂等对齐。
不做 HTTP 双写主路径;不做「两端自增再对账」。
2. 角色与库
| 端 | 角色 | 说明 |
|---|---|---|
| A | 智建线上主库 | Postgres(租户/应用库) |
| B | 宇恒本机正式库 | SQLite permanent(按用户绑定的 local_database_id) |
| 绑定 | (tenant_id, user_id, local_database_id) → online_db_id |
宇恒本地登记;智建侧可查询/登记同一映射,通道 remote 指向对应 A |
通道(管理员配置,或安装时模板下发):
local = B(sqlite,该用户库文件)
remote = A(该 online_db_id / 租户库 DSN)
方向 = bidirectional(或先 B→A,稳定后再双向)
冲突 = LWW(自动)+ 超级管理员可查覆盖日志;非用户 queue
表白名单 = 仅 UUID 主键业务表
业务写 ──► B(本地正式库,带 UUID)
│
├─ 触发器 → _ajz_sync_outbox → worker → A(同 PK upsert)
│
└─ A 上变更 ←── outbox 拉回 ── B(双向时)
对账兜底:reconcile(主键集合差)+ conflicts 队列
3. 松离线语义(写路径)
| 场景 | 行为 |
|---|---|
| 离线写 | 客户端生成 UUID → 直接写 B 正式表 → 成功即对用户可见;同时可标 sync_status=pending(可选列) |
| 联网写 | 同样写 B(带 UUID);触发器进 outbox,近实时推 A |
| 不做 | 离线只写 pending、正式表空着(那是紧离线,本方案不用) |
| 不做 | 业务主路径先 HTTP 打智建 permanent 再 mirror(接法②,本方案不用) |
Insert 约定:
- 请求/落库行必须带
id(UUID),客户端生成。 - 禁止依赖
INTEGER AUTOINCREMENT当同步键。 - 重复提交同一
id→ upsert / 忽略,不多行。
4. 表结构约定(A/B 同步表白名单)
| 项 | 要求 |
|---|---|
| 主键 | id TEXT(UUID 字符串) |
| 建议列 | updated_at、version(配合 LWW / 版本跳过) |
| 可选列 | sync_status(synced / pending / conflict)仅 UI,同步仍靠 outbox |
| 存量自增表 | 不进白名单,或先迁移 UUID 再进 |
通道 pk_columns |
默认 id;复合主键显式配置 |
5. 两端职责
宇恒客户端
| 项 | 做什么 |
|---|---|
| UUID | insert 前生成并写入;update/delete 带同一 id |
| 写路径 | 改 apply_write:始终先写本地 B(松);去掉「离线只 pending 不落库」 |
| 联网 | 不依赖 HTTP 双写;确保本机 B 上 dbsync 触发器/ agent 可用,或由智建侧连 B 的方式落地(见下「通道落地形态」) |
| 绑定 | 保留 BindingStore;启动时向智建登记/校验 online_db_id |
| UI | 可显示「待同步」;不展示冲突处理;以本地正式数据为离线真相 |
智建平台
| 项 | 做什么 |
|---|---|
| dbsync | 通道、outbox、ingest、reconcile、conflicts — 复用现有 |
| 表规范 | 控制台/文档写死:同步表必须 UUID 主键 |
| 绑定 API | 提供「登记/查询 online_db_id ↔ 租户库」供宇恒对齐(P1) |
| 对账入口 | 管理员 sync API 已有;可选网关代调给终端用户「一键对账」(P1) |
| 线上业务写 | 控制台/网页改 A 时同样走带 UUID 的写;触发器推回 B |
6. 通道落地形态:已选定 B(本机 sync agent)
dbsync worker 默认跑在智建 platform 上时,往往连不到用户电脑上的 SQLite B。选定:
形态 B(已定)
用户电脑:业务写 B → 本机 sync agent(触发器 / outbox)→ 推到线上 A
← 拉取 A 变更回 B(双向时)
智建平台:提供线上 A、鉴权、对账/冲突 API、通道元数据;不直连用户 SQLite
| 项 | 约定 |
|---|---|
| agent 位置 | 宇恒本机(独立进程或嵌入客户端) |
| 推送目标 | 智建线上库 A(按 online_db_id / 租户库) |
| 平台职责 | A 侧接收(兼容现有 ingest/应用逻辑)、conflicts、reconcile 入口 |
| 为何不选 A | 用户电脑公网不可达,平台无法直连 B |
| 为何不选 C | C 仅作过渡;主路径要近实时 outbox,用 B |
曾对比(归档)
| 形态 | 说明 | 结论 |
|---|---|---|
| A. 智建连远程 B | 平台 DSN 直连用户库 | 否(公网不可达) |
| B. 本机 sync agent | 本机推/拉 A | 采用 |
| C. 批量 ingest 过渡 | 联网后打包推 | 仅应急,非主路径 |
7. 与当前实现的差异(改造清单)
| 现状 | 本方案目标 |
|---|---|
宇恒 online_primary:离线 pending、不写正式库 |
离线 写正式库(UUID) |
| 宇恒联网:HTTP 先写线上再 mirror | 联网 写本地 B,由 dbsync 推 A |
| 智建 dbsync 偏管理员控制台 | 增加绑定对齐 +(可选)用户侧对账入口 |
| 业务表可能自增主键 | 同步表白名单强制 UUID |
建议改造顺序:
- 规范:同步表 UUID + 建表模板(智建 + 宇恒)
- 宇恒写路径:松离线落 B + 强制
id - 本机 agent:按形态 B 打通一条演示通道(本机 outbox → A)
- 绑定 API:online_db_id 可查可登记
- 对账 + LWW 覆盖日志:reconcile 沿用;LWW 落败快照仅超级管理员可查
- 下线接法②主路径(HTTP 双写仅作运维/兼容开关)
8. 数据流示例
离线插入
用户点保存
→ 客户端 uuid = U1
→ INSERT INTO B.orders (id=U1, ...) ✅ 本地立刻可见
→ outbox 暂存本地(触发器);无法推 A
联网后
→ worker/agent 投递 A:upsert id=U1
→ A、B 同主键;sync_status=synced(若有)
联网插入
→ 写 B (id=U2) → outbox → 秒级 upsert A
冲突
离线改 U1;同时线上也改 U1
→ LWW 自动留一版,另一版写入「自动覆盖日志」(含两边 payload)
→ 终端用户无感;仅平台超级管理员可查/导出(可选回滚)
→ 禁止换新主键重试
漏数兜底
POST reconcile → 按主键集合补缺 → 不多发号
9. 验收标准
- 离线插入(客户端 UUID)→ 本地立刻有行;联网后 A 与 B 同一
id,无第二行。 - 同一 UUID 重复写 / 重放 outbox → 幂等。
- 断网窗口结束 + 对账后,白名单表主键集合无持续缺口。
- 同 PK 并发 → LWW 自动覆盖,不改主键;落败方在超级管理员覆盖日志中可查。
- 自增旧表未进白名单,误配会被拒绝或文档明确排除。
- 关闭 HTTP 双写主开关后,业务仍仅靠 B + dbsync 对齐。
10. 明确不做
- 紧离线(只 pending、正式表不落)作为本方案主路径。
- 接法② HTTP 双写作为主同步。
- 两端自增 + 事后映射。
- 回放/投递失败时换新 UUID 重试。
11. 评审结论
| 项 | 结论 |
|---|---|
| 离线模型 | 松离线(本地正式库落 UUID) |
| 同步接法 | ① dbsync |
| 通道形态 | B 本机 sync agent |
| 冲突默认 | LWW(自动裁决,终端用户零操作);建议按 updated_at/version,单客户端场景可偏本机(lww_source) |
| 覆盖可追溯 | LWW 仍自动覆盖,但必须写「自动覆盖日志」(见下) |
| 谁可查日志 | 仅平台超级管理员(非公司 top / 租户管理员) |
| 兼容开关 | 过渡期保留 online_primary(HTTP 双写),灰度后再切默认 |
自动覆盖日志(相对现网 dbsync 的补强)
现网纯 LWW 不会把落败方写入 conflicts.json。本方案要求:
| 项 | 约定 |
|---|---|
| 何时写 | 每次因版本较旧而跳过(lww_target)或因 LWW 覆盖目标旧行(lww_source) |
| 记什么 | tenant_id、通道、表、row_pk、源/目标 version、两边 payload 快照、胜出策略、时间 |
| 存储 | 独立审计(如 data/dbsync/lww_audit.json 或平台审计表),不要当成用户待办冲突队列 |
| 终端用户 | 无入口、无提示、不阻断同步 |
| 公司 top | 不可见(与现「数据同步」控制台租户管理员权限分离) |
| 平台超级管理员 | 可查、可导出;可选「按快照回滚某一行」(P2) |
权限口径:
公司 top(租户管理员)→ 配自己公司的通道 / 对账(沿用现权限)
平台超级管理员 → 看全局 LWW 自动覆盖日志 / 应急回滚
终端用户 → 不参与冲突处理
12. 一句话验收口径
松离线写 B(最终 UUID)+ 本机 agent 走 dbsync;冲突自动 LWW;落败方进超级管理员可查的覆盖日志;主键不漂。
宇恒追加-审评意见
说明:本节是宇恒侧对上文方案的外部审评意见,不是方案正文的修订稿。采纳与否单独决议;未并入 §1–§12。
硬约束(宇恒侧):这边的修改不得影响原有用户操作与现网写库逻辑——默认行为保持现状;新能力仅 opt-in / 白名单生效。
A. 总评
方案主线(松离线写 B + UUID + 本机 agent + dbsync + LWW)与「离线可用且联网后主键不漂」目标匹配,可立。
但在宇恒落地时必须遵守:
| 原则 | 含义 |
|---|---|
| 默认不变 | 未开新模式时,等同现网:local_only 或现有 online_primary 行为与契约不变 |
| 显式开启 | 仅 YXD_SYNC_MODE=local_dbsync(名可再定)+ 同步表白名单 时走松离线/dbsync |
| 白名单隔离 | 未进白名单的表:仍可自增、仍走原 insert;禁止因全库切 UUID/强制 id 拖垮旧插件 |
| 双路径互斥 | 同一库/表不得同时 HTTP 双写与 local_dbsync,避免双写放大 |
| 可回滚 | 关开关即回到原行为,无需迁数据才能用旧功能 |
因此:正文目标可做,但宇恒改造必须是「旁路增量」,不是改默认写路径。
B. 同意保留的决策(在不影响原有的前提下)
| 项 | 意见 |
|---|---|
| 不做接法②作新主路径 | 同意;现网 online_primary 可作兼容保留,默认可不切走 |
| 形态 B 本机 agent | 同意;仅对已开通同步的用户/库启用 |
| 终端零冲突 UI | 同意;且未开通同步的用户完全无感(无新状态条、无强制 agent) |
| 过渡期保留 HTTP 开关 | 同意;默认勿切 local_dbsync |
C. 建议补强(保证「不影响原有」)
-
模式三分,默认旧行为
local_only:只写本地(现网兼容默认之一)online_primary:现网 HTTP 双写(已上线客户可继续)local_dbsync:新松离线 + agent(仅显式配置)
未配置 / 未识别 → 不得自动升到local_dbsync。
-
强制 UUID / 必带
id仅白名单表
网关:白名单表缺id可补 UUID 或 400;非白名单表保持原样(允许自增、允许不传 id)。
禁止「全局 create_table 改成 UUID」一刀切——可新增「同步表模板」,旧模板不动。 -
apply_write分支,不改旧分支语义local_only/online_primary:代码路径与响应字段兼容现网(可多字段,不可少成功语义)local_dbsync:才「始终写 B、不依赖离线 pending 空正式表」
旧调用方继续认success;勿要求全员改认pending。
-
agent 可选装
未装 agent / 未开通同步:业务写库与现网一致;禁止写前强依赖 agent 心跳导致保存失败。
「仅本机 / 待同步 / 已同步」仅对白名单且已开通同步的会话展示。 -
外键 / 闭包
仅约束「要进同步白名单」的表集;未同步的旧关联表不强制改造。 -
删改幂等、安全、对账
仍建议做,但范围限local_dbsync+ 白名单;不影响未开通路径。 -
建表模板
双端「同步表模板」新增;默认建表模板保持自增,避免新用户无感被切 UUID。 -
联网 reconcile
仅同步用户;设置页入口可选;默认不弹、不阻断。
D. 对现有用户操作逻辑的影响(按约束重述)
| 对象 | 要求结果 |
|---|---|
未开 local_dbsync 的用户 |
零影响:保存/查询/自增表/插件与现网一致 |
| 未进白名单的表 | 零影响:不强制 UUID、不强制 agent |
| 已开同步的白名单表 | 预期内变更:离线立刻落 B、带 UUID、可显示待同步 |
| 聊天 / 选站 / 税务等非 permanent 同步写路径 | 零影响 |
若某改造会导致「未开同步也改变保存结果」→ 不予合入,改回 opt-in。
E. 建议验收追加项(含「不影响原有」)
- 默认配置下:跑现网回归(insert 不传 id 的自增表、offline pending 若仍开
online_primary)与改前一致。 - 仅打开
local_dbsync+ 白名单后:松离线 UUID 验收(§9)通过。 - agent 停运:未开通用户保存仍成功;开通用户本地可写且待同步,恢复后主键不双行。
- 网页与客户端双入口:仅同步表;LWW 符合偏向;超管日志可查。
- 非白名单表加入通道:拒绝或警告。
local_dbsync与online_primary互斥;关local_dbsync后行为回到原模式。
F. 不建议纳入本方案(避免范围膨胀与误伤)
- 用对账替换 UUID 主键策略。
- 终端用户冲突工作台。
- 平台直连用户 SQLite(形态 A)。
- 默认全局改主键 / 默认切
local_dbsync/ 强制全员装 agent。
G. 一句话评审口径
方案可立,但宇恒必须旁路增量:默认不影响原有;仅白名单 + 显式 local_dbsync 走松离线。先灰度开通,再谈切默认。
智建追加-审评意见
说明:本节是智建/方案侧对正文及「宇恒追加-审评意见」的复核意见,不是方案正文修订稿。与宇恒追加并列,采纳单独决议。
A. 总评
同意宇恒总评:主线可立,必须白名单灰度,不可默认切全库。
智建侧补充:现网 dbsync(outbox / ingest / reconcile / LWW)够用当引擎;缺口在 本机 agent 协议面、LWW 覆盖审计(超管)、绑定 API,不是再造同步中间件。
与宇恒追加 无方向冲突;下文对 C 条逐项表态,便于开工排序。
B. 同意保留 / 同意宇恒已同意项
| 项 | 意见 |
|---|---|
| 松离线 + ① + 形态 B + LWW + 超管覆盖日志 | 维持正文定案 |
| 不做接法②主路径 / 不做形态 A / 终端零冲突 UI | 同意(与宇恒 B 节一致) |
过渡期保留 online_primary |
同意;切默认前须互斥,禁止双路径同时写 |
| 白名单灰度 | 同意并升为 P0 开工前提 |
C. 对「宇恒追加 · C 建议补强」的表态
| # | 宇恒建议 | 智建意见 | 建议处置 |
|---|---|---|---|
| 1 | 外键 / 同步闭包 | 同意 | 写入规范:白名单按闭包进;跨名单外键配置期拒绝 |
| 2 | agent 未就绪与「立刻可见」 | 同意 | UI 三态(仅本机/待同步/已同步)+ 写前/写后可探测 agent 心跳;属宇恒 P0 |
| 3 | 双入口吞改 | 同意偏保守 | 双入口表:先 B→A,稳定后再双向;LWW 默认可偏本机,但双入口表在超管日志外可加「弱提示已自动合并」(仍不选边) |
| 4 | delete / 重放顺序 | 同意 | 正文补:墓碑或 outbox delete;agent 按 outbox id 保序;禁止失败换新 UUID |
| 5 | YXD_SYNC_MODE=local_dbsync |
同意 | 三分:local_only / online_primary / local_dbsync;文档与发版说明同步 |
| 6 | 双端建表模板 | 同意,P0 | 智建 create + 宇恒 create 同时改;入通道校验非 TEXT UUID PK → 拒绝 |
| 7 | agent 凭证与 outbox 敏感列 | 同意 | 正文加安全节:最小权限、按 online_db_id 隔离、可吊销;outbox 敏感列加密或脱敏 at rest |
| 8 | 联网自动 reconcile | 同意 | 限流自动对账 + 设置页「同步修复」;不暴露 conflicts 给终端;公司 top 仍可走现控制台 |
D. 智建侧另补(宇恒未写或平台专属)
-
LWW 审计权限
维持:仅平台超级管理员;与公司 top「数据同步」菜单分离。实现上独立 API/页,勿挂在租户 sync 控制台下以免误授权。 -
A 侧接收面
agent 推送优先复用/扩展现有 ingest(或等价 upsert 接口),保证 认客户端 UUID、幂等;避免再开一套与 dbsync 语义不一致的 HTTP 写。 -
时钟与 version
LWW 依赖updated_at/version:约定客户端单调时钟或服务端授时规则,防止对时错误导致「旧盖新」。建议 version 用 outbox 单调序号为主、时间戳为辅。 -
超管日志保留策略
覆盖日志需 TTL/容量上限(如 90 天或按租户配额),避免无限涨;导出权限同超管。
E. 对现有用户操作逻辑的影响(复核)
| 对象 | 影响程度 | 说明 |
|---|---|---|
| 终端(白名单表) | 中高 | 同意宇恒:契约带 UUID + 可见性语义变化;用白名单限面 |
| 终端冲突 | 降低 | 同意;无选边 |
| 自增插件/脚本 | 高(仅误入白名单时) | 配置期拒绝可把风险压到「零误配」 |
| 「保存后线上立刻读到」 | 中 | 同意改为异步;需延迟可观测(agent 状态) |
| 公司 top | 低~中 | 多「闭包校验 / 单向先」配置纪律;仍无 LWW 审计 |
| 平台超管 | 新增 | 覆盖日志查询/导出;(P2)按快照回滚 |
结论:同意宇恒「冲击面用白名单隔离」;智建把住 入通道校验 + 超管审计隔离 + ingest 幂等 三条,终端无感冲突可成立。
F. 建议验收追加项(相对 §9 与宇恒 E)
- 采纳宇恒 E 全部四条(agent 停运、双入口 LWW、非白名单拒绝、模式互斥)。
- 超管可按
tenant_id/ 表 /row_pk检索覆盖日志,且公司 top Token 403。 - 白名单闭包:只配父表不配子表时,保存通道失败并给出明确错误。
local_dbsync下业务写不调用 permanent HTTP 双写主路径(开关关闭时无双写流量)。
G. 不建议纳入本方案
- 同意宇恒 F:不对账替代 UUID、不做终端冲突台、不做形态 A。
- 另:不做字段级自动合并(CRDT) 作本期范围;需要时另立专项。
- 不把 LWW 审计对租户管理员开放(即使只读),避免与「超管」口径混淆。
H. 一句话评审口径
同意宇恒「可立、先白名单再切默认」;正文方向不改。开工顺序建议:双端 UUID 模板与入通道校验 → local_dbsync 松离线写 B → agent 最小推送 + 超管 LWW 日志 → 再灰度关 HTTP 双写。
协商决议版(双方意见合成 · 以此为准开工)
效力:本节覆盖正文中与「默认切全站 / 写前强依赖 agent」相冲突的表述;技术主线(松离线、①、形态 B、LWW、超管日志)不变。
总原则(采纳宇恒硬约束):未显式开通前,宇恒现网操作与写库逻辑零影响;新能力仅local_dbsync+ 白名单 opt-in。
1. 定案一览
| 维度 | 决议 |
|---|---|
| 同步模型 | 松离线写 B(最终 UUID)+ 接法① dbsync |
| 通道形态 | B 本机 sync agent(平台不直连用户 SQLite) |
| 冲突 | 自动 LWW(用户零操作) |
| 落败方可追溯 | 自动覆盖日志,仅平台超级管理员可查(公司 top 不可见) |
| 宇恒默认模式 | 保持现网:local_only 或已在用的 online_primary,不自动升 local_dbsync |
| 新模式 | 显式 YXD_SYNC_MODE=local_dbsync + 表级白名单 才生效 |
| 双路径 | local_dbsync 与 online_primary 互斥(同库不同时开) |
| 建表 | 默认模板仍自增;另增「同步表模板」= UUID TEXT PK;入通道校验非 UUID → 拒绝 |
| 同步方向(首期) | 白名单表 先 B→A;双入口稳定后再开 bidirectional |
| 范围外 | 不做形态 A、不做终端冲突台、不做 CRDT 字段合并、不对账替代 UUID |
2. 比原文「更好」的关键修正
原文偏「目标态替换默认写路径」;协商后改为 旁路增量,避免伤宇恒存量:
| 原文风险 | 决议后 |
|---|---|
| 全库强制 UUID / 改默认 create | 仅同步模板 + 白名单;旧表旧模板不动 |
| 松离线成为默认写语义 | 仅 local_dbsync 分支;旧分支语义冻结 |
| 写前强依赖 agent 心跳(智建初评 C2) | 作废:agent 停也不得导致保存失败;仅开通用户显示「待同步」 |
| 双向一上来 | 首期单向 B→A,降低网页↔客户端互盖 |
| LWW 无痕 | 超管覆盖日志(两边 payload + 胜出策略 + TTL) |
3. 模式与写路径(宇恒)
local_only → 只写本地(现网)
online_primary → HTTP 双写 / 离线 pending(现网已落地,兼容保留)
local_dbsync → 白名单表:始终写 B(松)+ outbox;非白名单:仍走该模式下的「本地普通写」且不进同步
未配置 → 不得视为 local_dbsync
网关规则:
- 非白名单:不强制
id、允许自增;与现网一致。 - 白名单 + local_dbsync:无
id则客户端补 UUID(或 400);写 B 成功即返回成功;agent 仅异步。 - 关
local_dbsync→ 行为回到原模式(可回滚)。
4. 智建平台职责(收窄可交付)
| P0 | 内容 |
|---|---|
| 入通道校验 | UUID TEXT PK + 白名单闭包(父子表一起或拒绝) |
| ingest/应用面 | 认客户端 UUID,幂等 upsert;供本机 agent 推送 |
| LWW 超管审计 | 独立存储与 API;公司 top 403;TTL(建议 90 天) |
| version | outbox 单调序号为主,时间戳为辅 |
| P1 | 内容 |
|---|---|
| 绑定 API | online_db_id 登记/查询,与宇恒 BindingStore 对齐 |
| 联网限流 reconcile | 仅开通同步的库;设置页「同步修复」可选 |
| 单向→双向 | 按表白名单开关,默认仍 B→A |
| P2 | 内容 |
|---|---|
| 超管按快照回滚单行 | |
| 弱提示「已自动合并」 | 仅开通同步客户端,仍不选边 |
5. 本机 agent(形态 B)最小集
- 嵌入或独立进程;未开通同步可不装。
- 读本地
_ajz_sync_outbox(或等价),按 id 保序推 A;支持 delete。 - 凭证:最小权限、按
online_db_id隔离、可吊销;outbox 敏感列脱敏/加密。 - 心跳仅用于 UI 状态,不阻断
apply_write。
6. 分期(建议排期)
| 阶段 | 目标 | 退出标准 |
|---|---|---|
| M0 | 规范:同步表模板、入通道校验、模式三分文档 | 误配自增表无法进通道 |
| M1 | 宇恒:local_dbsync 旁路 + 白名单松离线写 B(仍可无 agent,只落本地) |
未开通用户回归 = 现网;开通用户离线可见 |
| M2 | agent 最小推送 B→A + ingest 幂等 | 联网后同 UUID 上云、不双行 |
| M3 | 超管 LWW 覆盖日志 + 限流 reconcile | 双入口覆盖可查;公司 top 不可见日志 |
| M4 | 灰度扩大白名单;评估是否对新客默认 local_dbsync |
旧客默认仍不变,除非显式迁移 |
明确:M4 之前不谈「全员切默认」。
7. 统一验收(合并 §9 + 双方 E)
不影响原有
- 默认 / 未开
local_dbsync:现网回归通过(含自增不传 id、原online_primary行为)。 - 非白名单表:不强制 UUID;加入通道被拒绝。
- 关
local_dbsync后行为回到原模式。 - 未开通用户:无强制 agent、无新冲突 UI、保存不因同步失败。
开通后(白名单)
- 离线写 B 立刻可见;联网同 UUID 上 A,幂等不双行。
- agent 停:本地仍可保存 +「待同步」;恢复后追上。
- 双入口同 PK:LWW 符合首期策略(偏本机或按 version);落败在超管日志。
- 公司 top 查覆盖日志 → 403;超管可检索/导出。
- 与
online_primary互斥,无双路径同时写。
8. 协商一句话
技术上走松离线 + 本机 agent + dbsync + LWW(超管可追溯);产品上必须旁路 opt-in——默认不影响宇恒原有操作,白名单灰度达标前不切默认。
宇恒追加-继续协商(第二轮)
说明:在「协商决议版」之上的第二轮协商意见,不改写 §1–§12 与决议正文;请智建对「待拍板」表态后可并入决议修订。
立场:决议版 总原则 + §1/§2/§6/§7「不影响原有」 已对齐宇恒硬约束 → 宇恒原则上接受决议版开工。下列为收口与防回潮。
1. 宇恒对决议版的表态
| 决议要点 | 宇恒态度 |
|---|---|
默认不升 local_dbsync;旁路 opt-in |
接受(硬条件,不可回退) |
| 默认建表仍自增;同步模板另增 | 接受 |
| 写前不因 agent 停而保存失败 | 接受(硬条件);请同步作废智建初评 C2「写前强依赖心跳」表述 |
| 首期 B→A;M4 前不谈全员默认 | 接受 |
| 分期 M0→M4 | 接受;建议 M1 退出标准增加「未开通用户自动化回归套件」 |
| 超管 LWW 日志 / 公司 top 403 | 接受(宇恒侧无异议) |
一句话:可以按决议版排期;宇恒侧合入准则仍是——未开通用户 diff 行为 = 0。
2. 请智建确认(防与初评打架)
| # | 议题 | 宇恒主张 | 需要智建回复 |
|---|---|---|---|
| R1 | agent 与保存 | 心跳只驱动 UI,永不 apply_write 失败 |
书面确认作废「写前探测失败则拒绝保存」 |
| R2 | 双端建表 | 「同时改」= 只加同步模板,默认模板不动 | 确认智建控制台默认建表仍自增 |
| R3 | 关 HTTP 双写 | M4 只评估新客或显式迁移客;旧 online_primary 客户保留 |
确认不会「灰度达标后一刀切关双写」 |
| R4 | 弱提示「已自动合并」 | 仅 local_dbsync 开通用户;默认关闭,配置打开 |
避免未开通用户弹任何同步文案 |
3. 仍待拍板(建议写进决议修订)
| # | 缺口 | 建议默认(宇恒提案) | 理由 |
|---|---|---|---|
| O1 | 白名单存在哪 | 智建通道配置为源;宇恒本地缓存副本;以通道为准 | 防两端名单漂移;未拉到名单前当未开通 |
| O2 | 谁有权改白名单 | 公司 top(现「数据同步」);终端用户只读 | 与现权限一致;避免用户误加自增表 |
| O3 | M1 无 agent 时「开通同步」含义 | 允许:仅本地松离线 + 待同步积压;产品文案写「需 agent 才上云」 | 方便分期,但不承诺已上云 |
| O4 | Binding API 是否挡 M2 | 不挡:M2 可用现网派生 online_db_id;P1 再对齐登记 |
降低串行依赖 |
| O5 | version 授时 | 优先 outbox 单调 id;客户端 updated_at 仅辅助;不对时不挡保存 |
落实「不影响保存」 |
| O6 | 同库表级互斥 | 决议写「同库互斥」偏严;提案改为:同表不可双路径;同库可「部分表 local_dbsync、其余保持原模式写本地」 | 更贴白名单灰度,少逼整库切模式 |
| O7 | 存量 online_primary 迁 local_dbsync |
另附迁移手册:先加白名单→装 agent→双跑观察→关 HTTP;禁止静默迁移 | 保护已上线双写客户 |
4. 宇恒侧本期承诺(换智建确认 R1–R4)
- M0/M1:模式三分 + 白名单判断进
apply_write,旧分支零行为 diff(附回归清单)。 - 不把 agent 做成安装强依赖。
- 同步 UI 与开关仅在开通后出现。
- M2 起才对接 ingest;协议以智建文档为准,客户端不自造第二套写语义。
5. 建议智建本期承诺
- 入通道 UUID + 闭包校验(M0)。
- ingest 幂等认客户端 UUID(M2 前就绪)。
- 超管审计 API 与租户控制台分离(M3)。
- 发版说明写明:默认客户无感;
local_dbsync为增值开通。
6. 第二轮协商一句话
决议版方向已收束;宇恒同意开工。请智建确认 R1–R4,并拍板 O1–O7(尤其 O6 同表互斥 vs 同库互斥)后,即可冻结决议修订版进入 M0。
最终冻结说明(2026-07-31)
R1–R4、O1–O7 已全部拍板并写入 松离线-dbsync方案-最终版.md。
此后改需求只改最终版并备注变更记录;本过程稿不再作为实施口径。