# 车辆数据管理中台设计 Spec

## 目标

建设一套独立的车辆数据管理中台，放在新项目目录 `vehicle-data-platform`。中台包含前端和后端，前端使用 Semi UI，整体风格高级、简洁、接近大厂数据控制台；后端使用 Go BFF 聚合现有车辆接入链路的数据能力。系统一期目标是让业务和运营人员可以稳定完成查车、看实时状态、查历史、追溯 RAW、看里程和定位数据质量问题，同时给平台运维提供只读链路健康态势。

## 产品定位更新：一个车辆服务

中台的第一性原则是“一个车辆服务”。GB32960、JT808、宇通 MQTT 是同一辆车的数据来源证据，不是三个并列的业务产品。所有主页面都应先回答车辆层面的问题，再在需要排障、对账、追溯时下钻到协议来源。

用户输入 VIN、车牌、手机号或来源标识后，系统需要尽量解析到同一个车辆上下文，并在实时监控、轨迹回放、历史查询、告警事件、统计分析之间保持这个上下文。协议只作为来源标签、可信度解释和 RAW 证据入口出现。

## 一期定位

一期优先服务运营、业务和数据质量人员，核心问题是：

- 车辆是否在线。
- 车辆在哪里。
- 最新状态是什么。
- 最近是否断链。
- 每日和区间里程是否可信。
- 原始报文和解析字段是否可追溯。
- 告警事件是否能追到影响车辆和证据。
- VIN、车牌、手机号、OEM 绑定是否正确。

链路运维能力作为辅助模块内嵌，展示 Gateway、NATS、Kafka、Redis、TDengine、MySQL 和 capacity-check 的关键健康状态，但一期不做复杂监控平台和告警工单闭环。

## 非目标

一期不做以下内容：

- 复杂多租户权限体系。
- 自定义大屏编排。
- 复杂工单闭环。
- 任意字段计算平台。
- 完整 BI 报表系统。
- 复杂三维轨迹或大屏动画。
- 对现有 Go gateway、NATS bridge、history writer、stat writer、realtime API 做破坏性改造。

## 项目结构

新建项目目录：

```text
vehicle-data-platform/
  apps/
    web/
    api/
  docs/
    product-spec.md
    api-contract.md
    deployment.md
  deploy/
    systemd/
    nginx/
  scripts/
```

### 前端技术栈

- React
- TypeScript
- Vite
- Semi UI
- ECharts
- 地图组件，一期可先用轻量地图封装，后续再替换为正式地图供应商

### 后端技术栈

- Go
- 标准库 HTTP 或轻量路由
- MySQL driver
- Redis client
- TDengine driver
- HTTP client 聚合现有 health、metrics、capacity-check 输出

后端作为 BFF，不让前端直接连接 MySQL、Redis、TDengine 或现有 realtime API。

## 信息架构

左侧导航围绕车辆服务组织，一期可以先保留现有 7 个一级模块，但命名和内容要向以下目标靠拢。

### 1. 运营总览

路径：`/dashboard`

能力：

- 在线车辆数。
- 今日活跃车辆。
- 今日上报量。
- 异常车辆数。
- Kafka lag。
- 链路健康状态。
- 车辆服务状态分布：健康、降级、离线、身份缺失、暂无来源。
- 来源覆盖分布：单源车辆、多源车辆、暂无来源车辆。
- 最新车辆分布地图小窗。
- 最近异常列表：断链、未绑定、里程异常、解析失败、跨来源不一致。

### 2. 车辆服务

路径：`/vehicles`

能力：

- 表格展示车牌、VIN、手机号、OEM、来源证据、在线来源数、车辆服务状态、最后上报、最近位置、绑定完整度。
- 支持 VIN、车牌、手机号、OEM 搜索。
- 支持服务状态、来源覆盖、在线状态、绑定完整度筛选。
- 支持查看详情、导出。
- 支持导入绑定入口的一期展示：提供导入说明和模板下载按钮，不提交数据；正式写入流程不纳入一期验收。

