Files
ShiErFeng/shierfeng-fastapi-backend/sql/pallet-workflow-deployment.md

147 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 托盘流转业务部署说明
## 2026-10-08 会议流程补齐(本机开发库已执行)
本轮源码增加物料日期、原发货标签、收货核对、隧道报表,以及“允许跳过先到托盘但必须填写原因”。用户明确批准开发库迁移和该 FIFO 规则后,已在本机开发库执行下列三份增量补丁并恢复9099后端。其他环境未执行,不能沿用本记录当作已迁移证明。
### 本机开发库执行与恢复验证记录
- 目标:`.env.dev` 对应 `127.0.0.1:3306/shierfeng-fastapi`,MySQL 8.0.36;43张业务及系统表均为 InnoDB。
- 已核实并停止本项目 `app.py --env=dev` 服务;迁移前无其他活跃目标库查询、无启用的 MySQL Event。
- 完整备份:`/private/tmp/shierfeng-dev-migration-20261008-6ce_sy6c/before.sql`,262663字节,文件权限600、父目录700。SHA-256:`c70393e09574f24820e252c9cfb084e9e15d86b185c8a7aa981a8088cd21a15b`。备份包括全部表、触发器、存储过程和事件;口令不进入命令行,临时口令文件已删除。
- 备份已实际恢复到隔离库 `shierfeng_rehearsal_20261008_6ce_sy6c`;43张表逐行摘要及数量与源库一致。三份补丁先在隔离库试跑通过,然后核对源库未变化、脚本摘要一致,再执行开发库迁移。
- 开发库执行顺序:`20261008_material_dates_mysql.sql` → `20261008_shipment_receipt_mysql.sql` → `20261008_usage_fifo_mysql.sql`,均成功。没有重跑初始化或旧隧道脚本。
- 迁移后按迁移前列集比对43张表的全部原数据摘要,结果一致;仅新增收货菜单1119。原库存、包数、编号、批号及历史事件未变;旧确认发货单收货状态为 `LEGACY`,其他为 `PENDING`;新增日期、收货人/时间和 FIFO 历史列均为空。新 CHECK 约束已核对;未自动授予任何普通角色。
- 后端已按原 Python 环境与 `--env=dev` 恢复,MySQL、Redis连接正常,`/docs` HTTP200;未登录访问收货接口返回业务401。没有修改 `.env.dev`。
- 实际恢复的隔离 MySQL 库还运行了完整业务服务验收:两托100包、原标签/日期、在途禁止入隧、无现场权限拒绝、确认收货、跳过原因校验、同隧道跨批使用、20包使用/80包原托退回、原标签快照不变、收货幂等不恢复已消耗数量,以及三条独立连接同时重放同键只扣减一次。数据仅新建于隔离库;另有一组新建夹具使用正式scope验证两托并发,排除测试批次总锁掩盖冲突,未向实际开发库灌入测试业务。
- 真实 MySQL 验收同时发现并修复入隧事务结束后访问过期 ORM 属性导致的 `MissingGreenlet`;ID及返回模型现在在事务结束前取值。验收使用与应用一致的提交后属性过期行为。
备份与验收产物位于系统临时目录,可能被系统清理;需长期留存时应转存到受控备份位置,不提交仓库。隔离演练库暂保留用于复核,不接业务服务。恢复到业务库将覆盖迁移后变化,必须另行确认停写及恢复目标;失败时不得直接重跑增量补丁。
### 开发库只读预检记录(2026-10-08)
使用 `.env.dev` 指向的 `127.0.0.1:3306/shierfeng-fastapi`,在只读事务中查询版本、结构元数据和收货菜单冲突,随后回滚并关闭连接;未执行备份、DDL、业务数据写入、角色授权或服务重启。
- 实际版本:MySQL 8.0.36;相关业务表均为 InnoDB。
- `biz_test_batch`、`biz_tunnel`、库存隧道/溯源列和事件隧道/溯源快照列已存在。
- `biz_filling_record.production_date/expiry_date` 尚不存在。
- 发货单5个收货字段以及 `biz_pallet_inventory.site_arrived_at` 尚不存在。
- 父菜单510为预期的 `business:shipment:list` 页面;菜单1119、`business:shipment:receive` 权限及1119的孤立角色授权均不存在。
- 后端9099端口仍有服务监听。执行迁移前仍须获准停写、完成备份与恢复方案核对;上述检查不代表已进入维护窗口,也不替代脚本内完整前置约束检查。
上述为执行前的只读预检历史记录;实际执行结果见上节。不要直接重跑已有补丁或初始化脚本。其他环境必须重新核对现状。
### 迁移顺序与风险
1. 只读核对目标库、MySQL版本、既有补丁和约束;不要仅凭文件存在判断已迁移。旧库需先具备 `20260922_test_data_batch_mysql.sql` 及 `20261005_tunnel_material_flow_mysql.sql` 的结构,不可重复执行已落库补丁。
2. 确认维护窗口、停写,完整备份结构、业务数据、菜单及角色关联,并验证恢复方案。
3. 执行 `sql/patches/20261008_material_dates_mysql.sql`:新增生产日期、有效期及日期关系约束;历史记录保持空值,不按装填时间补造日期。
4. 执行 `sql/patches/20261008_shipment_receipt_mysql.sql`:新增收货状态、人员、时间和幂等字段,库存实际收货时间,以及 `IN_TRANSIT` 状态和 `SHIPMENT_RECEIVED` 事件。旧已确认发货单标记 `LEGACY`;原库存位置、状态、包数和历史事件不变。
5. 执行 `sql/patches/20261008_usage_fifo_mysql.sql`,为使用记录和托盘事件新增可空原因及推荐快照列;旧记录保持空值。三份脚本均应在代码启用前完成。
6. 新权限 `business:shipment:receive` 不自动授予普通角色。先核对菜单 ID 1119 未被其他菜单占用;按职责授权发货页面入口、收货核对按钮及目标现场数据范围。接收方不需要来源仓库权限,发货方原双范围校验不放宽。
7. 逐项核对表结构、约束、历史保留结果后再发布三端代码。旧数据库直接运行新后端会因缺少列而报错,不能仅重启服务解决。MySQL DDL 隐式提交,出错必须停止;不可依赖 `ROLLBACK` 恢复整个迁移。
新建空库可使用已同步的 `sql/shierfeng-fastapi.sql`;禁止将包含重建语句的初始化脚本用于现有业务库升级。
### 新流程与历史兼容
- 新发货:仓库有料 → 出库在途 → 接收方逐托核对、整单确认 → 现场未使用 → 扫码入隧 → 实际使用 → 原托盘余料退回。未收货不可入隧;未全部核对不能确认,不支持部分收货。
- 收货不新增托盘号、生产批号或装填记录,不增加/扣减发货快照数量;重复确认采用独立幂等键,不把后续已消耗的余量恢复。
- 标签从原发货装填快照读取品种、生产批号、日期、数量;可补打,历史日期显示“未登记”。印刷托盘号可作为扫码入口,写操作统一使用返回的规范二维码标识。
- 混批与隧道溯源保留在后台及报表;普通操作页面不以内部溯源号代替生产批号。
- 先进先出采用已批准的“允许跳过但必须记录原因”:入隧和实际使用均在后端锁定原业务记录后用当前读复核同现场、同品种的可用候选;其他隧道或旧溯源周期物料不推荐。存在严格更早的实际到货候选时,必须填写不超过500字的原因,原因和推荐托盘/批号/数量/到货时间快照随原事件及使用记录提交。相同到货时间不强排ID;当前历史到货时间未知时不伪造先后,保留人工核对提示。
- FIFO 原因参与幂等摘要;无原因时保持旧摘要兼容。已成功请求重试直接返回原结果,不因候选变化再次扣减。仅服务端明确返回 `code=500, data=FIFO_SKIP_REASON_REQUIRED` 的已回滚请求可解除本机对应凭据以便补原因;网络结果未知和其他失败继续沿用原payload/key。
- 候选当前读使用 `FOR UPDATE NOWAIT`,锁冲突不会跳过早到候选或持有现场/隧道锁等待候选锁。仅 MySQL 3572/1213/1205 触发最多3次整事务原键重试,每次先完成回滚;断连等提交结果未知错误不会自动重放。持续繁忙时仍需客户端按原键恢复核对。
- APP 的 HTTP 非2xx或不完整业务结果不视为成功,入隧、使用及恢复重试均在确认结果后才解除原凭据。PC 成功回调仅清理与该请求完全一致的持久化记录,避免旧页面响应删除新操作;恢复时已确认的 FIFO 必填要求,不会因推荐刷新失败或延迟而丢失。
### 运行态验收门禁
迁移获批且完成后,用获准测试批次验证:两托各100包 → 标签与收货核对 → 同隧道跨批使用 → 20包使用/80包原托退回 → 原批号不变;同时验证重复点击、断网结果未知后重试、无现场权限、收货前使用、漏扫与错扫均被正确处理。核对四类隧道报表和两端日期展示。
本机隔离 MySQL 已验证完整流程、同键并发,以及正式scope两托交错入隧/使用的锁冲突回滚重试。普通角色菜单配置、打印机出纸和东集 CRUISE Gep/D737P_V1.0.5 实机 HID/回车行为仍需现场验收;构建成功不能替代设备验证,未接入设备原生广播 SDK。
## 适用范围与当前状态
本文适用于 MySQL 增量补丁:
`shierfeng-fastapi-backend/sql/patches/20260724_pallet_workflow_mysql.sql`
2026-07-27 已在本地主工作区 `.env.dev` 指向的 MySQL 8.0.36 执行该补丁,且完成下述本地核对。其他环境尚未执行,Redis 缓存也未清理;本记录不能替代其他环境的上线审批、备份及恢复演练。
## 上线前门禁
执行补丁前必须完成以下准备:
1. 对目标 MySQL 实例进行完整备份,至少覆盖库结构、业务数据、菜单和角色关联数据,并验证备份可读。
2. 在隔离环境完成恢复演练,确认恢复步骤、耗时和责任人,不能只以“备份命令成功”代替可恢复性验证。
3. 由 DBA 人工审查补丁、目标库现状、已有同名表结构、固定菜单 ID 和回退方案。
4. 申请维护窗口,在补丁执行和缓存清理完成前保持后端停止,不接入业务流量。
任一门禁未满足时,不得执行补丁。
## MySQL 补丁执行与核对
MySQL DDL 会隐式提交,因此必须将补丁的 DDL、DML 分节执行,并在每一节后逐项核对结果。执行失败时不能假设整个补丁已自动回滚,应立即停止后续步骤,由 DBA 根据实际已提交状态决定人工修复或从已验证备份恢复。
### 1. DDL 节
1. 先执行补丁中的 DDL 节,逐表核对表结构、索引、外键和约束。
2. `CREATE TABLE IF NOT EXISTS` 只会跳过已经存在的同名表,不会修复已存在但结构发生漂移的表。发现同名表时,必须先人工比对实际结构;存在差异时停止执行并制定独立修复方案。
3. DDL 节核对通过前,不得继续执行 DML 节。
### 2. DML 节
1. DML 节包含固定 64 行菜单 seed。执行后必须核对结果恰为 64 行,并确认稳定字段与补丁定义一致。
2. 任一固定 ID 与未知既有数据冲突时,必须停止并由 DBA、业务负责人共同人工处理;不得覆盖、改写或复用未知 ID,也不得绕过冲突继续执行。
3. DML 节核对失败时,不得清理缓存或启动后端。
### 3. 2026-07-27 本地执行记录
1. 执行前备份:`/private/tmp/shierfeng-fastapi-before-pallet-workflow-20260727-1925.sql`,文件权限 `600`,大小 69,180 字节,SHA-256 为 `a217a7b071c7e3ecda0d4c94dd1010711b6061025148689156405b70a02f6c7e`。已校验文件非空、可读且包含核心系统表;未执行恢复演练。
2. DDL 分节执行成功:新增 18 张 `biz_*` InnoDB 表,业务域幂等键的复合唯一索引列顺序已核对。
3. DML 分节使用标准 `mysql` 批处理执行,未使用 `--force` 或 continue-on-error 模式。64 条新业务菜单已写入,旧 AI/外链菜单、AI 字典及旧角色映射已核对为 0。
4. 新菜单没有自动授予普通角色;后续应通过现有角色菜单机制按实际职责分配。
## 历史 AI/Agno 遗留表
曾运行过历史 AI/Agno 版本的数据库可能残留以下 11 张表:
* `ai_models`
* `ai_chat_config`
* `ai_sessions`
* `ai_memories`
* `ai_metrics`
* `ai_eval_runs`
* `ai_knowledge`
* `ai_culture`
* `ai_traces`
* `ai_spans`
* `ai_schema_versions`
本补丁不会删除或修改这些表。未经另行确认,不得处理这些历史表。后续如需清理,应单独盘点表结构、数据量和外部依赖,完成备份与恢复验证,确认无消费者后,再通过独立变更审批和维护窗口人工执行。
## Redis 缓存清理
只有 MySQL 补丁全部执行成功且核对通过后,才能在目标 Redis 实例定向清理以下缓存:
* `api_cache:login:user:routers:*`
* `api_cache:login:user:info:*`
* `sys_dict:ai_provider_type`
对前两类模式应使用 `SCAN` 定位后逐项删除,只处理明确匹配的键;禁止使用 `FLUSHALL`。本轮未执行任何 Redis 缓存清理,不能把上述清单视为已清理证明。
## 启动与运行态验收
正式环境只有在 MySQL 补丁成功、逐节核对通过并完成上述定向缓存清理后,才可启动后端并开展运行态验收。至少应核对 `/getRouters` 返回的托盘业务菜单、真实角色权限,以及真实用户与仓库/客户现场映射下的业务访问范围,再验证响应式 Web 页面和 Android PDA HID 扫码回车流程。
本地环境已使用独立查询参数验证管理员 `/getRouters`:包含 3 个新业务目录和 17 个业务页面,不包含 AI 管理或“施尔丰仓库”。该结果不等于已完成 Redis 清理,也不代表普通角色已完成授权验收。
## 2026-07-27 当时未验证项(历史记录)
以下事项需要在后续真实环境中验证,本轮没有完成:
* 备份恢复演练。
* 真实角色与仓库/客户现场映射的端到端(E2E)流程。
* MySQL 行锁、并发和事务回滚行为。
* Redis 缓存清理。