Files
order_site/docs/项目全量分析报告-2026-10-17.md
T

21 KiB
Raw Blame History

order_site 项目全量分析报告(2026-10-17)

状态:参考(2026-10-17 全量分析快照)。架构与风险结论可参考;财务、备用金、显示名等实施状态以 README.md 为准。 代码基线:main @ 6850bc64(分析当时;当前基线见 README) 复核范围:后端、前端、数据库迁移、部署脚本、现行文档 复核方式:源码走查 + 类型检查 + Lint + 格式检查 + 全量测试 + 生产构建 + 2026-10-17 生产库只读聚合(default_transaction_read_only=on) 说明:本次没有做全量数据克隆;历史数据量引用自生产库只读聚合,已在文中标注。


一、结论速览

# 结论 影响
1 系统已是三来源订单履约 + 众包接单 + 寄卖仓库 + 凭证核销平台,不再是单一“快手自动发货”工具 文档与新人认知必须先统一来源模型
2 来源只有三个:kuaishou-91、pdd、douyin-mashida;91 回调与快手 send-code 是同一个 kuaishou-91 来源的两条数据通道 代码已正确使用 kuaishou-91 适配器;文档曾把二者写成两个来源,现已校正
3 工程纪律处于同类项目上游:严格 TS、99 个渐进迁移、SQL 护栏、回调验签、日志脱敏、生产配置校验、按需部署 具备继续承载财务系统的工程基础
4 最大风险集中在四处:资金门禁、Webhook 失败恢复、公开接口凭据、并发锁序 这四处会直接影响钱、单、凭证与账号安全
5 财务系统不能直接长在 worker_wallet_ledgers 上;现有表是“业务钱包流水”,不是会计总账 需要先建复式记账与对账底座,再接现有资金动作
6 前端与数据库事务层的测试仍偏薄;部分后端测试是源码字符串断言 财务系统必须补真实 PostgreSQL 集成测试与金额守恒测试

二、来源模型:三个来源,不是一个来源加另一个来源

flowchart LR
  A["kuaishou-91<br/>91 回调(订单骨架)"] --> O[("orders / order_items")]
  B["kuaishou-91<br/>快手 send-code(补全/兜底)"] --> O
  C["pdd"] --> O
  D["douyin-mashida"] --> O
  O --> M["product-match 引擎<br/>3 个来源适配器"]
  M --> W[("work_orders")]
  O --> F[("fulfillment_tasks")]
sourceKey 数据通道 角色
kuaishou-91 91 回调 订单骨架权威源
kuaishou-91 快手 send-code 商品/SKU/店铺补全源与兜底源
pdd 拼多多同步 两段式原始订单暂存后消费
douyin-mashida 抖音码速达推送 抖店订单、DYC 券、H5/兑换页

代码事实:

  • 来源键定义:apps/backend/src/services/product-match/types.ts:7
  • 适配器:apps/backend/src/services/product-match/adapters/kuaishou-91.ts
  • 注册表:apps/backend/src/services/product-match/adapters/registry.ts:69
  • 快手 send-code 的权威注释:apps/backend/src/services/worker-platform/sync-work-orders-from-send-code.ts:5

结论:91 与快手 send-code 必须继续共用一个 kuaishou-91 适配器。 拆开会导致同一店铺键空间、同一订单骨架被重复匹配,直接破坏“一个订单项一个执行载体”的不变式。


三、架构与运行形态

层 现状
后端 Node 22(生产)/ Express 5 / TypeScript 6;routes → services → repositories → pg
前端 React 19 / Vite 8 / Ant Design 6 / TanStack Query 5
数据库 PostgreSQL 16,node-pg-migrate,启动时自动迁移
网关 Caddy,统一压缩、静态缓存、反代
部署 Docker Compose;ubuntu-deploy.sh 按 Git 改动只重建变化的一端
运行 单实例;限流、调度器、SSE 订阅、列表缓存均在进程内存
存储 生产阿里云 OSS;开发 MinIO

后端入口与路由挂载:apps/backend/src/app.ts:109。抖音消息推送必须在全局 body parser 之前挂载,以保留原始报文验签:apps/backend/src/app.ts:42。

