Merge branch 'main' into dev
This commit is contained in:
+38
-182
@@ -1,200 +1,56 @@
|
||||
# order_site 文档索引
|
||||
# order_site 文档入口
|
||||
|
||||
> 最后补充:2026-11-05,新增《履约系统架构复盘与优化方案》;生产代码基线 `e8b76b3b` / 迁移 `136`,开发分支 `dev_11.5_2` 已推进到迁移 `141`(履约统一状态、追加事件与正式影子模型)。
|
||||
> 数据基线:生产 dump `backups/postgres/order_site-20261022-092601.dump`(数据 2026-07-10 ~ 2026-10-22);历史全量数字仅作基线,**上线验收以 [财务上线初始化与验收-2026-10-26.md](财务上线初始化与验收-2026-10-26.md) 为准**。
|
||||
> 本文是 `docs/` 的唯一入口。**整体财务流程看 [财务流程总览-2026-11-01.md](财务流程总览-2026-11-01.md)**;数据模型看 [成本中心与履约模型.md](成本中心与履约模型.md),接口看 [成本中心API契约.md](成本中心API契约.md)。
|
||||
> 新增文档必须在下表登记状态;过期文档不再直接改写结论,统一移入 `docs/archive/`。
|
||||
本文件只负责导航,不定义业务口径。
|
||||
|
||||
## 一、先记住六条口径
|
||||
## 唯一权威
|
||||
|
||||
### 1. 来源只有三个,不是四个
|
||||
[统一订单履约与财务模型-权威版](统一订单履约与财务模型-权威版.md)
|
||||
|
||||
| sourceKey | 包含的数据通道 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `kuaishou-91` | 91 回调 + 快手 send-code | **同一个来源的两条通道**:91 是订单骨架权威源,快手 send-code 是数据补全源与兜底源;共享店铺键空间与同一套匹配上下文 |
|
||||
| `pdd` | 拼多多订单同步 | 两段式 `pdd_raw_orders → orders` |
|
||||
| `douyin-mashida` | 抖音码速达推送 | 抖店订单、DYC 券、H5/兑换页 |
|
||||
所有订单、内部 SKU、履约渠道、履约状态、商品归一、成本与财务相关开发,必须先阅读该文档。
|
||||
|
||||
**不要把 91 与快手 send-code 拆成两个来源、两个适配器或两条业务线。** 产品匹配层的唯一来源键是 `kuaishou-91`(`apps/backend/src/services/product-match/types.ts`),适配器是 `adapters/kuaishou-91.ts`。但订单表与成本映射里存储的 `provider` 仍是 `orders.provider = 91kaquan`;成本中心会把 `91 / open_91 / kuaishou-91` 这些别名归一为 `91kaquan`,映射键必须按落库值建。
|
||||
## 项目规则
|
||||
|
||||
### 2. 一个订单 = 骨架 + 买家凭证 + 一个履约方式
|
||||
[AGENTS.md](../AGENTS.md)
|
||||
|
||||
- 骨架:`orders` + `order_items`
|
||||
- 买家凭证:快手电子凭证(`kuaishou_industry_vouchers`)或抖音券(`redeem_certificates`)
|
||||
- 履约方式只有四种:`affiliate_dash` 自动发货、`work_orders` 接单平台、`legacy_platform` 已下线历史平台、`manual` 人工
|
||||
- **电子凭证只是核销码,不参与履约方式判定**;有核销码的订单仍可能是自动发货/接单平台/人工
|
||||
- 判定顺序固定:工单 → 自动发货任务 → 历史平台任务 → 其余为人工
|
||||
- 人工块必须进入人工支出与成本快照,不能静默消失
|
||||
包含任务读取顺序、数据安全边界、文档维护规则和提交要求。
|
||||
|
||||
### 3. 履约方式与成本模型必须分开
|
||||
## 运维资料
|
||||
|
||||
- `fulfillment_channel`(+ `fulfillment_status`)回答“谁执行”;`cost_model` 回答“成本怎么算”
|
||||
- 自动发货:`affiliate_purchase`
|
||||
- 接单平台:`work_order_reward`
|
||||
- 人工:`manual_actual`(逐单实际金额)
|
||||
- 历史平台:`legacy_cost`(历史未采集则显式标记)
|
||||
- 电子凭证不建成本项,也不作为成本类型
|
||||
- 未确认成本时保持 `cost_missing`,不默认 0
|
||||
|
||||
### 4. 成本只在一个地方改
|
||||
|
||||
- 商品主数据:`product_catalog`
|
||||
- 渠道 SKU 映射:`channel_product_mappings`
|
||||
- 成本金额:只在 `cost_versions` 改,按生效日期新增版本
|
||||
- 订单/工单/人工单只保存 `cost_snapshot_id`,历史成本永不回写
|
||||
- 自动发货、接单平台、人工客服共用同一个成本解析器;匹配不到成本进入 `cost_missing`,不默认 0
|
||||
|
||||
### 5. 人工成本只有一条链路
|
||||
|
||||
```text
|
||||
订单列表/详情「确认履约」→ 扣客服积分/备用金 → 写 cost_snapshots(manual_case)
|
||||
```
|
||||
|
||||
| 名称 | 业务含义 | 当前状态 |
|
||||
| --- | --- | --- |
|
||||
| `manual_expenses` | **客服备用金支出明细**:客服从自己的备用金里充值/采购/赔偿,减少客服余额 | 已实施(迁移 100);确认履约的现金支出也写这里 |
|
||||
| `cost_snapshots` | **人工成本的唯一落点**:`subject_type='manual_case'`,`subject_id=order_item_id`(资金来源写 metadata) | 已实施(迁移 104) |
|
||||
|
||||
**没有独立的登记单,也没有审批与报销环节。** `manual_expense_records` / `manual_expense_events` 已随迁移 `104` 归并下线(这两张表在生产 102 上从未创建)。后续做财务系统时,人工成本的钱与账都从这条链路走,不要再另造一张人工支出表。
|
||||
|
||||
### 6. 历史人工直接放弃,上线后必须全覆盖
|
||||
|
||||
- 历史人工支出找不回来,**直接放弃**:不补录、不做样本校准、不阻塞上线;
|
||||
- 上线后每一笔人工单必须有处理人、实际金额、备用金支出与成本快照;
|
||||
- 人工单无成本记录、人工单未扣备用金、金额与备用金流水不一致,均不允许关账。
|
||||
|
||||
### 7. 文档状态
|
||||
|
||||
| 状态 | 含义 |
|
||||
| 文档 | 用途 |
|
||||
| --- | --- |
|
||||
| 现行 | 与当前代码一致,改动代码时必须同步更新 |
|
||||
| 方案 | 尚未实施,但作为下一阶段实现依据 |
|
||||
| 参考 | 外部协议、历史数据或解释性材料,不作为实现依据 |
|
||||
| 历史 | 只用于追溯,不得作为实现依据;位于 `docs/archive/` |
|
||||
| [生产升级操作手册](生产升级操作手册.md) | 含迁移、履约切换、财务重建的生产升级与回滚步骤 |
|
||||
| [部署启动与数据库重建](部署启动与数据库重建.md) | 本地与生产部署、数据库重建 |
|
||||
| [数据库备份与恢复](数据库备份与恢复.md) | 备份、恢复、OSS |
|
||||
| [数据库SQL约束与运维](数据库SQL约束与运维.md) | SQL 护栏与生产观测 |
|
||||
|
||||
## 二、财务系统当前进度
|
||||
## 专项参考
|
||||
|
||||
| 模块 | 状态 | 事实 |
|
||||
| --- | --- | --- |
|
||||
| 客服备用金台账 | **已实施 P0** | 迁移 `100/101/107`;账户、流水、支出、对账;编号 `FA-<用户名>`;客服只能使用本人账户 |
|
||||
| 后台用户中文显示名 | **已实施** | `admin_users.display_name`,备用金姓名触发器同步;审计、登录记录、任务处理人优先显示中文名 |
|
||||
| 商品主数据 + 渠道 SKU 映射 | **已实施 P0/P1** | 2,017 个标准商品、4,897 条映射:`tpl:` 710、`man:` 1,195、`aff:` 49、`wo:` 63;订单项已按履约证据/人工内部 SKU 归一 |
|
||||
| 成本中心 | **已实施 P0** | 迁移 `103`;710 个规则级版本 + 2 个全局占位版本;工单成本快照 151,939 条,其中 actual 129,430、estimated 22,509 |
|
||||
| 销售事实 / 订单毛利 | **已实施 P0** | 迁移 `103`;375,447 项、收入 ¥3,143.61 万、成本 ¥572.95 万、毛利 ¥2,570.66 万;`sales_daily_facts.channel` |
|
||||
| 人工成本录入(确认履约) | **已实施 P0(2026-10-26 单事务 + 防重复)** | 确认即扣积分/备用金并写 `actual` 快照;钱与成本同事务、订单项级唯一;无登记单/审批/报销 |
|
||||
| 人工 SKU 配置自动匹配 | **已实施(2026-10-26)** | 保存配置立即回填 + 定时 rematch + 确认时按 SKU 兜底匹配 |
|
||||
| 人工缺成本监控 | **已实施(2026-10-26)** | `manual_cost_missing`:首次人工配置之后的订单项未确认即入队,确认后自动收口 |
|
||||
| 履约方式统一 | **已实施 P0** | 迁移 `103`;375,447 项全部回填:接单平台 153,148、人工 115,194、历史平台 53,901、自动发货 53,204 |
|
||||
| 人工商品归一 | **已实施 P1(本次快照恢复执行)** | 人工 115,194 项已归一为 1,195 个 `man:<内部SKU>` 商品;历史人工支出仍不补录 |
|
||||
| 影子总账 | **已实施 P0(2026-10-26)** | `finance_accounts/journal_entries/journal_lines/periods`;销售事实按日凭证 + 手工凭证 + 试算平衡;不接管钱包余额 |
|
||||
| 成本异常归档 | **已实施** | 迁移 `108`;已处理异常超 60 天搬入 `cost_exceptions_archive`,open 行不归档;`COST_EXCEPTION_RETENTION_DAYS` 可调 |
|
||||
| 平台对账 / 期间关账 | **已实施 P0** | 平台账单 JSON 导入匹配、差异明细、标记解决;关账/反关账;见 `/admin/finance/ledger` |
|
||||
| 平台退款 API | **部分实施** | 快手行业(91)同意退款已接入;抖音/拼多多暂未接 API,仍手工登记 |
|
||||
专项参考只解释具体平台、工具或历史问题,不能覆盖唯一权威文档。
|
||||
|
||||
> 分支状态(2026-10-27):`dev` 已合并 `dev1023` 与人工成本完整性修复,迁移收敛为 `103`–`105`(103 财务基础、104 财务控制/L1、105 拼单/寄卖客服);已验证 001→105 与 102→105 两条升级路径。**未推送、未部署生产**;生产口径仍以 `main` 为准。上线前按 [财务上线初始化与验收-2026-10-26.md](财务上线初始化与验收-2026-10-26.md) 初始化资金与人工 SKU。
|
||||
> 财务与履约口径以 [财务与履约口径总纲-2026-10-23.md](财务与履约口径总纲-2026-10-23.md) 为准。
|
||||
|
||||
## 三、统一实施顺序
|
||||
|
||||
```text
|
||||
0. 统一履约事实(渠道 + 成本模型正交) 已完成(迁移 113)
|
||||
1. 商品主数据 + 渠道 SKU 映射 已完成 P0(仅自动发货/接单平台)
|
||||
2. 成本中心 + 销售事实 已完成 P0
|
||||
2.5 人工成本链路收敛(确认履约 → 扣积分/备用金 → 写快照) 已完成 P0(迁移 104)
|
||||
3. 人工商品归一与上线后人工成本全覆盖 已完成代码;生产数据需上线后配置 SKU(历史不补录)
|
||||
4. 退款冲减与异常队列 已完成手工退款 + 快手平台退款;人工缺成本已入队
|
||||
5. 影子总账(销售事实 + 手工凭证) 已完成 P0(迁移 108)
|
||||
6. 平台对账、期间关账 已完成 P0(手工账单导入);平台自动拉单未实施
|
||||
```
|
||||
|
||||
**第 0 步已完成。** 迁移、回填、代码改造与验收结果见 [成本中心与履约模型](成本中心与履约模型.md) §六、§八。下一步只做第 3 步人工商品归一,不要同时改退款或总账。
|
||||
|
||||
## 四、当前必须拍板
|
||||
|
||||
| # | 问题 | 当前结论 | 影响 |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | 收入金额口径 | ✅ 用户实付(`orders.total_amount`) | 收入基数 |
|
||||
| 2 | 收入确认时点 | ✅ 先按 `paid_at` 归属销售日;成本在快照生成后回填 | 利润表与预收账款 |
|
||||
| 3 | 打手报酬 | ✅ 支出/成本,总额法 | 履约成本 |
|
||||
| 4 | 退款/仲裁 | ✅ 暂不实现,只预留反向凭证 | 后续冲减 |
|
||||
| 5 | 人工支出如何入账 | ✅ 逐单实际金额;从客服备用金扣款;客服只能用本人账户 | 人工成本与备用金 |
|
||||
| 6 | 历史人工支出 | ✅ **不补录**,只取少量样本校准 | 上线范围 |
|
||||
| 7 | 电子凭证是否作为分类 | ✅ **不作为履约/成本分类**,只是核销码状态 | 报表口径 |
|
||||
| 8 | 平台服务费/支付通道费 | ⏳ 待定 | 费用科目与对账 |
|
||||
| 9 | 寄卖货款成本确认时点 | ⏳ 待定 | 存货/采购成本 |
|
||||
| 10 | 是否需要发票/税务、是否多币种 | ⏳ 待定 | 当前按 CNY、无税务实现 |
|
||||
|
||||
## 五、现行与参考文档
|
||||
|
||||
| 文档 | 状态 | 用途 |
|
||||
| --- | --- | --- |
|
||||
| [财务与履约口径总纲-2026-10-23.md](财务与履约口径总纲-2026-10-23.md) | **现行唯一口径** | 履约方式、成本模型、人工全覆盖、历史策略、实施顺序、运营日检与验收 SQL |
|
||||
| [财务流程总览-2026-11-01.md](财务流程总览-2026-11-01.md) | 现行 | 断代后财务全流程:六条管道、成本快照、事实、总账、退款、异常、运维与测试 |
|
||||
| [订单全流程与内部SKU架构.md](订单全流程与内部SKU架构.md) | 现行 | 平台入单、中文内部 SKU、渠道判定、四类履约载体、商品归一与财务落账的完整链路 |
|
||||
| [履约系统架构复盘与优化方案-2026-11-05.md](履约系统架构复盘与优化方案-2026-11-05.md) | 方案 | 履约状态、载体、尝试、异常队列与后台信息架构的分阶段重构方案 |
|
||||
| [订单服务收集与状态页设计-2026-11-03.md](订单服务收集与状态页设计-2026-11-03.md) | 现行 | 分类级资料配置、发布版本与工单快照、`/o` 客户状态页、自动发布核销和通知预留 |
|
||||
| [成本中心与履约模型.md](成本中心与履约模型.md) | 现行 | 商品、成本版本、快照、异常、销售事实的数据模型;迁移 `103`–`105`;履约回填;迁移基线与本地库同步;索引与性能 |
|
||||
| [成本中心API契约.md](成本中心API契约.md) | 现行 | 成本中心接口字段替换总表、枚举、模块边界(后端 5 模块 + 前端 4 个固定 Tab) |
|
||||
| [人工支出与备用金.md](人工支出与备用金.md) | 现行(P0 已实施) | 确认履约流程/权限、客服备用金台账、本人账户与编号规则 |
|
||||
| [财务上线初始化与验收-2026-10-26.md](财务上线初始化与验收-2026-10-26.md) | **现行上线手册** | 迁移后资金/人工 SKU 初始化、验收 SQL、日常监控 |
|
||||
| [财务系统集成方案.md](财务系统集成方案.md) | 现行方案(影子总账 P0 已实施) | 复式记账、总账表、对账、关账;P1/P2 平台自动对账待接 |
|
||||
| [财务系统深度分析-2026-10-27.md](财务系统深度分析-2026-10-27.md) | 参考(一次性审计,不改变现行口径) | 2026-10-27 代码/数据/权限审计、风险清单与上线前修复路线 |
|
||||
| [dev合并main评估-2026-10-27.md](dev合并main评估-2026-10-27.md) | 参考(合并评估) | dev 领先 main 的改动、迁移收敛、生产规模升级实测与发布检查清单 |
|
||||
| [财务代码审计复核-2026-10-27.md](财务代码审计复核-2026-10-27.md) | 参考(代码复核) | 对“旧报表重复扣减、总账 DELETE、钱包 BIGINT、死锁”等结论的逐条校正与补充 |
|
||||
| [打手重复奖励核对-2026-10-27.md](打手重复奖励核对-2026-10-27.md) | 待人工核对 | 8 组疑似重复奖励、16 条流水、多计 ¥196.20;含 84886 寄卖误报说明 |
|
||||
| [影子总账说明.md](影子总账说明.md) | 现行说明(P0 已实施) | 影子总账是什么、和钱包流水的区别、对账与转正标准 |
|
||||
| [项目全量分析报告-2026-10-17.md](项目全量分析报告-2026-10-17.md) | 历史参考 | 2026-10-17 架构与风险;财务口径以总纲为准 |
|
||||
| [接单模板匹配引擎重构设计.md](接单模板匹配引擎重构设计.md) | 现行(P0/P1 已实施) | `kuaishou-91 / pdd / douyin-mashida` 三来源匹配引擎 |
|
||||
| [履约配置/多发货平台与电子凭证整体链路.md](履约配置/多发货平台与电子凭证整体链路.md) | 现行 | 进单、履约、领取、电子凭证的整体链路 |
|
||||
| [affiliate-dash-发货平台/affiliate-dash对接.md](affiliate-dash-发货平台/affiliate-dash对接.md) | 现行 | affiliate-dash 自动履约接口与字段 |
|
||||
| [履约配置/cloudtentacles发货平台.md](履约配置/cloudtentacles发货平台.md) | 历史参考 | 已下线通道的第三方接口样例,不代表现行实现 |
|
||||
| [91卡券/6.开发设计.md](91卡券/6.开发设计.md) | 现行 | `kuaishou-91` 来源的 91 侧接入设计 |
|
||||
| [抖音-码速达/00-总览.md](抖音-码速达/00-总览.md) | 现行 | 抖音码速达接入总览与增量记录 |
|
||||
| [抖音-码速达/12-按SKU分类改造总设计.md](抖音-码速达/12-按SKU分类改造总设计.md) | 现行 | 抖音三层分流与载体唯一 |
|
||||
| [部署启动与数据库重建.md](部署启动与数据库重建.md) | 现行 | 本地/生产启动、迁移、重建 |
|
||||
| [数据库备份与恢复.md](数据库备份与恢复.md) | 现行 | 备份、恢复、OSS |
|
||||
| [数据库SQL约束与运维.md](数据库SQL约束与运维.md) | 现行 | SQL 护栏与生产观测 |
|
||||
|
||||
### SQL 草案(未接入迁移)
|
||||
|
||||
草案只作设计与复盘依据;接入 `apps/backend/src/db/migrations/` 时再拆成 `NNN_slug.sql`,并先跑 `npm run check:sql`。
|
||||
|
||||
| 文件 | 用途 | 接入前必须处理 |
|
||||
| --- | --- | --- |
|
||||
| [drafts/2026-10-17-载体判定与人工块量化.sql](drafts/2026-10-17-载体判定与人工块量化.sql) | 载体分布/人工块量化查询、`carrier_type` 判定与回填 | **已过时**:`carrier_type` 已从商品/成本/快照/异常表删除;只读查询里的口径结论已吸收进总纲 §二 |
|
||||
| [drafts/2026-10-17-成本中心与销售事实-DDL草案.sql](drafts/2026-10-17-成本中心与销售事实-DDL草案.sql) | `product_catalog`、`channel_product_mappings`、`cost_items/versions/snapshots/exceptions`、`sales_daily_facts` | 已落地为 `103`–`105`;草案里的 `carrier_type` 已被 `cost_model` / 渠道三列取代,仅作设计追溯 |
|
||||
| [drafts/2026-10-31-112-履约渠道拆分-迁移草案.sql](drafts/2026-10-31-112-履约渠道拆分-迁移草案.sql) | 渠道/状态/来源拆列、`sku_channel_rules`、异常两级化、水位表、卡券成本项 | 已落地为 `apps/backend/src/db/migrations/112_fulfillment_channel_split.sql`;草案保留作设计追溯 |
|
||||
| [drafts/2026-10-31-同步链路重构-旧函数对照.md](drafts/2026-10-31-同步链路重构-旧函数对照.md) | 16 个旧同步/回填入口 → 6 个新管道作业的对照与验收口径 | 已落地:三条管道服务 + 六个定时任务 + 后台「履约渠道」页 |
|
||||
| [archive/2026-10-23/2026-10-17-人工支出登记-DDL草案.sql](archive/2026-10-23/2026-10-17-人工支出登记-DDL草案.sql) | `manual_fulfillment_cases`、`manual_expense_records`、`manual_expense_events` | **已作废**:`manual_expense_records` / `manual_expense_events` 已随迁移 `104` 归并下线,人工成本改走「人工录单 → 扣备用金 → 写快照」;文件已移入 archive |
|
||||
|
||||
## 六、厂商协议与外部资料
|
||||
|
||||
这些目录是平台方文档或抓取资料,**不作为本项目实现说明**:
|
||||
|
||||
| 目录 | 内容 |
|
||||
| 文档或目录 | 用途 |
|
||||
| --- | --- |
|
||||
| `91卡券/` | 91 卡券公开接口、签名、加密示例(项目接入结论见 `91卡券/6.开发设计.md`) |
|
||||
| `行业电子凭证/` | 快手电子凭证接口、售后、测试指南 |
|
||||
| `发货平台-2/` | 早期发货平台协议,现行为 `affiliate_dash`;保留作历史接口对照 |
|
||||
| `抖音-码速达/接口API/` | 抖音码速达出网接口 |
|
||||
| `抖音-码速达/消息推送/` | 抖音码速达推送消息字段与签名 |
|
||||
| [设备认证-dcauth协议](设备认证-dcauth协议.md) | 设备认证协议 |
|
||||
| [affiliate-dash-发货平台](affiliate-dash-发货平台/) | affiliate-dash 对接资料 |
|
||||
| [91卡券](91卡券/) | 91 卡券接口与签名资料 |
|
||||
| [抖音-码速达](抖音-码速达/) | 抖音码速达接口、消息与接入资料 |
|
||||
| [行业电子凭证](行业电子凭证/) | 快手行业电子凭证协议 |
|
||||
| [发货平台-2](发货平台-2/) | 历史发货平台协议 |
|
||||
| [履约配置](履约配置/) | 专项接入与排障参考 |
|
||||
| [微博微豆-CK接口与兑换链路确认-2026-11-07](微博微豆-CK接口与兑换链路确认-2026-11-07.md) | 微博微豆接口与兑换链路 |
|
||||
| [打手重复奖励核对-2026-10-27](打手重复奖励核对-2026-10-27.md) | 历史财务核对记录 |
|
||||
|
||||
## 七、历史文档
|
||||
## 历史归档
|
||||
|
||||
| 位置 | 说明 |
|
||||
| --- | --- |
|
||||
| [archive/README.md](archive/README.md) | 2026-10-08 及更早的阶段分析、寄卖方案、性能快照、一次性迁移检查脚本;2026-10-17 复核文档 |
|
||||
| [archive/2026-10-17/载体判定与成本中心落地-复核与草案.md](archive/2026-10-17/载体判定与成本中心落地-复核与草案.md) | 2026-10-17 第二轮复核与数据量化;结论已吸收进现行成本中心文档,仅作历史追溯 |
|
||||
| [archive/2026-10-23/](archive/2026-10-23/) | 2026-10-23 重写前的四篇:`成本中心与三块履约模型`、`人工支出登记落地方案`、`客服备用金台账实施方案`、`财务履约改造交接总结`;结论已分别并入现行 5 篇文档 |
|
||||
[archive](archive/) 中的文档均已失效,只用于追溯。
|
||||
|
||||
## 八、维护规则
|
||||
2026-11-08 统一重构前的订单、履约、成本、财务、架构与 SQL 草案已归档到:
|
||||
|
||||
1. 改代码影响业务口径时,先改现行文档,再提交代码。
|
||||
2. 文档头部必须写「状态 + 最后校准日期 + 代码基线」。
|
||||
3. 旧分析不要在原文件上继续堆结论;新建当期报告,旧文件移入 `docs/archive/<日期>/`。
|
||||
4. 行号只用于当期基线;跨版本引用优先写文件与函数名。
|
||||
5. 新增来源时只加一个 `ProductMatchSourceKey` + 一个适配器;**91 + 快手 send-code 永远算一个 `kuaishou-91`**。
|
||||
6. 成本金额只改 `cost_versions`,不要在多个业务表直接改价;历史订单只读 `cost_snapshots`。
|
||||
7. 报表维度统一用 `canonical_product_id + shop_id + stat_date`,不要直接用原始 `sku_code` 或 `orders.total_amount`。
|
||||
8. 新增 SQL 草案放 `docs/drafts/`,命名 `<日期>-<主题>.sql`;**不得**直接放进 `apps/backend/src/db/migrations/`(后端启动会自动迁移),接入时再拆编号并先跑 `npm run check:sql`。
|
||||
9. 财务系统实现顺序以本索引 §三 为准;单篇文档里的分期若与本索引冲突,以本索引为准。
|
||||
[archive/2026-11-08](archive/2026-11-08/)
|
||||
|
||||
## 维护规则
|
||||
|
||||
1. 业务和架构口径只修改唯一权威文档。
|
||||
2. 不再新增第二份“现行架构”“现行财务口径”或“总纲”。
|
||||
3. 外部平台协议可以保留,但不得覆盖项目自身模型。
|
||||
4. 已被替代的内部设计文档移入 `docs/archive/<日期>/`。
|
||||
5. 文档中的代码与迁移基线必须来自实际仓库和生产只读核对。
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# 2026-11-08 历史文档归档
|
||||
|
||||
本目录保存 2026-11-08 统一重构前使用的订单、履约、成本、财务和架构文档。
|
||||
|
||||
这些文档只用于追溯当时的设计与数据来源,不再作为现行口径、开发依据或验收标准。
|
||||
|
||||
现行唯一权威文档:
|
||||
|
||||
[统一订单履约与财务模型-权威版](../../统一订单履约与财务模型-权威版.md)
|
||||
+14
-4
@@ -1,7 +1,8 @@
|
||||
# 历史文档归档
|
||||
|
||||
> 这里的文档只用于追溯当时的分析过程,**不是现行实现说明**。
|
||||
> 代码、数据库结构与线上行为以仓库当前 `main` 和 `docs/README.md` 中标记为「现行」的文档为准。
|
||||
> 代码、数据库结构与线上行为只以
|
||||
> [统一订单履约与财务模型-权威版](../统一订单履约与财务模型-权威版.md) 为准。
|
||||
|
||||
## 2026-10-08
|
||||
|
||||
@@ -18,7 +19,7 @@
|
||||
|
||||
| 文档 | 归档原因 |
|
||||
| --- | --- |
|
||||
| `2026-10-17/载体判定与成本中心落地-复核与草案.md` | 2026-10-17 第二轮复核与数据量化;现行结论已吸收进 `成本中心与三块履约模型.md` 与 `财务系统集成方案.md`,仅保留作数据与 DDL 验证追溯 |
|
||||
| `2026-10-17/载体判定与成本中心落地-复核与草案.md` | 2026-10-17 第二轮复核与数据量化;仅保留作数据和 DDL 验证追溯 |
|
||||
|
||||
## 2026-10-23
|
||||
|
||||
@@ -26,9 +27,18 @@
|
||||
| --- | --- |
|
||||
| `2026-10-23/2026-10-23-本地库原地改造.sql` | 逐列把 `carrier_type` / `cost_type` 改成 `cost_model` / `fulfillment_mode` 的一次性脚本;迁移收敛为 `103`–`107` 后不再成立,**禁止在新环境执行**,仅作改造矩阵追溯 |
|
||||
|
||||
## 2026-11-08
|
||||
|
||||
2026-11-08 完成订单、履约、商品、成本和财务口径统一。
|
||||
|
||||
此前所有相关业务架构、财务方案、字段契约和 SQL 草案整体归档到:
|
||||
|
||||
[2026-11-08](2026-11-08/)
|
||||
|
||||
## 使用建议
|
||||
|
||||
- 需要当前架构与风险:看 `docs/项目全量分析报告-2026-10-17.md`(参考)和 `docs/README.md`(状态索引)。
|
||||
- 需要财务系统设计:看 `docs/财务系统集成方案.md`;实施顺序以 `docs/README.md` §三 为准。
|
||||
- 需要当前架构、数据边界和实施计划:只看
|
||||
[统一订单履约与财务模型-权威版](../统一订单履约与财务模型-权威版.md)。
|
||||
- 需要某个平台协议:看对应的厂商文档目录(`91卡券/`、`行业电子凭证/`、`发货平台-2/`、`抖音-码速达/接口API/`、`抖音-码速达/消息推送/`)。
|
||||
- 历史文档中的代码行号、测试数量、迁移数量不要直接引用。
|
||||
- 历史文档不得重新标记为“现行”,需要复活时必须并入唯一权威文档。
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
|
||||
### 2)接单模板匹配引擎重构(`10464fea`,P0+P1)
|
||||
|
||||
按 [接单模板匹配引擎重构设计.md](../接单模板匹配引擎重构设计.md) 抽出 `services/product-match/`(适配器按**来源**划分:`kuaishou-91` / `pdd` / `douyin-mashida`,其中 `kuaishou-91` 同时覆盖 91 回调与快手 send-code 两条数据通道)。生产回放 6000 条订单项:`kuaishou-91`/PDD 决策 **0 差异**,抖音 5 条全为修正。旧 `work-product-match-mappers.ts` 变为门面,签名不变。
|
||||
按 [接单模板匹配引擎重构设计.md](../archive/2026-11-08/接单模板匹配引擎重构设计.md) 抽出 `services/product-match/`(适配器按**来源**划分:`kuaishou-91` / `pdd` / `douyin-mashida`,其中 `kuaishou-91` 同时覆盖 91 回调与快手 send-code 两条数据通道)。生产回放 6000 条订单项:`kuaishou-91`/PDD 决策 **0 差异**,抖音 5 条全为修正。旧 `work-product-match-mappers.js` 改为兼容门面,签名不变。
|
||||
|
||||
### 3)工单「发布并核销」支持抖音券(本次)
|
||||
|
||||
|
||||
@@ -348,7 +348,7 @@
|
||||
| 可观测性 | `utils/logger.ts:96/122`、`repositories/task-event-repo.ts:16`、`repositories/admin-notification-repo.ts:25`、`services/realtime/realtime-event-service.ts:92` | 日志 / 任务事件 / 后台待办 + SSE |
|
||||
| 环境变量白名单(硬约束) | `config/env-documentation.test.ts:57/63`、`.env.server.example`、`.env.mac-docker.example` | 新增 env 必须登记,否则测试红 |
|
||||
| 隐私红线 | `services/worker-platform/sync-worker-orders-service.ts:206-220` | 打手工单素材不含买家信息 |
|
||||
| 平台接入设计范本 | `docs/91卡券/6.开发设计.md`(来源建模/配置/签名/代码落点/测试范围)、`docs/履约配置/多发货平台与电子凭证整体链路.md` | 本项目的「新平台接入」方法论 |
|
||||
| 平台接入设计范本 | `docs/91卡券/6.开发设计.md`(来源建模/配置/签名/代码落点/测试范围)、`docs/archive/2026-11-08/多发货平台与电子凭证整体链路.md` | 本项目的「新平台接入」方法论 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -68,6 +68,10 @@ bash deploy/restore-db.sh --verify
|
||||
|
||||
`--verify` 会把最新带有效清单的备份恢复到一个隔离的临时 PostgreSQL 容器(不接入业务网络,不影响线上库),并打印迁移列表与各表行数。建议之后每月执行一次演练——没验证过的备份等于没有备份。
|
||||
|
||||
生产升级前的恢复验证是硬门禁,并且必须验证本次生成的指定备份,而不是只验证任意旧备份。
|
||||
具体步骤和当前恢复阻断项见
|
||||
[生产升级操作手册](生产升级操作手册.md)。恢复验证未通过时禁止执行生产迁移。
|
||||
|
||||
### 4. 配置每日定时备份
|
||||
|
||||
```bash
|
||||
|
||||
@@ -0,0 +1,657 @@
|
||||
---
|
||||
type: 生产运维操作手册
|
||||
description: order_site 生产结构升级、数据切换、验收与回滚的唯一执行步骤。
|
||||
tags: [生产, 部署, 数据库, 迁移, 备份, 回滚, 财务]
|
||||
status: current
|
||||
version: 1.0
|
||||
updated_at: 2026-11-08
|
||||
---
|
||||
|
||||
# 生产升级操作手册
|
||||
|
||||
> 本手册适用于包含数据库迁移、领域模型切换或财务重建的生产升级。
|
||||
> 业务与架构口径仍以
|
||||
> [统一订单履约与财务模型-权威版](统一订单履约与财务模型-权威版.md) 为唯一权威。
|
||||
>
|
||||
> 涉及普通文档修改、无迁移的小版本更新,可继续使用
|
||||
> [部署启动与数据库重建](部署启动与数据库重建.md)。
|
||||
> 只要包含迁移、表结构切换或派生数据重建,必须按本手册执行。
|
||||
|
||||
## 一、本次升级基线
|
||||
|
||||
以下信息是 2026-11-08 的首次执行基线。后续每次升级必须由发布负责人更新,
|
||||
旧值只允许保留在发布记录中,不能继续作为执行依据。
|
||||
|
||||
| 项目 | 值 |
|
||||
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 发布日期 | 2026-11-08 |
|
||||
| 发布分支 | `dev_11.8` |
|
||||
| 目标提交 | `d76e8265f806342c670d570e8ee72f5e8ab08fdc` |
|
||||
| 生产起始迁移 | `146` |
|
||||
| 目标迁移 | `150` |
|
||||
| 新增迁移 | `147_internal_sku_product_routing.sql`、`148_fulfillment_execution_truth.sql`、`149_finance_derived_scope.sql`、`150_voucher_consume_order_received_scope.sql` |
|
||||
| 升级类型 | 履约、内部 SKU、商品路由、财务派生数据硬切 |
|
||||
| 预计维护窗口 | 2–3 小时 |
|
||||
| 核心停写时间 | 20–40 分钟 |
|
||||
|
||||
同生产规模本地演练结果:
|
||||
|
||||
- 数据量:订单 `456777`、订单项 `456762`、履约 `456762`。
|
||||
- `146 → 150` 单事务迁移:约 `61 秒`。
|
||||
- 90 天财务重建:约 `14–17 秒`。
|
||||
- 第二次财务重建:`ledger.adjusted = 0`,幂等成立。
|
||||
- 严格财务审计:`critical: []`。
|
||||
- 原始订单、订单项、收入、退款和资金流水守恒。
|
||||
|
||||
## 二、绝对禁止
|
||||
|
||||
1. 禁止使用 `deploy/ubuntu-deploy.sh` 执行本次 `147–150` 升级;它会在旧后端
|
||||
仍运行时执行迁移。
|
||||
2. 禁止在生产执行 `deploy/ubuntu-deploy.sh --reset-db`。
|
||||
3. 禁止使用 `--skip-backup`。
|
||||
4. 禁止在迁移前跳过 `restore-db.sh --verify`。
|
||||
5. 禁止在旧后端仍运行时执行 `147–150` 硬切迁移。
|
||||
6. 禁止迁移后用旧镜像启动后端;旧代码不兼容 `order_items.legacy_*`。
|
||||
7. 禁止为了赶进度绕过硬门禁、数据守恒检查或财务审计。
|
||||
8. 禁止自动猜测缺失渠道、商品归属或人工配置。
|
||||
9. 禁止删除或重写原始订单、退款、真实工单、资金流水和审计日志。
|
||||
10. 禁止在迁移过程中重启 PostgreSQL、强制杀迁移事务或重复启动第二个迁移进程。
|
||||
11. 禁止在本轮观察期结束前删除 `legacy_*` 字段和兼容表。
|
||||
|
||||
## 三、角色与记录
|
||||
|
||||
执行前至少确定以下角色:
|
||||
|
||||
| 角色 | 职责 |
|
||||
| ------------ | ---------------------------------------------- |
|
||||
| 发布负责人 | 冻结提交、确认窗口、决定继续或回滚 |
|
||||
| 数据库执行人 | 备份、迁移、统计刷新、数据检查 |
|
||||
| 验收人 | 独立执行审计、核对输出,不复用执行人的口头结论 |
|
||||
| 业务负责人 | 确认已知待分类项、财务口径和恢复营业 |
|
||||
|
||||
整个过程中必须记录:
|
||||
|
||||
- 升级前后 commit。
|
||||
- 升级前后迁移号。
|
||||
- 数据库与配置备份 OSS key、sha256、迁移号和文件大小。
|
||||
- 每个阶段的开始时间、结束时间和退出码。
|
||||
- 三组审计的完整输出。
|
||||
- 财务重建 dry-run 与 execute 的完整 JSON。
|
||||
- 上线验收 SQL 的 PASS、FAIL、WARN 清单。
|
||||
- 继续、暂停或回滚的决定及确认人。
|
||||
|
||||
## 四、上线前门禁
|
||||
|
||||
以下条件必须全部满足,否则不得进入维护窗口。
|
||||
|
||||
### 4.1 代码门禁
|
||||
|
||||
```bash
|
||||
cd /srv/order_site # 替换为服务器实际目录
|
||||
git fetch --prune
|
||||
git switch dev_11.8
|
||||
git pull --ff-only
|
||||
git status --short
|
||||
git rev-parse HEAD
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- `git status --short` 无输出。
|
||||
- `git rev-parse HEAD` 等于本次批准的提交。
|
||||
- 后端 `npm run check` 通过。
|
||||
- 前端 `npm run check` 通过。
|
||||
- 本次发布没有未提交文件。
|
||||
|
||||
### 4.2 生产只读基线
|
||||
|
||||
先执行只读检查,不写数据库:
|
||||
|
||||
```bash
|
||||
docker compose exec -T postgres \
|
||||
sh -lc 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -v ON_ERROR_STOP=1 -f -' <<'SQL'
|
||||
BEGIN READ ONLY;
|
||||
|
||||
SELECT COALESCE(filename, name) AS migration
|
||||
FROM schema_migrations
|
||||
ORDER BY COALESCE(filename, name) DESC
|
||||
LIMIT 5;
|
||||
|
||||
SELECT
|
||||
(SELECT count(*) FROM orders) AS orders,
|
||||
(SELECT count(*) FROM order_items) AS order_items,
|
||||
(SELECT count(*) FROM order_refunds WHERE status = 'confirmed') AS refunds,
|
||||
(SELECT COALESCE(sum(amount_fen), 0) FROM order_refunds WHERE status = 'confirmed') AS refund_fen,
|
||||
(SELECT count(*) FROM work_orders) AS work_orders,
|
||||
(SELECT count(*) FROM fulfillment_tasks) AS fulfillment_tasks,
|
||||
(SELECT count(*) FROM fund_entries) AS fund_entries;
|
||||
|
||||
COMMIT;
|
||||
SQL
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- 当前最高迁移必须是 `146`。
|
||||
- 订单、订单项、退款和资金流水数量记录到发布单。
|
||||
- `docker compose ps`、`/health/ready` 和外网主入口均正常。
|
||||
|
||||
### 4.3 恢复验证硬门禁
|
||||
|
||||
这是 P0 门禁。备份文件存在不等于可回滚。
|
||||
|
||||
```bash
|
||||
bash deploy/backup-db.sh
|
||||
bash deploy/restore-db.sh --list
|
||||
bash deploy/restore-db.sh --verify --key '<本次备份完整 OSS key>'
|
||||
```
|
||||
|
||||
必须确认:
|
||||
|
||||
- `backup-db.sh` 退出码为 `0`。
|
||||
- OSS manifest、sha256 和文件大小有效。
|
||||
- `restore-db.sh --verify` 退出码为 `0`。
|
||||
- 临时恢复库最高迁移为升级前迁移。
|
||||
- 订单、订单项等关键表数量与生产只读基线一致。
|
||||
|
||||
> 2026-11-08 审核结论:当前备份恢复到隔离库时,会因
|
||||
> `idx_order_items_pending_internal_sku` 依赖函数恢复顺序,以及 `livehub_ro`
|
||||
> 角色不存在而返回非零。恢复脚本因此会判定备份不可用。
|
||||
>
|
||||
> 在上述问题修复并重新验证通过前,本次升级状态为 **禁止上线**。
|
||||
> 不允许使用 `--allow-unverified`、手工忽略 `pg_restore` 错误或跳过此门禁。
|
||||
|
||||
### 4.4 调度任务门禁
|
||||
|
||||
升级前在后台关闭全部定时任务:
|
||||
|
||||
```text
|
||||
后台 → 平台配置 → 监控任务 → 任务总开关 → 关闭 → 保存任务
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- 总开关显示关闭。
|
||||
- 所有任务不再排下一次执行。
|
||||
- 升级期间不得重新开启,直到财务重建、业务配置和上线验收全部通过。
|
||||
|
||||
该配置保存在数据库中,会被升级前备份一并保存。
|
||||
|
||||
## 五、维护窗口执行顺序
|
||||
|
||||
严格按照以下顺序执行。任何一步失败都立即停止,不得跳步。
|
||||
|
||||
### 5.1 预构建镜像
|
||||
|
||||
在停止业务前完成构建,不替换正在运行的容器:
|
||||
|
||||
```bash
|
||||
docker compose build backend web
|
||||
docker compose --profile tools build tools
|
||||
```
|
||||
|
||||
构建失败时停止,不进入维护窗口。
|
||||
|
||||
### 5.2 进入维护状态
|
||||
|
||||
先把公网流量切到维护页,或只允许办公网 IP 访问,并保留管理员内部访问通道。
|
||||
迁移后的业务配置需要通过后台 UI 完成,不能全程只启动 backend。
|
||||
如果无法在维护期间隔离公网用户和保留管理员入口,暂停升级。
|
||||
|
||||
通知停止接单后执行:
|
||||
|
||||
```bash
|
||||
docker compose stop web backend
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- `web`、`backend` 已停止。
|
||||
- PostgreSQL 保持运行。
|
||||
- 此时开始计算核心停写时间。
|
||||
|
||||
### 5.3 生成最终升级前备份
|
||||
|
||||
虽然 4.3 已验证恢复链路,这里仍必须生成停机后的最终备份:
|
||||
|
||||
```bash
|
||||
# 重新执行 4.2 的只读计数 SQL,记录停机后的最终基线
|
||||
bash deploy/backup-db.sh
|
||||
bash deploy/restore-db.sh --list
|
||||
```
|
||||
|
||||
记录:
|
||||
|
||||
- 完整 OSS key。
|
||||
- 对应配置备份 OSS key。
|
||||
- manifest 中的迁移号,必须为 `146`。
|
||||
- sha256 和文件大小。
|
||||
|
||||
最终停机备份也必须做隔离恢复验证:
|
||||
|
||||
```bash
|
||||
bash deploy/restore-db.sh --verify --key '<最终备份完整 OSS key>'
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- 命令退出码为 `0`。
|
||||
- manifest、sha256 和下载校验通过。
|
||||
- 临时恢复库最高迁移为 `146`。
|
||||
- 订单、订单项和资金流水数与停机后的最终基线一致。
|
||||
|
||||
最终备份恢复验证未通过时,不得执行迁移。
|
||||
|
||||
### 5.4 执行数据库迁移
|
||||
|
||||
必须先确认旧后端已停止,再执行:
|
||||
|
||||
```bash
|
||||
docker compose run --rm --no-deps backend node dist/db/migrate.js
|
||||
```
|
||||
|
||||
预期执行:
|
||||
|
||||
```text
|
||||
147_internal_sku_product_routing
|
||||
148_fulfillment_execution_truth
|
||||
149_finance_derived_scope
|
||||
150_voucher_consume_order_received_scope
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- 命令退出码为 `0`。
|
||||
- 不允许中断、重复启动或并行启动。
|
||||
- 迁移失败时保持后端停止,不自动重启。
|
||||
|
||||
迁移后检查:
|
||||
|
||||
```bash
|
||||
docker compose exec -T postgres sh -lc \
|
||||
'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Atc "
|
||||
SELECT COALESCE(filename, name)
|
||||
FROM schema_migrations
|
||||
ORDER BY COALESCE(filename, name) DESC
|
||||
LIMIT 5
|
||||
"'
|
||||
```
|
||||
|
||||
最高迁移必须为 `150`。
|
||||
|
||||
### 5.5 刷新统计信息
|
||||
|
||||
迁移后立即执行,否则履约审计可能超时并产生错误计划:
|
||||
|
||||
```bash
|
||||
docker compose exec -T postgres sh -lc \
|
||||
'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -v ON_ERROR_STOP=1 -c "
|
||||
VACUUM (ANALYZE)
|
||||
orders,
|
||||
order_items,
|
||||
fulfillments,
|
||||
fulfillment_attempts,
|
||||
fulfillment_issues,
|
||||
internal_skus,
|
||||
sku_channel_routes,
|
||||
manual_fulfillment_configs,
|
||||
product_catalog,
|
||||
cost_snapshots,
|
||||
sales_daily_facts,
|
||||
finance_journal_entries
|
||||
"'
|
||||
```
|
||||
|
||||
命令失败时停止上线;不要用放宽超时替代统计刷新。
|
||||
|
||||
### 5.6 启动新后端
|
||||
|
||||
先只启动后端,不启动 Web:
|
||||
|
||||
```bash
|
||||
docker compose up -d --no-deps --force-recreate backend
|
||||
docker compose exec -T backend sh -lc \
|
||||
'curl -fsS http://127.0.0.1:3000/health/ready'
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- 健康检查返回成功。
|
||||
- 后端日志中定时任务系统显示已停用。
|
||||
- 不允许用旧镜像执行此步骤。
|
||||
|
||||
## 六、迁移后审计
|
||||
|
||||
### 6.1 数据回填与订单级核销补投
|
||||
|
||||
调度任务保持关闭,执行:
|
||||
|
||||
```bash
|
||||
bash deploy/post-deploy.sh --only=backfill
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- 命令退出码为 `0`。
|
||||
- `revenue:backfill` 完成后 `revenue_basis = 'unknown'` 为 `0`。
|
||||
- `voucher:backfill-order-received` 完成最近 7 天订单级核销补投,剩余待入队为 `0`。
|
||||
- 新任务来源为 `order_received`,`target_key` 使用 `order:<订单ID>`。
|
||||
- `VACUUM ANALYZE` 成功。
|
||||
|
||||
`post-deploy.sh` 末尾仍可能打印旧上线手册链接和“从接单模板初始化”提示;
|
||||
以本手册为准,不要按旧提示重复初始化商品。
|
||||
|
||||
### 6.2 商品路由审计
|
||||
|
||||
```bash
|
||||
docker compose --profile tools run --rm --no-deps tools \
|
||||
npm run audit:product-routing -- --strict
|
||||
```
|
||||
|
||||
以下结构性异常必须为 `0`:
|
||||
|
||||
- 无主路由且无人工配置的 `man:` 商品。
|
||||
- 同一内部 SKU 多主路由。
|
||||
- `manual / third_party_voucher` 商品缺少内部 SKU。
|
||||
- 非法商品来源。
|
||||
|
||||
`fallback_without_primary`、`missing_manual_route` 和未路由商品可以保留为
|
||||
“待分类”,但必须逐类记录数量,交业务负责人在本轮维护窗口内确认。
|
||||
严格审计可能因这些已知待分类项返回非零;只有确认失败项全部属于已签字类别、
|
||||
且上述结构性异常均为 `0` 时,才允许继续。
|
||||
|
||||
### 6.3 履约审计
|
||||
|
||||
```bash
|
||||
docker compose --profile tools run --rm --no-deps tools \
|
||||
npm run audit:fulfillment -- --strict
|
||||
```
|
||||
|
||||
以下完整性指标必须为 `0`:
|
||||
|
||||
- 正式履约缺失。
|
||||
- 正式履约状态差异。
|
||||
- 执行尝试缺失。
|
||||
- 开放异常缺失。
|
||||
- 履约事件未关联正式记录。
|
||||
- 近 24 小时重复尝试。
|
||||
|
||||
以下业务异常不得增加,并必须已经进入结构化待办:
|
||||
|
||||
- `missing_internal_sku`
|
||||
- `missing_channel`
|
||||
- `manual_config_missing`
|
||||
- `carrier_missing`
|
||||
- `state_inconsistent`
|
||||
- `user_refund`
|
||||
- `platform_cancelled`
|
||||
|
||||
其中 `state_inconsistent`、售后关闭仍进入履约队列、已分配但无有效载体属于
|
||||
恢复营业前必须处理或由业务负责人明确签字的阻塞项。
|
||||
|
||||
2026-11-08 演练基线:
|
||||
|
||||
- 待处理履约项 `476`。
|
||||
- 状态不一致 `7`。
|
||||
- 售后关闭仍进入履约队列 `24`。
|
||||
- 已分配但无有效载体 `27`。
|
||||
|
||||
### 6.4 财务重建 dry-run
|
||||
|
||||
先定义本次财务回看区间:
|
||||
|
||||
```bash
|
||||
RECONCILE_FROM=2026-08-11
|
||||
RECONCILE_TO=2026-11-08
|
||||
```
|
||||
|
||||
执行 dry-run:
|
||||
|
||||
```bash
|
||||
docker compose --profile tools run --rm --no-deps tools \
|
||||
npm run finance:rebuild-derived -- \
|
||||
--date-from="$RECONCILE_FROM" \
|
||||
--date-to="$RECONCILE_TO"
|
||||
```
|
||||
|
||||
检查:
|
||||
|
||||
- `closedPeriods` 为空;若包含已关账期间,停止并先走财务确认流程。
|
||||
- `scopeItems > 0`。
|
||||
- `protectedTotals` 与生产基线一致。
|
||||
- `plan` 中的 estimated 快照、销售事实和总账调整数量能够解释。
|
||||
|
||||
### 6.5 业务配置
|
||||
|
||||
为完成后台操作,启动 Web;此时公网仍必须停留在维护入口,不能对普通用户开放:
|
||||
|
||||
```bash
|
||||
docker compose up -d --no-deps --force-recreate web
|
||||
```
|
||||
|
||||
由业务负责人完成,脚本不能代替:
|
||||
|
||||
1. 钱包管理 → 补建客服备用金账户并按需拨付。
|
||||
2. 商品与成本 → 积分钱包 → 发放三平台积分。
|
||||
3. 商品与成本 → 标准商品 → 按需执行「按工单回填商品」和「归一人工商品」。
|
||||
4. 商品与成本 → 人工 SKU 配置 → 扫描并逐项配置。
|
||||
5. 商品与成本 → 标准商品 → 处理未路由、待分类和人工兜底项。
|
||||
|
||||
> 迁移 `122` 已负责接单模板商品初始化。本手册不再要求执行旧的
|
||||
> “从接单模板初始化”步骤。
|
||||
|
||||
完成业务配置后重新执行商品路由审计,并记录前后数量变化。
|
||||
|
||||
### 6.6 财务重建
|
||||
|
||||
业务配置完成后,重新执行 6.4 的 dry-run,确认 `protectedTotals`、已关账期间和
|
||||
计划数量仍符合预期。业务负责人确认后再执行:
|
||||
|
||||
```bash
|
||||
docker compose --profile tools run --rm --no-deps tools \
|
||||
npm run finance:rebuild-derived -- \
|
||||
--date-from="$RECONCILE_FROM" \
|
||||
--date-to="$RECONCILE_TO" \
|
||||
--execute \
|
||||
--confirm=REBUILD_DERIVED
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- `protectedTotals` 前后完全一致。
|
||||
- 订单、订单项、收入、退款、人工支出和资金流水守恒。
|
||||
- 已过账总账只追加反向/补差凭证,不删除历史凭证。
|
||||
- 所有成本缺口都进入结构化异常,不做自动猜测。
|
||||
|
||||
再执行一次相同命令验证幂等:
|
||||
|
||||
```bash
|
||||
docker compose --profile tools run --rm --no-deps tools \
|
||||
npm run finance:rebuild-derived -- \
|
||||
--date-from="$RECONCILE_FROM" \
|
||||
--date-to="$RECONCILE_TO" \
|
||||
--execute \
|
||||
--confirm=REBUILD_DERIVED
|
||||
```
|
||||
|
||||
第二次必须满足:
|
||||
|
||||
- `ledger.adjusted = 0`。
|
||||
- `protectedTotals` 再次保持完全一致。
|
||||
|
||||
然后执行:
|
||||
|
||||
```bash
|
||||
docker compose --profile tools run --rm --no-deps tools \
|
||||
npm run audit:finance -- --strict
|
||||
```
|
||||
|
||||
要求 `critical` 为空。
|
||||
|
||||
## 七、上线验收
|
||||
|
||||
停止调度任务期间执行:
|
||||
|
||||
```bash
|
||||
bash deploy/post-deploy.sh \
|
||||
--only=verify \
|
||||
--launch-at='YYYY-MM-DD HH:mm:ss+08'
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- 退出码为 `0`。
|
||||
- FAIL 必须为 `0`。
|
||||
- WARN 必须逐项记录并由业务负责人签字。
|
||||
- `audit:finance --strict` 必须同时通过。
|
||||
|
||||
2026-11-08 演练中,在做完财务重建后仍有:
|
||||
|
||||
- `07 客服备用金账户已补建`:需在后台完成初始化后才可通过。
|
||||
- `15 近 7 天非人工成本覆盖`:演练时为 WARN,原因为 `206`,必须确认成本缺口。
|
||||
|
||||
## 八、恢复营业
|
||||
|
||||
验收通过后:
|
||||
|
||||
```bash
|
||||
docker compose up -d --no-deps --force-recreate web
|
||||
```
|
||||
|
||||
然后:
|
||||
|
||||
1. 后台 → 平台配置 → 监控任务 → 开启任务总开关 → 保存。
|
||||
2. 确认任务运行状态恢复,且下一次执行时间已生成。
|
||||
3. 检查主站、打手端、领取页和订单服务链接。
|
||||
|
||||
必须完成以下冒烟检查:
|
||||
|
||||
- 后台登录。
|
||||
- 订单列表、详情和筛选。
|
||||
- 接单工单列表、详情和状态操作。
|
||||
- 履约渠道页和商品与成本页签数量一致。
|
||||
- 人工 SKU、自动发货、接单平台、第三方卡券和统一结算分类正确。
|
||||
- 财务总账试算平衡。
|
||||
- 打手端登录、订单页和大厅。
|
||||
- 领取链接 `/h5/<订单号>`。
|
||||
- 订单服务链接 `/o` 和 `/o/<订单号>`。
|
||||
|
||||
## 九、观察期
|
||||
|
||||
恢复营业后:
|
||||
|
||||
- 前 60 分钟持续观察错误率、慢查询、定时任务和订单入单。
|
||||
- 前 7 天每天检查商品路由、履约和财务严格审计。
|
||||
- 一个完整财务期间持续对平后,才允许讨论删除兼容表、`legacy_*`
|
||||
字段和旧脚本。
|
||||
|
||||
观察期内不得删除:
|
||||
|
||||
- `product_channel_capabilities`
|
||||
- `manual_sku_registry` 派生行
|
||||
- `internal_sku_channels`
|
||||
- `order_items.legacy_*`
|
||||
- `fulfillments`、`fulfillment_attempts`、`fulfillment_issues`、`fulfillment_state_events`
|
||||
|
||||
## 十、失败与回滚
|
||||
|
||||
### 10.1 迁移命令失败
|
||||
|
||||
如果迁移尚未提交:
|
||||
|
||||
1. 保持 backend/web 停止。
|
||||
2. 保存完整迁移日志。
|
||||
3. 确认 PostgreSQL 中不存在半提交状态。
|
||||
4. 修复迁移或取消本次发布。
|
||||
5. 取消发布时,先切回升级前 commit 并重新构建 backend/web,再启动旧后端。
|
||||
6. 不得在未确认迁移事务已回滚时启动任何一版后端。
|
||||
|
||||
### 10.2 迁移已提交但新后端失败
|
||||
|
||||
硬切后的数据库不兼容旧镜像。选择以下一种:
|
||||
|
||||
1. **修复前进**:保持停服,修复新后端,禁止用旧镜像连接迁移 `150`。
|
||||
2. **整库回滚**:使用已通过验证的升级前备份恢复。
|
||||
|
||||
整库回滚:
|
||||
|
||||
回滚前必须先切回旧代码并重建旧镜像。否则 `restore-db.sh` 会用当前新镜像补迁移,
|
||||
把刚恢复的 `146` 再次升级到 `150`。
|
||||
|
||||
```bash
|
||||
git switch --detach '<升级前 commit>'
|
||||
docker compose build backend web
|
||||
bash deploy/restore-db.sh \
|
||||
--key '<升级前最终备份 OSS key>' \
|
||||
--config-key '<对应配置备份 OSS key>' \
|
||||
--yes
|
||||
```
|
||||
|
||||
恢复后:
|
||||
|
||||
1. 确认最高迁移为 `146`。
|
||||
2. 启动 backend/web。
|
||||
3. 执行健康检查、登录和近期订单抽查。
|
||||
4. 恢复调度任务总开关。
|
||||
|
||||
> 当前恢复脚本只有在 4.3 硬门禁通过后才可用于回滚。
|
||||
> 恢复脚本失败时,数据库可能处于部分恢复状态,必须立即停止业务并人工处理。
|
||||
|
||||
### 10.3 财务重建失败
|
||||
|
||||
财务重建是幂等的数据阶段,不应因为一次失败立即整库回滚:
|
||||
|
||||
1. 保持停服和调度关闭。
|
||||
2. 保存失败 JSON、日志和当前 protected totals。
|
||||
3. 修复数据或脚本后重跑。
|
||||
4. 只有原始订单、退款、资金流水发生不守恒或数据库不可用时才考虑整库回滚。
|
||||
|
||||
### 10.4 验收失败
|
||||
|
||||
验收 FAIL 或关键审计异常时不得恢复营业:
|
||||
|
||||
1. 保持 backend 健康但 Web 不开放。
|
||||
2. 调度保持关闭。
|
||||
3. 按失败项修复或走整库回滚。
|
||||
4. 修复后从对应阶段重新执行,不跳步。
|
||||
|
||||
## 十一、发布记录模板
|
||||
|
||||
```text
|
||||
发布日期:
|
||||
发布负责人:
|
||||
数据库执行人:
|
||||
验收人:
|
||||
业务负责人:
|
||||
|
||||
升级前 commit:
|
||||
目标 commit:
|
||||
升级前迁移:
|
||||
目标迁移:
|
||||
|
||||
升级前备份 key:
|
||||
升级前备份 sha256:
|
||||
升级前配置备份 key:
|
||||
恢复验证结果:
|
||||
|
||||
维护开始时间:
|
||||
迁移开始时间:
|
||||
迁移结束时间:
|
||||
统计刷新结束时间:
|
||||
财务重建结束时间:
|
||||
验收结束时间:
|
||||
恢复营业时间:
|
||||
|
||||
商品路由审计:
|
||||
履约审计:
|
||||
财务 dry-run:
|
||||
第一次财务重建:
|
||||
第二次财务重建:
|
||||
财务严格审计:
|
||||
上线验收 FAIL:
|
||||
上线验收 WARN:
|
||||
|
||||
已知待分类项及负责人:
|
||||
最终结论:继续 / 暂停 / 回滚
|
||||
```
|
||||
@@ -0,0 +1,882 @@
|
||||
---
|
||||
type: 权威架构与实施计划
|
||||
description: 订单、内部 SKU、履约路由、履约执行、商品、成本与财务的唯一权威口径及重构计划。
|
||||
tags: [订单, 内部SKU, 履约, 商品, 成本, 财务, 迁移]
|
||||
status: authoritative
|
||||
version: 2.4
|
||||
updated_at: 2026-11-08
|
||||
---
|
||||
|
||||
# 统一订单、履约与财务模型
|
||||
|
||||
> 状态:**唯一权威文档**。
|
||||
> 最后校准:2026-11-08。
|
||||
> 生产基线:迁移 `146`。
|
||||
> 开发基线:迁移 `150`(仅本地,尚未部署生产)。
|
||||
>
|
||||
> 从本文件生效起,订单、内部 SKU、履约渠道、履约载体、标准商品、成本和财务相关实现,
|
||||
> 只能以本文件为业务口径。其他旧分析只作为历史资料,不再具备设计或验收效力。
|
||||
|
||||
## 一、最终结论
|
||||
|
||||
系统按六个业务域拆分:
|
||||
|
||||
```text
|
||||
订单接入
|
||||
→ 商品身份
|
||||
→ 履约路由
|
||||
→ 履约执行
|
||||
→ 财务核算
|
||||
→ 运营治理
|
||||
```
|
||||
|
||||
换一种更具体的表达:
|
||||
|
||||
```text
|
||||
平台订单与原始行
|
||||
→ 中文内部 SKU
|
||||
→ 主渠道与兜底渠道
|
||||
→ 当前履约单与执行尝试
|
||||
→ 标准商品与成本事实
|
||||
→ 销售事实、总账与报表
|
||||
```
|
||||
|
||||
每一层只能回答一个问题:
|
||||
|
||||
| 层 | 唯一问题 | 唯一真源 |
|
||||
| --- | --- | --- |
|
||||
| 订单接入 | 平台实际发生了什么 | `orders` / `order_items` / 原始报文 |
|
||||
| 商品身份 | 业务上这是什么商品 | `internal_skus` |
|
||||
| 履约路由 | 这个商品默认由谁履约 | `sku_channel_routes` |
|
||||
| 履约执行 | 当前实际执行到哪一步 | `fulfillments` / `fulfillment_attempts` |
|
||||
| 财务商品 | 收入与成本归到哪个标准商品 | `product_catalog` / `channel_product_mappings` |
|
||||
| 财务核算 | 应该记多少钱 | `cost_snapshots` / `sales_daily_facts` / `journal_*` |
|
||||
|
||||
任何页面、接口、任务和报表都必须从各自真源读取,不得根据另一层的字段反推。
|
||||
|
||||
## 二、不可违反的规则
|
||||
|
||||
1. **原始订单事实永不删除。**
|
||||
`orders`、`order_items`、平台原始报文、平台售后与退款事实、真实工单执行记录、
|
||||
真实钱包和资金流水、后台审计日志必须保留。
|
||||
|
||||
2. **标准商品不表达当前履约渠道。**
|
||||
`canonical_sku` 前缀、`product_catalog.category` 和商品名称都不能反推当前渠道。
|
||||
|
||||
3. **人工配置不等于当前走人工。**
|
||||
人工配置只表示具备人工执行或人工兜底能力。当前渠道必须来自路由结果。
|
||||
|
||||
4. **一个内部 SKU 最多一个主渠道。**
|
||||
其他启用渠道只能是显式兜底,并记录优先级与用途。
|
||||
|
||||
5. **`assigned` 不等于履约完成。**
|
||||
`assigned` 只允许表示路由已确定;载体是否存在由 `carrier_status` 单独表达。
|
||||
|
||||
6. **财务层只读上游。**
|
||||
成本、事实和总账不得反向修改订单、路由、载体或商品来源。
|
||||
|
||||
7. **派生数据必须可重建。**
|
||||
成本快照、销售事实、总账、异常队列和读模型都必须能够从原始订单、
|
||||
输入配置和事件重算。
|
||||
|
||||
8. **页面与统计使用同一读模型。**
|
||||
同一个数量,页签、卡片、列表和导出不得各自拼口径。
|
||||
|
||||
9. **历史文档不再定义现行规则。**
|
||||
旧架构、旧财务方案和旧迁移说明只能放入归档目录。
|
||||
|
||||
10. **一次只允许一个权威写入口。**
|
||||
核心状态只允许由对应领域服务修改;其他模块只能调用该服务。
|
||||
|
||||
## 三、领域边界
|
||||
|
||||
### 3.1 订单接入域
|
||||
|
||||
负责:
|
||||
|
||||
- 接收 91、快手送码、拼多多、抖音码速达的数据。
|
||||
- 保存平台订单、订单项、原始报文、支付和售后事实。
|
||||
- 保证来源重放幂等。
|
||||
- 将平台商品字段解析为中文内部 SKU。
|
||||
|
||||
不负责:
|
||||
|
||||
- 选择履约渠道。
|
||||
- 创建工单或履约任务。
|
||||
- 计算成本。
|
||||
- 决定标准商品。
|
||||
|
||||
`order_items` 只保存订单项与平台商品事实。迁移 `148` 后,重复的履约状态、
|
||||
渠道、配置关联和商品归一字段已改名为 `legacy_*` 冻结留档;
|
||||
运行时不得读取或写入这些旧列。订单项履约状态统一从 `v_order_item_current` 或
|
||||
`fulfillments` 读取。
|
||||
|
||||
### 3.2 商品身份域
|
||||
|
||||
目标真源:
|
||||
|
||||
```text
|
||||
internal_skus
|
||||
id
|
||||
internal_sku_key -- NFKC、去空白、小写后的稳定键
|
||||
display_name -- 运营可读名称
|
||||
status -- active / disabled / merged
|
||||
merged_into_id -- 合并目标
|
||||
```
|
||||
|
||||
所有人工配置、渠道路由、订单项快照和渠道规则都必须通过 `internal_sku_id` 关联,
|
||||
不再长期依赖多张表重复保存同一个中文文本。
|
||||
|
||||
平台字段到内部 SKU 的唯一入口:
|
||||
|
||||
```text
|
||||
internal_sku_mappings
|
||||
provider
|
||||
shop_id
|
||||
match_type
|
||||
match_value
|
||||
internal_sku_id
|
||||
priority
|
||||
enabled
|
||||
```
|
||||
|
||||
匹配顺序固定:
|
||||
|
||||
```text
|
||||
provider + shop 精确
|
||||
→ provider 精确
|
||||
→ shop 精确
|
||||
→ 全局
|
||||
```
|
||||
|
||||
### 3.3 履约路由域
|
||||
|
||||
目标真源:
|
||||
|
||||
```text
|
||||
sku_channel_routes
|
||||
id
|
||||
internal_sku_id
|
||||
channel
|
||||
route_role -- primary / fallback
|
||||
priority
|
||||
enabled
|
||||
carrier_config_json
|
||||
source
|
||||
created_by
|
||||
updated_at
|
||||
```
|
||||
|
||||
渠道枚举:
|
||||
|
||||
```text
|
||||
affiliate_dash
|
||||
work_order
|
||||
third_party_voucher
|
||||
manual
|
||||
on_account
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
- `active + primary` 每个内部 SKU 最多一条。
|
||||
- `fallback` 可以多条,按 `priority` 依次尝试。
|
||||
- 主渠道失败时才能尝试兜底渠道。
|
||||
- 运营指定和自动判定必须写差异化 `source`。
|
||||
- 路由配置不能保存“当前订单结果”;当前结果属于履约域。
|
||||
|
||||
### 3.4 履约执行域
|
||||
|
||||
唯一真源为 `fulfillments`、`fulfillment_attempts`、`fulfillment_issues`。
|
||||
`v_order_item_current` 是订单项与正式履约的一对一读投影;
|
||||
`v_fulfillment_item_state` 是履约队列专用读模型。两者都不得回退 `order_items.legacy_*`。
|
||||
|
||||
```text
|
||||
fulfillments
|
||||
id
|
||||
order_item_id
|
||||
order_id
|
||||
internal_sku
|
||||
status -- pending / assigned / archived
|
||||
channel
|
||||
source
|
||||
locked
|
||||
pending_reason
|
||||
pending_detail
|
||||
fulfillment_config_id
|
||||
canonical_product_id
|
||||
route_status -- unrouted / configured
|
||||
carrier_status -- not_required / missing / creating / ready / failed / terminal
|
||||
current_attempt_type -- task / work_order / 空
|
||||
current_attempt_source_id
|
||||
current_attempt_status
|
||||
issue_code
|
||||
issue_category
|
||||
retryable
|
||||
owner_role
|
||||
created_at
|
||||
updated_at
|
||||
|
||||
fulfillment_attempts
|
||||
id
|
||||
fulfillment_id
|
||||
attempt_no
|
||||
attempt_type -- task / work_order
|
||||
source_id
|
||||
status
|
||||
result_code
|
||||
result_message
|
||||
is_current
|
||||
started_at
|
||||
finished_at
|
||||
context_json
|
||||
|
||||
fulfillment_issues
|
||||
id
|
||||
fulfillment_id
|
||||
issue_code
|
||||
issue_category
|
||||
severity
|
||||
retryable
|
||||
auto_retryable
|
||||
owner_role
|
||||
status -- open / acknowledged / waiting / resolved
|
||||
detail_json
|
||||
first_seen_at
|
||||
last_seen_at
|
||||
resolved_at
|
||||
```
|
||||
|
||||
状态写入规则:
|
||||
|
||||
- 状态服务锁 `fulfillments`,不再锁或更新 `order_items` 履约状态。
|
||||
- 配置关联写入 `fulfillments.fulfillment_config_id / canonical_product_id`。
|
||||
- 任务和工单只追加 `fulfillment_attempts`,由触发器刷新当前尝试摘要。
|
||||
- 状态变化写入 `fulfillment_state_events`;事件只禁止 UPDATE,父记录删除时允许级联清理。
|
||||
- `v_order_item_current` 以正式表字段覆盖订单项旧名,保证所有业务查询只有一个读口径。
|
||||
|
||||
状态必须正交:
|
||||
|
||||
```text
|
||||
商业订单状态
|
||||
≠ 路由状态
|
||||
≠ 载体状态
|
||||
≠ 当前尝试状态
|
||||
≠ 异常状态
|
||||
≠ 锁定原因
|
||||
≠ 财务状态
|
||||
```
|
||||
|
||||
同一订单项只能有一个当前尝试。历史尝试只追加,不覆盖。
|
||||
|
||||
### 3.5 商品与财务域
|
||||
|
||||
标准商品目标结构:
|
||||
|
||||
```text
|
||||
product_catalog
|
||||
id
|
||||
canonical_sku
|
||||
canonical_name
|
||||
source_kind -- affiliate / work_order / voucher / manual / settlement
|
||||
internal_sku_id -- 可空;关联业务内部 SKU
|
||||
category -- 仅展示,不参与路由
|
||||
unit_name
|
||||
status
|
||||
```
|
||||
|
||||
`canonical_sku` 前缀只用于兼容识别。运行时和统计必须读取 `source_kind`,
|
||||
不能再散落 `LIKE 'man:%'` 之类的业务判断。
|
||||
|
||||
商品映射:
|
||||
|
||||
```text
|
||||
channel_product_mappings
|
||||
provider + shop_id + platform_sku
|
||||
→ product_catalog
|
||||
```
|
||||
|
||||
渠道规则关联的产品只用于说明该渠道执行时对应的财务商品,
|
||||
不能反向决定路由。
|
||||
|
||||
成本与财务:
|
||||
|
||||
```text
|
||||
cost_versions -- 成本规则与价格版本,是输入真源
|
||||
cost_snapshots -- 单个订单项在某时点的成本事实,可重建
|
||||
sales_daily_facts -- 收入、退款、成本汇总,可重建
|
||||
finance_journal_* -- 总账凭证,可重建
|
||||
```
|
||||
|
||||
## 四、单一真源矩阵
|
||||
|
||||
| 信息 | 唯一写入方 | 唯一真源 | 明确禁止 |
|
||||
| --- | --- | --- | --- |
|
||||
| 平台订单与订单项 | 订单接入服务 | `orders` / `order_items` | 财务或履约服务改写平台事实 |
|
||||
| 平台原始报文 | 各平台适配器 | 原始表 / `raw_payload_json` | 覆盖历史报文 |
|
||||
| 中文内部 SKU | 商品身份服务 | `internal_skus` | 各业务表各自发明同义 SKU |
|
||||
| 平台字段到内部 SKU | 映射服务 | `internal_sku_mappings` | 按名称猜测渠道 |
|
||||
| 主渠道与兜底 | 路由服务 | `sku_channel_routes` | UI 根据商品前缀筛选 |
|
||||
| 当前履约状态 | 履约状态服务 | `fulfillments` | 多服务直接更新订单项 |
|
||||
| 执行尝试 | 履约尝试服务 | `fulfillment_attempts` | 用最大 ID 猜当前任务 |
|
||||
| 当前异常 | 履约异常服务 | `fulfillment_issues` | 自由 JSON 字符串代替问题模型 |
|
||||
| 标准商品 | 商品主数据服务 | `product_catalog` | 用商品来源反推渠道 |
|
||||
| 平台商品到财务商品 | 商品归一服务 | `channel_product_mappings` | 人工在多个页面重复维护 |
|
||||
| 成本规则 | 成本中心 | `cost_versions` | 业务表直接改金额 |
|
||||
| 成本事实 | 成本快照服务 | `cost_snapshots` | 改价覆盖历史 |
|
||||
| 销售事实 | 事实服务 | `sales_daily_facts` | 报表直接从订单表现算另一套 |
|
||||
| 总账 | 总账服务 | `finance_journal_*` | 业务端直接写凭证 |
|
||||
| 页面投影 | 只读投影 | `v_*` / materialized view | 页面自行拼口径 |
|
||||
|
||||
## 五、当前系统的问题证据
|
||||
|
||||
2026-11-08 生产只读核对结果:
|
||||
|
||||
- 生产迁移 `146`,本地开发基线迁移 `150`。
|
||||
- 启用标准商品 `1127`:`aff:` 30、`tpl:` 903、`tpv:` 46、`man:` 148。
|
||||
- `man:` 商品中只有 105 个当前主渠道为人工;41 个已走其他主渠道,2 个无主渠道。
|
||||
- 人工页头部显示 `107`,商品列表显示 `148`,相差的 41 个就是跨渠道旧商品。
|
||||
- 41 个跨渠道 `man:` 商品中:卡券 33、自动发货 3、接单平台 2、统一结算 3。
|
||||
- 另有 2 个 `man:` 商品无主渠道,但保留人工配置,属于人工兜底。
|
||||
- 自动发货的 3 个商品中,`man:suit_shadow_gothic` 与 `man:套装-狂沙舞者`
|
||||
有有效人工兜底配置,必须保持 active,但不能出现在“人工客服”页签。
|
||||
- 最终可归档对象是 36 个:卡券 33、接单平台 2、无人工兜底的自动发货 1。
|
||||
- 生产活动履约视图共 31744 行,其中 1226 行仍有结构化异常:
|
||||
- 用户退款 532;
|
||||
- 平台取消 126;
|
||||
- 缺内部 SKU 29;
|
||||
- 缺渠道 26;
|
||||
- 人工配置缺失 19;
|
||||
- 其余为载体重试、人工复核、状态不一致等。
|
||||
- 当前任务重复为 0,多个活跃工单为 0,说明“当前尝试”约束已经开始生效。
|
||||
|
||||
这些问题证明:
|
||||
|
||||
1. 旧模型不是完全不可用,但多个真源同时存在。
|
||||
2. 页面已经出现“总览按渠道、列表按来源”的口径分叉。
|
||||
3. 历史清理功能曾经存在,但在后续重构中被移除。
|
||||
4. 文档基线和生产基线不一致,旧文档仍在被当作现行依据。
|
||||
|
||||
## 六、数据保留与重建边界
|
||||
|
||||
本次重构允许清理派生数据,但必须严格分级。
|
||||
|
||||
### A 级:永久保留,不得删除或重写历史
|
||||
|
||||
- `orders`
|
||||
- `order_items` 的原始平台字段
|
||||
- 平台原始订单表与原始报文字段
|
||||
- 平台售后、退款、支付事实
|
||||
- `work_orders`、`work_order_shares`、`work_order_events`
|
||||
- `fulfillment_tasks` 中真实执行与结果记录
|
||||
- `fulfillments`、`fulfillment_attempts`、`fulfillment_issues`
|
||||
- `fulfillment_state_events`
|
||||
- `worker_wallet_ledgers`、`fund_accounts` 的真实资金流水
|
||||
- `admin_audit_logs`
|
||||
- 财务期间、已确认退款和真实资金账户
|
||||
|
||||
A 级数据只能追加新事件或做字段兼容迁移,不能为了“模型整齐”重写历史事实。
|
||||
|
||||
### B 级:业务输入,必须迁移而不是重建
|
||||
|
||||
- `internal_sku_mappings`
|
||||
- `sku_channel_routes` 中的有效主渠道与显式兜底
|
||||
- `work_product_rules` 及模板匹配配置
|
||||
- `manual_fulfillment_configs`
|
||||
- `product_catalog` 中仍有效的标准商品
|
||||
- `channel_product_mappings`
|
||||
- `cost_versions`
|
||||
- 第三方平台配置、店铺配置和账号配置
|
||||
|
||||
迁移时必须人工核对冲突,不得自动选最新或按出现次数猜测。
|
||||
|
||||
### C 级:可删除并从 A/B 级重建
|
||||
|
||||
- `cost_snapshots`
|
||||
- `cost_exceptions`
|
||||
- `sales_daily_facts`
|
||||
- `finance_journal_entries` / `finance_journal_lines` 仅允许在空库或明确废弃的测试库重建;
|
||||
已有环境的已过账凭证不得删除,只能追加反向/补差凭证
|
||||
- `v_fulfillment_item_state` 及其依赖投影
|
||||
- 商品统计投影、渠道统计投影、页面汇总缓存
|
||||
- 管道水位与失败重试状态
|
||||
|
||||
重建前必须备份;重建后必须通过 A/B 级数据守恒检查。
|
||||
|
||||
### D 级:兼容期结束后删除
|
||||
|
||||
- `product_channel_capabilities`
|
||||
- 已冻结的 `internal_sku_channels`
|
||||
- `sku_channel_rules` 中由 `internal_sku_mappings` 和 `sku_channel_routes` 取代的规则
|
||||
- `manual_sku_registry` 中可由配置重建的登记行
|
||||
- 订单项上的 `legacy_*` 重复履约结果字段,在审计留存期结束后删除
|
||||
- 商品表中的历史来源前缀判断代码
|
||||
- 旧路由补丁脚本和一次性迁移工具
|
||||
|
||||
## 七、UI 与 API 统一口径
|
||||
|
||||
“标准商品目录”的页签必须表示**当前路由状态**,不是商品来源:
|
||||
|
||||
```text
|
||||
全部
|
||||
自动发货
|
||||
接单平台
|
||||
第三方卡券
|
||||
人工客服
|
||||
统一结算
|
||||
未路由
|
||||
```
|
||||
|
||||
商品来源作为独立列展示:
|
||||
|
||||
```text
|
||||
aff: / tpl: / wo: / tpv: / man:
|
||||
```
|
||||
|
||||
列表必须显示:
|
||||
|
||||
```text
|
||||
商品
|
||||
来源
|
||||
当前主渠道
|
||||
兜底渠道
|
||||
当前状态
|
||||
成本状态
|
||||
```
|
||||
|
||||
以下行为禁止:
|
||||
|
||||
- “人工客服”页签显示当前主渠道不是 `manual` 的商品。
|
||||
- 用 `product_catalog.category` 决定路由或页签。
|
||||
- 用 `man:` 前缀判断当前人工订单量。
|
||||
- 通过商品名称或标题自动猜测渠道。
|
||||
- 同一页面使用两个不同统计 SQL。
|
||||
|
||||
统一读模型至少提供:
|
||||
|
||||
```text
|
||||
product_id
|
||||
canonical_sku
|
||||
canonical_name
|
||||
source_kind
|
||||
internal_sku_id
|
||||
current_primary_channel
|
||||
fallback_channels
|
||||
manual_config_id
|
||||
current_status
|
||||
has_active_cost
|
||||
```
|
||||
|
||||
## 八、存量数据处理方案
|
||||
|
||||
### 8.1 已被其他渠道接管的 `man:` 商品
|
||||
|
||||
处理原则:
|
||||
|
||||
1. 先确认目标主渠道已有活动商品。
|
||||
2. 将仍指向旧 `man:` 的人工兜底改指目标商品。
|
||||
3. 保留订单项、成本版本、成本快照和历史引用。
|
||||
4. 只把旧 `man:` 商品置为 `archived`,不硬删除。
|
||||
5. 如果历史成本快照必须保留旧商品维度,不改变历史快照。
|
||||
|
||||
预期清理范围:
|
||||
|
||||
- 33 个卡券重复商品;
|
||||
- 2 个接单平台重复商品;
|
||||
- 1 个没有有效人工兜底配置的自动发货重复商品。
|
||||
|
||||
以上共 36 个 `manual_normalization` 旧商品,属于可确认归档对象。
|
||||
|
||||
另外 2 个自动发货 `man:` 商品有有效人工兜底配置,不归档、不进入人工主渠道页签。
|
||||
|
||||
### 8.2 统一结算商品
|
||||
|
||||
3 个当前主渠道为 `on_account` 的商品不是人工商品。
|
||||
|
||||
处理方式:
|
||||
|
||||
- 保留商品和历史引用;
|
||||
- 增加统一结算分类;
|
||||
- 从人工页签移出;
|
||||
- 由 `on_account` 路由与结算成本口径管理。
|
||||
|
||||
### 8.3 无主渠道但有人工配置的商品
|
||||
|
||||
目前有 2 个,属于合法人工兜底。
|
||||
|
||||
处理方式:
|
||||
|
||||
- 保留;
|
||||
- 在商品页显示“未路由 / 人工兜底”;
|
||||
- 不计入“已分配”;
|
||||
- 由运营决定是否补主渠道。
|
||||
|
||||
### 8.4 历史清理功能
|
||||
|
||||
`31b6d2d6` 曾实现跨渠道 `man:` 商品归档,但 `974044a4` 在人工 SKU 重构中删除了入口,
|
||||
并把筛选测试改成保留所有 `man:` 商品。
|
||||
|
||||
后续清理必须:
|
||||
|
||||
- 作为一次性数据迁移,而不是临时页面按钮;
|
||||
- 有 dry-run、数量、样本和备份;
|
||||
- 有真实 PostgreSQL 集成测试;
|
||||
- 不依赖“运营记得点清理”。
|
||||
|
||||
## 九、目标迁移路线
|
||||
|
||||
| 阶段 | 状态 | 是否改生产数据 |
|
||||
| --- | --- | --- |
|
||||
| 0 口径冻结与文档收口 | 已完成 | 否 |
|
||||
| 1 只读审计与领域约束 | 本地完成 | 否 |
|
||||
| 2 建立目标身份与投影 | 本地完成 | 只新增结构 |
|
||||
| 3 迁移路由与商品配置 | 本地完成,生产未执行 | 是,需备份 |
|
||||
| 4 重建履约模型 | 本地完成,生产未执行 | 是,需备份 |
|
||||
| 5 重建财务派生数据 | 本地完成,生产未执行 | 是,需备份与对账 |
|
||||
| 6 停止旧写路径并删除兼容层 | 履约侧已完成,全局未开始 | 是,需观察期结束 |
|
||||
|
||||
### 阶段 0:口径冻结与文档收口
|
||||
|
||||
状态:本次完成。
|
||||
|
||||
产出:
|
||||
|
||||
- 本文件成为唯一权威。
|
||||
- 旧业务架构文档全部归档。
|
||||
- `docs/README.md` 只保留入口。
|
||||
- `AGENTS.md` 固定执行规则。
|
||||
|
||||
验收:
|
||||
|
||||
- 活跃文档中不再存在竞争性的架构结论。
|
||||
- 所有 Agent 和开发者从本文件开始。
|
||||
|
||||
### 阶段 1:只读审计与领域约束
|
||||
|
||||
目标:
|
||||
|
||||
- 不改变生产数据,先建立全量审计。
|
||||
- 核对内部 SKU、路由、商品、履约和财务的冲突。
|
||||
|
||||
工作:
|
||||
|
||||
1. 建立内部 SKU 重复与合并候选报告。
|
||||
2. 建立商品来源与主渠道冲突报告。
|
||||
3. 建立无主渠道、多主渠道、无载体和退款混入履约报告。
|
||||
4. 建立成本快照无法重建报告。
|
||||
5. 为每类冲突定义责任角色和处理动作。
|
||||
|
||||
验收 SQL:
|
||||
|
||||
```text
|
||||
同一内部 SKU 主渠道数 > 1 必须为 0
|
||||
启用商品无 source_kind 必须为 0
|
||||
人工配置指向非 man 商品 必须为 0
|
||||
当前主渠道非 manual 的 man 商品出现在人工页 必须为 0(保留则必须有显式兜底)
|
||||
assigned 且 carrier_status=missing 必须进入异常队列
|
||||
退款/取消出现在普通履约队列 必须为 0
|
||||
同一订单项当前尝试 > 1 必须为 0
|
||||
```
|
||||
|
||||
### 阶段 2:建立目标身份与投影
|
||||
|
||||
目标:
|
||||
|
||||
- 建立 `internal_skus`。
|
||||
- 为 `product_catalog` 增加 `source_kind` 和 `internal_sku_id`。
|
||||
- 建立统一商品投影 `v_product_current`。
|
||||
- 建立统一履约投影 `v_fulfillment_current`。
|
||||
|
||||
本地已完成身份表、商品来源字段和 `v_product_current`,并已切换商品列表、
|
||||
总览与渠道映射的读取口径。生产未执行。
|
||||
|
||||
本地产出:
|
||||
|
||||
- 变更前备份:`backups/postgres/order_site-pre-unified-20261108.dump`,
|
||||
SHA-256 `661d7751d76fcd7db80af92e97d1e84245a25c60b0ec76b8d83ca930fcbb5142`。
|
||||
- 迁移 `147`:统一内部 SKU、标准商品来源与履约路由;建立 `internal_skus`、
|
||||
`sku_channel_routes`、`v_product_current` 和商品来源约束,完成旧路由读取面下线。
|
||||
- 迁移 `148`:履约状态、配置、载体和当前尝试硬切到 `fulfillments`;
|
||||
任务/工单只维护尝试历史;订单项旧履约列冻结并统一读取 `v_order_item_current`。
|
||||
- 迁移 `149`:建立 `v_finance_order_item_scope`,统一销售事实、重建与审计的收入、
|
||||
退款、商品、渠道和业务日口径,并增加销售凭证按日查询索引。
|
||||
- 迁移 `150`:核销任务允许订单级来源;`收到订单后`由订单入库事件直接入队,
|
||||
使用 `order:<订单ID>` 去重,不读取履约渠道、载体或订单项状态。
|
||||
- 商品列表、总览、渠道映射和商品下拉统一读取商品当前渠道。
|
||||
- 运行期代码停止写入 `product_channel_capabilities`,该表仅保留到兼容期结束。
|
||||
- 只读审计:`npm run audit:product-routing -- --strict`。
|
||||
- 本地严格审计关键异常归零:孤儿人工商品、多主路由、`man/tpv` 缺内部 SKU、非法来源。
|
||||
- 自动/卡券/接单主渠道商品的人工配置均保留为显式 `fallback`,没有被误升为人工主渠道。
|
||||
- 1 个无主路由、无人工配置、无启用映射的 `man:` 商品已归档,未删除历史引用。
|
||||
- 旧 `internal_sku_channels` 已冻结:运行时不再读、不再写,也不再有视图或触发器依赖。
|
||||
- 空库从迁移 `001` 顺序执行到 `150` 已通过;新库不再保留任何旧履约影子同步触发器。
|
||||
- 无主路由的活动商品会进入“未路由”,不自动猜测渠道。
|
||||
|
||||
当前本地仍需业务处理的数据:
|
||||
|
||||
- 待分类订单项尚未命中内部 SKU 映射的,进入 `missing_channel`;
|
||||
- 已分配人工订单项缺少启用人工配置的,进入 `manual_config_missing`。
|
||||
|
||||
验收:
|
||||
|
||||
- 旧字段与新投影差异有清单。
|
||||
- 商品列表和总览读取同一投影后数量一致。
|
||||
- 目前 41 个跨渠道 `man:` 商品和 2 个无主渠道商品全部能分类。
|
||||
|
||||
### 阶段 3:迁移路由与商品配置
|
||||
|
||||
状态:本地完成,生产未执行。按确认后的硬切换方案,不保留双读、双写和旧表运行期兼容。
|
||||
|
||||
目标:
|
||||
|
||||
- 将 `internal_sku_channels` 迁移到 `sku_channel_routes`。
|
||||
- 将人工配置、卡券配置、自动发货配置和接单模板配置关联到 `internal_sku_id`。
|
||||
- 清理旧商品和错误兜底。
|
||||
|
||||
规则:
|
||||
|
||||
- 一个内部 SKU 一个主渠道。
|
||||
- 其余渠道全部显式 `fallback`。
|
||||
- 自动创建的标准商品必须有 `source_kind`。
|
||||
- 历史 `man:` 清理只归档,不删除。
|
||||
|
||||
验收:
|
||||
|
||||
- 路由迁移前后主渠道结果一致。
|
||||
- 人工页数量等于当前人工渠道商品数。
|
||||
- 卡券和统一结算不再出现在人工页。
|
||||
- 运行时 `internal_sku_channels` 读写点为 `0`。
|
||||
- 旧路由表和影子同步触发器已停用,后续只通过 `sku_channel_routes` 修改路由。
|
||||
|
||||
### 阶段 4:重建履约模型
|
||||
|
||||
状态:本地完成,生产未执行。
|
||||
|
||||
目标:
|
||||
|
||||
- 以 A 级原始订单和真实载体为输入,重建 `fulfillments`、`fulfillment_attempts`、
|
||||
`fulfillment_issues`。
|
||||
- 旧订单项履约状态字段已停止读写并冻结留档。
|
||||
|
||||
本地产出:
|
||||
|
||||
1. `fulfillments` 增加 `status / source / locked / pending_* / config / canonical_product`
|
||||
等正式字段,并从订单项存量状态一次性回填。
|
||||
2. 历史任务和工单补齐到 `fulfillment_attempts`,不再从订单项回调状态。
|
||||
3. `transitionFulfillmentStateWithExecutor`、渠道分配和配置关联全部改写正式表。
|
||||
4. `v_fulfillment_item_state` 只投影 `fulfillments + fulfillment_attempts +
|
||||
fulfillment_issues + sku_channel_routes`。
|
||||
5. 全部业务读 SQL 切到 `v_order_item_current`,禁止直接读取订单项旧状态列。
|
||||
6. 状态事件、任务尝试、工单尝试和配置变化触发器统一围绕正式履约表工作。
|
||||
7. 真实 PostgreSQL 集成测试覆盖状态写入、幂等、事件留痕、当前尝试和配置关联。
|
||||
8. 新空库 `001 → 150` 与迁移 `145` 备份升级库均完成硬切验证。
|
||||
|
||||
验收:
|
||||
|
||||
- 同一订单项只有一个当前尝试。
|
||||
- 所有 `assigned` 都有明确 `carrier_status` 或开放 issue。
|
||||
- 退款、取消进入售后队列。
|
||||
- 页面按钮作用域与后端动作一致。
|
||||
- 运行时对 `order_items.legacy_fulfillment_*` 和 `legacy_canonical_product_id`
|
||||
的读写点均为 `0`。
|
||||
- 旧 `sync_fulfillment_shadow*` 函数和旧影子同步触发器均为 `0`。
|
||||
|
||||
### 阶段 5:重建财务派生数据
|
||||
|
||||
状态:本地完成,生产未执行。
|
||||
|
||||
本地提前发现并修复:销售凭证增量同步读取当日余额时,必须统计同一天全部
|
||||
`sales_revenue_adjustment / sales_refund_adjustment / sales_cost_adjustment`,
|
||||
不能只按原始凭证的 `ref_id = 日期` 读取,否则重复同步会累计重复补记。
|
||||
|
||||
目标:
|
||||
|
||||
- 保留 A 级订单、退款事实和 B 级配置。
|
||||
- 删除可重建的 estimated 成本快照和销售事实;
|
||||
- 已过账总账保持 append-only,通过反向/补差凭证收敛到新事实;
|
||||
- 保留真实退款、人工支出、资金流水、actual 快照和对账原始批次。
|
||||
|
||||
重建顺序:
|
||||
|
||||
```text
|
||||
product normalization
|
||||
→ cost snapshot
|
||||
→ sales facts
|
||||
→ journal adjustment
|
||||
→ reconciliation
|
||||
```
|
||||
|
||||
本地产出:
|
||||
|
||||
- `v_finance_order_item_scope` 成为销售范围唯一读模型。
|
||||
- `finance:rebuild-derived` 默认 dry-run,执行需要
|
||||
`--execute --confirm=REBUILD_DERIVED`。
|
||||
- 重建前后校验订单数、订单项数、订单收入、退款、人工支出和资金流水,不守恒立即失败。
|
||||
- 删除旧的 `finance-cutover-v2.ts`;该脚本会删除退款、人工支出和资金流水,违反 A 级保留规则。
|
||||
- 本地重建区间 `2026-10-30 → 2026-11-08`:
|
||||
- 财务范围 8 个订单项,收入 `8000` 分,退款 `0`;
|
||||
- 销售事实收入 `8000` 分,退款 `0`,成本 `0`;
|
||||
- 总账收入 `8000` 分,退款 `0`,成本 `0`;
|
||||
- 第二次重建总账调整为 `0`,证明幂等;
|
||||
- 严格审计关键异常 `0`;
|
||||
- 遗留 2 个待归一商品项和 2 个 `manual_cost_missing`,均有结构化异常,不自动猜测。
|
||||
- 重建前派生数据备份在本地 schema
|
||||
`finance_rebuild_backup_20261108_1915`,不属于生产迁移结构。
|
||||
|
||||
验收命令:
|
||||
|
||||
```bash
|
||||
npm run finance:rebuild-derived
|
||||
npm run finance:rebuild-derived -- --execute --confirm=REBUILD_DERIVED
|
||||
npm run audit:finance -- --strict
|
||||
```
|
||||
|
||||
验收:
|
||||
|
||||
- 收入总额守恒。
|
||||
- 退款总额守恒。
|
||||
- 成本快照无重复。
|
||||
- 事实与总账可对平。
|
||||
- 所有成本缺失有结构化异常。
|
||||
|
||||
### 阶段 6:停止旧写路径并删除兼容层
|
||||
|
||||
状态:本地运行期旧写路径已收敛;兼容数据表和冻结字段保留到生产观察期结束。
|
||||
|
||||
本地已完成:
|
||||
|
||||
- 数据库迁移由 `154–168` 重组为 `147–149`:内部 SKU/商品路由、履约执行、
|
||||
财务派生三段各一个文件;未迁入旧 `dev` 的 `147–153`。
|
||||
- 迁移 `150` 增加订单级收单核销来源。订单入库后仅按平台策略投递
|
||||
`order_received` 任务,不再依赖渠道或载体;旧 `unmatched` 开启时自动继承一次。
|
||||
- 删除会直接写已改名订单项列的 `reclassify-post-cutover.ts` 和
|
||||
`merge-duplicate-products.ts`。
|
||||
- 删除重复的 `finance:rebuild-cutover` 入口,部署脚本统一调用
|
||||
`finance:rebuild-derived --execute --confirm=REBUILD_DERIVED`。
|
||||
- 删除失效的 `finance:sync` 脚本别名。
|
||||
- 商品来源筛选、归一纠正、成本分支、人工 SKU 清单统一读取
|
||||
`product_catalog.source_kind` 与 `internal_sku_id`。
|
||||
- 商品创建写入口显式写入 `source_kind`,数据库约束只允许
|
||||
`affiliate_dash / work_order / third_party_voucher / manual / unclassified`。
|
||||
- `product_channel_capabilities`、`manual_sku_registry`、`internal_sku_channels` 和历史
|
||||
`legacy_*` 字段继续保留为审计留存,不在生产观察期前删除。
|
||||
|
||||
生产升级演练(本地临时库):
|
||||
|
||||
- 输入:`backups/postgres/order_site-20261106-192520.dump`,备份迁移 `145`;
|
||||
恢复后执行 `146 → 150`。
|
||||
- 数据规模:订单 `456777`、订单项 `456762`、商品 `1572`、正式履约 `456762`。
|
||||
- 升级和迁移全部成功;恢复时唯一失败的是备份自身依赖顺序导致的函数索引,
|
||||
在函数恢复后按原定义补建,随后迁移 `148` 正常删除该索引。
|
||||
- 财务重建前存在旧事实/总账差异;执行一次 `finance:rebuild-derived --execute` 后,
|
||||
销售范围 `21653` 项、收入 `170241674` 分、退款 `77370` 分、成本 `104881187` 分,
|
||||
事实与总账完全对平,严格审计 `critical: []`。
|
||||
- 第二次重建返回 `adjusted: 0`,证明总账调整幂等。
|
||||
- 原始订单 `456777`、订单项 `456762`、订单收入 `3646267730` 分、退款 `7` 笔 /
|
||||
`77370` 分、资金流水 `2` 条在两次重建前后完全守恒。
|
||||
- 仍需运营处理:`8` 个只有人工兜底、没有主路由的配置,`162` 个待归一订单项,
|
||||
以及 `476` 个已结构化标记的待履约异常。上述数据不做自动猜测。
|
||||
|
||||
只有前五个阶段持续稳定后才允许:
|
||||
|
||||
- 删除 `product_channel_capabilities`。
|
||||
- 删除 `manual_sku_registry` 的派生行。
|
||||
- 删除订单项已冻结的 `legacy_*` 重复渠道字段。
|
||||
- 删除商品前缀业务判断。
|
||||
- 删除旧管道、旧同步脚本和兼容 API。
|
||||
|
||||
禁止一次性同时删除旧字段和旧数据。
|
||||
|
||||
## 十、测试与生产门禁
|
||||
|
||||
以下检查必须进入代码测试或每日生产审计。
|
||||
|
||||
### 数据模型
|
||||
|
||||
- 一个内部 SKU 最多一个 primary route。
|
||||
- 一个 fulfillment 最多一个 current attempt。
|
||||
- 一个订单项最多一个 fulfillment。
|
||||
- issue code 只能来自受控枚举。
|
||||
- assigned 必须有 route 和 channel。
|
||||
|
||||
### 商品
|
||||
|
||||
- 每个 active product 必须有 `source_kind`。
|
||||
- `source_kind` 与渠道专用商品类型一致。
|
||||
- 人工页数量必须等于当前 primary manual 商品数。
|
||||
- 总览、列表、导出必须使用同一投影。
|
||||
- 旧 `man:` 商品不得在没有主渠道或收口状态时继续显示为人工。
|
||||
|
||||
### 履约
|
||||
|
||||
- 用户退款、平台取消不得出现在普通补载体队列。
|
||||
- 同一订单项不得同时有活跃工单和活跃自动发货任务。
|
||||
- 当前尝试必须是已存在且唯一的历史尝试。
|
||||
- 所有重试动作必须按 issue_code 限定作用域。
|
||||
|
||||
### 财务
|
||||
|
||||
- 成本事实不可变,只能新增、替代或冲减。
|
||||
- 事实、总账、退款和订单收入必须可对平。
|
||||
- 财务重建必须从 A 级数据可重复执行。
|
||||
|
||||
### 文档
|
||||
|
||||
- 任何架构变更必须更新本文件。
|
||||
- 旧文档不得再标记为“现行”。
|
||||
- 文档中的迁移号和代码基线必须与生产一致。
|
||||
|
||||
## 十一、禁止事项
|
||||
|
||||
1. 不删除原始订单、平台报文、真实工作单、真实资金流水和审计日志。
|
||||
2. 不根据商品名称、前缀或分类猜测履约渠道。
|
||||
3. 不让多个服务同时写履约核心状态。
|
||||
4. 不用自由 JSON 字符串代替结构化 issue。
|
||||
5. 不以“最新”“出现最多”或“看起来像”解决映射冲突。
|
||||
6. 不在没有投影和差异报告时切换读写路径。
|
||||
7. 不把历史清理做成依赖运营点击的临时按钮。
|
||||
8. 不为兼容旧口径保留第二份“现行文档”。
|
||||
9. 不在一次发布中同时完成数据清理、模型切换和旧字段删除。
|
||||
10. 不把“已经跑过测试”当成生产口径正确的证明。
|
||||
|
||||
## 十二、执行后的文档结构
|
||||
|
||||
```text
|
||||
AGENTS.md
|
||||
常驻规则、任务路由、数据安全边界
|
||||
|
||||
docs/README.md
|
||||
文档总入口
|
||||
|
||||
docs/统一订单履约与财务模型-权威版.md
|
||||
唯一业务与架构权威
|
||||
|
||||
docs/部署启动与数据库重建.md
|
||||
docs/数据库备份与恢复.md
|
||||
docs/数据库SQL约束与运维.md
|
||||
运维参考
|
||||
|
||||
docs/91卡券/
|
||||
docs/发货平台-2/
|
||||
docs/抖音-码速达/
|
||||
docs/行业电子凭证/
|
||||
docs/affiliate-dash-发货平台/
|
||||
外部协议与平台参考,不得覆盖本文件
|
||||
|
||||
docs/archive/
|
||||
历史方案、旧口径和一次性分析
|
||||
```
|
||||
|
||||
## 十三、当前下一步
|
||||
|
||||
本地阶段 0–6 已按硬切方案完成,生产仍停留在迁移 `146`。后续顺序固定为:
|
||||
|
||||
1. 生产升级只按 [生产升级操作手册](生产升级操作手册.md) 执行。
|
||||
2. 升级前备份必须完成隔离恢复验证;恢复验证未通过时禁止迁移。
|
||||
3. `147 → 150` 作为同一硬切迁移组执行,迁移后刷新统计并完成商品、履约、
|
||||
财务三组严格审计;无法确定的数据进入未路由或待分类,不做猜测。
|
||||
4. 执行 `finance:rebuild-derived` 的 dry-run,核对 A 级数据守恒后,
|
||||
再按窗口执行 `--execute --confirm=REBUILD_DERIVED`,并验证第二次重建幂等。
|
||||
5. 观察一个完整财务期间,确认页面、履约、事实和总账持续对平。
|
||||
6. 观察期结束后,再单独发布兼容表、旧脚本别名和 `legacy_*` 字段的删除迁移。
|
||||
|
||||
+10
-5
@@ -219,7 +219,7 @@ docker compose ps
|
||||
docker compose logs -f backend
|
||||
```
|
||||
|
||||
## 财务/成本上线后的初始化(迁移 103–105)
|
||||
## 财务/成本上线后的初始化(当前开发基线 150)
|
||||
|
||||
代码与迁移只负责建表;**存量订单回填、备用金账户、积分余额、商品目录、人工 SKU 不会自动创建**。
|
||||
部署成功后按「回填 → 商品初始化 → 财务同步 → 验收」四步走:
|
||||
@@ -228,13 +228,13 @@ docker compose logs -f backend
|
||||
|
||||
```bash
|
||||
bash deploy/post-deploy.sh --dry-run # 先看计划与待回填量
|
||||
bash deploy/post-deploy.sh --only=backfill # ① 收入回填 + ② 履约方式回填
|
||||
bash deploy/post-deploy.sh --only=backfill # ① 收入回填 + ② 订单级收单核销补投
|
||||
```
|
||||
|
||||
> 不要在商品目录为空时直接跑 `--only=sync`:财务同步会为每个未归一订单项写一条
|
||||
> `product_mapping_missing` 成本异常(生产规模 90 天实测约 36 万条),后台异常队列会被淹没。
|
||||
|
||||
脚本包含 `revenue:backfill`、渠道/成本管道重建(`finance:rebuild-cutover`)与只读验收;任何一步都能重跑,
|
||||
脚本包含 `revenue:backfill`、财务派生数据重建(`finance:rebuild-derived`)与只读验收;任何一步都能重跑,
|
||||
`--only=backfill|sync|verify` 可单独执行。
|
||||
|
||||
> 生产 backend 镜像没有 `tsx` 与 `scripts/`,脚本通过 `tools` 镜像执行
|
||||
@@ -255,14 +255,15 @@ bash deploy/post-deploy.sh --only=backfill # ① 收入回填 + ② 履约
|
||||
商品归一完成后执行:
|
||||
|
||||
```bash
|
||||
bash deploy/post-deploy.sh --only=sync # ③ 成本快照 / 销售事实
|
||||
bash deploy/post-deploy.sh --only=sync # ③ 成本快照 / 销售事实 / 总账调整
|
||||
```
|
||||
|
||||
> 工具镜像每次运行都会重建(层缓存下只需几秒),确保 `git pull` 后执行的是当前脚本。
|
||||
|
||||
### 4. 总账与验收
|
||||
|
||||
5. 财务 → 总账与对账 → 同步销售事实到总账 → 检查试算平衡;按需关账/导入平台账单。
|
||||
5. 财务 → 总账与对账 → 检查试算平衡;`post-deploy.sh` 已按日追加销售事实调整凭证,
|
||||
之后按需关账/导入平台账单。
|
||||
|
||||
```bash
|
||||
bash deploy/post-deploy.sh --only=verify # ④ 只读验收
|
||||
@@ -287,6 +288,10 @@ cd /home/order_site && git pull
|
||||
bash deploy/ubuntu-deploy.sh # 想看这次会做什么:加 --dry-run
|
||||
```
|
||||
|
||||
如果本次包含数据库迁移、履约/商品路由切换或财务派生数据重建,不要直接执行上述命令,
|
||||
必须按照 [生产升级操作手册](生产升级操作手册.md) 的停写、备份验证、迁移、审计、
|
||||
财务重建和验收顺序执行。
|
||||
|
||||
后端启动时自动执行未应用的增量迁移,一般不必单独跑迁移。
|
||||
|
||||
确认:
|
||||
|
||||
Reference in New Issue
Block a user