### 3. 实时监控

路径：`/realtime`

能力：

- 表格视图和地图视图切换。
- 展示 VIN、车牌、来源证据、速度、SOC、总里程、最后上报时间、位置。
- 地图按车辆服务状态和在线状态分色，协议只用于点位详情里的来源证据。
- 支持只看在线车辆、异常车辆、断链车辆和多源不一致车辆。
- 点击车辆后打开右侧抽屉展示最新实时字段摘要、来源新鲜度和跳转入口。

### 4. 车辆详情

路径：`/vehicles/:vin`

能力：

- 顶部身份卡：车牌、VIN、OEM、协议、在线状态。
- Tabs：
  - 最新状态。
  - 历史位置。
  - RAW 报文。
  - 里程统计。
  - 数据质量。
- 多协议对比：同一车辆在 GB32960、JT808、YUTONG_MQTT 下的最新时间、字段完整度、里程差异。

### 5. 轨迹回放

路径：`/history`

能力：

- 查询条件：VIN/车牌/手机号、时间范围、来源筛选。
- 地图轨迹播放，支持起点、终点、当前播放点和速度。
- 表格与地图联动：点击点位能看到该点时间、位置、速度、里程和来源。
- 可跳转 RAW 证据、统计分析和告警事件。

### 6. 历史查询

路径：`/history`

能力：

- Tab：历史位置、RAW 报文、解析字段。
- 查询条件：VIN、协议、时间范围、消息类型、字段筛选。
- RAW 支持分页、字段裁剪、是否包含 payload、JSON 详情查看。
- 解析字段使用扁平化字段名，支持选择字段缩小响应体。

### 7. 告警事件

路径：`/quality`，后续可独立为 `/alerts`

能力：

- 展示来源断链、未绑定、无 VIN、无车牌、无手机号、RAW 解析失败、里程突变、跨来源不一致。
- 每条告警必须能跳回车辆详情、轨迹回放、历史 RAW 或统计证据。
- 一期支持人工确认和状态展示，通知发送作为后续阶段。

### 8. 统计分析

路径：`/mileage`

能力：

- 日里程查询。
- 区间里程查询。
- 协议来源对比。
- 异常标记：总里程倒退、突增、缺失、跨协议不一致。
- 在线率、数据完整率和来源一致性作为后续统计卡片。

### 9. 运维质量

路径：`/quality`

能力：

- 断链车辆。
- 未绑定车辆。
- 无 VIN、无车牌、无手机号车辆。
- RAW 解析失败。
- capacity-check 结果。
- Kafka/NATS/TDengine/Redis/MySQL 关键状态。

## 高德地图设计

地图供应商使用高德地图。用户提供了 Web JS 和 API 服务两类 key，系统实现时需要按用途分开：

- Web JS key 只通过前端运行时配置注入，例如 `window.__LINGNIU_PLATFORM_CONFIG__.amap.webJsKey`，不写死在 TypeScript 源码。
- 安全密钥或代理服务地址同样通过运行时配置注入。
- API 服务 key 放在后端或 ECS 环境变量中，只用于后端地理编码、行政区划或后续服务端地图能力。
- 前端没有拿到可用 key 时，`VehicleMap` 使用坐标预览降级，不阻塞查车、查轨迹和查告警。

地图一期覆盖三类业务场景：

- 实时监控：多车点位、在线状态、异常状态、点位详情。
- 轨迹回放：折线、起终点、当前播放点、表格联动。
- 告警事件：告警车辆定位和影响范围提示。

## 跨页面车辆上下文

全局搜索解析到车辆后，需要把 VIN、车牌、手机号、来源和服务状态作为页面上下文：

- 车辆服务行可以跳转车辆档案。
- 实时监控车辆可以跳转轨迹回放、历史查询、统计分析和告警事件。
- 轨迹点可以跳转同日里程统计和 RAW 证据。
- 里程异常可以跳转对应日期轨迹和 RAW 证据。
- 告警事件可以跳转车辆档案、历史证据和统计证据。

