按周工交付的 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),不做归一化以免整树摘要失效。
6.9 KiB
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 |
必填、枚举、边界自动出用例,比手写清单全 |
推荐的命令(外包侧):
# 文件名太长,先存成变量,后面照抄即可
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 是给你的实现提示,重点是三处最容易做错的:
- I-02 / I-12 的幂等键不是
eventId(报文里没这个字段),按对应components.parameters的说明算。 - I-18 是 GET,签名时
sha256(body)取空串的 hash,path含 query 一并算。 rejectedDetail里出现的条目一律不重试,只有整批 5xx 才重试。