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),不做归一化以免整树摘要失效。
This commit is contained in:
commit
a7605ef8b8
121 files changed
+23629
No files matched your search
@@ -0,0 +1,156 @@
|
||||
# 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 方案的刻意设计。
|
||||
Reference in new issue
Block a user