暂存提交
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
# 后端缺口修复回归报告
|
||||
|
||||
日期:2026-07-31
|
||||
范围:Auth、IAM、Order、Firstleg、Warehouse、File 及其公共依赖
|
||||
测试边界:未连接或写入测试数据库,未启动业务服务,未占用现有服务端口。
|
||||
|
||||
## 1. 修复结论
|
||||
|
||||
### 1.1 订单权限与草稿稳定性
|
||||
|
||||
- 商户订单列表增加 `merchant:order:list`,详情增加 `merchant:order:view`。
|
||||
- 平台订单列表和详情统一增加已初始化的 `platform:order:list`。
|
||||
- 订单号改为基于雪花 ID 生成,消除原秒级时间加三位随机数在并发下重复的风险。
|
||||
- 仓库、往来单位返回空名称、错误仓库 ID、空地址元素或空能力元素时,转换为受控业务错误,不再进入未捕获空指针。
|
||||
- 地址和收货能力快照格式化增加空元素防护。
|
||||
|
||||
### 1.2 平台内部用户与权限
|
||||
|
||||
- 内部用户列表改为明确 DTO,返回 `membershipId`、`userId`、`authUserId`、登录名、姓名、电话、邮箱、成员编号、状态和 `roleIds`。
|
||||
- 列表增加 `platform:user:list` 服务端权限校验。
|
||||
- 保留原新增路径,兼容关联已有 Auth 账号,同时支持完整创建平台账号。
|
||||
- 新增编辑、启停和重置密码接口,分别校验 `platform:user:edit`、`platform:user:status`、`platform:user:reset-password`。
|
||||
- Auth 支持平台应用域账号、账号创建幂等、显示名同步、状态变更和密码重置。
|
||||
- IAM/Auth 创建、资料和状态写入增加补偿处理;成功写入后不再执行可能破坏一致性的远程查询。
|
||||
- 企业资料查询增加 `merchant:profile:view` 权限校验。
|
||||
|
||||
### 1.3 企业资质文件契约
|
||||
|
||||
- File multipart 接口成为唯一公开资质上传入口。
|
||||
- 删除 IAM 旧 JSON POST 路由、DTO、Service 固定冲突方法以及 OpenAPI 成功声明。
|
||||
- 初始化 SQL 不再生成 `/phase1-seed/...` 虚假已审核资质。
|
||||
- 新增 `企业资质文件迁移说明.md`,要求取得真实原文件、写入 File 存储并校验后,才能事务更新旧记录 URL。
|
||||
|
||||
### 1.4 订单持久化幂等与错误语义
|
||||
|
||||
- 创建草稿和提交订单强制接收 `Idempotency-Key`,唯一范围为租户、操作者、操作和幂等键。
|
||||
- 请求摘要包含资源与请求内容;同键同请求回放首次结果,同键不同请求或处理中请求返回 409。
|
||||
- 幂等记录、业务写入和完成状态位于同一本地事务,数据库唯一键负责并发互斥。
|
||||
- 不存在订单优先返回 404;Warehouse 下游异常、空响应和无效主数据转换为受控 404、403、422 或 503。
|
||||
|
||||
### 1.5 Firstleg 与 Warehouse 管理闭环
|
||||
|
||||
- Firstleg 增加任务分页、详情、按订单查询、分配历史和分配/改派权限,所有仓储查询均带目标租户。
|
||||
- `idx_task_tenant_created` 同时写入新库建表脚本和可重复执行的既有库增量迁移。
|
||||
- Warehouse 增加租户级往来单位、快递公司分页、详情、新增、编辑和启停;停用保留历史主数据,不物理删除。
|
||||
- IAM 同步新增六个 Warehouse 按钮权限及四个 Firstleg 权限,并保持平台管理员、订单运营角色授权一致。
|
||||
|
||||
## 2. 自动化回归
|
||||
|
||||
独立总审执行命令:
|
||||
|
||||
```powershell
|
||||
mvn -pl iam,warehouse,order,firstleg -am clean test
|
||||
```
|
||||
|
||||
结果:在完整纯 ASCII 临时构建副本中执行,10 个 Reactor 模块全部构建成功。副本文件数与实施工作树一致;未连接数据库、未启动服务。正式仓同步后还会再次执行同一 `clean test`。
|
||||
|
||||
| 模块 | 测试数 | 结果 |
|
||||
|---|---:|---|
|
||||
| common-core | 2 | 通过 |
|
||||
| common-web | 4 | 通过 |
|
||||
| common-security | 6 | 通过 |
|
||||
| auth-service | 10 | 通过 |
|
||||
| iam-service | 48 | 通过 |
|
||||
| order-service | 14 | 通过 |
|
||||
| firstleg-service | 6 | 通过 |
|
||||
| warehouse-service | 23 | 通过 |
|
||||
|
||||
重点新增覆盖:订单持久化幂等、404/409/503 语义、平台用户完整生命周期、权限初始化、企业分页、Firstleg 租户过滤与权限、Warehouse CRUD/唯一性/Schema 契约,以及 OpenAPI YAML 解析。
|
||||
|
||||
静态检查:`git diff --check` 通过;仅存在工作树既有的 CRLF/LF 转换提示,不属于补丁空白错误。
|
||||
|
||||
## 3. 仍需环境联调确认
|
||||
|
||||
- 历史两次订单 `S0500` 的完整异常栈仍未取得,因此不能声称已还原历史唯一根因;本次已消除代码中能够确定的编号碰撞和空数据未受控风险。
|
||||
- 测试库旧 `/phase1-seed/...` 记录没有原文件,不能安全自动改成随机 UUID。本次没有写测试库,需取得真实营业执照文件后按迁移说明处理。
|
||||
- 本地 Warehouse 五张表与 Entity/SQL 的只读核验一致;历史查询 500 没有异常栈,不能把其唯一根因归结为 Schema 漂移。
|
||||
- `PENDING`、`REJECTED` 资质样本仍需由测试负责人准备脱敏数据后,完成浏览器五状态验收。
|
||||
- Dashboard 数量统计、并发请求隔离、示例 Store 和前端强制授予 `dashboard:view` 属于前端问题,不在后端增加虚假兼容逻辑。
|
||||
|
||||
## 4. 索引同步
|
||||
|
||||
- 已更新 `order/AGENTS.md`、`iam/AGENTS.md`、`auth/AGENTS.md`、`file/AGENTS.md`。
|
||||
- 新增平台内部用户 DTO、Service 和测试入口后,已同步更新根目录 `AGENTS.md`。
|
||||
- 企业资质迁移说明和本报告均为中文文档。
|
||||
- 已更新 `warehouse/AGENTS.md`、`firstleg/AGENTS.md` 和根 `AGENTS.md`,并在中文 API 文档补充 IAM、订单幂等、Firstleg 与 Warehouse 管理契约。
|
||||
- 正式仓同步与最终测试结果在同步完成后写入本报告末尾。
|
||||
|
||||
## 5. 正式仓同步与最终复核
|
||||
|
||||
- 审核通过的文件已按显式文件清单安全同步至 `D:\baiyue-firstleg`;未使用目录覆盖、`reset` 或清理操作,正式仓原有未提交修改已保留。
|
||||
- 正式仓已于 2026-07-31 14:52:33 执行并通过:
|
||||
|
||||
```powershell
|
||||
mvn "-DargLine=-Djdk.attach.allowAttachSelf=true" -pl iam,warehouse,order,firstleg -am clean test
|
||||
```
|
||||
|
||||
共 10 个 Reactor 模块构建成功;该 JVM 参数仅规避本机 Mockito 动态代理加载异常缓慢,不改变业务配置。
|
||||
- 正式仓 `git diff --check` 通过。本轮未写数据库、未启动业务服务、未占用业务端口。
|
||||
|
||||
### 5.1 未提交 SQL 执行清单(尚未执行)
|
||||
|
||||
1. `order/src/main/resources/db/order.sql`:创建 `ord_idempotency_record`。
|
||||
2. `iam/src/main/resources/db/phase1-admin-rbac.sql`:补齐 Firstleg、Warehouse 权限和角色授权。
|
||||
3. `warehouse/src/main/resources/db/warehouse-express-company.sql`:创建快递公司表。
|
||||
4. `firstleg/src/main/resources/db/firstleg.sql`:新库基础结构。
|
||||
5. `firstleg/src/main/resources/db/phase1-firstleg-task-list-index.sql`:对既有 Firstleg 库可重复执行,补齐 `fl_fulfillment_task.idx_task_tenant_created`;新库已在基础建表脚本中包含该索引。
|
||||
|
||||
如后续获得明确数据库写入授权,应先开发库、校验后测试库,并逐项保留执行结果;本报告不构成实际写库记录。
|
||||
@@ -0,0 +1,62 @@
|
||||
# 企业资质文件迁移说明
|
||||
|
||||
## 统一接口边界
|
||||
|
||||
企业资质的唯一真实上传入口是:
|
||||
|
||||
```http
|
||||
POST /api/merchant/v1/files/qualifications
|
||||
Content-Type: multipart/form-data
|
||||
```
|
||||
|
||||
表单字段为 `file`,可选字段为 `certificateNo`。File 服务先校验并保存真实图片,再通过内部接口通知 IAM 创建资质和审核记录。IAM 的商户资质接口只负责查询,不再提供 JSON 上传入口。
|
||||
|
||||
有效的商户预览地址格式为:
|
||||
|
||||
```text
|
||||
/api/merchant/v1/files/qualifications/{uuid}.jpg
|
||||
/api/merchant/v1/files/qualifications/{uuid}.png
|
||||
```
|
||||
|
||||
数据库中的 URL 不是文件本身。禁止只生成 UUID 并修改 `document_url`,也禁止用空文件或任意图片冒充营业执照。
|
||||
|
||||
## 历史数据盘点
|
||||
|
||||
发布前先以只读方式盘点历史路径:
|
||||
|
||||
```sql
|
||||
SELECT id, tenant_id, qualification_type, document_url, status
|
||||
FROM baiyue_iam.iam_tenant_qualification
|
||||
WHERE deleted = 0
|
||||
AND (document_url IS NULL
|
||||
OR document_url NOT REGEXP '^/api/merchant/v1/files/qualifications/[0-9a-fA-F-]{36}\\.(jpg|png)$');
|
||||
```
|
||||
|
||||
盘点结果中的每条记录都必须找到原始图片。找不到原始图片时,将记录标记为“待业务补传”,不得伪造文件,也不得直接改 URL。
|
||||
|
||||
## 可落地迁移步骤
|
||||
|
||||
1. 暂停对应资质的替换操作,记录资质 ID、租户 ID、旧 URL 和原文件校验和。
|
||||
2. 从可信旧存储取得原始图片,校验文件签名、扩展名和不超过 5 MB 的大小限制。
|
||||
3. 使用迁移工具按 File 服务同一规则生成 UUID 文件名,将真实文件写入共享存储的 `qualifications/{tenantId}/` 目录。
|
||||
4. 写入完成后,从 File 服务平台预览接口读取新文件并核对 SHA-256;读取失败时不得修改数据库。
|
||||
5. 在单条事务中按 `id + tenant_id + 旧 document_url` 条件更新 IAM 的 `document_url`。受影响行数不是 1 时立即回滚。
|
||||
6. 再次通过平台预览接口验收;验收完成前保留旧文件和旧 URL 清单,以便回滚。
|
||||
|
||||
数据库更新模板如下,执行时必须替换为经过文件校验的真实值:
|
||||
|
||||
```sql
|
||||
START TRANSACTION;
|
||||
UPDATE baiyue_iam.iam_tenant_qualification
|
||||
SET document_url = :verified_new_url
|
||||
WHERE id = :qualification_id
|
||||
AND tenant_id = :tenant_id
|
||||
AND document_url = :expected_old_url
|
||||
AND deleted = 0;
|
||||
-- 仅当 ROW_COUNT() = 1 且新文件已通过 File 预览校验时提交,否则回滚。
|
||||
COMMIT;
|
||||
```
|
||||
|
||||
## 新环境初始化
|
||||
|
||||
初始化脚本不再创建 `/phase1-seed/...` 虚假资质。测试环境需要可下单的商户时,应使用脱敏但真实存在的 JPG/PNG 文件走 File 上传、平台审核完整流程,使租户达到 `ACTIVE` 且资质达到 `APPROVED`。初始化账号、文件和审核结果应作为一套环境数据验收,不得仅靠 SQL 绕过文件保存。
|
||||
@@ -0,0 +1,91 @@
|
||||
# 重量 OCR 接入说明
|
||||
|
||||
## 功能位置
|
||||
|
||||
重量 OCR 已作为功能模块并入 `integration-service`,不再作为独立微服务部署,不新增端口、数据库或注册服务名。
|
||||
|
||||
主要代码:
|
||||
|
||||
- `controller/WeightOcrController.java`:内部批量识别接口。
|
||||
- `service/ocr/WeightOcrBatchService.java`:批次编排、结果汇总和文件落盘。
|
||||
- `service/ocr/ImageCropper.java`:图片下方中央区域裁剪。
|
||||
- `service/ocr/WeightCandidateSelector.java`:重量候选筛选。
|
||||
- `service/ocr/WeightOcrStoragePolicy.java`:输入、输出目录边界保护。
|
||||
- `provider/ocr/BaiduMeterClient.java`:百度令牌缓存、识别、限速和重试。
|
||||
|
||||
## 接口
|
||||
|
||||
```text
|
||||
POST /internal/integrations/weight-ocr/batches
|
||||
X-Internal-Service-Token: 内部服务令牌
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
请求示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"inputDirectory": "batch-001",
|
||||
"outputDirectory": null,
|
||||
"cropStartRatio": 0.5,
|
||||
"horizontalTrimRatio": 0.25,
|
||||
"recursive": false
|
||||
}
|
||||
```
|
||||
|
||||
`inputDirectory` 默认相对于 `WEIGHT_OCR_INPUT_ROOT`,`outputDirectory` 默认在 `WEIGHT_OCR_OUTPUT_ROOT` 下按批次 ID 自动创建。接口拒绝访问两个受控根目录之外的路径。
|
||||
|
||||
## 必需配置
|
||||
|
||||
```text
|
||||
BAIDU_OCR_ENABLED=true
|
||||
BAIDU_OCR_API_KEY=百度应用的API Key
|
||||
BAIDU_OCR_SECRET_KEY=百度应用的Secret Key
|
||||
INTERNAL_SERVICE_TOKEN=至少32字节的内部令牌
|
||||
```
|
||||
|
||||
本地默认目录:
|
||||
|
||||
```text
|
||||
${java.io.tmpdir}/baiyue-weight-ocr/input
|
||||
${java.io.tmpdir}/baiyue-weight-ocr/output
|
||||
```
|
||||
|
||||
国内服务器默认目录:
|
||||
|
||||
```text
|
||||
/data/baiyue/weight-ocr/input
|
||||
/data/baiyue/weight-ocr/output
|
||||
```
|
||||
|
||||
可选配置:
|
||||
|
||||
| 环境变量 | 默认值 | 说明 |
|
||||
| --- | ---: | --- |
|
||||
| `WEIGHT_OCR_MAX_IMAGE_SIZE` | `3MB` | 单张原图及裁剪图上限 |
|
||||
| `WEIGHT_OCR_MAX_IMAGE_PIXELS` | `40000000` | 解码后最大像素数 |
|
||||
| `WEIGHT_OCR_MAX_BATCH_SIZE` | `50` | 单批图片上限 |
|
||||
| `BAIDU_OCR_CONNECT_TIMEOUT` | `10s` | 建连超时 |
|
||||
| `BAIDU_OCR_REQUEST_TIMEOUT` | `60s` | 单次请求超时 |
|
||||
| `BAIDU_OCR_MIN_REQUEST_INTERVAL` | `600ms` | 百度请求最小间隔 |
|
||||
| `BAIDU_OCR_MAX_QPS_RETRIES` | `3` | 百度 QPS 限制重试次数 |
|
||||
|
||||
## 输出文件
|
||||
|
||||
```text
|
||||
批次输出目录/
|
||||
├─ batch-results.json
|
||||
├─ cropped/
|
||||
└─ raw/
|
||||
```
|
||||
|
||||
接口和结果文件仅返回相对于受控根目录的路径,不返回服务器绝对路径。真实百度响应不写入日志,只保存在批次的 `raw` 目录。
|
||||
|
||||
## 安全边界
|
||||
|
||||
- 接口仅供内部服务调用,必须校验 `X-Internal-Service-Token`。
|
||||
- 百度能力默认关闭,密钥只从环境变量或配置中心密文注入。
|
||||
- 同一实例一次只执行一个 OCR 批次,避免并发压垮第三方接口。
|
||||
- 单批顺序调用百度接口,并对 QPS 错误执行有上限的退避重试。
|
||||
- 支持 `jpg`、`jpeg`、`png`、`bmp`,同时限制文件大小和解码像素数。
|
||||
- 当前不访问业务数据库,识别结果由调用方按自己的业务边界处理。
|
||||
Reference in New Issue
Block a user