前端是三个入口共用一套构建产物:

  • 后台:HashRouter
  • 打手端:独立域名 worker.khhao.com
  • 买家侧:/claim、/h5、/redeem 独立路径路由

四、当前规模(实测)

指标 后端 前端
源码文件 / 行数 371 / 77,811 179 / 52,812
CSS — 7,448 行
测试文件 / 行数 109 / 16,249 26 / 2,221
测试/源码比 约 20.9% 约 4.2%
接口声明 270(后台 197、打手 51) —
测试结果(本次) 740 项:737 pass / 3 skipped / 0 fail 143 pass / 0 fail
生产构建 通过 通过(主 chunk 524.69 kB,有 >500 kB 警告)

数据库:99 个迁移、53 张表。

提交历史:1,069 commits,作者高度集中(git shortlog 前两位 824 / 250),bus factor 约等于 1。


五、核心业务链路

5.1 进单与匹配

  1. 三个来源统一调用 upsertOrderFromSource。
  2. 按 (provider, platform, platformOrderId) 做 pg_advisory_xact_lock 去重。
  3. resolveOrderItemForFulfillment 解析履约载体:affiliate_dash 或 manual_dispatch。
  4. syncWorkerOrdersForSourceOrder 用 product-match 引擎匹配接单模板,生成工单。

关键点:

  • 匹配引擎是纯函数,来源差异只在适配器。
  • 并列最高分返回 ambiguous,不猜。
  • 抖音 sku_code 恒为内部 SKU;引流标题只进 snapshot.productTitle,永不参与匹配。
  • 抖音命中 affiliate_dash 后不建工单(apps/backend/src/services/worker-platform/sync-worker-orders-service.ts:65)。

5.2 工单与结算

状态机:

pending_material → unassigned → open → in_progress
                                      → pending_acceptance → accepted
                                      → problem → open / cancelled
  • 抢单:条件更新 WHERE status='open' AND assigned_worker_id IS NULL。
  • 结算:acceptWorkOrderAndSettle 锁工单与份额,释放/延迟解冻押金,抵扣售后欠款,可能升级等级。
  • 拼单:母单可长期 open,份额 joined → submitted → accepted/cancelled。
  • 赠送单:确认加好友后取消/脱离不再退押金。

5.3 寄卖仓库

  • 提报:consignment_submissions,冻结发布押金。
  • 入库:consignment_inventories,审核通过生成 INV…。
  • 匹配:品类强隔离、三态比对、低配不充高配、unknown 不判精确。
  • 履约:internal_stock 内部现货,或 worker_deposit 指派打手。
  • 结算:验收后释放发布押金,补发货款 cost_price_fen || asking_price_fen。
  • 撤销:打手押金与卖家押金可 auto / refund / forfeit / keep_frozen,显式覆盖必须填原因。

5.4 凭证与券

类型 表 核销方式
快手行业电子凭证 kuaishou_industry_vouchers 快手 OpenAPI
抖音 DYC 券 redeem_certificates coupons.verifyV3

两套表、两套状态机,不可混用。发布/指派时按来源分流:publish-voucher-service.ts。

5.5 三块履约与成本(2026-10-17 只读数据增补)

真正决定成本和监管方式的是执行载体,不是订单来源:

块 载体 成本 生产数据
自动发货 affiliate_dash 任务 固定,按皮肤/SKU 上游已有 cost_amount,但未落库
接单平台 work_orders 变动,按模板/单价/拼单 最近 30 天已验收 62,669 单
人工客服 目前无载体 人工工时/按单 最近 30 天 44,657 个已支付订单项无任务也无工单

关键数据:

  • 91 无载体订单 42,391、PDD 2,258、抖音 8;全部 claim_status=active。
  • manual_dispatch 任务全库只有 6 条,说明人工块基本没进任务系统。
  • 已验收工单的 orders.order_status 仍为 paid,订单主状态不能代表履约完成。
  • 最近 30 天已验收工单:91 报酬/订单金额约 86.0%、PDD 80.0%、抖音 96.5%。口径已确认(2026-10-17):total_amount 即用户付款金额、计收入,打手报酬计支出(总额法);91 的 total_amount 与快手 paymentFen 数据核验 100% 一致。详见 载体判定与成本中心落地-复核与草案.md §九。
  • 同一个商品名对应多个 sku_code:「指挥官密钥1个」27 个、「苏尔南钻石100颗」35 个,不能直接按 sku_code 做销量统计。
  • 当前 30 天订单基本是一单一品,但模型必须按订单项设计。

