Files
lingniu-vehicle-ingest/vehicle-data-platform/docs/oneos-customer-vehicle-scope-contract.md

181 lines
6.4 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.
# OneOS 客户车辆范围内部接口契约(草案)
更新时间2026-07-14
## 1. 目的与安全边界
该接口仅向车辆数据中台提供 OneOS 已确认的客户车辆授权范围,不提供密码,不允许浏览器直连,也不承担实时遥测查询。
- OneOS 是客户、合同、交还车事实和车辆档案的权威来源。
- 车辆数据中台只保存可重建的只读投影。
- 客户 ID 必须来自已验证的 OneOS 会话或内部同步任务,不能采用浏览器请求参数。
- 归属不确定、VIN 缺失、存在多客户冲突的车辆必须放入异常列表,不能进入授权列表。
- 内部请求需要服务身份认证、时间戳、防重放和请求 ID网关必须剥离外部同名身份头。
## 2. 推荐接口
### 查询客户车辆快照
```http
GET /inner/v1/customer-vehicle-scopes/{customerId}?cursor=&limit=500
Authorization: Service <service-token>
X-Request-Id: <uuid>
X-Request-Timestamp: <unix-seconds>
X-Request-Signature: <hmac-sha256>
```
响应:
```json
{
"code": 0,
"data": {
"customerId": "1001",
"scopeVersion": "2026-07-14T12:00:00.123Z/987654",
"generatedAt": "2026-07-14T12:00:00.123Z",
"complete": true,
"nextCursor": null,
"items": [
{
"vehicleId": "2001",
"vin": "LXXXXXXXXXXXXXXXX",
"plateNumber": "沪A00000",
"customerId": "1001",
"contractId": "3001",
"contractCode": "HT20260001",
"projectName": "示例项目",
"modelName": "示例车型",
"brandName": "示例品牌",
"operationStatus": "2",
"scopeStartAt": "2026-07-01T08:00:00+08:00",
"sourceUpdatedAt": "2026-07-14T11:59:58.456+08:00"
}
],
"rejected": [
{
"vehicleId": "2002",
"reason": "VIN_MISSING"
}
]
},
"requestId": "..."
}
```
约束:
- 雪花 ID 一律用 JSON 字符串传输,避免 JavaScript 数字精度丢失。
- `scopeVersion` 对同一业务快照稳定;分页中的每一页必须来自同一个快照。
- `complete=false` 表示快照不完整,车辆中台不得发布该版本。
- `items` 内 VIN 必须非空、标准化为大写并在当前快照内唯一。
- `rejected` 只返回机器可读原因和内部车辆 ID不返回敏感客户信息。
- 建议 `ETag=scopeVersion`,支持 `If-None-Match` 降低同步流量。
### 批量检查客户车辆归属
供登录后单车访问和安全审计使用,不代替快照同步:
```http
POST /inner/v1/customer-vehicle-scopes/check
Content-Type: application/json
{
"customerId": "1001",
"vins": ["LXXXXXXXXXXXXXXXX"]
}
```
响应必须对每个 VIN 返回 `allowed/denied/unknown``unknown` 与接口异常在外部访问场景中均按拒绝处理。
## 3. 当前车辆判定
候选记录至少满足:
```text
vehicle_info.del_flag = 0
vehicle_lease_order_record.del_flag = 0
最新有效 delivery_vehicle.delivery_status IN (2,3)
不存在该交车单对应的有效 return_vehicle_task.status IN (2,3,5)
vehicle_lease_order_record.customer_id = customerId仅作为独立归属交叉校验
VIN 非空且唯一
```
同时必须核验:
- 记录客户等于合同 `COALESCE(other_customer_id, customer_id)`
- 不使用 `vehicle_lease_order_record.last_return_time` 判定当前生命周期OneOS 还车草稿保存会提前写入该聚合字段;
- 聚合记录的合同、交车单和最近历史记录一致;
- 不存在同一 VIN/vehicleId 同时授权给多个客户;
- 合同保存没有覆盖已发生的交还车事实。
生产数据审计完成前,该判定仅为候选口径,不得直接开放外部客户。
## 4. 身份声明契约
客户请求由 OneOS Gateway 完成登录态验证后,可向车辆中台传递短时签名声明:
```json
{
"iss": "oneos-gateway",
"aud": "vehicle-data-platform",
"sub": "1001",
"subjectType": "customer",
"customerId": "1001",
"tenantId": "000000",
"roles": ["customer_vehicle_viewer"],
"iat": 1784001600,
"exp": 1784001900,
"jti": "..."
}
```
车辆中台必须校验发行方、受众、签名、有效期和 `jti`,并把 `customerId` 写入请求上下文。禁止从 Query、Body 或普通转发头覆盖它。
## 5. 车辆中台投影
建议表:
```text
business_customer
customer_id, status, source_version, synced_at
business_customer_vehicle_scope
customer_id, vin, vehicle_id, contract_id, scope_start_at,
source_version, source_updated_at, published_at
business_scope_sync_run
run_id, customer_id, source_version, status,
received_count, accepted_count, rejected_count, started_at, finished_at, error
business_scope_audit
request_id, principal_id, customer_id, action, vin, decision, reason, created_at
```
唯一约束至少包括 `(customer_id, vin)`;发布新版本时应在事务中整体切换,不能边分页边覆盖当前版本。
## 6. 失败策略
- 首次同步失败:客户门户不可用,不回退到全量车辆。
- 已有快照过期:达到配置的最大陈旧时间后拒绝访问,并告知“业务车辆范围同步异常”。
- 单车不在范围:统一返回 404避免泄露 VIN 是否存在。
- 多客户冲突或 VIN 缺失:隔离并告警,不授权。
- OneOS 账号停用:会话校验立即失败;车辆中台短时声明最长建议 5 分钟。
## 7. 验收用例
1. 客户 A 无法通过 VIN、车牌、导出、轨迹、告警 ID 或分页游标访问客户 B 的车辆。
2. 车辆还车后,新快照发布即从客户范围移除;旧 URL 也返回 404。
3. 车辆再次交付给另一客户后,仅新客户可见。
4. `other_customer_id` 存在时,只授权给有效丙方客户。
5. 缺 VIN、多客户冲突、聚合与合同不一致的车辆不进入任何外部范围。
6. OneOS 不可用、签名错误、Scope 过期或分页版本变化时全部失败关闭。
7. 1,000 台车辆的快照分页结果无重复、无遗漏,条件请求可返回 304。
8. 所有拒绝决策保留 request ID、主体、VIN 摘要和原因,且不记录访问令牌。
## 8. 兼容与回滚
- 保留现有 Dubbo `RemoteVehicleService`,但在修复前明确标记 `listByCustomerId` 不可用于外部授权。
- 新 HTTP 内部接口使用独立 `/inner/v1` 前缀,不改变现有页面接口。
- 先以影子模式计算快照并与人工样本对账,再允许车辆中台消费。
- 若上线后异常,关闭客户入口并回退到上一个已验证 Scope 版本;不得回退为“无 Scope 查询”。