按周工交付的 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),不做归一化以免整树摘要失效。
4.7 KiB
4.7 KiB
Mock 样例(可直接拿去打)
六组报文全部取自 2026-11-09 20:21 的真实一次运行,不是手编的示例。 对应证据:
06_统一闭环题自测证据/05_SOS链路.json
1. I-01 事件上报 · 请求
POST /internal/iot/v1/events/batch HTTP/1.1
Content-Type: application/json
X-Idempotency-Key: batch-20261109-2021-001
{
"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 响应
{"code":0,"msg":"ok","data":{
"accepted":1, "rejected":0, "duplicated":0, "unregistered":0, "rejectedDetail":[]}}
3. I-01 失败样例(四种)
// ① 缺 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 设备状态快照
{
"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 原始报文留档
{
"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,已作废)。
// 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. 怎么用这些样例自测
# 登录拿 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 方案的刻意设计。