Files
baiyue-firstleg/deploy/sql/README.md
T

243 lines
20 KiB
Markdown
Raw 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.
# 测试环境 SQL 执行说明
## 唯一数据库初始化与发布入口
- 国内区域固定入口:`头程数据库统一增量-MySQL8.sql`。文件名保留历史兼容,内容维护为当前完整数据库基线和存量环境兼容升级,不再按日期拆分发布脚本。
- 海外区域固定增量入口:`海外区域统一增量-MySQL8.sql`;空库先分别执行 `lastleg-service/src/main/resources/db/lastleg.sql`与 `warehouse-overseas-service/src/main/resources/db/warehouse.sql` 基线,再执行该入口。固定入口会创建并校验独立的 `baiyue_event_bridge_overseas`,再升级 `baiyue_lastleg`与 `baiyue_lastlag_warehouse`;IAM 安全事件 Inbox 和可恢复投影已并入 `baiyue_lastleg.ll_security_*`,Redis 只作可重建镜像。
- Lastleg 基线和海外固定增量仅确定性初始化国内固定 `platform_admin`(`authUserId=1000001`、`tenantId=0`)的 USER/AUTHORIZATION version=0 安全投影;其他既有开发账号不建立兼容表或长期补投入口。
- 国内、海外 Compose 部署默认设置 `SPRING_SQL_INIT_MODE=never`,执行任一 SQL 均需用户单独授权。
- 该脚本汇总一期、二期及已实现三期出仓能力的数据库基线、存量升级、IAM 权限资源和最终结构校验,适用于 MySQL 8.0。
- 正式上线前的数据库变更直接维护该文件中的当前基线、存量兼容处理和最终校验,不再创建按日期拆分的发布 SQL;正式上线后的迁移策略在生产发布规范中另行冻结。
- 当前测试环境尚未上线,船期价格表相关表、字段和索引只维护在现有初始化建表定义及本固定入口中,不向 `phase1-order-extension.sql`、`phase2-fba-pricing-migration.sql` 或新的增量脚本追加同一结构。
- 模块 `src/main/resources/db/` 下的 SQL 用于开发溯源;`deploy/sql/` 下已有日期文件全部冻结为历史记录,不再单独部署,也不得与固定入口重复执行。
- 固定入口不包含 `auth/phase1-admin-accounts.sql` 和 `warehouse/warehouse-seed.sql`;仅在开发/测试基线账号缺失时创建平台管理员,重复执行不覆盖现有密码。脚本不创建固定客户、客户账号或演示订单;客户必须通过正式建档/注册流程创建。正式平台公共仓库主数据已内联到固定入口;义乌、东莞、洛杉矶、纽约四个固定作业仓均初始化 `RECEIVING`,其中洛杉矶和纽约使用海外接柜入仓收货语义,FBA 目的地址不创建作业能力。
- `warehouse/phase2-pallet-location-schema-migration.sql` 的有效结构已被当前 `phase2-pallet-location-schema.sql` 和后续共享溢出位迁移完整覆盖,因此不重复内联,避免每次部署无条件删除并重建同名唯一索引。
- 脚本会创建 9 个独立数据库:`baiyue_auth`、`baiyue_iam`、`baiyue_order`、`baiyue_warehouse`、`baiyue_firstleg`、`baiyue_file`、`baiyue_audit`、`baiyue_event_bridge`、`baiyue_finance`。Gateway、Print、Integration Service 无数据库。
- IAM 消息中心基线已内联到固定入口,包括 5 张 `iam_notification_*` 表、任务/事件幂等约束、平台消息管理权限、企业成员收件箱权限及默认角色授权;模块溯源脚本为 `iam/src/main/resources/db/notification-center.sql`。
- IAM 跨区安全事件基线已内联到固定入口,包括主体权限版本、客户状态版本和可靠事件发送箱 3 张表;模块溯源脚本为 `iam/src/main/resources/db/security-event-outbox.sql`。IAM 新版本启动前必须先执行固定入口,避免安全事件 Relay 和授权快照查询因缺表失败。
- 完整执行所有增量区块并通过末段真实结构校验后,脚本最末才会返回唯一的 `PASS`;任一强校验失败会通过 `SIGNAL` 终止。
后续追加增量必须满足:
1. 只新增或兼容升级,不清表、不删除业务数据。
2. 新字段、索引、约束必须先查询 `information_schema`,允许整份脚本重复执行。
3. 系统权限或字典配置使用唯一键和 `ON DUPLICATE KEY UPDATE` 幂等写入。
4. 每个增量区块末尾增加只读断言,并同步维护统一脚本末尾的总体验证。
5. MySQL DDL 会隐式提交,执行前仍应在目标环境确认连接和授权;不能把跨库脚本视为可整体回滚事务。
## Finance 首期人工财务基线
- Finance 数据库为 `baiyue_finance`,模块溯源脚本为 `finance/src/main/resources/db/finance.sql`,测试和存量环境仍只执行统一入口。
- 首期只支持 CNY,包含平台主体、客户默认 30 天账期、账单及明细、人工收款及账单分配、单票/整柜人工成本、体积分摊结果、Firstleg 费用来源事件、幂等记录和不可变审计日志。
- 不包含钱包、发票、供应商在线应付、银行自动对账、复杂核销、汇率和月结。
- 统一脚本末尾会强校验 13 张 Finance 表、客户隔离/CNY/人工凭证关键字段,以及费用来源、Inbox、账单版本快照、收款、成本和写操作幂等唯一约束;任一缺失不会返回 `PASS`。
## 历史一期回归脚本
- 历史文件:`2026-07-31一期回归测试环境增量迁移.sql`,仅供追溯,不再作为统一入口。
- 适用数据库:MySQL 8.0。
- 执行账号需要对 `baiyue_iam`、`baiyue_warehouse`、`baiyue_order`、`baiyue_firstleg` 具备建表、改表、建索引、创建临时存储过程和数据写入权限。
- 脚本不会创建数据库,不会清理或删除业务数据,也不会写入演示租户、演示用户、演示仓库、演示往来单位或快递公司样本。
- 脚本可重复执行。MySQL 的 DDL 会隐式提交,因此不能把整份跨库脚本视为可整体回滚的事务。
- 该历史脚本曾内联 IAM 客户档案字段迁移和 `platform:customer:view` 权限迁移,当前不得再单独执行。
## IAM 来源与执行顺序
固定入口中的 IAM 段按以下模块迁移依赖顺序组织,并通过元数据判断或 `ON DUPLICATE KEY UPDATE` 保持可重复执行:
1. IAM 基线表必须已存在(`iam.sql`)。
2. 权限父菜单和既有客户列表/审核权限基线(`phase1-admin-rbac.sql`、`rbac-role-management-v2.sql`)。
3. `phase1-platform-master-data-and-permission-management.sql` 中的 `platform:customer:view`、既有角色继承及管理员授权。
4. `phase1-customer-profile.sql` 中的十个 `iam_tenant` 客户档案字段。
5. `phase1-onboarding.sql` 中的 `PROFILE_REQUIRED` 默认状态、审核结果字段、资质审核备注及成员审计字段。
固定入口同时幂等补齐审核自动开户所需的全局 `MERCHANT_OWNER` 角色模板、全局商户菜单/按钮权限和角色授权;执行后应使用 `iam/src/test/resources/db/verify-phase1-admin-rbac.sql` 确认模板存在且权限完整。
测试环境只执行当前固定入口;历史脚本和模块脚本不应在固定入口执行后再次串行执行。
## 执行方式
在 Navicat、DataGrip 或 MySQL 命令行中以“运行脚本”方式完整执行,确保客户端支持 `DELIMITER`。不要只选中局部语句执行。
执行前先重新连接目标数据库,开启客户端 keepalive,并关闭“遇错继续执行”;出现连接断开、语法错误或 `SQLSTATE 45000` 后不得从失败位置续跑。由于 DDL 会隐式提交,存量环境可能已经部分更新;修复失败原因后应使用同一固定入口从第一行完整重跑,依靠脚本的元数据判断和幂等写入收敛结构。若出现 MySQL `4031`,先处理客户端连接保活或由数据库管理员调整 `wait_timeout` / `interactive_timeout`,再重新连接执行。
执行结束后必须看到 `migration_status = PASS`。如果中途出现 `SQLSTATE 45000`,必须按错误中给出的缺失表、字段或权限处理后重新完整执行。
## 三期分柜、预装、拣货与装柜当前基线
- 模块表结构来源:`firstleg/src/main/resources/db/phase3-split-preload-schema.sql`、`firstleg/src/main/resources/db/phase3-loading-delivery-schema.sql`。
- 三期平台权限直接维护在统一初始化与发布入口中,避免额外增加独立权限脚本。
- 测试和生产环境仍只执行固定入口 `头程数据库统一增量-MySQL8.sql`,不得再串行执行上述模块脚本。
- 必须先执行统一增量并取得 `PASS`,再启动或重启 Firstleg Service;否则统一订单摘要查询会因缺少三期操作表而失败。
- 统一脚本会创建智能装柜任务 `fl_loading_pick_task`,并把历史入库汇总任务按字段签名无损迁移到 `fl_inbound_loading_pick_task`;未知混合结构会直接终止。`WAIT_SPLIT` 是二期有效终点,脚本不会改写主表或状态历史。
- 下载中心固定使用 `5103040-5103041`,库位权限迁移到 `5103060-5103064`;入库装柜权限迁移到 `5102121-5102129`,迁移会按 `permission_code` 保留角色授权,目标 ID 被其他语义占用时直接终止。
部署前可只读盘点:
```sql
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'baiyue_firstleg'
AND table_name IN (
'fl_preload_plan', 'fl_split_operation', 'fl_loading_evidence',
'fl_loading_operation', 'fl_loading_pick_task'
)
ORDER BY table_name;
SELECT permission_code
FROM baiyue_iam.iam_permission
WHERE tenant_id = 0 AND app_code = 'PLATFORM' AND status = 'ACTIVE' AND deleted = 0
AND permission_code IN (
'firstleg:inbound:split', 'firstleg:inbound:preload',
'firstleg:inbound:preload-view',
'platform:firstleg:inbound:loading:edit',
'platform:firstleg:inbound:loading:view',
'platform:firstleg:inbound:loading:complete',
'platform:firstleg:inbound:delivery:complete',
'platform:firstleg:inbound:picking:edit',
'platform:firstleg:inbound:picking:view'
)
ORDER BY permission_code;
```
## 公共导出中心存量升级
固定入口已包含 File 当前 6 张表,并通过 `information_schema` 为旧版 `file_export_task` 幂等补齐 8 个调度、重试和租约字段,不再允许通过 `DROP TABLE` 重建。执行完成后可额外核验:
```sql
SELECT COUNT(*) = 3 AS export_tables_ready
FROM information_schema.tables
WHERE table_schema = 'baiyue_file'
AND table_name IN ('file_export_task', 'file_export_outbox', 'file_export_task_guard');
SELECT COUNT(*) = 1 AS creation_guard_ready
FROM baiyue_file.file_export_task_guard
WHERE guard_key = 'GLOBAL_CREATE';
SELECT COUNT(*) = 8 AS scheduler_columns_ready
FROM information_schema.columns
WHERE table_schema = 'baiyue_file' AND table_name = 'file_export_task'
AND column_name IN ('dispatch_version', 'attempt_count', 'max_attempts', 'next_retry_at',
'lease_owner', 'lease_until', 'last_heartbeat_at', 'execution_deadline_at');
```
任一结果不是 1,禁止启动 File Service;只能继续追加兼容性增量修复,不得删除存量导出任务。
## 二期第三方测量增量
- 模块脚本:`firstleg/src/main/resources/db/phase2-third-party-single-measurement-migration.sql`。
- 历史二期脚本:`2026-08-04-二期入库新增表字段-MySQL8一键执行.sql` 已冻结,仅供追溯。
- 当前固定入口 `头程数据库统一增量-MySQL8.sql` 已内联该增量以及订单船司字段、二期 28 项 IAM 权限和最新仓储资源租户字段。
- 新增 `external_request_hash`、`inbound_detail_id`、`external_detail_no` 和第三方明细唯一索引,用于一条回传绑定一条订单货物明细及一张文件中心图片。
- 部署 Firstleg 新版本前必须完整执行固定入口,并确认末尾总体验证为 `PASS`。
## 稳定箱号与单箱当前测量
- 固定入口已包含 `fl_inbound_carton_label`,首次打印时按订单货物明细冻结每个实际箱的 `box_code` 和箱下标;重复打印、部分补打及设备测量均复用该映射。
- `fl_inbound_measurement_item` 已补齐 `box_code`、`machine_no`、`device_measured_at`、`updated_at`,并通过 `uk_measure_box_code (tenant_id, box_code)` 保证同一客户下每个箱号只有一条当前测量记录。
- 部署 Firstleg 新版本前必须完整执行固定入口。末尾会强校验映射表、四个测量字段及三个唯一约束,任一缺失均不会返回 `PASS`。
## 当前主体字段语义核验
- 业务单租户阶段,业务表中的 `tenant_id > 0` 是客户 ID 和客户隔离键,不表示上级租户;费用项目是 `tenant_id = 0` 的平台公共主数据,入库费用明细仍以 `tenant_id > 0` 隔离客户并引用公共 `fee_item_id`。
- `fl_third_party_call_log.tenant_id = 0` 仅表示第三方主体未知或尚未解析的哨兵值,不是平台客户记录或平台操作作用域,绝不能据此授权、查询或写入客户业务数据。上线后可只读统计:
```sql
SELECT COUNT(*) AS unresolved_third_party_calls
FROM baiyue_firstleg.fl_third_party_call_log
WHERE tenant_id = 0;
```
- 平台公共仓库、地址、服务能力、往来单位 `wh_partner`、快递公司、托盘、库位、预占和占用固定归平台作用域 `tenant_id=0`;Firstleg 的 `warehouse_resource_tenant_id` 同步固定为 `0`。
- 客户订单、客户文件和客户费用规则仍使用 `tenant_id>0` 做客户隔离;往来单位不是客户私有数据,统一脚本会把 `wh_partner` 和 `wh_partner_type` 的作用域归零。
## 平台公共资源归零迁移与核验
测试环境仍只执行固定入口 `头程数据库统一增量-MySQL8.sql`,不要再串行执行模块脚本。执行前可只读盘点公共资源旧归属:
```sql
SELECT 'wh_warehouse' AS resource, COUNT(*) AS total, COALESCE(SUM(tenant_id <> 0), 0) AS non_platform
FROM baiyue_warehouse.wh_warehouse
UNION ALL SELECT 'wh_warehouse_address', COUNT(*), COALESCE(SUM(tenant_id <> 0), 0) FROM baiyue_warehouse.wh_warehouse_address
UNION ALL SELECT 'wh_service_capability', COUNT(*), COALESCE(SUM(tenant_id <> 0), 0) FROM baiyue_warehouse.wh_service_capability
UNION ALL SELECT 'wh_express_company', COUNT(*), COALESCE(SUM(tenant_id <> 0), 0) FROM baiyue_warehouse.wh_express_company
UNION ALL SELECT 'wh_pallet', COUNT(*), COALESCE(SUM(tenant_id <> 0), 0) FROM baiyue_warehouse.wh_pallet
UNION ALL SELECT 'wh_location', COUNT(*), COALESCE(SUM(tenant_id <> 0), 0) FROM baiyue_warehouse.wh_location
UNION ALL SELECT 'wh_location_reservation', COUNT(*), COALESCE(SUM(tenant_id <> 0), 0) FROM baiyue_warehouse.wh_location_reservation
UNION ALL SELECT 'wh_location_occupancy', COUNT(*), COALESCE(SUM(tenant_id <> 0), 0) FROM baiyue_warehouse.wh_location_occupancy
UNION ALL SELECT 'fl_inbound_pallet_allocation.resource_scope', COUNT(*),
COALESCE(SUM(warehouse_resource_tenant_id <> 0), 0)
FROM baiyue_firstleg.fl_inbound_pallet_allocation;
```
脚本会先把明确公共资源迁到 `0`,按父仓库回填地址和能力,再迁移平台往来单位、托盘、库位、预占、占用及 Firstleg 资源归属快照。末尾 `PASS` 前会强校验公共资源(含往来单位)全部归零、父子一致,以及客户费用规则不存在 `tenant_id=0`。执行后可再只读核验:
```sql
SELECT
(SELECT COUNT(*) FROM baiyue_warehouse.wh_warehouse WHERE tenant_id <> 0)
+ (SELECT COUNT(*) FROM baiyue_warehouse.wh_warehouse_address WHERE tenant_id <> 0)
+ (SELECT COUNT(*) FROM baiyue_warehouse.wh_service_capability WHERE tenant_id <> 0)
+ (SELECT COUNT(*) FROM baiyue_warehouse.wh_partner
WHERE tenant_id <> 0 OR data_scope_id <> 0)
+ (SELECT COUNT(*) FROM baiyue_warehouse.wh_partner_type
WHERE tenant_id <> 0 OR data_scope_id <> 0)
+ (SELECT COUNT(*) FROM baiyue_warehouse.wh_express_company WHERE tenant_id <> 0)
+ (SELECT COUNT(*) FROM baiyue_warehouse.wh_pallet WHERE tenant_id <> 0)
+ (SELECT COUNT(*) FROM baiyue_warehouse.wh_location WHERE tenant_id <> 0)
+ (SELECT COUNT(*) FROM baiyue_warehouse.wh_location_reservation WHERE tenant_id <> 0)
+ (SELECT COUNT(*) FROM baiyue_warehouse.wh_location_occupancy WHERE tenant_id <> 0)
+ (SELECT COUNT(*) FROM baiyue_firstleg.fl_inbound_pallet_allocation
WHERE warehouse_resource_tenant_id <> 0) AS public_scope_violations,
(SELECT COUNT(*) FROM baiyue_warehouse.wh_overseas_storage_fee_rule WHERE tenant_id = 0)
AS customer_scope_violations;
SELECT
(SELECT COUNT(*) FROM baiyue_warehouse.wh_warehouse_address a
JOIN baiyue_warehouse.wh_warehouse w ON w.id = a.warehouse_id
WHERE a.tenant_id <> w.tenant_id)
+ (SELECT COUNT(*) FROM baiyue_warehouse.wh_service_capability c
JOIN baiyue_warehouse.wh_warehouse w ON w.id = c.warehouse_id
WHERE c.tenant_id <> w.tenant_id)
+ (SELECT COUNT(*) FROM baiyue_warehouse.wh_pallet p
JOIN baiyue_warehouse.wh_warehouse w ON w.id = p.warehouse_id
WHERE p.tenant_id <> w.tenant_id)
+ (SELECT COUNT(*) FROM baiyue_warehouse.wh_location l
JOIN baiyue_warehouse.wh_warehouse w ON w.id = l.warehouse_id
WHERE l.tenant_id <> w.tenant_id) AS parent_child_scope_mismatches;
```
上述三个结果 `public_scope_violations`、`customer_scope_violations`、`parent_child_scope_mismatches` 必须都为 `0`。
## 船司 FBA 价格公共作用域
- 当前测试环境 `fl_carrier_fba_rate` 为空表,不执行存量价格迁移。
- 初始化表结构将船司 FBA 价格定义为平台公共价格,Firstleg 创建、查询和计费匹配固定使用 `tenant_id = 0`;客户计费规则仍按客户 `tenant_id > 0` 隔离。
- 初始化或重建测试库后,再启动或重启 `firstleg-service`。
## 海外仓阶梯费用增量
- `2026-08-05` 增量已追加到固定入口末尾,不创建新的日期部署脚本。
- Warehouse 新增 `wh_overseas_storage_fee_rule` 和 `wh_overseas_storage_fee_tier`,包含客户唯一索引、分页索引、阶梯起始天唯一索引和规则明细查询索引。
- IAM 新增 `platform:overseas-storage-fee:list/create/edit/delete` 四项权限,默认授予平台系统管理员。
- Warehouse Service 启动前必须先执行固定入口;末尾只有两张表、五个索引和四项权限均存在才返回 `PASS`。
## 四期海外权限目录
- 固定入口已同步 `iam/src/main/resources/db/lastleg-permissions.sql` 的 `platform:overseas-*` 权限,并默认授予平台系统管理员。
- 旧 `platform:lastleg:*` 权限会撤销角色关联并停用;不保留旧码兼容映射。
- 四期目录保留海外出库、派送列表入口;五期写操作和客户派送权限由后续五期区块直接收敛,不使用旧码兼容映射。
## 五期海外排车、出库与派送权限
- 国内固定入口已在四期 `lastleg-permissions.sql` 权限段之后完整内联 `iam/src/main/resources/db/phase5-delivery-permissions.sql`;测试和部署只执行固定入口,不再单独执行模块脚本。
- 平台端固定使用排车列表/编辑/取消/转派送、出库列表/创建/取消、派送列表/退回/状态、异常订单列表/创建和客户回访列表/编辑十四项权限;列表权限包含详情及只读辅助接口,写操作保持独立授权。
- 客户端固定使用 `merchant:warehouse:delivery:list` 和 `merchant:warehouse:delivery:create`;客户默认管理员获得两项权限,其他客户角色不自动扩权。
- `WAREHOUSE_OPERATOR` 获得十四项后台作业权限,`WAREHOUSE_TALLY` 只获得排车、出库、派送、异常订单和客户回访五项列表只读;国内、海外 PDA 岗位不得获得上述后台权限。
## 五期海外排车与出库结构升级
- 五期数据库部署仍只执行 `海外区域统一增量-MySQL8.sql`;空库先执行 Lastleg 与 Warehouse Overseas 当前基线,再完整执行固定入口并确认最末 `migration_status = PASS`。
- 固定入口只补目标字段并做 fail-fast 校验,不回填、改号、清理或从其他表推断开发旧行。`ll_dispatch_pda_task.warehouse_id` 存在 `NULL`、空值或 `0`,或任一待收敛全局业务号/任务号、完成幂等键发生冲突时,脚本立即 `SIGNAL`;应重新造数,重置或清理仍需用户另行授权。
- 数据门禁通过后,脚本原位把 `dispatch_no`、`outbound_no`、排车 PDA `task_no`、出库 PDA `task_no` 收敛为全局唯一,并建立 `(customer_id, completion_idempotency_key)` 完成命令唯一约束;旧客户复合索引不保留。
- 必须在启动或重启 Lastleg Service 前完成固定入口;不得单独执行模块基线补丁、日期脚本或手工兼容 SQL。