这一点是产品一致性的硬约束。页面之间不应只靠用户手动复制 VIN。

## 视觉与交互设计

整体视觉使用 Semi UI 原生组件为基础，避免大屏炫技风。目标是云控制台、数据控制台、飞书后台一类的专业感。

### 设计原则

- 灰白背景，深色正文，蓝青强调色。
- 红橙只用于异常、告警、风险。
- 表格优先，不用卡片堆满页面。
- KPI 卡片少而准。
- 右侧抽屉承载详情，不频繁跳整页。
- RAW 和 parsed JSON 使用代码查看器或结构化 JSON Tree。
- 地图是业务辅助，不作为首页背景。
- 所有列表页都有稳定筛选区、刷新时间和导出入口。

### 页面骨架

- 顶部栏：系统名、全局车辆搜索、环境状态、刷新时间、用户入口。
- 左侧栏：7 个一级导航。
- 主体区：页面标题、筛选/操作区、数据区。
- 右侧抽屉：车辆摘要、RAW 详情、异常解释。

## 后端 BFF 设计

后端统一暴露 `/api/*`，并托管前端静态文件。

### API 响应格式

成功：

```json
{
  "data": {},
  "traceId": "string",
  "timestamp": 1783080000000
}
```

分页：

```json
{
  "data": {
    "items": [],
    "total": 100,
    "limit": 50,
    "offset": 0
  },
  "traceId": "string",
  "timestamp": 1783080000000
}
```

错误：

```json
{
  "error": {
    "code": "QUERY_FAILED",
    "message": "查询失败",
    "detail": "具体错误"
  },
  "traceId": "string",
  "timestamp": 1783080000000
}
```

### 后端模块

#### vehicle

职责：

- 车辆台账。
- 身份绑定。
- VIN、车牌、手机号、OEM 查询。

数据源：

- MySQL `vehicle_identity_binding`。
- MySQL `vehicle_realtime_snapshot` 和 `vehicle_realtime_location` 用于补充在线状态和最新上报。

#### realtime

职责：

- 实时位置。
- 实时快照。
- 单车当前状态。
- 单车协议 realtime raw 摘要。

数据源：

- MySQL `vehicle_realtime_snapshot`。
- MySQL `vehicle_realtime_location`。
- Redis `vehicle:realtime-raw:{protocol}:{vin}`。
- Redis online key 族。

#### history

职责：

- 历史位置。
- RAW frame 查询。
- RAW 字段过滤。

数据源：

- TDengine `vehicle_locations`。
- TDengine `raw_frames`。
- TDengine `raw_frame_payload_chunks`。

#### mileage

职责：

- 日里程。
- 区间里程。
- 里程异常解释。

数据源：

- MySQL `vehicle_daily_mileage`。

#### quality

职责：

- 无 VIN。
- 无车牌。
- 无手机号。
- 长时间未上报。
- 里程突变。
- 解析失败。

数据源：

- MySQL identity 和 realtime 表。
- TDengine raw_frames。
- Redis online。

#### ops

职责：

- capacity-check。
- 服务 readyz。
- Kafka/NATS/Redis/TDengine/MySQL 状态摘要。

数据源：

- 现有本机 health endpoint。
- 现有 metrics endpoint。
- `/opt/lingniu-go-native/current/capacity-check` 输出。

## 一期 API

### Dashboard

- `GET /api/dashboard/summary`

返回：

- 车辆在线数。
- 今日活跃数。
- 今日上报量。
- 协议分布。
- 异常计数。
- 链路健康摘要。

### Vehicles

- `GET /api/vehicles`
- `GET /api/vehicles/:vin`
- `GET /api/vehicles/:vin/realtime`
- `GET /api/vehicles/:vin/protocols`

### Realtime

- `GET /api/realtime/locations`
- `GET /api/realtime/snapshots`
- `GET /api/realtime/raw/:protocol/:vin`

