feat: add Z12/Z13 bind APIs, stock import, and sync docs

Enable auto default sync channels on agent activate, bind-code/phone confirm flows, publish ALTER, and align admin/yuheng docs with the production bind path.
This commit is contained in:
whm
2026-08-05 11:47:20 +08:00
parent b04b180d30
commit cb56e6847e
31 changed files with 1882 additions and 91 deletions

View File

@@ -2,14 +2,15 @@
> 面向:**宇恒一号客户端**对接同学
> 平台侧仓库智建ai建站
> 依据:`松离线-dbsync方案-最终版.md`(冻结)
> 本地测试基址示例:`http://127.0.0.1:8180`;生产示例:`https://aisite.yuxindazhineng.com`
> 依据:`松离线-dbsync方案-最终版.md`(冻结)、`联调后修改意见-宇恒松离线.md`Z12/Z13 产品路径)
> 本地测试基址示例:`http://127.0.0.1:8180`;生产示例:`https://aisite.yuxindazhineng.com`
> **生产·宇信达联调登录**:手机号 `13531041944`(公司侧专用;勿用超管号 `13531041945` / 演示号 `13800000001`
---
## 1. 你要做什么(一句话)
未开通用户**零改动**。仅当显式 `YXD_SYNC_MODE=local_dbsync` 且表在白名单时:业务写进本机正式库 BUUID→ 写 outbox → **本机 agent** 调智建 push API → 落到线上库 A。agent 停了也**不能挡保存**。
未开通用户**零改动**。仅当显式 `YXD_SYNC_MODE=local_dbsync`(或库级选「同步」)且走白名单/Binding 时:业务写进本机正式库 BUUID→ 写 outbox → **本机 agent** 调智建 push API → 落到线上库 A。agent 停了也**不能挡保存**。
```text
业务保存 ──► 本机 B最终 UUID立刻可见
@@ -21,6 +22,10 @@
智建 POST .../push ──► 线上 A
```
**生产开通推荐Z12/Z13**:不要引导用户手抄 `channel_id`
后台启用智能体 / 发绑定码 / 同号确认 → 换票带 `sync_bound` + 落点 → 本机库选「同步」即可用。
手建通道 + `YXD_SYNC_CHANNEL_ID` 仅作**运维高级 / 联调过渡**。
---
## 2. 硬约束(违反即不合入)
@@ -28,7 +33,7 @@
| # | 要求 |
|---|------|
| H1 | 未开通:保存 / 自增表 / 插件与现网 **行为 diff = 0** |
| H2 | **禁止**自动升为 `local_dbsync`(仅显式配置) |
| H2 | **禁止**自动升为 `local_dbsync`(仅显式配置或用户库级选「同步」 |
| H3 | agent 停运 / 推送失败 → **保存仍成功**;心跳只驱动 UI |
| H4 | 默认建表仍自增;仅「同步表」用 UUID TEXT PK |
| H5 | 旧 `online_primary` 客户禁止静默关双写 |
@@ -37,7 +42,7 @@
开通判定(写路径):
```text
mode == local_dbsync AND 表白名单缓存命中该表
mode == local_dbsync AND 表白名单缓存命中 或 Binding 整库策略)
→ 走松离线旁路
否则 → 原写路径
```
@@ -61,18 +66,21 @@ mode == local_dbsync AND 表白名单缓存命中该表
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
YXD_SYNC_CHANNEL_ID=<智建控制台通道 ID>
# 过渡:可手填;生产应优先用换票/agents/me 的 channel_id
YXD_SYNC_CHANNEL_ID=<可选过渡缓存>
YXD_SYNC_ACCESS_TOKEN=<Bearer管理员/智能体「数据同步」,或登录用户 JWT自助须先 Binding>
# 可选
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
```
调试兜底表白名单(通道拉取失败前):
@@ -85,18 +93,131 @@ 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。
```http
POST /api/v1/auth/bind/phone-lookup
Content-Type: application/json
{ "phone": "13531041944" }
```
响应要点:`exists``tenant_name``masked_name``need_confirm``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"
}
```
| 场景 | 行为 |
|------|------|
| 同号命中公司成员 | **必须询问**「已有账号是否绑定」;确认才 `phone-confirm` |
| 用户取消 | 不绑定;可改走绑定码 / 换号 |
| 无此成员 | 提示用绑定码;**勿**用超管号 `13531041945` 测 |
| 生产联调样例 | 智建与宇恒均为 **`13531041944`** |
### 未绑定时客户端流程Z13d · 宇恒待接)
```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. 表白名单须 **UUID TEXT/UUID PK** + **外键闭包**
3. 表白名单可空(整库 Binding 策略);若填表**UUID TEXT/UUID PK** + **外键闭包**
4. 方向推荐 **本地 → 线上**;冲突策略推荐 **源端覆盖lww_source**
5. 保存通过校验后记下 **通道 ID**
5. 保存通过校验后记下 **通道 ID**(过渡写入 `YXD_SYNC_CHANNEL_ID`
6. **二选一鉴权**
- 管理路径:发带「数据同步」的智能体 Token / 管理员 JWT
- **用户自助**:终端用登录用户 JWT先登记 Bindingpush 带本人 `online_db_id`
**单服务器**:一条通道 + 一个 `YXD_SYNC_CHANNEL_ID` 即可
**单服务器**:一条默认同步通道即可(自动或手建)
**多服务器**:每台线上 Postgres **各建一条通道**;按本机库选择对应 `channel_id`(建议登记 Binding
Binding多库 / 用户自助时建议登记;登录 JWT 即可,不必管理员权):
@@ -359,6 +480,15 @@ CREATE TABLE IF NOT EXISTS orders (
- [ ] 重复 push 同 version 幂等
- [ ] agent 停:仍可本地保存;恢复后按序追上
- [ ] delete 保序,不换新 UUID
- [ ] 空表:`schema/ensure` 后线上出现空表Z10c
### 生产绑定Z12/Z13
- [ ] 启用智能体后换票 / `agents/me` 已有 `sync_bound=true`(无需手抄通道)
- [ ] 绑定码 redeem 成功
- [ ] 同号 `13531041944`lookup → **弹窗** → confirm取消不绑
- [ ] 未用超管号 `13531041945` 做绑定联调
- [ ] 库选「同步」后可 drain零手填 `CHANNEL_ID`
### 冲突
@@ -377,15 +507,19 @@ CREATE TABLE IF NOT EXISTS orders (
| 方法 | 路径 | 谁用 |
|------|------|------|
| POST | `/api/v1/auth/token` | 换票;响应可含 `channel_id`/`online_db_id`/`sync_bound`Z12a |
| GET | `/api/v1/agents/me` | 智能体自查落点Z12b |
| 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` | agent / 用户 JWT |
| POST | `/api/v1/agent/sync/channels/{id}/schema` | agent / 用户 JWT拉线上表结构含空表 |
| POST | `/api/v1/agent/sync/channels/{id}/schema/ensure` | 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}/bootstrap` | 全量灌库 |
| POST | `/api/v1/agent/sync/channels/{id}/schema` | 拉线上表结构(含空表) |
| POST | `/api/v1/agent/sync/channels/{id}/schema/ensure` | 本机空表建到线上Z10 |
| GET/POST | `/api/v1/admin/sync/bindings` | 管理员或用户自助 |
| GET | `/api/v1/platform/dbsync/lww-overrides` | 仅超管 |
| POST | `/api/v1/platform/dbsync/lww-overrides/{id}/rollback` | 仅超管 |
@@ -396,8 +530,18 @@ 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。
2. 控制台建通道:`remote` 优先本机 **Postgres**;拷贝通道 ID。
3. 拿 token管理员登录或智能体 client_credentials
4. 宇恒设:
@@ -411,6 +555,7 @@ YXD_SYNC_ACCESS_TOKEN=...
5. 对白名单表插一行 → 看本机 B + outbox → agent 推上 A → 比对 UUID。
6. 多服务器演练:再建第二条通道指向另一 Postgres`CHANNEL_ID` 验证不串库。
7. **空表**sync 周期调 `schema/ensure` + `schema`Z10c否则空表不会出现在线上。
---
@@ -419,6 +564,7 @@ YXD_SYNC_ACCESS_TOKEN=...
| 文档 | 内容 |
|------|------|
| `松离线-dbsync方案-最终版.md` | 双方冻结方案 |
| `联调后修改意见-宇恒松离线.md` | 联调结论 + Z12/Z13 产品路径 |
| `docs/同步表约定.md` | UUID / 接口约定 |
| `docs/数据同步-开通说明.md` | 管理员开通 |
| `docs/数据同步-迁移手册.md` | 旧客迁移 |
@@ -427,4 +573,4 @@ YXD_SYNC_ACCESS_TOKEN=...
---
**分工提醒**智建只提供平台通道、校验、push/whitelist/Binding/LWW**写网关、outbox、agent、未开通回归**由宇恒在己方仓库实现,勿改智建仓业务代码。
**分工提醒**智建只提供平台通道、校验、push/whitelist/Binding/LWW/绑定 API**写网关、outbox、agent、未开通回归、Z13 弹窗与选同步即用**由宇恒在己方仓库实现,勿改智建仓业务代码。