feat(platform): consolidate production vehicle data workflows
This commit is contained in:
206
vehicle-data-platform/docs/oneos-change-approval-proposal.md
Normal file
206
vehicle-data-platform/docs/oneos-change-approval-proposal.md
Normal file
@@ -0,0 +1,206 @@
|
||||
# OneOS 客户车辆门户变更审批提案
|
||||
|
||||
更新时间:2026-07-14
|
||||
|
||||
状态:已停止。2026-07-14 用户明确要求不修改 `ln-asset-management` 任何逻辑;此前本地试验改动已全部撤销,OneOS 仓库保持干净。本文件仅保留为风险证据,不构成待执行审批项。
|
||||
|
||||
## 1. 审批目标
|
||||
|
||||
本提案只解决客户只读访问车辆数据所必需的三件事:
|
||||
|
||||
1. OneOS 能稳定识别客户账号并输出不可伪造的客户身份;
|
||||
2. OneOS 的“当前客户车辆”事实不会因合同保存被破坏;
|
||||
3. 车辆数据中台收到客户身份后,只能访问该客户的车辆 Scope。
|
||||
|
||||
车辆锁车、控车以及保险、结算、事故、违章等客户功能不在本批次范围内。
|
||||
|
||||
## 2. 当前源码证据
|
||||
|
||||
### 2.1 客户车辆 RPC 当前会泄露全量车辆
|
||||
|
||||
`ln-asset-management/src/main/java/com/ln/asset/api/impl/RemoteVehicleServiceImpl.java:83`
|
||||
的 `listByCustomerId` 忽略 `customerId`,实际只按 `del_flag=0` 查询。其 VO 转换也没有回填
|
||||
`customerId` 和 `contractCode`。
|
||||
|
||||
该接口在修复前必须保持内部禁用,不能作为车辆数据中台的授权来源。
|
||||
|
||||
### 2.2 当前租赁 Mapper 会丢字段
|
||||
|
||||
`ln-asset-management/src/main/resources/mapper/VehicleLeaseOrderRecordMapper.xml:6`
|
||||
的 `BaseResultMap` 与 `Base_Column_List` 缺少以下实体字段:
|
||||
|
||||
- `customer_id`、`project_name`;
|
||||
- `delivery_vehicle_id`、`last_delivery_name`;
|
||||
- `return_vehicle_task_id`、`last_return_name`;
|
||||
- `update_by`。
|
||||
|
||||
使用这些自定义查询取得记录后,上述字段会变成空值。生产审计同时发现聚合记录与最新历史记录有
|
||||
325 条关键字段差异,不能把空值当成“无业务关系”。
|
||||
|
||||
### 2.3 合同保存会清空交还车事实
|
||||
|
||||
`VehicleLeaseOrderRecordServiceImpl.java:262` 在 `deliveryVehicleId == null` 时,同时清空交车和还车的
|
||||
单据 ID、时间、里程与操作人。合同提交/更新并不代表交车事实撤销,因此这里违反业务事实的单一写入原则。
|
||||
|
||||
交车字段只能由交车完成/撤销流程修改;还车字段只能由还车完成/撤销流程修改。合同更新只能更新客户、合同、
|
||||
项目和业务组织字段。
|
||||
|
||||
### 2.4 客户账号当前不能安全登录
|
||||
|
||||
- `CustomerInfoServiceImpl.java:188` 先尝试创建 `sys_user`,之后才保存客户档案;远程调用失败被吞掉,两个库之间不存在事务一致性。
|
||||
- `SysUserRegistrar.java:27` 给所有业务账号使用共享初始密码 `ln123456`。
|
||||
- `RemoteUserServiceImpl.java:222` 把业务账号开通绑定到公开注册开关 `sys.account.registerUser`。
|
||||
- `UserType.java:14` 只支持 `sys_user` 和 `app_user`;`customer` 会在 Sa-Token 权限解析时抛异常。
|
||||
- 密码登录按 `tenantId + username` 查询,短信登录默认取同手机号的第一条记录,均不能可靠区分客户账号。
|
||||
- 更新客户档案不会同步账号;删除客户时账号删除异常同样只记日志。
|
||||
|
||||
生产审计结果是 335 个有效客户中,当前客户账号数量为 0,因此不能直接批量启用现有逻辑。
|
||||
|
||||
## 3. 推荐变更批次
|
||||
|
||||
### B1:修复客户车辆业务事实(`ln-asset-management`)
|
||||
|
||||
预计修改文件:
|
||||
|
||||
- `src/main/resources/mapper/VehicleLeaseOrderRecordMapper.xml`
|
||||
- `src/main/java/com/ln/asset/modules/contract/mapper/VehicleLeaseOrderRecordMapper.java`
|
||||
- `src/main/java/com/ln/asset/modules/contract/service/impl/VehicleLeaseOrderRecordServiceImpl.java`
|
||||
- `src/main/java/com/ln/asset/api/impl/RemoteVehicleServiceImpl.java`
|
||||
- `ln-asset-api/src/main/java/com/ln/asset/api/RemoteVehicleService.java`
|
||||
- `ln-asset-api/src/main/java/com/ln/asset/api/domain/vo/RemoteVehicleVo.java`
|
||||
- 对应单元/集成测试文件
|
||||
|
||||
变更内容:
|
||||
|
||||
1. 补齐 Mapper 的所有实体字段映射与列清单;禁止“读出空值再全实体更新”覆盖已有事实。
|
||||
2. 把合同字段更新与交车/还车生命周期更新拆开:合同保存不再修改任何交还车字段。
|
||||
3. 增加显式的当前 Scope 查询,条件必须同时包含有效车辆、有效客户、有效合同、已交车未还车、
|
||||
`record.customer_id = COALESCE(contract.other_customer_id, contract.customer_id)`。
|
||||
4. 异常关系返回隔离原因,不为其生成授权记录。
|
||||
5. 修复 `listByCustomerId`,但将其标注为兼容接口;车辆中台继续使用已实现的最小权限 RDS 快照同步,
|
||||
不依赖一次 RPC 返回无限列表。
|
||||
6. 交车、还车聚合更新失败必须让业务事务失败或写入可重试 Outbox,不能仅记录日志后继续成功。
|
||||
|
||||
明确不做:
|
||||
|
||||
- 不把遥测位置、在线状态或总里程回写为交还车业务事实;
|
||||
- 不恢复 `vehicle_info.customer_id` 作为客户归属;
|
||||
- 不修改锁车、控车业务。
|
||||
|
||||
验收测试:
|
||||
|
||||
- 客户 A 查询结果不含客户 B 车辆;空客户 ID 返回空集合;
|
||||
- 丙方客户存在时只归属 `other_customer_id`;
|
||||
- 未交车、已还车、客户/合同不一致、缺 VIN 的车辆均不授权;
|
||||
- 合同重复保存前后,交还车单 ID、时间、里程完全不变;
|
||||
- 同一车辆存在多个当前关系时整体隔离,而不是任选一条;
|
||||
- 本段验收基线已被事务事实影子查询取代;当前只读中台口径为 639 个候选、613 个可发布、26 个隔离。
|
||||
|
||||
回滚:
|
||||
|
||||
- B1 不删除字段、不改变 Dubbo 方法签名;可按服务版本回滚;
|
||||
- 新查询与旧接口并存一个版本,车辆中台只读同步可独立停用;
|
||||
- 数据修复 SQL 与代码发布分开审批,禁止发布脚本自动改写异常关系。
|
||||
|
||||
### B2:建立客户账号一致性(`ln-cloud` + `ln-asset-management`)
|
||||
|
||||
预计修改文件/模块:
|
||||
|
||||
- `ln-cloud/ruoyi-common/ruoyi-common-core/.../UserType.java`
|
||||
- `ln-cloud/ruoyi-common/ruoyi-common-satoken/.../SaPermissionImpl.java`
|
||||
- `ln-cloud/ruoyi-api/ruoyi-api-system/.../RemoteUserService.java`
|
||||
- `ln-cloud/ruoyi-modules/ruoyi-system/.../RemoteUserServiceImpl.java`
|
||||
- `ln-cloud/ruoyi-modules/ruoyi-system/.../ISysUserService.java`
|
||||
- `ln-cloud/ruoyi-modules/ruoyi-system/.../SysUserServiceImpl.java`
|
||||
- `ln-cloud/ruoyi-auth` 新增独立客户认证策略
|
||||
- `ln-asset-management` 客户账号开通、更新、停用 Outbox/补偿任务
|
||||
- 新增账号绑定/激活所需数据库迁移与测试
|
||||
|
||||
变更内容:
|
||||
|
||||
1. 增加明确的 `CUSTOMER("customer")` 类型,并为客户主体返回固定、最小的门户权限,不继承后台菜单权限。
|
||||
2. 新增内部“业务账号开通”接口,不再复用公开自助注册开关;接口以
|
||||
`(tenantId, userType, businessId)` 幂等,并校验用户名、手机号冲突。
|
||||
3. 增加显式业务绑定,不能仅依赖 `sys_user.user_id == customer_info.id` 的偶然约定。
|
||||
4. 客户档案事务写入 Outbox;账号、角色、绑定创建失败可重试、可告警、可人工补偿。前端明确展示“账号待开通”,
|
||||
不再静默成功。
|
||||
5. 删除共享默认密码。采用一次性随机激活凭证,短时有效、单次使用;激活后立即失效。
|
||||
6. 新增独立 `customer_password` / `customer_sms` 登录策略。客户类型由受信客户端配置或策略固定,不能由浏览器
|
||||
任意传入;后台密码登录仍只允许后台账号。
|
||||
7. 客户停用、删除或合作终止时撤销其会话,并产生身份版本变更事件。
|
||||
8. 存量补偿先输出冲突清单;335 个客户不得按手机号自动合并,审计发现的 4 个手机号匹配必须人工确认。
|
||||
|
||||
验收测试:
|
||||
|
||||
- 同用户名/手机号存在不同主体类型时,客户登录只能命中 customer;
|
||||
- 客户账号不能使用后台登录策略,后台账号不能使用客户策略;
|
||||
- 公开注册关闭时,内部业务账号开通仍可按授权调用;
|
||||
- 重复 Outbox 消息不会创建重复账号、绑定或角色;
|
||||
- 激活凭证不能复用,日志中不出现明文凭证或密码;
|
||||
- 删除/停用客户后现有 token 立即失效;
|
||||
- 客户权限解析不抛 `UserType not found`,且没有后台菜单权限。
|
||||
|
||||
回滚:
|
||||
|
||||
- 新客户认证使用独立 grant type 和独立客户端,关闭该客户端即可停止入口;
|
||||
- 绑定表和 Outbox 只新增,不破坏现有后台账号;
|
||||
- 回滚应用版本前先停止补偿消费者,不删除已经创建的客户账号,只统一停用,避免 ID 被复用。
|
||||
|
||||
### B3:向车辆中台签发短时身份(`ln-cloud/ruoyi-auth`)
|
||||
|
||||
推荐新增内部/登录后交换接口:
|
||||
|
||||
```http
|
||||
POST /inner/v1/vehicle-platform/token
|
||||
Authorization: Bearer <oneos-customer-token>
|
||||
```
|
||||
|
||||
服务端从 Sa-Token 会话和业务绑定取得 `userId/customerId/tenantId/userType`,签发最长 5 分钟、
|
||||
`aud=vehicle-data-platform` 的短时 JWT。浏览器不能提交或覆盖 `customerId`。
|
||||
|
||||
最低声明:
|
||||
|
||||
```json
|
||||
{
|
||||
"iss": "oneos-auth",
|
||||
"aud": "vehicle-data-platform",
|
||||
"sub": "<sys_user.user_id>",
|
||||
"subjectType": "customer",
|
||||
"customerId": "<customer_info.id>",
|
||||
"tenantId": "<tenant_id>",
|
||||
"scope": ["vehicle:read"],
|
||||
"identityVersion": 1,
|
||||
"iat": 0,
|
||||
"exp": 0,
|
||||
"jti": "<random>"
|
||||
}
|
||||
```
|
||||
|
||||
安全要求:
|
||||
|
||||
- 使用非对称签名,车辆中台只持有公钥;密钥 ID 支持轮换;
|
||||
- 严格校验发行方、受众、算法、`exp/nbf/iat`、主体类型和客户 ID;
|
||||
- 网关删除外部传入的同名身份头;不信任 `X-Customer-Id`;
|
||||
- Scope 投影过期、身份绑定缺失或账号停用时,车辆中台失败关闭;
|
||||
- 任何越权详情统一返回 404,避免泄露 VIN 或告警 ID 是否存在。
|
||||
|
||||
回滚:停止 token 交换接口或撤销对应客户端;车辆中台客户入口关闭,内部管理员入口不受影响。
|
||||
|
||||
## 4. 数据库变更必须单独审批
|
||||
|
||||
在修复 1 组重复聚合记录并确认软删除语义前,不直接添加唯一约束。建议顺序:
|
||||
|
||||
1. 输出重复记录和 26 条隔离关系的业务核对清单;
|
||||
2. 由合同/交还车业务负责人确认每条修复方式;
|
||||
3. 在预发布库回放合同保存、交车、还车、再次交车和丙方客户用例;
|
||||
4. 再评估 `vehicle_lease_order_record(vehicle_id)` 唯一约束及 Scope 查询索引;
|
||||
5. DDL 使用在线方式并准备反向 DDL,不与应用代码在同一步骤自动执行。
|
||||
|
||||
## 5. 推荐审批顺序
|
||||
|
||||
1. B1/B2 已停止,不修改 OneOS 业务逻辑;
|
||||
2. 先完成车辆中台只读 Scope 投影与异常隔离;
|
||||
3. 客户身份入口需另行确定可信身份来源并通过双客户越权测试;
|
||||
4. 最后才进行外部客户灰度。
|
||||
|
||||
每个批次独立提交、独立发布、独立回滚。未经用户明确同意,不修改上述 OneOS 文件。
|
||||
Reference in New Issue
Block a user