Files
hepu/docs/contract/6_J-00_OpenAPI使用说明_V1.8.md
aomin a7605ef8b8 chore(repo): 导入 M-Z 业务底座 V1.9 基线并建立仓库规范
按周工交付的 SEC-Z-01 清理后源码建立 M-Z 主干,并按 Git 仓库惯例重排目录。

- aomin-gateway/  后端工程 87 文件,原样保留,路径与构建命令未变
- demo/           演示前端与设备模拟器 9 文件(原 02_前端与设备端),非正式三端
- docs/handover/  交付与安全清理材料 6 份,内容未改
- docs/contract/  J-00 规格、OpenAPI、内部五接口、状态机、Mock 样例
- docs/reference/ 指纹与校验清单,含 84 个源码文件的 sha256 清单

目录重排只动位置不动内容:源码树 84 文件哈希与交付一致,逐文件自校验通过;
12 条 Flyway 迁移与交付包内镜像逐字节一致。

未纳入:迁移镜像目录(与工程内一套重复,改留指纹)、target/、证据 raw、
应急恢复脚本、评审用虚构台账数据。

安全:SEC-Z-01 15 处明文已清零,导入前重新扫描无新增命中,本仓库无历史污染。
行尾按交付字节原样保存(.gitattributes 设 * -text),不做归一化以免整树摘要失效。
2026-11-13 17:32:37 +08:00

