# 宇恒 × 智建 · 松离线数据同步使用文档 > 面向:**宇恒一号客户端**对接同学 > 平台侧仓库:智建(ai建站) > 依据:`松离线-dbsync方案-最终版.md`(冻结)、`联调后修改意见-宇恒松离线.md`(Z12/Z13 产品路径) > 本地测试基址示例:`http://127.0.0.1:8180`;生产示例:`https://aisite.yuxindazhineng.com` > **生产·宇信达联调登录**:手机号 `13531041944`(公司侧专用;勿用超管号 `13531041945` / 演示号 `13800000001`) --- ## 1. 你要做什么(一句话) 未开通用户**零改动**。仅当显式 `YXD_SYNC_MODE=local_dbsync`(或库级选「同步」)且走白名单/Binding 时:业务写进本机正式库 B(UUID)→ 写 outbox → **本机 agent** 调智建 push API → 落到线上库 A。agent 停了也**不能挡保存**。 ```text 业务保存 ──► 本机 B(最终 UUID,立刻可见) │ ▼ outbox(积压可接受) │ ▼ 本机 agent(可选装) 智建 POST .../push ──► 线上 A ``` **生产开通(推荐,Z12/Z13)**:不要引导用户手抄 `channel_id`。 后台启用智能体 / 发绑定码 / 同号确认 → 换票带 `sync_bound` + 落点 → 本机库选「同步」即可用。 手建通道 + `YXD_SYNC_CHANNEL_ID` 仅作**运维高级 / 联调过渡**。 --- ## 2. 硬约束(违反即不合入) | # | 要求 | |---|------| | H1 | 未开通:保存 / 自增表 / 插件与现网 **行为 diff = 0** | | H2 | **禁止**自动升为 `local_dbsync`(仅显式配置或用户库级选「同步」) | | H3 | agent 停运 / 推送失败 → **保存仍成功**;心跳只驱动 UI | | H4 | 默认建表仍自增;仅「同步表」用 UUID TEXT PK | | H5 | 旧 `online_primary` 客户禁止静默关双写 | | H6 | 未开通用户:**零同步文案**(无强制状态条、无「已自动合并」) | 开通判定(写路径): ```text mode == local_dbsync AND (表白名单缓存命中 或 Binding 整库策略) → 走松离线旁路 否则 → 原写路径 ``` 同表互斥:某表不可同时 HTTP 双写 + dbsync 白名单。 --- ## 3. 模式三分(环境变量) | `YXD_SYNC_MODE` | 含义 | 说明 | |-----------------|------|------| | `local_only` | 仅本地 | 默认之一 | | `online_primary` | HTTP 双写 / 离线 pending | **旧客保留**;仅配了 `YXD_ONLINE_API_BASE` 且未写 MODE 时可兼容升为此模式 | | `local_dbsync` | 松离线 + 白名单 + agent | **必须显式写出**,永不因「配了线上地址」自动升 | 建议本地测试: ```bash # 默认无感:不要设 local_dbsync,或显式: YXD_SYNC_MODE=local_only ``` 开通增值(**过渡 / 运维**仍可用 env;生产优先换票落点): ```bash YXD_SYNC_MODE=local_dbsync YXD_SYNC_AGENT=1 YXD_ONLINE_API_BASE=http://127.0.0.1:8180 # 过渡:可手填;生产应优先用换票/agents/me 的 channel_id YXD_SYNC_CHANNEL_ID=<可选过渡缓存> YXD_SYNC_ACCESS_TOKEN= # 可选 YXD_SYNC_WHITELIST_TTL_SEC=600 YXD_SYNC_AGENT_INTERVAL_SEC=5 YXD_SYNC_WHITELIST_CACHE=cache/db_sync/whitelist.json # 同号绑定联调(生产宇信达) YXD_SYNC_LOGIN_PHONE=13531041944 ``` 调试兜底表白名单(通道拉取失败前): ```bash YXD_SYNC_WHITELIST=orders,order_items # 或 YXD_SYNC_DBSYNC_TABLES=orders,order_items ``` --- ## 3.1 生产绑定与落点(Z12 / Z13 · 必读) ### 产品约定 1. **一个登录账号 / 一个智能体 ↔ 本公司同步落点**;个人库默认隔离,禁止 A 数据进 B 库。 2. **禁止**把「手抄通道 ID / 先去控制台新建通道」当作普通用户开通主路径。 3. 公司默认同步通道由智建在**启用智能体**时自动创建(`is_system_default`);控制台「数据同步」留给运维改 DSN。 4. 库选「同步」→ 自动 Binding + drain(宇恒 Z13e);全程零手填 DSN/通道。 ### 换票带回绑定(Z12a) `POST /api/v1/auth/token`(client_credentials)或登录响应可含: | 字段 | 说明 | |------|------| | `channel_id` | 已绑则非空 | | `online_db_id` | 已绑则非空 | | `database_name` | 可读落库名 | | `sync_bound` | `true` = 已绑落点;`false` = 须走绑定流程 | 通道解析顺序建议:`env 过渡缓存` → 换票/`agents/me` → Binding → 租户仅 1 条通道自动选用。 ### 智能体自查(Z12b) ```http GET /api/v1/agents/me Authorization: Bearer <智能体 Token> ``` 返回 `channel_id` / `online_db_id` / `database_name` / `sync_bound` / `status`(无需「管理智能体」权限)。 ### 绑定码(Z13a/b) 管理员(需「数据同步」): ```http POST /api/v1/admin/bind-codes Authorization: Bearer <管理员 JWT> Content-Type: application/json { "max_uses": 1, "expires_hours": 168, "note": "开通单" } ``` ```http GET /api/v1/admin/bind-codes DELETE /api/v1/admin/bind-codes/{code} ``` 终端兑换(公开): ```http POST /api/v1/auth/bind-code/redeem Content-Type: application/json { "code": "A1B2C3D4", "host_key": "<本机稳定宿主机 key>", "name": "可选显示名" } ``` 成功 → 智能体挂到该公司 + 默认同步落点,`sync_bound=true`。 ### 同号探测 / 确认(Z13c / Z13c-1) **禁止静默绑定**。有手机号时必须先 lookup,命中后**弹窗确认**再 confirm。 **推荐(仅宇恒 · 安全凭票免登录)**:用户已登录宇恒时,由**宇恒后端**用共享 Secret 签发短时凭票,客户端调: ```http POST /api/v1/auth/yuheng/ticket-exchange Content-Type: application/json { "ticket": "YHT1..", "host_key": "<本机稳定宿主机 key>", "local_database_id": "可选" } ``` 成功直接返回智能体 `access_token` + `sync_bound` / `channel_id` / `online_db_id`(**无需**智建账号密码,也**不要**再传 `attested_same_phone`)。 凭票 payload(JSON,HMAC-SHA256,前缀 `YHT1`)字段: | 字段 | 说明 | |------|------| | `iss` | 固定 `yuheng` | | `aud` | 固定 `aijianzhan` | | `phone` | 宇恒当前已绑手机(须已是智建公司成员) | | `host_key` | 与请求一致 | | `exp` | Unix 秒;建议 60–120s,智建拒 >now+10m | | `jti` | 一次性随机串(防重放) | | `scope` | `sync_bind` | | `name` / `local_database_id` | 可选 | 配置(智建 `platform.yaml` → `Agent.YuhengTicket`):`Enabled` + 与宇恒共享的 `Secret`。生产必换 Secret;**其它客户端不得使用**。 启动前可拉策略(公开,无需登录): ```http GET /api/v1/auth/bind/policy ``` | 字段 | 说明 | |------|------| | `trial_mode` | `true` = 试运行(不强制绑定短信) | | `require_for_bind` | 是否强制短信(与 `SMS.RequireForBind` + Provider≠off 一致) | | `yuheng_ticket_enabled` | 是否启用凭票换票 | | `message` | 给人看的提示文案 | --- 仍可用手机号 API(无凭票或试运行): ```http POST /api/v1/auth/bind/phone-lookup Content-Type: application/json { "phone": "13531041944" } ``` 响应要点:`exists`、`tenant_name`、`masked_name`、`need_confirm`、`sms_required_unless_attested`、`message`(**不**执行绑定)。 ```http POST /api/v1/auth/bind/phone-confirm Content-Type: application/json { "phone": "13531041944", "host_key": "<本机 host_key>", "confirm": true, "local_database_id": "可选,本机库 ID", "attested_same_phone": true, "sms_code": "" } ``` | 字段 | 说明 | |------|------| | `attested_same_phone` | **试运行**可传;**正式且已启凭票**时禁用,须改用 ticket-exchange | | `sms_code` | **试运行**可不传;正式异号必填 | > **试运行**(当前):`SMS.RequireForBind=false` 或 `Provider=off` → 绑定不校验短信,仍须 `confirm=true`。正式:`RequireForBind: true` 且 Provider 非 off。 | 场景 | 行为 | |------|------| | 同号命中公司成员 | **必须询问**「已有账号是否绑定」;确认才 `phone-confirm` / 或凭票换票 | | 用户取消 | 不绑定;可改走绑定码 / 换号 | | 无此成员 | 提示用绑定码;**勿**用超管号 `13531041945` 测 | | 生产联调样例 | 智建与宇恒均为 **`13531041944`** → 凭票或弹确认 | ### 未绑定时客户端流程(Z13d · 宇恒已接 2026-08-05) > 宇恒落地:宿主 `ensure_sync_bound_interactive`;本机 `/database/sync/bind/*`;选「同步」走 `POST /database/sync/mode`(Z13e)。生产仍须智建部署含 `ticket-exchange` / `bind/policy` 的 gateway,并对齐凭票 Secret。 ```text 换票 / agents/me → sync_bound=false ├─ 有手机号 → phone-lookup │ ├─ need_confirm → 【弹窗】确认?→ phone-confirm / 取消 │ └─ 未命中 → 绑定码或换号表单 └─ 无手机号 → 绑定码表单 绑定成功 → 库选「同步」→ Binding + drain(零通道配置) ``` --- ## 4. 智建侧前置(公司管理员) ### 生产推荐(Z12/Z13) 1. 公司级配置默认同步 DSN(`DBSync.DefaultRemoteDSN`,生产 Postgres)。 2. **启用智能体**(勿要求用户先「新建通道」)→ 平台自动建默认同步通道并写回智能体落点。 3. (可选)生成**绑定码**发给终端;或引导用户用公司成员手机号做同号确认(须弹窗)。 4. 运维需要时再在「数据同步」改 remote DSN / 查看通道 ID(可复制)。 ### 运维高级 / 联调过渡(手建通道) 1. 登录智建控制台 → **数据同步** → 新建通道。 2. **生产**:`remote.driver=postgres`,DSN 例:`postgres://user:pass@host:5432/db?sslmode=disable`(须可达)。 3. 表白名单可空(整库 Binding 策略);若填表须 **UUID TEXT/UUID PK** + **外键闭包**。 4. 方向推荐 **本地 → 线上**;冲突策略推荐 **源端覆盖(lww_source)**。 5. 保存通过校验后记下 **通道 ID**(过渡写入 `YXD_SYNC_CHANNEL_ID`)。 6. **二选一鉴权**: - 管理路径:发带「数据同步」的智能体 Token / 管理员 JWT;或 - **用户自助**:终端用登录用户 JWT;先登记 Binding,push 带本人 `online_db_id`。 **单服务器**:一条默认同步通道即可(自动或手建)。 **多服务器**:每台线上 Postgres **各建一条通道**;按本机库选择对应 `channel_id`(建议登记 Binding)。 Binding(多库 / 用户自助时建议登记;登录 JWT 即可,不必管理员权): ```http POST /api/v1/admin/sync/bindings Authorization: Bearer Content-Type: application/json { "local_database_id": "用户本机库 ID", "online_db_id": "线上库 ID", "channel_id": "<通道ID>", "database_name": "可选,本机库可读名(控制台优先展示)", "display_name": "可选,线上库可读名(控制台优先展示)", "note": "可选" } ``` 不传可读名时控制台仍显示 id;宇恒有命名库名时建议一并写入,便于 SyncPage「本地库名 ↔ 线上库名」。 ```http GET /api/v1/admin/sync/bindings?local_database_id=... ``` --- ## 5. 宇恒侧实现清单 ### 5.1 写网关旁路(M1,可无 agent) 对 `insert / update / delete / 写 SQL`: 1. 读模式与白名单。 2. **未命中**:原路径,响应形状与现网一致(可多字段,不可少成功语义)。 3. **命中**: - insert:缺 id 或非法 id → **自动补**小写带连字符 UUID; - 写入本机正式库 B; - append outbox(失败只打日志,**不挡保存**); - `sync_status`:`pending` / `local_only_table` 等仅开通用户可见。 文案:`需 agent 才上云`(不得暗示已上云)。 ### 5.2 Outbox 建议路径(等价即可): ```text cache/db_sync/outbox//pending.jsonl ``` 每条建议字段: | 字段 | 说明 | |------|------| | `id` | outbox 记录 UUID | | `seq` | 单调版本(如 `time.time_ns()`),作 push 的 `version` | | `op` | `insert` / `update` / `update_by_id` / `delete` | | `table_name` | 表名 | | `row_pk` | 行主键 UUID | | `payload` | 含 `data` / `update_data` / `where_*` | | `status` | `pending` | 规则:按 `seq` **保序**消费;失败标记 error 并**停该库后续**,恢复后重试;**禁止**失败后换新 UUID。 ### 5.3 本机 Agent(M2) 启用:`YXD_SYNC_AGENT=1` 且 `mode=local_dbsync`。默认可不启。 循环建议: 1. (TTL)拉白名单 → 写本地缓存。 2. `list_pending` → 逐条 push → 成功 `mark_done` / 失败 `mark_error` 并 break。 3. 写心跳文件(供 `/sync/status` 展示 `agent.running` / `last_beat`)。 **拉白名单** ```http GET /api/v1/agent/sync/channels/{channel_id}/whitelist Authorization: Bearer ``` 响应要点:`tables`、`pk_columns`、`conflict_policy`。 **推单条** ```http POST /api/v1/agent/sync/channels/{channel_id}/push Authorization: Bearer Content-Type: application/json { "table": "orders", "op": "insert", "row_pk": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "row": { "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "title": "demo" }, "version": 1710000000000000000, "client_outbox_id": "outbox-record-uuid", "online_db_id": "用户自助必填(本人 Binding);管理员/智能体可选" } ``` | `op` | 平台行为 | |------|----------| | `insert` / `update` / `update_by_id` | upsert 到 remote A | | `delete` | 按 pk 删 A | 幂等:同 `version` 已落地 → 跳过成功(`skipped=true`)。 LWW:目标更新 → 按通道策略;源端覆盖会记**超管**审计(公司管理员不可见)。 重复 push(双 drain)正确性由 version 保证;客户端可用 drain 锁减流量,非平台必做。 remote 暂不可达:`503` + `retryable:true`。 **下行(仅线上 / 灌库 / 补齐)** ```http POST /api/v1/agent/sync/channels/{channel_id}/bootstrap Authorization: Bearer Content-Type: application/json { "table": "orders", "after_pk": "", "limit": 200, "online_db_id": "用户自助必填" } ``` 或 `POST .../pull`,`mode` 取: | mode | 作用 | |------|------| | `bootstrap` | 分页全量(循环至 `has_more=false`) | | `pks` | 只取 A 主键,本机 diff | | `rows` | 按 `row_pks` 取行 | 客户端把 `result.items` upsert 进本机 B 时务必 **WithApplying**(或等价),避免回声进 outbox。 空表:`result.columns` 仍会返回;本机应用其 `CREATE TABLE IF NOT EXISTS`(见下「表结构同步」)。 成功响应示例: ```json { "success": true, "result": { "ok": true, "applied": false, "skipped": true, "conflict": false, "applied_version": 1710000000000000000, "message": "already applied (same version)", "client_outbox_id": "outbox-record-uuid" } } ``` 批量:`POST .../push/batch`,body `{ "items": [ ... ] }`,最多 100,保序遇错即停。 也可设完整 URL:`YXD_SYNC_PUSH_URL=...`(覆盖默认拼装)。 **表结构同步(空表也要建)** 仅靠 outbox 行 push 时,**空表不会出现在线上**(无变更事件)。同步周期应额外: 1. **本机 → 线上**:对本机每张业务表(含 0 行)调用 ensure: ```http POST /api/v1/agent/sync/channels/{channel_id}/schema/ensure Authorization: Bearer Content-Type: application/json { "online_db_id": "用户自助必填", "tables": [ { "table": "accounts", "pk_column": "id", "columns": ["id", "username", "password", "email", "nickname", "status", "created_at", "updated_at"] } ] } ``` 平台对每张表 `CREATE TABLE IF NOT EXISTS`(列一律 TEXT + 指定 PK);已存在则跳过。 2. **线上 → 本机**:先拉结构,本机缺表则建空表,再 bootstrap 行: ```http POST /api/v1/agent/sync/channels/{channel_id}/schema Authorization: Bearer Content-Type: application/json { "online_db_id": "用户自助必填" } ``` 响应 `result.tables[].columns` + `row_count`;对本地缺失表执行 `CREATE TABLE IF NOT EXISTS`(建议 TEXT + PK=`pk_column`)。 `pull`/`bootstrap` 的 `result.columns` 同样可用于单表建空表。 ### 5.4 状态接口(建议) `GET /database/sync/status`(或你们现有等价路由)对开通用户返回: - `mode` - `local_dbsync.whitelist_tables` / `outbox_pending` - `agent.enabled_flag` / `running` / `last_error` - `note`:未开通勿强塞同步 UI --- ## 6. UUID 约定 - 标准形式:**小写 + 连字符** `8-4-4-4-12` - 入库前 `normalize`;无连字符 32 hex 可规范化 - 默认建表模板**不要**改成 UUID;只给同步表白名单表用 SQLite 同步表示例: ```sql CREATE TABLE IF NOT EXISTS orders ( id TEXT PRIMARY KEY NOT NULL, title TEXT, updated_at TEXT NOT NULL DEFAULT (datetime('now')) ); ``` --- ## 7. 从旧双写迁入(O7,摘要) 1. 该表先停 `online_primary` 双写。 2. 观察无残留。 3. 再进白名单并切 `local_dbsync`。 4. 装 agent,看 outbox 清空。 5. **禁止**静默全员迁移;旧客默认不变。 完整步骤见智建仓:`docs/数据同步-迁移手册.md`。 --- ## 8. 联调检查表 ### 未开通回归(必过) - [ ] 不设 `local_dbsync`:插入自增表与现网一致 - [ ] 无同步强制文案、无强制装 agent - [ ] 保存不因同步模块报错失败 ### 开通 + 无 agent - [ ] 白名单表本地立刻可见(UUID) - [ ] outbox 增长;响应提示需 agent 才上云 - [ ] 非白名单表仍走原路径 ### 开通 + agent - [ ] 拉白名单成功并缓存 - [ ] push 后线上 A 出现**同一 UUID**(不双行) - [ ] 重复 push 同 version 幂等 - [ ] agent 停:仍可本地保存;恢复后按序追上 - [ ] delete 保序,不换新 UUID - [ ] 空表:`schema/ensure` 后线上出现空表(Z10c) - [ ] 缺列:ensure 后 push 含新列不再 503(Z10d) - [ ] 指纹:`schema/fingerprint` 返回 content_hash;智能体带挂载 `online_db_id` 不 403(Z14/Z14c) ### 生产绑定(Z12/Z13) - [ ] 启用智能体后换票 / `agents/me` 已有 `sync_bound=true`(无需手抄通道) - [ ] 绑定码 redeem 成功 - [ ] 同号 `13531041944`:lookup → **弹窗** → confirm;取消不绑 - [ ] 未用超管号 `13531041945` 做绑定联调 - [ ] 库选「同步」后可 drain,零手填 `CHANNEL_ID` ### 冲突 - [ ] 终端**无**冲突处理台 - [ ] 公司管理员打 conflicts API → 403 - [ ] 超管可在平台工作台看 LWW 日志 / 回滚 --- ## 9. 智建 API 速查 基址:`{YXD_ONLINE_API_BASE}`,鉴权:`Authorization: Bearer ...` - 管理路径:需「数据同步」 - **用户自助**:登录用户 JWT + 本人 Binding;push 须带 `online_db_id` - LWW 仅超管 | 方法 | 路径 | 谁用 | |------|------|------| | POST | `/api/v1/auth/token` | 换票;响应可含 `channel_id`/`online_db_id`/`sync_bound`(Z12a) | | GET | `/api/v1/agents/me` | 智能体自查落点(Z12b) | | POST | `/api/v1/auth/yuheng/ticket-exchange` | 宇恒凭票免登录换票(仅宇恒 HMAC) | | GET | `/api/v1/auth/bind/policy` | 绑定策略:`require_for_bind` / `trial_mode` / `yuheng_ticket_enabled` | | POST | `/api/v1/auth/bind-code/redeem` | 绑定码兑换(公开,Z13b) | | POST | `/api/v1/auth/bind/phone-lookup` | 同号探测,不绑定(Z13c) | | POST | `/api/v1/auth/bind/phone-confirm` | 同号确认后绑定(Z13c-1) | | GET/POST/DELETE | `/api/v1/admin/bind-codes` | 管理员生成/列表/撤销绑定码(Z13a) | | GET | `/api/v1/agent/sync/channels/{id}/whitelist` | agent / 用户 JWT | | POST | `/api/v1/agent/sync/channels/{id}/push` | agent / 用户 JWT | | POST | `/api/v1/agent/sync/channels/{id}/push/batch` | agent / 用户 JWT | | POST | `/api/v1/agent/sync/channels/{id}/pull` | agent / 用户 JWT(下行) | | POST | `/api/v1/agent/sync/channels/{id}/bootstrap` | 全量灌库 | | POST | `/api/v1/agent/sync/channels/{id}/schema` | 拉线上表结构(含空表) | | POST | `/api/v1/agent/sync/channels/{id}/schema/ensure` | 本机空表建到线上;已存在可补列(Z10/Z10d) | | POST | `/api/v1/agent/sync/channels/{id}/schema/fingerprint` | 线上表指纹 `row_count`+`content_hash`(Z14;智能体可用挂载 online_db_id) | | GET/POST | `/api/v1/admin/sync/bindings` | 管理员或用户自助 | | GET | `/api/v1/platform/dbsync/lww-overrides` | 仅超管 | | POST | `/api/v1/platform/dbsync/lww-overrides/{id}/rollback` | 仅超管 | OpenAPI:`GET /api/v1/meta/openapi.yaml` --- ## 10. 本地联调最小步骤 ### 生产路径(推荐) 1. 智建起栈;公司配置 `DefaultRemoteDSN`(或联调用空 DSN → sqlite 文件)。 2. 启用智能体 → 自动绑默认同步通道;或管理员 `POST .../admin/bind-codes` 发码。 3. 宇恒:`host_key` 换票 / `agents/me` 看 `sync_bound`;未绑则 lookup→确认 或 redeem。 4. 本机库选「同步」→ Binding + agent drain;**不必**手填 `YXD_SYNC_CHANNEL_ID`。 5. 同号联调用 **`13531041944`**,禁止超管号。 ### 过渡 / 手建通道(仍可用) 1. 智建本机起栈(`.env` 已是本地:`AIJZ_PUBLIC_BASE_URL=http://127.0.0.1:8180`)。 2. 控制台建通道:`remote` 优先本机 **Postgres**;拷贝通道 ID。 3. 拿 token(管理员登录或智能体 client_credentials)。 4. 宇恒设: ```bash YXD_SYNC_MODE=local_dbsync YXD_SYNC_AGENT=1 YXD_ONLINE_API_BASE=http://127.0.0.1:8180 YXD_SYNC_CHANNEL_ID=... YXD_SYNC_ACCESS_TOKEN=... ``` 5. 对白名单表插一行 → 看本机 B + outbox → agent 推上 A → 比对 UUID。 6. 多服务器演练:再建第二条通道指向另一 Postgres,换 `CHANNEL_ID` 验证不串库。 7. **空表**:sync 周期调 `schema/ensure` + `schema`(**Z10c 宇恒已接** `sync_schema.ensure_before_drain`),否则空表不会出现在线上。 --- ## 11. 相关文档(智建仓) | 文档 | 内容 | |------|------| | `松离线-dbsync方案-最终版.md` | 双方冻结方案 | | `联调后修改意见-宇恒松离线.md` | 联调结论 + Z12/Z13 产品路径 | | `docs/同步表约定.md` | UUID / 接口约定 | | `docs/数据同步-开通说明.md` | 管理员开通 | | `docs/数据同步-迁移手册.md` | 旧客迁移 | | `docs/数据同步-中间件.md` | 平台能力与 API | | `docs/发版说明-数据同步.md` | 默认无感发版说明 | --- **分工提醒**:智建只提供平台通道、校验、push/whitelist/Binding/LWW/绑定 API;**写网关、outbox、agent、未开通回归、Z13 弹窗与选同步即用**由宇恒在己方仓库实现,勿改智建仓业务代码。