详细设计见 成本中心与三块履约模型.md。


六、工程质量亮点

  1. 严格类型:strict、noUncheckedIndexedAccess、exactOptionalPropertyTypes。
  2. 测试纪律:后端 740 项,覆盖匹配引擎、押金策略、退款、路径判定、日志脱敏、SQL 形状。
  3. SQL 护栏:check:sql 检查历史迁移不可修改、热点索引存在、禁止 COUNT(*) OVER()。
  4. 生产配置校验:生产强制 session secret 长度、显式 CORS 白名单、存储凭据完整。
  5. 回调验签:91、快手、affiliate-dash、抖音四条外部链路均有验签;91/affiliate 有时间戳容差。
  6. 账号安全:后台/打手口令 scrypt + 盐;会话落库 + session_version;打手设备数限制。
  7. 日志脱敏:敏感 key、URL 参数、JSON 字段统一脱敏,并有单测。
  8. 部署与备份:健康检查、优雅关闭、日志轮转、迁移前备份、按需重建。
  9. 零 TODO/FIXME:源码中没有遗留标记;文档密度高。

七、风险清单(按当前代码复核)

P0 · 资金与一致性

# 发现 证据 影响
1 发单金额高于用户付款只有前端提醒,后端无强制校验 前端 apps/frontend/src/pages/admin/panels/work-order-payment.ts:17;后端发布只校验 >0 apps/backend/src/services/worker-platform/admin-work-order-management-service.ts:228 直接调 API 可以发出亏损单;改价、发布、指派三入口没有统一门禁
2 寄卖审核可由请求体改 workerId,并按改后归属结算货款 apps/backend/src/services/worker-platform/consignment-admin-service.ts:606;供货方反查优先库存归属 apps/backend/src/repositories/worker-platform/consignment-supplier-repo.ts:67 钱可能结给错误的人;还会按手机号自动绑定
3 寄卖审核详情全量返回游戏账号密码 credentialsJson,只需 consignment.view apps/backend/src/services/worker-platform/consignment-admin-service.ts:183 查看权限即可拿到卖家凭证,权限粒度过粗
4 抢单与指派加锁顺序相反 抢单先锁钱包 apps/backend/src/repositories/worker-platform/work-order-grab-repo.ts:25;指派先锁工单 :156,再锁钱包 :171 并发下可形成死锁,接口 40P01 / 500
5 自动工单硬编码零押金,模板押金字段不生效 apps/backend/src/services/worker-platform/sync-worker-orders-service.ts:245 自动发单没有押金约束;deposit_threshold_amount 也只读写/展示
6 发布工单时凭证核销失败不回滚;指派却会拦截 发布 apps/backend/src/services/worker-platform/admin-work-order-management-service.ts:250;指派 apps/backend/src/services/worker-platform/admin-work-order-assignment-service.ts:75 同一条业务规则两套行为;抖音券缺失时工单仍可能进入大厅

P1 · 可靠性与公开面

