diff --git a/.env.example b/.env.example index 932bcec..1ade53e 100644 --- a/.env.example +++ b/.env.example @@ -1,11 +1,11 @@ DATABASE_URL=mysql://user:password@localhost:3306/database -# Required: external AI SoH prediction service. +# 必填:外部 SoH 预测服务地址 SOH_PREDICTION_API_BASE_URL=http://127.0.0.1:8000 # SOH_PREDICTION_CACHE_TTL_SECONDS=86400 # SOH_PREDICTION_TIMEOUT_MS=10000 -# Optional logging knobs (defaults are usually fine): +# 可选:日志级别与输出格式 # LOG_LEVEL=info # trace|debug|info|warning|error|fatal # LOG_FORMAT=pretty # pretty|json — defaults to TTY ? pretty : json # LOG_DB=false # reserved for database query logging if enabled later diff --git a/AGENTS.md b/AGENTS.md index 2ece570..0ba0afe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,7 +33,7 @@ Environment variable: DATABASE_URL=mysql://user:password@host:3306/database ``` -Optional AI prediction service: +Required AI prediction service: ```bash SOH_PREDICTION_API_BASE_URL=http://127.0.0.1:8000 diff --git a/README.md b/README.md index 6c217a7..f588cb1 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,41 @@ # battery-soh -一个基于 **Bun + TanStack Start + ORPC** 的电池健康展示系统。应用会被打包成单个二进制文件,前端页面、SSR 服务和 ORPC API 一起发布;业务数据只读接入甲方现有 MySQL 表 `ls_battery_info`,本项目不写入、不迁移、不修改甲方数据库。 +电池健康运营看板,用于接入客户现有设备数据,持续呈现电量状态、健康预测、风险分布与维护建议。系统以只读方式连接客户数据库,不改动生产数据;当健康预测暂不可用时,页面会明确显示不可用状态,避免用误导性数值替代真实结果。 -## 数据源 +## 产品能力 -甲方提供的只读表结构: +- **健康总览**:聚合展示设备规模、平均健康度、30/90 天趋势与预警设备占比。 +- **风险识别**:按健康度、低电量、充电状态与预测风险生成重点关注设备清单。 +- **实时明细**:支持按设备名称、编号、电量与充电状态筛选设备,快速定位需要排查的对象。 +- **维护建议**:基于当前可用数据给出巡检、复查与优先处理建议。 +- **可信展示**:缺少预测结果时显示“预测不可用”,不会将缺失值渲染为 `0%`。 -| 字段名 | 数据类型 | 说明 | -| --- | --- | --- | -| `id` | `int(11)` 自增 | 主键 ID | -| `user_id` | `int(11)` | 用户 ID | -| `mac` | `varchar(50)` | 设备 MAC | -| `dev_model` | `varchar(20)` | 设备型号 | -| `dev_name` | `varchar(50)` | 设备名称 | -| `is_low_power` | `varchar(10)` | 是否低电量:`true` / `false` | -| `power_status` | `tinyint(4)` | `0` 未充电,`1` 正在充电,`2` 充电完成 | -| `power` | `tinyint(4)` | 当前电量 `0~100` | -| `create_time` | `datetime` | 创建时间 | -| `remark` | `varchar(500)` | 备注,可空 | +## 数据接入 -环境变量: +系统接入客户现有 MySQL 数据源,业务运行时仅执行只读查询。需要配置: ```bash DATABASE_URL=mysql://user:password@host:3306/database ``` -AI SoH 预测服务是必填依赖;未配置时应用会在环境变量校验阶段失败,避免把预测缺失误展示为真实 SoH: +客户设备表:`ls_battery_info`。 + +| 字段名 | 数据类型 | 业务含义 | +| --- | --- | --- | +| `id` | `int(11)` auto increment | 记录 ID | +| `user_id` | `int(11)` | 用户 ID | +| `mac` | `varchar(50)` | 设备编号 | +| `dev_model` | `varchar(20)` | 设备型号 | +| `dev_name` | `varchar(50)` | 设备名称 | +| `is_low_power` | `varchar(10)` | 是否低电量:`true` / `false` | +| `power_status` | `tinyint(4)` | `0` 未充电,`1` 充电中,`2` 已充满 | +| `power` | `tinyint(4)` | 当前电量 `0~100` | +| `create_time` | `datetime` | 采集时间 | +| `remark` | `varchar(500)` | 备注 | + +## 健康预测 + +看板需要接入外部 SoH 预测服务: ```bash SOH_PREDICTION_API_BASE_URL=http://127.0.0.1:8000 @@ -33,7 +43,7 @@ SOH_PREDICTION_CACHE_TTL_SECONDS=86400 SOH_PREDICTION_TIMEOUT_MS=10000 ``` -服务端会向 `${SOH_PREDICTION_API_BASE_URL}/predict` 发起 POST 请求,并把返回的 `now_soh`、`month_soh`、`trmonth_soh`、`risk_score` 等字段用于看板展示。预测结果按设备和最新采集记录做内存 TTL 缓存,默认 24 小时;如果单次预测失败或历史数据不足,对应设备显示“预测不可用”,但不会把缺失值展示成 `0%`。 +服务端会调用 `${SOH_PREDICTION_API_BASE_URL}/predict`,使用返回的当前健康度、30 天趋势、90 天趋势和风险评分生成看板视图。预测结果会按设备与最新采集记录缓存,默认 24 小时;单台设备预测失败或历史数据不足时,仅该设备显示为“预测不可用”。 ## 快速开始 @@ -43,53 +53,53 @@ bun install bun run dev ``` -如果甲方暂时没有提供数据库连接,可以用 Docker Compose 启动本地 MySQL 并填充示例数据: +打开浏览器: + +- `http://localhost:3000/`:设备健康运营看板 +- `http://localhost:3000/batteries`:设备状态明细 +- `http://localhost:3000/api/docs`:接口文档 + +## 本地演示环境 + +如果暂时没有生产数据库连接,可以使用 Docker Compose 启动本地 MySQL 并填充演示数据: ```bash docker compose up --build ``` -Compose 会启动三个服务: +Compose 会启动: - `db`:本地 MySQL 8.4 -- `seed`:执行 `bun run seed`,用 Drizzle MySQL schema + `drizzle-seed` 重置本地 `ls_battery_info` 并写入示例数据 -- `app`:使用同一个 `DATABASE_URL` 启动单二进制应用 +- `seed`:初始化本地 `ls_battery_info` 演示数据 +- `app`:启动应用服务 -也可以手动 seed 本地库: +也可以手动初始化本地数据: ```bash DATABASE_URL=mysql://battery:battery@localhost:3306/battery_soh bun run seed ``` -`seed` 是本地开发/验收脚本,会建表并重置示例数据;应用运行时仍然只执行 `SELECT`,不会写入数据库。 +`seed` 仅用于本地开发和演示环境;应用运行时仍保持只读查询,不写入业务数据库。 -打开浏览器: +## 系统结构 -- `http://localhost:3000/`:SoH 预测与风险洞察看板 -- `http://localhost:3000/batteries`:设备电池实时状态 -- `http://localhost:3000/api/docs`:Scalar 渲染的 ORPC OpenAPI 文档 - -## 架构 - -``` +```text src/ -├── routes/ # TanStack Start 文件路由:页面 + API 端点 +├── routes/ # 页面与 API 路由 ├── server/ -│ ├── api/ # ORPC contract / router -│ ├── battery/mysql.ts # 甲方 MySQL 只读查询 -│ └── prediction/client.ts # AI SoH 预测客户端与缓存 -├── domain/battery.ts # 电池领域类型、归一化、展示聚合 -├── client/orpc.ts # isomorphic ORPC client -└── styles.css # Tailwind v4 entry +│ ├── api/ # 接口契约与路由 +│ ├── battery/mysql.ts # 设备数据只读查询 +│ └── prediction/client.ts # 健康预测服务客户端 +├── domain/battery.ts # 电池领域模型与看板聚合 +├── client/orpc.ts # 前端接口客户端 +└── styles.css # 全局样式入口 ``` -接口保持模板里的 ORPC 模式: +核心接口: -- `battery.dashboard`:读取每个 `mac` 的最新记录并生成看板聚合数据 -- `battery.batteries`:分页返回每台设备最新记录,支持 `pageSize`、`cursor`、`search`、`lowPower`、`powerStatus`、`sort` 筛选/排序 -- `battery.history`:按 `mac` 返回该设备历史记录,按 `create_time desc` 限制 500 条 - -所有业务查询都是 `SELECT`,没有 mutation,也没有 mock/fallback 数据。 +- `battery.dashboard`:生成健康运营看板数据。 +- `battery.batteries`:分页返回每台设备的最新状态,支持搜索、筛选和排序。 +- `battery.history`:返回单台设备最近 500 条历史记录。 ## 部署 @@ -99,21 +109,21 @@ bun run compile ./out/server- ``` -Docker 镜像会在构建阶段产出单个 `./server` 二进制,运行阶段只需要配置 `DATABASE_URL`。 +构建产物为单个服务二进制文件,运行时需要配置 `DATABASE_URL` 与 SoH 预测服务地址。 -## 脚本 +## 常用命令 | 命令 | 作用 | | --- | --- | -| `bun run dev` | Vite 开发服务器 | -| `bun run build` | 构建到 `.output/` | -| `bun run compile` | 生成单二进制 `out/server-` | -| `bun run seed` | 为本地 MySQL 创建甲方表并填充示例数据 | +| `bun run dev` | 启动开发服务 | +| `bun run build` | 构建应用 | +| `bun run compile` | 生成单二进制产物 | +| `bun run seed` | 初始化本地演示数据 | | `bun run typecheck` | TypeScript 类型检查 | -| `bun run test` | 运行所有 `*.test.ts` | -| `bun run fix` | Biome 格式化 + lint + 整理 imports | +| `bun run test` | 运行测试 | +| `bun run fix` | 格式化与静态检查 | -## 验证 +交付前验证: ```bash bun run fix && bun run typecheck && bun run test && bun run build