139 lines
6.9 KiB
Markdown
Raw Permalink 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.
# J-00 OpenAPI 机器可读版 · 使用说明
**文件**:`6_J-00_接入接口规格_V1.8_OpenAPI.yaml`(OpenAPI 3.0.3,v1.8.0)—— **与本说明放在同一目录**,可直接用编辑器或 Swagger Editor 打开
**对应**:`6_J-00_接入接口规格_V1.8.md`(同一个契约的人读版)
**编制**:周工 | 2026-11-02
> **为什么文件名这么长**:这是故意的。同一份契约有两个形态——`.md` 讲"为什么",`.yaml` 讲"长什么样"。两个文件共用 `6_J-00_接入接口规格_V1.8` 前缀,在文件夹里**永远相邻**,谁也漏不掉;仅仅一个叫 `internal-iot.yaml` 的文件,脱离上下文就没人知道它是 J-00 的机读版。
---
## 一、这是什么
一份**机器可读的接口契约**。内容和 J-00 V1.8 一一对应,只是换了一种能被工具直接消费的写法。
**两份文件的分工,不要理解成两份契约:**
| | 管什么 | 举例 |
|---|---|---|
| **本文件(YAML)** | **长什么样** | 路径、方法、字段类型、必填、枚举、长度上限、错误结构 |
| **J-00 V1.8** | **为什么这样** | 告警状态机、四条硬边界、幂等三档算法、断档与 0x04、`tsSource` 为什么不能伪造 |
有些东西**写不进 YAML**,比如「`deviceTime` 没有就传 null,禁止用 `receivedAt` 顶替——填了等于伪造时源」。所以:**字段定义以本文件为准,业务语义的解释权仍在 J-00。**
两者不一致时,以本文件为准,同时回改 J-00,两边同版本号。
---
## 二、里面有什么
| 项 | 数量 | 说明 |
|---|---:|---|
| 接口 | **6** | 在役 5 个(I-01/02/05/12/18)+ 二期预留 1 个(I-17) |
| schema | 20 | Event/DeviceStatus/RawFrame/Command/CommandResult 及其批次包装 |
| 公共参数 | 8 | 鉴权头 4 个 + 幂等键 4 个(每接口一个) |
| 公共响应 | 4 | 400/401/429/500 |
**五个在役接口:**
| 编号 | 方法 | 路径 | `operationId` |
|---|---|---|---|
| `I-01` | POST | `/events/batch` | `ingestEvents` |
| `I-02` | POST | `/device-status/batch` | `ingestDeviceStatus` |
| `I-12` | POST | `/raw-frames` | `ingestRawFrames` |
| `I-18` | GET | `/commands/pending` | `pullPendingCommands` |
| `I-05` | POST | `/commands/result` | `reportCommandResults` |
| `I-17` | POST | `/commands/{commandId}/dump` | 二期预留,**本期固定 404,不要实现** |
**枚举已全部写死,且与 J-00 逐值一致:**
| 枚举 | 值数 | 内容 |
|---|---:|---|
| `eventType` | **29** | 10 对发生/解除 + 9 个单值 |
| `sourceChannel` | 4 | `OWN_GW`/`HORN_HOST`/`HORN_CELL`/`MIR_CELL` |
| `result` | 5 | `ACKED`/`SENT`/`TIMEOUT`/`DEVICE_OFFLINE`/`FAILED` |
| `rejectReason` | 4 | `RATE_LIMITED`/`SCHEMA_INVALID`/`UNKNOWN_CHANNEL`/`SENSOR_ID_INVALID` |
| `cmdType` | 8 | `set_mode`/`set_ack_policy`/`time_sync`/`set_report_cfg`/`del_sensor`/`reboot`/`diag_dump`/`set_ota` |
---
## 三、能拿它做什么(五件事)
> 下表里的 `$Y` 指本文件名。因为它带中文和版本号,直接敲命令很累,下面给了变量写法,复制即用。
| 用途 | 怎么用 | 省了什么 |
|---|---|---|
| **接口校验** | 用 `swagger-cli validate` 或编辑器插件跑一遍 | 字段漏写、枚举越界当场暴露,不用等联调 |
| **生成服务端骨架** | `openapi-generator-cli generate -i "$Y" -g spring` | 五个 Controller 的入参出参自动生成,外包只填业务 |
| **生成前端类型** | `-g typescript-fetch` 或 `typescript-axios` | 陈工不用照表格手敲 TS 类型 |
| **起 Mock 服务** | `prism mock "$Y"` | 前端不用等后端就能联调 |
| **生成测试用例** | `-g jmeter` 或 `schemathesis run` | 必填、枚举、边界自动出用例,比手写清单全 |
**推荐的命令(外包侧):**
```bash
# 文件名太长,先存成变量,后面照抄即可
Y="6_J-00_接入接口规格_V1.8_OpenAPI.yaml"
# 1. 语法与规范校验
npx @redocly/cli lint "$Y"
# 2. 生成 Spring Boot 服务端接口骨架
npx @openapitools/openapi-generator-cli generate \
-i "$Y" -g spring \
-o ./generated --additional-properties=interfaceOnly=true
# 3. 起 Mock 服务(前端联调用)
npx @stoplight/prism-cli mock "$Y" -p 4010
```
---
## 四、与 J-00 V1.8 的逐项核对
已用脚本比对,以下全部一致:
| 项 | J-00 位置 | YAML 位置 |
|---|---|---|
| 五个接口的编号与路径 | §1.1 | `paths` |
| `eventType` 29 值 | §1.5.1 | `schemas.EventType.enum` |
| 事件对象 12 个字段与必填性 | §1.3 | `schemas.Event` |
| I-02 十个字段 | §1.8 | `schemas.DeviceStatus` |
| I-12 八个字段(含 `rawFrame` 定死 Base64) | §1.9.2 | `schemas.RawFrame` |
| `result` 5 值 | §3.3 | `schemas.CommandResult.result` |
| I-18 四个查询参数与上限 | §3.2 | `paths./commands/pending.parameters` |
| 鉴权四层 + 幂等键算法 | §1.2 | `components.parameters`(每个接口的幂等键**分别写**,因为取法不同) |
| 响应结构与 `unregistered` 非错误语义 | §1.7 | `schemas.IngestResponse` |
**幂等键按接口分开写,这是 V1.6 的重点修正:**
| 接口 | 幂等键 | 为什么不能统一 |
|---|---|---|
| I-01 | `{sourceChannel}-{首条 eventId}-{条数}` | 有 `eventId` |
| **I-02** | `{sourceChannel}-{首条 sensorId}-{reportedAt}-{条数}` | **I-02 报文里没有 `eventId`** |
| **I-12** | `{sourceChannel}-{首条 rawRef}-{条数}` | **I-12 报文里没有 `eventId`**,`rawRef` 就是 `MD5(原始帧字节)` |
| I-05 | `{nodeId}-{首条 commandId}-{条数}` | 有 `commandId` |
| I-18 | **不带** | GET 拉取,重复拉天然幂等,靠租约去重 |
---
## 五、已知未定项(不藏着)
| 项 | 现状 | 何时定 |
|---|---|---|
| **错误响应里的 `code` 具体码值** | 只写了 `{code, message}` 结构,**没固定码值** | 待与业务层错误码表统一后回填。当前按 HTTP 段理解:400xx 请求非法/401xx 鉴权失败/429xx 限流 |
| **I-17 的请求体** | 只写了「本期 404」 | 二期启用诊断包时再补 |
| **`params` 的结构** | `additionalProperties: true`,随 `cmdType` 变 | 八种命令字的参数结构**不在本文件里**,由业务层命令模块保证;外包按 `cmdType` 做编码即可 |
---
## 六、对陈工和外包各说一句
**给陈工**:这份 YAML 可以生成 TS 类型,`openapi-generator -g typescript-fetch`。你前端**不用照 J-00 的表格手敲字段**,也不用维护第二份接口定义——生成一次即可,接口变了重生成。
**给外包(谢工)**:五个接口全在这里。各字段的 `description` 是给你的实现提示,重点是三处最容易做错的:
1. **I-02 / I-12 的幂等键不是 `eventId`**(报文里没这个字段),按对应 `components.parameters` 的说明算。
2. **I-18 是 GET,签名时 `sha256(body)` 取空串的 hash,`path` 含 query 一并算。**
3. **`rejectedDetail` 里出现的条目一律不重试**,只有整批 5xx 才重试。