Files
hepu/docs/contract/Mock样例.md
T
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

157 lines
4.7 KiB
Markdown
Raw 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.
# Mock 样例(可直接拿去打)
> 六组报文全部取自 2026-11-09 20:21 的**真实一次运行**,不是手编的示例。
> 对应证据:`06_统一闭环题自测证据/05_SOS链路.json`
---
## 1. I-01 事件上报 · 请求
```http
POST /internal/iot/v1/events/batch HTTP/1.1
Content-Type: application/json
X-Idempotency-Key: batch-20261109-2021-001
```
```json
{
"sourceChannel": "OWN_GW",
"events": [{
"eventId": "EVT-SOS-3B9B2CDB9CD4",
"sensorId": "3F7A9C23",
"sourceChannel": "OWN_GW",
"eventType": "SOS_PRESS",
"deviceTime": null,
"receivedAt": "2026-11-09T20:21:12+08:00",
"tsSource": 3,
"protocolVersion": "gw-1.2",
"seq": 16872,
"payload": {"deviceTypeRaw": 5, "rawEventCode": 1, "batteryMv": 3610},
"rawRef": "e1abbc2d6515f118ac9e7e113c68d677"
}]
}
```
**三个刻意的点**
- `deviceTime: null` —— 433 帧没有时间字段,按 J-00 必须传 null,不许拿 `receivedAt` 顶替
- `tsSource: 3` —— 网关打戳,界面不能显示成"发生时间"
- `payload.deviceTypeRaw: 5` —— 任何帧都必须带,缺了整条拒收
## 2. I-01 响应
```json
{"code":0,"msg":"ok","data":{
"accepted":1, "rejected":0, "duplicated":0, "unregistered":0, "rejectedDetail":[]}}
```
## 3. I-01 失败样例(四种)
```jsonc
// ① 缺 deviceTypeRaw
{"code":0,"data":{"accepted":0,"rejected":1,"rejectedDetail":[
{"eventId":"EVT-BAD-01","reason":"SCHEMA_INVALID"}]}}
// ② SN 与通道不符(OWN_GW 传带前缀的 SN)
{"code":0,"data":{"accepted":0,"rejected":1,"rejectedDetail":[
{"eventId":"EVT-BAD-02","reason":"SENSOR_ID_INVALID"}]}}
// ③ tsSource 越界
{"code":0,"data":{"accepted":0,"rejected":1,"rejectedDetail":[
{"eventId":"EVT-BAD-03","reason":"SCHEMA_INVALID"}]}}
// ④ 批级通道非法 → 整批 400
{"code":400,"msg":"sourceChannel 非法:H_MQTT"}
```
## 4. I-02 设备状态快照
```json
{
"sourceChannel": "OWN_GW",
"items": [{
"sensorId": "3F7A9C23",
"sourceChannel": "OWN_GW",
"batteryMv": 3610,
"csq": 22,
"online": true,
"reportedAt": "2026-11-09T20:21:10+08:00"
}]
}
```
## 5. I-12 原始报文留档
```json
{
"sourceChannel": "OWN_GW",
"frames": [{
"sensorId": "3F7A9C23",
"rawRef": "e1abbc2d6515f118ac9e7e113c68d677",
"frameHex": "A55A213F7A9C2350100001000000E8B4",
"frameLen": 17,
"receivedAt": "2026-11-09T20:21:12+08:00"
}]
}
```
> `rawRef` 与 I-01 必须同一种算法(MD5 32 位或 SHA-256 64 位),否则回指链断。
## 6. I-18 / I-05 下行命令
> 编号按 J-00 V1.8 §三接口表:领取是 **I-18**、回执是 **I-05**(原写 I-20/I-21,已作废)。
```jsonc
// I-18 拉取(长轮询,wait 最长 30s)
GET /internal/iot/v1/commands/pending?nodeId=iot-node-1&wait=30
{"code":0,"data":{"nodeId":"iot-node-1","hasMore":false,"commands":[
{"commandId":"CMD17942268075877","gatewayId":"GW-0001","targetId":"3F7A9C23",
"cmdType":"time_sync","deliveryMode":"REALTIME",
"params":{"ts":"2026-11-09T20:21:12+08:00"},
"leaseExpireAt":"2026-11-09T20:22:12+08:00","expireAt":"2026-11-12T20:21:12+08:00",
"retryCount":0}]}}
// I-05 回执(result 五值;resultCode 是标准码,不是厂家原码)
POST /internal/iot/v1/commands/result
{"nodeId":"iot-node-1","results":[
{"commandId":"CMD17942268075877","result":"ACKED","resultCode":"0","resultMsg":"OK",
"ackAt":"2026-11-09T20:21:14+08:00","rawResultCode":"00"}]}
{"code":0,"msg":"ok"}
```
## 7. 服务端推给家属端(SSE)
```
event: alarm
data:{"type":"alarm","alarmId":2796,"alarmNo":"AL20261109202112922",
"householdId":9001,"level":"S1","tier":"T1","ruleKey":"SOS",
"title":"紧急呼叫","content":"老人按下紧急按钮,请立即联系",
"deviceName":"床头SOS","deviceSn":"3F7A9C23",
"triggerAt":"2026-11-09T20:21:12","delayed":false}
```
---
## 8. 怎么用这些样例自测
```bash
# 登录拿 token(账号由 DemoDataInitializer 在空库首次启动时生成)
curl -X POST http://127.0.0.1:8080/api/v1/auth/wx/password-login \
-H "Content-Type: application/json" \
-d '{"phone":"13800000000","password":"123456"}'
# 打一条 SOS(把上面第 1 节的 body 存成 sos.json)
curl -X POST http://127.0.0.1:8080/internal/iot/v1/events/batch \
-H "Content-Type: application/json" \
-H "X-Idempotency-Key: batch-local-001" \
-d @sos.json
# 查告警是否生成
curl "http://127.0.0.1:8080/api/v1/alarms?size=3" -H "Authorization: Bearer <token>"
```
预期:1 秒内家属端 SSE 收到 `event: alarm`,列表首条是刚才那条 SOS。
> **注意**:`sensorId` 必须已经入库(后台「设备入库」录入或跑 `03` 的虚构台账数据),
> 否则会返回 `unregistered`,不建档也不告警 —— 这是 A 方案的刻意设计。