refactor(stage10): ele / feedback 拆出 repository + model,并补契约测试

背景
- 这两个域把 SQL 与处理器放在同一文件,是全仓仅有的两个零接口测试的后端域。
  直接拆会改动 SQL 与参数顺序,而硬约束要求不得变更统计口径 —— 因此按
  "可注入化 -> 补契约测试 -> 再提取" 的顺序做。

改动
- ele:拆为 routes.ts(校验与组装)/ repository.ts(全部 SQL)/ model.ts(xlsx 解析、
  取值清洗、筛选片段、插入值组装等纯逻辑),并改为 registerEleRoutes(app, deps) 可注入。
- feedback:拆为 routes.ts / repository.ts,同样可注入;建表与截图上传也作为依赖注入。
- 两域各补测试:ele 7 个接口契约 + 6 个模型用例,feedback 9 个接口契约。
  mock pool 逐条断言 SQL 文本与参数顺序(含分页、状态白名单、批量插入的 30 列顺序)。
- 架构测试新增一条:已完整分层的三个域(vehicles / ele / feedback)必须有 repository.ts
  且 routes.ts 不得出现 SQL。

等价性验证(关键)
- 把改造前的实现从 git 取出,与改造后的实现跑同一批请求(含真实 xlsx 解析路径),
  对比每一步落库 SQL、参数、HTTP 状态与响应体:
    feedback:6 个场景,SQL + 参数 + 状态完全一致(差异仅 DDL 已移交 db/schema 层)
    ele     :5 个场景,SQL + 参数 + 状态 + 响应体完全一致(仅随机 batchId/时间戳做掩码)
- 期间的修正:曾把 /mine 与 /list 的列集合统一,二者实际不同(管理列表多 user_id/user_name),
  已按原样保留;测试同时锁定了这一差异。

lint / test(161) / build 全绿,可达性 0 未引用文件。
This commit is contained in:
dsh-agent
2026-09-11 10:36:05 +08:00
parent 795fb207cb
commit c199f031c5
10 changed files with 1252 additions and 482 deletions
+14 -8
View File
@@ -91,12 +91,17 @@ server/
| 域 | 文件 | 说明 |
| --- | --- | --- |
| `vehicles/` | `routes.ts` `repository.ts` `model.ts` `utils.ts` `types.ts` | 唯一已完整分层到 repository 的域,SQL 有指纹测试 |
| `mileage/` | `index.ts`(聚合)+ `monitoring.ts` `targets.ts` `trend.ts` `daily-report.ts` `vehicle-recent.ts` + `*-model.ts` + `cache.ts` `oneos-api.ts` `daily-report-{service,store,scheduler}.ts` | 路由 / 模型 / 服务已分开 |
| `energy/` | `index.ts`(聚合)+ `hydrogen-bi-v2.ts` `hydrogen-station-board.ts` `electric.ts` `etc.ts` + `query-model.ts` `cache.ts` `constants.ts` | 路由 / 模型已分开,SQL 仍在路由内 |
| `vehicles/` | `routes.ts` `repository.ts` `model.ts` `utils.ts` `types.ts` | 完整分层SQL 有契约测试 |
| `ele/` | `routes.ts` `repository.ts` `model.ts`+ `model.test.ts` `routes.test.ts` | ✅ 完整分层;改造前后 SQL/参数/响应体已做等价性验证 |
| `feedback/` | `routes.ts` `repository.ts` `oss.ts`+ `routes.test.ts` | ✅ 完整分层;同上 |
| `mileage/` | `index.ts`(聚合)+ `monitoring.ts` `targets.ts` `trend.ts` `daily-report.ts` `vehicle-recent.ts` + `*-model.ts` + `cache.ts` `oneos-api.ts` `daily-report-{service,store,scheduler}.ts` | 路由 / 模型 / 服务已分开,**SQL 仍在各路由文件内** |
| `energy/` | `index.ts`(聚合)+ `hydrogen-bi-v2.ts` `hydrogen-station-board.ts` `electric.ts` `etc.ts` + `query-model.ts` `cache.ts` `constants.ts` | 路由 / 模型已分开,**SQL 仍在路由内** |
| `scheduling/` | `index.ts`(聚合)+ `suggestions.ts` `notify.ts` + `algorithm.ts` `notification-model.ts` | 同上 |
| `hydrogen-heatmap/``vehicle-heatmap/` | `routes.ts` + `model.ts` | 路由 / 模型已分开 |
| `ele/``feedback/` | `routes.ts`+ `oss.ts` | **尚未拆出 repository**SQL 与处理器在同一文件 |
| `hydrogen-heatmap/``vehicle-heatmap/` | `routes.ts` + `model.ts` | 纯模型已抽出,**SQL 仍在 `routes.ts`** |
已完整分层的三个域(`vehicles` / `ele` / `feedback`)由架构测试守护:`routes.ts` 不得出现 SQL
且必须存在 `repository.ts`。其余域尚未拆出 repository——拆分时**不要改变 SQL 与参数顺序**,
并建议先按 `ele/routes.test.ts` 的方式补契约测试再动。
### 中间件顺序(在 `app.ts` 中显式体现)
@@ -132,9 +137,10 @@ cors → read-only → /api/auth(公开) → authMiddleware → 各业务域
诚实记录,避免后来者以为已经做完:
- **后端仍有两个域没拆出 repository**`ele/routes.ts` `feedback/routes.ts` 仍把 SQL
与处理器放在同一文件(形状见上表)。拆分时**不要改变 SQL 与参数顺序**——这两个域目前
没有 SQL 指纹测试,建议先补契约测试再动。
- **后端仍有域没拆出 repository**`mileage` / `energy` / `scheduling` / 两个热力图的 SQL 仍在
各自的 `routes.ts`(或平级模块)里(形状见上表)。`vehicles` / `ele` / `feedback` 已完成,
可作为模板:路由只做校验与组装,SQL 进 `repository.ts`,纯逻辑进 `model.ts`
并用 mock pool 的契约测试锁定 SQL 与参数。
- **运行时建表已集中到 `server/db/schema/`**,并在 `DB_READ_ONLY=1` 时整体跳过(由架构测试守护,
已实测不触碰数据库)。它仍由业务接口在首次调用时触发,而不是只由 `bootstrap.ts` 调用——
要彻底改成显式迁移,需要先建立数据库变更脚本流程,避免"代码里偷偷建表"。