# 2026-08-11 M09-D1 商品目录与库存底座 ## 工程结果 - 工程状态:当前工作树已完成,待以 `feat(M09-D1): 完成商品目录与库存流水底座` 中文标题提交并取得 SHA。 - 新增分类、商品、SKU、门店上架、门店销售设置、每周最多 8 段且支持跨日的营业时段;分类/商品/SKU 支持软删除后的代码或条码复用,写操作统一使用 `expectedVersion` 乐观锁。 - 新增 `TRACKED` / `UNLIMITED` 库存策略、可用/锁定/损耗三类数量,以及入库、调整、盘点、损耗、批量锁定、释放和扣减服务;批量操作同事务完成,任何一个 SKU 失败均整体回滚。 - 库存请求以租户、门店和大小写敏感 requestId 建立全局幂等记录;请求指纹不一致明确拒绝,锁定归属按业务类型和业务号核对,重复释放、跨订单释放和超额扣减不会改动库存。 - 每次库存变动写入带 `version_after` 的不可变流水,数据库双触发器拒绝 UPDATE/DELETE;流水增量与库存最终值可对账,版本唯一键防止遗漏或重复版本。 - 商品/库存路由接入 Fastify,补 `product.catalog.read/write`、`inventory.read/adjust` capability、角色默认授权、服务端菜单和租户/门店范围校验;STAFF 只读、STORE_ADMIN 授权门店、TENANT_ADMIN 与 PLATFORM_ADMIN 边界均有测试。 - 迁移 runner 改为按单个迁移 marker/checksum 只执行 pending 文件,旧库可直接增量应用 M09-D1;interrupted up/down DDL 后可在同一库原地重试,不需要清空或重建。 - up/verify/down 在同一专用连接上持有按数据库名派生的 MySQL 命名锁,两个发布进程会串行执行;不同构建必须等前一进程完成后再校验 marker/checksum,避免交错 DDL 形成混合 schema。 - 迁移包含触发器时,runner 在执行任何触发器 DDL 前检查生产前置;binlog 开启时必须启用 `log_bin_trust_function_creators=1` 并使用独立迁移身份,否则在建表前拒绝执行。 ## 数据库结果 `2026081107_m09d1_product_inventory_foundation` 新增 9 张表: 1. `qipai_product_categories` 2. `qipai_products` 3. `qipai_product_skus` 4. `qipai_product_store_listings` 5. `qipai_product_store_settings` 6. `qipai_product_store_hours` 7. `qipai_product_inventory` 8. `qipai_product_inventory_requests` 9. `qipai_product_inventory_ledger` ## 验证证据 - `node scripts/check-m09-d1-product-inventory.mjs`:PASS,静态门禁确认迁移、路由、RBAC、服务、真实 MySQL 断言和 Windows/WSL 门禁均已接线。 - 后端 `npm run build`、后端全量 `npm test`:PASS。 - 管理端 `npm run build`、`npm test`:PASS。 - WSL 原生临时副本 + MySQL 8.4.10:完成 `up → verify → down → up → verify`,179 条 up、141 条 verify、171 条 down;双连接迁移锁、interrupted up/down DDL 原地重跑、增量 marker/checksum、触发器生产前置和 cleanup probe 均 PASS。 - 真实 MySQL 业务用例覆盖门店唯一性、跨日时段、商品/SKU 版本冲突、并发锁定单赢家、重复 requestId 重放与冲突、批量原子回滚、锁定/释放/扣减、损耗/盘点、负库存拒绝、流水对账与不可变触发器。 - Windows 汇总门禁在全部 M09-D1 与 V5.7 文件显式暂存后执行最终复跑;不得将提交前的未跟踪完整性提示记为功能失败。 ## 阶段结论 `M09-D1=DONE`。唯一执行游标进入 `M09-D2`,下一阶段建立商品订单、订单项快照、支付衔接与库存占用生命周期。生产触发器前置属于部署强制条件,不是可绕过的外部阻塞。