# 发现 证据 影响
7 Webhook 先去重落库、后处理业务;失败后平台重推被永久跳过 抖音 apps/backend/src/services/platforms/douyin-mashida/notify-service.ts:95;affiliate-dash apps/backend/src/services/platforms/affiliate-dash/notify-service.ts:70 建单/发券/同步任一步失败,事件已写入 webhook_events,重推返回 duplicate,订单可能永久丢失
8 抖音回调同步串行调用上游,单次超时 20 秒 apps/backend/src/services/platforms/douyin-mashida/source-config-service.ts:136 回调响应可能超过平台超时,与 #7 叠加后无法恢复
9 /collect/*、/redeem/* 只凭订单号,无第二因子 apps/backend/src/routes/collect.ts:22、:32;apps/backend/src/routes/redeem.ts:24、:34 可查询/写入待补全订单资料;知道订单号即可触发买家券核销
10 /collect/upload 可匿名上传任意场景文件到 OSS apps/backend/src/routes/collect.ts:42、:49;场景名只做字符串清洗 apps/backend/src/services/file-storage/file-storage-service.ts:360 不校验订单存在,换 orderNo 即可绕过限流桶,存在存储滥用风险
11 /files/object 无鉴权;claim token 默认永久有效 apps/backend/src/routes/files.ts:12;默认 apps/backend/src/config/defaults.ts:65,生产示例同样为 0 .env.server.example:27 链接或对象 key 泄露即长期可访问
12 无 CSP/HSTS/X-Frame-Options;后台 token 存 localStorage deploy/caddy/Caddyfile 只有缓存头;apps/frontend/src/utils/admin-auth.ts:1、:101 任一 XSS 即可接管后台会话
13 先到先匹配,后到的快手补全数据不会纠正既有工单 已有工单直接 already_exists 跳过 apps/backend/src/services/worker-platform/sync-worker-orders-service.ts:97 价格/模板可能停留在首次粗匹配结果
14 单实例耦合:限流桶、调度器、SSE、列表缓存均在进程内 apps/backend/src/middleware/rate-limit.ts:26;services/realtime/realtime-event-service.ts 直接扩容会出现重复定时任务、限流失效、缓存不一致

P2 · 可维护性与运维

# 发现 证据
15 巨型文件:WorkOrdersPanel.tsx 3,686 行、AdminTaskDetailPage.tsx 2,015 行、work-order-query-repo.ts 1,499 行、consignment-repo.ts 1,478 行 实测
16 前端无组件渲染测试、无 E2E;部分后端测试是源码字符串断言 测试目录与用例实现
17 无 CI;质量门禁只靠本机 pre-push,可被 SKIP_CHECKS=1 绕过 .githooks/pre-push
18 dev 分支已完全落后 main,实际是单分支开发 git log main..dev 为空
19 迁移启动时自动执行且无 down;多副本会竞争迁移 apps/backend/src/startup/bootstrap.ts:32
20 uncaughtException 只记录不退出 apps/backend/src/index.ts:57
21 本地 Node 24,生产镜像 Node 22;前端主 chunk 524.69 kB 警告 构建输出、deploy/docker/backend.Dockerfile:11
22 备份会把 apps/backend/data 配置打包上传 OSS,可能含 PDD RSA 私钥/平台 Cookie deploy/backup-db.sh:119

三块履约与成本增补(2026-10-17)

# 发现 证据 影响
C1 人工块没有载体、没有 case、没有完成状态 最近 30 天 44,657 个已支付订单项无任务也无工单;manual_dispatch 仅 6 条;已验收工单的订单仍 order_status=paid 人工履约不可监管、不可计量、不可对账
C2 成本数据散落且无版本/快照 自动发货 cost_amount 只映射不落库;工单价格在 work_product_rules;人工无成本表 改价无法追溯,历史毛利不可重算,三块成本口径不一致
C3 订单金额口径不统一 91 totalAmount=maxAmount(platforms/ninetyone/order-service.ts:48);PDD order_amount;抖音 pay_amount 直接汇总 orders.total_amount 会把不同财务口径相加
C4 SKU 与数量口径不稳定 同一商品名对应 27/35 个 sku_code;order_items.quantity 对「5个」类商品不可靠 店铺/日期/皮肤销量统计会漏计、重计或错并
C5 无订单项级金额字段 order_items 仅有 sku_code/sku_name/quantity/spec_json/item_snapshot_json 多商品订单无法直接分摊收入,需要快照/分摊规则

八、文档现状与本次整理

本次已完成:

  1. 新增 docs/README.md:文档唯一入口、状态约定、三来源口径。
  2. 新增 docs/archive/README.md:历史文档说明。
  3. 将 6 份过期阶段性文档移入 docs/archive/2026-10-08/,不删除内容,保留追溯。
  4. 统一以下文档的来源口径:
    • README.md
    • docs/接单模板匹配引擎重构设计.md
    • docs/抖音-码速达/00-总览.md
    • docs/抖音-码速达/10-三层分流设计.md
    • docs/抖音-码速达/12-按SKU分类改造总设计.md
    • docs/履约配置/多发货平台与电子凭证整体链路.md
    • docs/91卡券/5.当前项目对接配置.md
    • docs/91卡券/6.开发设计.md
  5. 校正“设计稿/未实施”状态:
    • 匹配引擎:P0 + P1 已实施,P2/P3 待办。
    • 抖音三层分流:抖音侧已实施。
  6. 校正过期测试数:抖音总览中的 636/115 改为 2026-10-17 复核的 740/143。
  7. 2026-10-17 增补:新增 成本中心与三块履约模型.md,把自动发货/接单平台/人工客服三块、统一成本中心、销售事实与人工 case 纳入现行设计;本报告同步补入生产只读数据与 C1~C5 风险。

仍保留为“设计/待办”的内容:

  • work_product_match_entries 新表尚未落地(只在设计中),当前仍靠 compile.ts 编译旧模板/绑定。
  • 匹配触发点收敛、寄卖建议价/大厅改价统一走 pricing.ts 尚未完成。
  • 抖音“待人工队列”仍未做。
  • product_catalog / channel_product_mappings / cost_items / cost_versions / cost_snapshots / sales_daily_facts / manual_fulfillment_cases 均未落地。

九、财务系统集成结论(摘要)

现有财务能力是业务钱包 + 流水,不是会计总账:

  • worker_wallets:可用余额、冻结押金、累计入账、累计结算。
  • worker_wallet_ledgers:冻结/释放/扣减/结算等流水。
  • worker_finance_requests:充值/提现申请。
  • 售后欠款、寄卖发布押金、工单报酬、货款结算分散在多个 repo。

缺口:

  1. 没有复式记账(借贷不平无法发现)。
  2. 没有会计期间/月结/关账。
  3. 没有平台侧对账(91、快手、PDD、抖音、affiliate-dash)。
  4. 没有订单级收入/成本/毛利。
  5. 余额是可变字段,缺少“由流水重算”的校验。
  6. 资金事件缺少统一的 business_event_id 幂等键。

建议:先建影子总账 + 对账,不要一开始替换钱包。成本金额与商品维度单独由成本中心负责,人工块由人工 case 负责;三者关系见 成本中心与三块履约模型.md,总账细节见 财务系统集成方案.md 与 影子总账说明.md。


十、建议路线

立即(1–3 天)

  1. 后端统一“发单金额 ≤ 用户付款”校验,改价/发布/指派共用。
  2. 修复 Webhook 去重时序,改为 processing / succeeded / failed 或失败删除。
  3. 统一抢单/指派锁序,或对 40P01 做有限重试。
  4. 寄卖审核禁止直接改 worker_id;确需改派走独立接口 + 原因 + 复核。

短期(1–2 周)

  1. 发布与凭证核销统一为“失败即不发布”,或明确异步补偿。
  2. /collect、/redeem 增加一次性 token/二次校验;上传前校验订单存在。
  3. 生产强制 CLAIM_TOKEN_TTL_HOURS > 0;私有文件短期签名;补安全响应头。
  4. 先落商品主数据 + 销售事实:product_catalog、channel_product_mappings、sales_daily_facts,解决店铺/日期/皮肤销量与数量归一。
  5. 再落成本中心影子期:cost_items / cost_versions / cost_snapshots,自动发货接上游固定成本,工单接现有规则金额,人工接按单/按小时成本。

中期(1 个月)

  1. 人工 case:载体判定、无载体自动建 case、分配/SLA/证据/主管复核、人工成本快照。
  2. 财务影子总账:finance_journal_entries / lines + 业务事件映射。
  3. CI + PostgreSQL 集成测试;补金额守恒、并发抢单、Webhook 失败恢复测试。
  4. 财务对账:平台账单/支付流水/钱包流水三方核对。
  5. 订单级损益:收入、履约成本、打手报酬、人工成本、平台费、退款。
  6. 拆分巨型文件;补前端组件测试与 1–2 条 E2E。

十一、一句话总结

代码与工程纪律足以支撑下一阶段的财务系统;但财务系统必须建在“商品主数据 + 成本中心 + 不可变复式分录 + 业务事件幂等 + 对账”之上,而不是继续给 worker_wallets 加字段。 先修资金门禁、Webhook 恢复、锁序与公开接口;再把人工块纳入 case 监管,最后接财务总账,风险最低。