### History

- `GET /api/history/locations`
- `POST /api/history/raw-frames/query`

RAW query 使用 POST，避免字段过滤数组导致 URL 过长。

### Mileage

- `GET /api/mileage/daily`
- `GET /api/mileage/range`

### Quality

- `GET /api/quality/issues`
- `GET /api/quality/unbound-vehicles`
- `GET /api/quality/offline-vehicles`

### Ops

- `GET /api/ops/health`
- `GET /api/ops/capacity`

## 数据源映射

### MySQL

- `vehicle_identity_binding`：车辆身份事实表。
- `vehicle_realtime_snapshot`：每协议每 VIN 最新轻量快照。
- `vehicle_realtime_location`：每协议每 VIN 最新位置。
- `vehicle_daily_mileage`：每日里程统计。
- `jt808_registration`：JT808 注册与鉴权辅助信息。

### Redis

- `vehicle:realtime-raw:{protocol}:{vin}`：最新完整协议 parsed 状态。
- `vehicle:online:*`：在线状态。
- `vehicle:last_seen`：最近活跃排序。
- `vehicle:rt-kv:*`：扁平化实时字段。

### TDengine

- `raw_frames`：RAW 证据层。
- `raw_frame_payload_chunks`：超长 payload 分片。
- `vehicle_locations`：历史位置。

## 权限设计

一期做轻量鉴权：

- 登录页。
- 单一管理员账号或配置文件 token。
- 前端请求带 bearer token。
- 后端校验 token。

后续再扩展 RBAC：

- 业务只读。
- 运维只读。
- 管理员。

## 部署设计

ECS 部署：

- 后端端口：`20300`。
- 后端托管前端静态文件。
- `/api/*` 是后端接口。
- `/` 和前端路由返回静态入口。
- systemd unit：`lingniu-vehicle-platform.service`。

访问地址：

```text
http://115.29.187.205:20300
```

## 环境变量

后端需要：

- `HTTP_ADDR=:20300`
- `MYSQL_DSN`
- `REDIS_ADDR`
- `REDIS_USERNAME`
- `REDIS_PASSWORD`
- `REDIS_DB`
- `TDENGINE_DSN`
- `TDENGINE_DATABASE=lingniu_vehicle_ts`
- `CAPACITY_CHECK_BIN=/opt/lingniu-go-native/current/capacity-check`
- `AUTH_TOKEN`

## 验收标准

一期完成时必须满足：

1. 新项目目录 `vehicle-data-platform` 存在。
2. 前端使用 Semi UI。
3. UI 有完整导航、统一布局、统一视觉规范。
4. 可以查看车辆台账。
5. 可以查询实时位置和实时状态。
6. 可以进入单车详情。
7. 可以查询历史位置。
8. 可以查询 RAW frame，并支持字段裁剪。
9. 可以查看日里程和区间里程。
10. 可以查看数据质量问题。
11. 可以查看链路健康状态。
12. 后端 API 返回统一响应结构。
13. 前端核心列表、详情和查询来自真实后端 API。
14. ECS 部署后可通过 `http://115.29.187.205:20300` 访问。
15. 后端 systemd 服务健康。
16. 浏览器验证主要页面可访问、筛选可用、详情抽屉可用。

## 测试策略

### 后端

- API handler 单元测试。
- query 参数解析测试。
- response envelope 测试。
- 数据源 repository 测试。
- 健康检查测试。

### 前端

- TypeScript build。
- 页面 smoke test。
- API client 测试。
- 主要页面空态、加载态、错误态检查。

### 部署

- 本地前端 build。
- 后端 go test。
- ECS systemd 启动。
- `/api/ops/health` 返回正常。
- 浏览器打开首页、车辆台账、实时监控、历史查询。

## 后续演进

- RBAC 权限。
- 车辆绑定导入写入流程。
- 告警通知。
- 轨迹回放。
- BI 报表。
- 自定义字段分析。
- 运维监控大盘。
