From 929a53852797eb9f2c1a900e2b566fe50a5204fd Mon Sep 17 00:00:00 2001 From: yumoqing Date: Wed, 9 Sep 2026 16:57:55 +0800 Subject: [PATCH] =?UTF-8?q?docs(deploy):=20METHODOLOGY=E8=A1=A5dsync?= =?UTF-8?q?=E7=AB=A0=E8=8A=82=E2=80=94=E2=80=94dmig=E7=AE=A1=E7=BB=93?= =?UTF-8?q?=E6=9E=84/dsync=E7=AE=A1=E9=85=8D=E7=BD=AE=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=9A=84=E8=81=8C=E8=B4=A3=E8=BE=B9=E7=95=8C(=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=AE=9A=E5=A4=BA:=E6=95=B0=E6=8D=AE=E4=B8=80?= =?UTF-8?q?=E6=9D=A1=E9=80=9A=E9=81=93,m0016=E6=92=A4=E9=94=80)=E3=80=81?= =?UTF-8?q?=E5=9F=9F=E5=AE=9A=E4=B9=89+24=E6=9D=A1=E9=97=A8=E7=A6=81+?= =?UTF-8?q?=E5=8F=AA=E5=A2=9E=E6=94=B9=E4=B8=8D=E5=88=A0+=E6=9C=BA?= =?UTF-8?q?=E6=9E=84=E8=BF=87=E6=BB=A4+=E5=AF=86=E9=92=A5=E7=9B=B4?= =?UTF-8?q?=E8=BF=81+=E5=8D=95=E4=BA=8B=E5=8A=A1ROLLBACK=E8=AF=AD=E4=B9=89?= =?UTF-8?q?=E3=80=81=E5=AE=9E=E6=B5=8B=E8=AE=B0=E5=BD=95(PRIMARY=E7=BA=A6?= =?UTF-8?q?=E6=9D=9F=E5=90=8D=E5=9D=91)=E3=80=81=E7=94=9F=E4=BA=A7?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E6=97=B6=E6=9C=BA(=E6=99=9A=E4=BA=8Ecreate?= =?UTF-8?q?=5Ftables)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/METHODOLOGY.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/deploy/METHODOLOGY.md b/deploy/METHODOLOGY.md index d65b532..675a21a 100644 --- a/deploy/METHODOLOGY.md +++ b/deploy/METHODOLOGY.md @@ -166,3 +166,39 @@ CREATE TABLE IF NOT EXISTS pipeline_deploy_ledger ( 2. **只在测试跑 DDL 口头说"生产一样"** → 必然漂移。用 `ddiff.py` 强制对账。 3. **回退没有 down** → 不可逆变更(DROP 列、删数据)必须有备份兜底,备份在操作前。 4. **破坏性语句进自动化** → 永远 `[NEEDS_APPROVAL]`,人工执行。 + +## 7. 配置数据同步(dsync.py,2026-09-09 用户定夺:数据一条通道) + +**职责边界**:dmig 只管表结构(DDL)与环境参数;业务配置数据(模型网关/定价/产品/ +折扣/供应商/记账配置)**不走 git 迁移**,一律由 `dsync.py` 按域同步(m0016 种子迁移已撤销—— +同一份数据两条通道毫无意义)。事务数据(usage/balance/detail/bill/subscription)永远不同步。 + +**域定义** `deploy/dsync_domains.json`:每域 = 表清单 + 机构过滤列 + order 拓扑序; +`gate` 段 = 全库悬空引用门禁 SQL(模型→供应商/账号/模板/ppid、供应商→机构注册+记账开户、 +产品→分类/资源实体、折扣→产品……返回行 = 失败)。加新域 = 加一段配置 + 补对应门禁。 + +**流程**: +``` +测试机: ./py3/bin/python deploy/dsync.py export -o /tmp/pkg.json # 全部域 +传输: ssh 管道 cat 直传(包内含 llm_account.api_key 密文——禁入 git,禁落中间盘) +生产机: ./py3/bin/python deploy/dsync.py import pkg.json --dry-run # 预演 +生产机: ./py3/bin/python deploy/dsync.py import pkg.json # 正式 +生产机: ./py3/bin/python deploy/dsync.py gate # 日常体检(只读) +``` + +**安全语义**: +- 只增改不删:按主键 upsert,目标多出的行保留(生产专属数据绝不误删) +- 机构过滤:只带 org ∈ {'0','*',''} ∪ 目标环境 organization 实有机构(测试 test_* 机构数据跳过) +- 密钥直迁:两环境 password_key sha256 一致(已核对),api_key 密文原样搬运 +- 前置检查:目标缺表直接中止(提示先跑 create_tables.py) +- 导入前强制 dbackup 备份涉及表;全部导入 + 24 条门禁在**单事务**内,任一悬空 → + ROLLBACK(绝不落地半份数据);全绿才 COMMIT +- 门禁失败 exit 2 / 一般失败 exit 1 / 成功 exit 0 + +**实测记录(2026-09-09 测试机自导自入 + 负向验证)**:241 行全 updated 幂等; +篡改 vendor_id 为悬空值 → 门禁精准拦截「模型→供应商 1 行悬空」→ ROLLBACK → 复跑 gate +全绿(零污染)。踩坑:information_schema 主键约束名是 `PRIMARY` 不是 `PRIMARY KEY` +(查空 → upsert 全走 INSERT 撞 1062,首版即崩,测试机负向验证抓到)。 + +**生产导入时机**:必须晚于 create_tables.py 建表(llm_* 等 13 张表在生产不存在时 +前置检查会正确中止)。