feat: 实现边缘节点资产与离线状态管理 (#76)

This commit is contained in:
QiuSW
2026-08-28 14:25:32 +08:00
parent a9fd8e8a47
commit 2db49fc955
20 changed files with 970 additions and 10 deletions
+12 -2
View File
@@ -2,8 +2,8 @@
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
wiki_page: Architecture-and-Code-Map
wiki_url: https://git.ilapage.cn/ila/yovision/wiki/Architecture-and-Code-Map.-
wiki_revision: 502d61f5c765c6c9b71432cdbbf0159c9b9c1071
synchronized_at: 2026-08-28T03:50:51Z
wiki_revision: 5c2b5df080b160c1174be3e935fffba420885bff
synchronized_at: 2026-08-28T06:14:33Z
<!-- gitea-wiki-mirror:end -->
# 架构与代码地图
@@ -215,3 +215,13 @@ PostgreSQL 表 `sense_provisioning_batches` 保存幂等键、配额快照和汇
- 前端:`Sense/ui/src/views/sense/quota/` 与 `Sense/ui/src/api/sense/quota.js`;复用 BasicLayout、Axios、Element Plus Alert/Row/Progress/Form/Table/Pagination/Dialog/Tag/Button 和权限指令。
- 本模块不导入 Brain/Bell 模型,不访问其数据库,也不定义跨项目配额契约。
<!-- sense-quota:end -->
<!-- sense-edge-nodes:start -->
## Sense 边缘节点代码路径
- 领域投影、DTO、服务、审计、合成夹具与测试:`Sense/server/app/sense/edge_node/`。
- GoAdmin 路由:`Sense/server/app/admin/router/sense_edge_node.go`;只开放 `GET /api/v1/edge-nodes` 与 `GET /api/v1/edge-nodes/:id`,复用 JWT、Casbin、PermissionAction 和统一响应封装。
- PostgreSQL 表:`sense_edge_nodes` 保存最后已知投影,`sense_edge_node_events` 保存不可变状态转换;迁移 `2026082813000_edge_node.go` 建立动态菜单及 implementation_operator/site_admin/viewer 的只读权限,不写入夹具。
- go-admin-ui 页面:`Sense/ui/src/views/sense/edge-node/`;API 封装:`Sense/ui/src/api/sense/edge-node.js`。页面复用 BasicLayout、Element Plus 表格/分页/Dialog/Tag/Alert 和权限指令。
- 内部 `ApplyHeartbeat` 是未来 Sense 适配器的投影写入口,本工单不把它暴露为 HTTP API,也不定义跨项目契约。
<!-- sense-edge-nodes:end -->
+13 -2
View File
@@ -2,8 +2,8 @@
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
wiki_page: Business-Rules-and-Glossary
wiki_url: https://git.ilapage.cn/ila/yovision/wiki/Business-Rules-and-Glossary.-
wiki_revision: f7a08ae4eaa7557f2b8a470d895b06567f77d0e1
synchronized_at: 2026-08-28T03:51:05Z
wiki_revision: 8f81b925af671209341f1282e128c7f048bca8ec
synchronized_at: 2026-08-28T06:14:44Z
<!-- gitea-wiki-mirror:end -->
# 业务规则与术语
@@ -188,3 +188,14 @@ synchronized_at: 2026-08-28T03:51:05Z
- 32/64/128 只展示当前配置和目标硬件性能测试状态。未验证不得解释为支持或稳定承载承诺。
- 配额调整必须记录旧值、新值、操作人、时间和原因;viewer 与实施/运维角色只读,只有站点管理员可调整配额和重新启用设备。
<!-- sense-quota:end -->
<!-- sense-edge-nodes:start -->
## Sense 边缘节点状态规则
- **边缘节点投影**:Sense 保存的节点最后已知运行状态,不是 Brain/Bell 的共享机器身份或跨产品事实源。
- **在线**:最近心跳距读取时刻不超过 90 秒,且没有未完成的恢复阶段。
- **离线**:最近心跳距读取时刻超过 90 秒。离线是读取时推导状态,不得用“未知”覆盖最后已知的控制隧道、视频数据面、负载和回填队列;所有这些值必须同时标明陈旧。
- **恢复中**:心跳已经恢复,但控制隧道、视频数据面或回填通道仍在独立收敛。只有恢复阶段明确收敛后才显示在线。
- 状态转换写入不可变事件;列表和详情读取写入脱敏操作审计,不记录凭据或原始心跳载荷。
- 合成夹具必须显式调用,生产迁移和启动不得自动写入节点。
<!-- sense-edge-nodes:end -->
+80 -2
View File
@@ -2,8 +2,8 @@
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
wiki_page: Local-Development-and-Verification
wiki_url: https://git.ilapage.cn/ila/yovision/wiki/Local-Development-and-Verification.-
wiki_revision: e1755deff68c95188e6bf2f759c7ec93293c8715
synchronized_at: 2026-08-27T15:22:48Z
wiki_revision: cfec18809b3cb0d938003102c9caa5e6d6f4e818
synchronized_at: 2026-08-28T06:25:12Z
<!-- gitea-wiki-mirror:end -->
# 本地开发与验证
@@ -399,3 +399,81 @@ D:\supervisor\supervisord.exe ctl /c D:\supervisor\supervisord.conf reload
当前 Go Supervisor 的 `reload` 会重新读取独立配置;实际受影响实例必须以命令输出和 reload 前后 PID 为准。切换托管前先停止占用 Sense 端口的非 Supervisor 实例,防止自动启动进入 Backoff。验证至少包含 Supervisor 状态为 Running、`http://127.0.0.1:18080/health` 与首页返回 200,以及受控重启后 Sense 和受管 MediaMTX PID 均更新。
<!-- sense-supervisor:end -->
<!-- sense-local-events:start -->
### Sense 本地事件验证
合成数据通过 `local_event.SeedSyntheticFixture` 在测试中显式装载,不存在生产自动开关,也不要求 Brain 或 Bell 进程。定向及回归命令:
```powershell
cd Sense/server
go test -race ./app/sense/local_event
go test ./...
go vet ./...
go build ./...
cd ../ui
corepack pnpm@9.15.1 lint
corepack pnpm@9.15.1 test:unit
corepack pnpm@9.15.1 build:prod
```
PostgreSQL 迁移测试使用独立 schema;连接值只放当前进程环境,不写入仓库或日志:
```powershell
$env:SENSE_LOCAL_EVENT_MIGRATION_TEST_DATABASE_URL = '<隔离 PostgreSQL 连接>'
go test ./cmd/migrate/migration/version -run TestLocalEventMigrationOnPostgres -count=1 -v
```
验证应覆盖:candidate/confirmed 与 pending/success/failed 的独立组合、分页和时间/状态/关键词筛选、详情及保留提示、viewer/实施/站点管理员只读权限、操作审计,以及 Brain/Bell 均未启动时的合成候选 smoke。没有可用 PostgreSQL 测试连接时必须明确记录为未验证,不得以 SQLite 单测替代 PostgreSQL 结论。
<!-- sense-local-events:end -->
<!-- sense-operations:start -->
### Sense 运维中心验证
定向验证:
```powershell
cd Sense/server
go test -race ./app/sense/operations
go test ./app/admin/router ./cmd/migrate/migration/version
go test ./...
go vet ./...
go build ./...
cd ../ui
corepack pnpm@9.15.1 lint
corepack pnpm@9.15.1 test:unit
corepack pnpm@9.15.1 build:prod
```
合成 smoke 应覆盖设备认证失败、设备时间漂移、媒体退避、孤儿路由、本地推理 unavailable、筛选分页、详情、设备同步探测重试、媒体排队重试、版本冲突、在途防重和脱敏审计。Brain/Bell 不应启动或成为测试依赖。真实摄像头与 MediaMTX 故障恢复仍须在获准环境验证,日志不得记录设备地址、Stream URI 或凭据。
<!-- sense-operations:end -->
<!-- sense-edge-nodes:start -->
### Sense 边缘节点验证
定向验证:
```powershell
cd Sense/server
go test -race ./app/sense/edge_node
go test ./cmd/migrate/migration/version -run EdgeNode
go test ./...
go vet ./...
cd ../ui
corepack pnpm@9.15.1 lint
corepack pnpm@9.15.1 test:unit
corepack pnpm@9.15.1 build:prod
```
PostgreSQL 迁移测试只在提供隔离连接时执行:
```powershell
$env:SENSE_EDGE_NODE_MIGRATION_TEST_DATABASE_URL = '<隔离 PostgreSQL 连接>'
go test ./cmd/migrate/migration/version -run TestEdgeNodeMigrationOnPostgres -count=1 -v
```
验证应覆盖在线、超过 90 秒的离线、心跳恢复但通道未收敛、最后已知状态与陈旧时长、负载和回填队列、不可变状态事件、只读权限、脱敏读取审计,以及 Brain/Bell 不运行时的独立性。合成节点只能由测试或显式开发调用;没有隔离 PostgreSQL 连接时必须记录迁移真库测试未执行。
<!-- sense-edge-nodes:end -->
+10 -2
View File
@@ -2,8 +2,8 @@
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
wiki_page: Product-Requirements
wiki_url: https://git.ilapage.cn/ila/yovision/wiki/Product-Requirements.-
wiki_revision: e298b5a31fcc39e3e2d9b4df543a4bc50d94bcaa
synchronized_at: 2026-08-28T03:53:13Z
wiki_revision: dcbdcf563017a1749fa76ad5f78c74a2c3cc6be1
synchronized_at: 2026-08-28T06:16:00Z
<!-- gitea-wiki-mirror:end -->
# 产品需求
@@ -224,3 +224,11 @@ SEN-011 将默认 16 路实现为可配置的 Sense 本地交付配额。统一
容量页面只展示 16/32/64/128 的当前配置和性能测试状态。除已经验证的 16 路学校试点基线外,其余档位在完成目标硬件压测前都不得解释为单机承载承诺。
<!-- sense-quota:end -->
<!-- sense-edge-nodes:start -->
## Sense 边缘节点资产与离线状态
Sense 为网管和非技术运维人员提供只读的“边缘节点”页面,集中查看节点名称、位置、运行版本、模型版本、运行时长、承载路数、控制隧道、视频数据面和回填队列。节点最近心跳超过 90 秒即在读取时显示为离线;离线不会清空最后一次采集到的通道和队列状态,页面必须同时标明陈旧时长。心跳恢复后,连接状态与控制、视频、回填通道分别收敛,未全部收敛时显示“恢复中”。列表、详情及状态变化均可审计。
本能力只管理 Sense 自有投影,不建立 Brain/Bell 共享身份、控制协议或跨项目回填执行;Brain、Bell 未运行时仍可独立查看。合成节点仅供显式开发和测试,不由生产启动或迁移自动写入。
<!-- sense-edge-nodes:end -->
+10 -2
View File
@@ -2,8 +2,8 @@
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
wiki_page: Deployment-and-Operations
wiki_url: https://git.ilapage.cn/ila/yovision/wiki/Deployment-and-Operations.-
wiki_revision: 95965345e43d7fc403486c8afaecf36d79b757d0
synchronized_at: 2026-08-28T03:53:21Z
wiki_revision: 34b85f1c3fc2c3e0e7fa0de3df056940fcb71333
synchronized_at: 2026-08-28T06:17:09Z
<!-- gitea-wiki-mirror:end -->
# YoVision 部署与运维
@@ -92,3 +92,11 @@ Sense\start_sense.bat
批量导入被拒绝时还应检查模板只含 line_number/name/location/address,地址必须为不带账号、查询参数或片段的 HTTP(S) ONVIF 地址。条目失败时按页面原因检查网络、获准网段、凭据和接入状态;仅重试失败项,不删除已成功设备。日志、导出和问题记录不得粘贴摄像头凭据。
<!-- sense-provisioning:end -->
<!-- sense-edge-nodes:start -->
## Sense 边缘节点状态排错
升级后看不到“边缘节点”菜单时,先确认数据库迁移 `2026082813000_edge_node.go` 已成功,再重新登录或刷新动态菜单。implementation_operator、site_admin、viewer 均只有列表和详情读取权限,本模块没有网页写入、删除或远程控制接口。
节点超过 90 秒没有心跳即显示离线。离线时页面继续显示最后已知的隧道、视频、负载和回填状态,并标明陈旧时长,这不表示通道仍实时可用。心跳恢复但通道未收敛时显示“恢复中”,应分别检查控制隧道、视频数据面和回填队列。当前版本只提供 Sense 内部投影入口,不包含外部心跳接入协议或跨节点回填执行;没有节点数据时不会自动生成演示节点。
<!-- sense-edge-nodes:end -->