# order_site 项目全量分析报告(2026-10-17) > 状态:**现行** > 代码基线:`main @ 6850bc64`(工作区干净) > 复核范围:后端、前端、数据库迁移、部署脚本、现行文档 > 复核方式:源码走查 + 类型检查 + 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 集成测试与金额守恒测试 | --- ## 二、来源模型:三个来源,不是一个来源加另一个来源 ```mermaid flowchart LR A["kuaishou-91
91 回调(订单骨架)"] --> O[("orders / order_items")] B["kuaishou-91
快手 send-code(补全/兜底)"] --> O C["pdd"] --> O D["douyin-mashida"] --> O O --> M["product-match 引擎
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 工单与结算 状态机: ```text 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% 一致。详见 [载体判定与成本中心落地-复核与草案-2026-10-17.md](载体判定与成本中心落地-复核与草案-2026-10-17.md) §九。 - 同一个商品名对应多个 `sku_code`:「指挥官密钥1个」27 个、「苏尔南钻石100颗」35 个,不能直接按 `sku_code` 做销量统计。 - 当前 30 天订单基本是一单一品,但模型必须按订单项设计。 详细设计见 [成本中心与三块履约模型.md](成本中心与三块履约模型.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](README.md):文档唯一入口、状态约定、三来源口径。 2. 新增 [docs/archive/README.md](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](成本中心与三块履约模型.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](财务系统集成方案.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 监管,最后接财务总账,风险最低。