2026-08-11 14:05:11 +08:00
---
id : T-018
title : 建立 Sense NVR 管理面设备与实时监看纵切
phase : 3
deps : [ T-004, T-014]
2026-08-11 14:42:25 +08:00
status : DONE
2026-08-11 14:05:11 +08:00
created : 2026-08-11
2026-08-11 14:06:12 +08:00
issue : 63
2026-08-11 14:38:22 +08:00
context_ref : a4427a6d2b08e6e8a86d913b24abb61ebcfff906
claim_branch : claims/T-018
work_branch : agent/codex/T-018
2026-08-11 14:05:11 +08:00
write_paths :
- docs/tasks/T-018.md
- Sense/cmd/sense-api/
- Sense/internal/config/
- Sense/internal/console/
- Sense/README.md
- docs/00-ai-start-here.md
- docs/03-tech-stack.md
- docs/04-architecture.md
- docs/06-tasks.md
- docs/routes.md
- docs/current-state.md
- tests/test_sense_console_contract.py
---
## 问题 / 背景
Sense 已有 ONVIF/RTSP 接入、MediaMTX 控制、Control API v1、对账、探活和本地 16 路容量证据,但客户目前只能通过 API、脚本或静态原型理解这些能力。T-004 已确认 Sense 的五入口信息架构;本任务把其中最能证明 NVR 管理面价值的“设备 + 实时监看”落成可运行纵切,并保留总览、接入任务和运维中心的诚实入口。
本任务不是完整 NVR:常态录像仍由客户现有 NVR 承担,YoVision 暂不实现录像计划、录像索引或回放;MediaMTX 继续作为独立数据面,Sense 只提供管理面和受限播放入口。为避免在 JWT/OIDC、反向代理和 MediaMTX 外部认证尚未冻结时暴露视频,本版控制台只允许回环工程环境启用。
## 关联需求与交互(如适用)
- 用户故事:US-001、US-002、US-008、US-009;本任务只完成其中设备查询、状态理解和按需监看的首个纵切,不宣称批量导入、完整能力探测或全量运维 API 已完成。
- 交互清单:IX-002~ IX-004、IX-013~ IX-015、IX-019、IX-020,以及“桌面与大屏”中的按需预览和 128 路分页约束。
- 相关页面 / 路由:已确认原型 `docs/design/sense/index.html` ;新增工程路由 `/sense-console/` ,不冻结为 Bell 客户公共路由。
## 方案
1. 在 `Sense/internal/console/` 增加由 Go `embed` 提供的自包含 HTML/CSS/JavaScript 控制台,不引入前端框架、CDN、字体或第三方播放器依赖;外观沿用 T-004 已确认的深色接入运维台,不重新设计信息架构。
2. 控制台复用同源 Sense Control API v1。操作者输入 Site ID 和 Bearer token 后加载设备页;token 只保存在当前 JavaScript 内存中,刷新即丢失,不进入 URL、DOM 可见文本、`localStorage` 、`sessionStorage` 、cookie 或日志。
3. 设备列表默认每页 16 项,使用服务端 cursor,支持模态、期望态和实际态筛选;显示配额、期望态/实际态、收敛、失败码、重试时间和策略投影版本。页面只把当前页统计标为“当前页”,不伪造站点总量。
4. 实时监看只允许从当前已授权设备中选择具有 `video_capture` 能力的设备,最多同时打开 4 路;默认不自动播放。播放使用 MediaMTX v1.19.3 官方浏览器 WebRTC 页面,地址由仓库外环境配置提供,UI 不显示 RTSP/ONVIF、凭据或完整播放地址。
5. `/sense-console/` 默认关闭。启用时 Sense HTTP 监听与 MediaMTX WebRTC 基地址都必须是显式回环地址;配置含 userinfo、查询、fragment、非 HTTP(S) 或非回环主机时启动失败。页面添加 CSP、`frame-ancestors 'none'` 、`nosniff` 、`no-store` 和严格 Referrer Policy。
6. 总览、接入任务和运维中心继续保留为五入口结构:总览只汇总已加载事实;接入任务明确标识本纵切尚未实现批量导入;运维中心显示当前页未收敛项并提供受限 `/metrics` 入口,不伪造分片、隧道或告警数据。
7. 添加 Go handler/config/UI 契约测试;在 Edge 以 1440× 900、375× 812 和 812× 375 检查焦点、无横向溢出、44px 触控目标、空态/鉴权失败/依赖失败和 `prefers-reduced-motion` 。实流人工验收可继续使用一台已准入海康相机,不要求新增摄像头。
## 不可变约束
- 阈值 / 数值边界:站点默认 16 路、可配置 1~128;设备列表默认页长 16;本任务浏览器同时预览上限固定为 4,128 路不得一次加载全部详情或视频。
2026-08-11 14:38:22 +08:00
- 判定式 / 状态转换:Control API 写入受理不等于实际态收敛;未知或请求失败不得显示在线;只有 `video_capture + desired_state=enabled + actual_state=online + converged=true` 的设备可启动预览。
2026-08-11 14:05:11 +08:00
- 安全边界:控制台和 WebRTC 基地址仅回环;默认关闭;Bearer token 仅驻留页面内存;不得显示或持久化摄像头凭据、完整 RTSP/ONVIF URI、MediaMTX source、token、客户数据或真实视频证据。非回环/TLS/JWT/OIDC/MediaMTX 外部认证另立任务。
- 既有契约:不修改 Sense Control API v1、事件 v0.1、Bell schema 或 MediaMTX 生成客户端;MediaMTX 仍是独立二进制,Sense 不代理媒体字节;T-004 原型保持产品结构权威,本任务只实现其明确子集。
## 验收要点
2026-08-11 14:38:22 +08:00
- 任务相关验证:`go -C Sense test ./...` 、`go -C Sense vet ./...` 、`go -C Sense build ./...` 、`python -m unittest discover -s tests -p "test_sense_console_contract.py" -v` ;覆盖默认关闭、回环限制、配置拒绝、路由/安全头、内存 token、16 项 cursor 页面、最多 4 路按需预览和状态降级。
2026-08-11 14:05:11 +08:00
- 完整门禁:运行 `./init.ps1` 、`git diff --check` 。本任务不改变 PostgreSQL migration、Control API OpenAPI 或 MediaMTX 生成源,因此不触发 `scripts/test_postgres.ps1` 和生成客户端漂移以外的新增 schema 门禁;根入口仍会执行既有 generate/test/vet/build。
- 人工 / 设备验收:必需。项目负责人打开实际 `/sense-console/` ,确认与 T-004 五入口一致、设备/配额/状态可理解、最多 4 路按需监看、错误状态不伪装在线;可使用一台已准入海康设备或 T-014 合成流。未确认前任务文件保持 `DOING` , Issue 使用 `status/review` ,不得标 `DONE` 。
- 构建产物:`Sense` Go 二进制内嵌控制台静态资源;`go -C Sense build ./...` 可重现。无独立前端构建产物。
## 边界(不改什么)
不实现录像计划、常态录像、回放、证据切片、批量 CSV 导入、Site/Area/RBAC CRUD、Bell 业务预警、Brain 推理、非回环部署或生产会话认证;不修改 `_reference/` ,不复制 MiBeeNvr 或 MediaMTX UI/播放器源码,不改已确认的 `docs/design/sense/index.html` 。
## 协作约束
- 责任 Agent: codex。
- 唯一写入者:codex。
- 委派:不启用。
2026-08-11 14:06:12 +08:00
- Gitea:主 Issue 为 #63 ;领取时填写 `context_ref` 、`claims/T-018` 与 `agent/codex/T-018` 。
2026-08-11 14:05:11 +08:00
任何新增写路径先检查与其他活跃任务是否重叠;同一时刻只有一个 Agent 修改本任务的 `write_paths` 。
## 执行记录
### 2026-08-11 任务定义
- 项目负责人将开发优先级从 Brain/Bell 后续链调整为先做 Sense; T-018 因此定义为 Sense NVR 管理面首个可运行纵切,原 Brain→Bell ingress 顺延为后续建议任务。
- 复用 T-004 已确认的信息架构和现有 Control API/MediaMTX 基础,不新增前端或媒体依赖;录像/回放、非回环认证和完整运维 API 明确排除。
- 基线 `./init.ps1` 通过:68 项根测试、19 项 Brain 测试及 Sense/Bell generate/test/vet/build 全绿。
2026-08-11 14:06:12 +08:00
- 任务定义已合入默认分支并创建唯一 Gitea Issue #63 ;本映射提交合入后才添加 `status/todo` 并允许 dispatcher 分配。
2026-08-11 14:38:22 +08:00
### 2026-08-11 领取与基线
- dispatcher `ila` 从默认分支 `a4427a6d2b08e6e8a86d913b24abb61ebcfff906` 创建并读回 `claims/T-018` 、`agent/codex/T-018` ; Issue #63 已分配给 `ila` ,标签为 `status/doing` ,结构化 CLAIM 评论与本文件 `write_paths` 一致。
- T-007 仍为 `status/waiting` ,不属于活跃写路径预留;T-017 的残留 PR 元数据异常不对应活跃 Issue,默认分支已包含其合并提交。
### 2026-08-11 实现与自动化验收
- `sense-api` 新增默认关闭的 `/sense-console/` 内嵌路由和运行时配置;配置层与 handler 双重拒绝非回环、userinfo、路径、query、fragment 和非 HTTP(S) 的播放基地址,控制台只能与已开启的回环 PostgreSQL Control API 一起运行。
- 自包含 HTML/CSS/原生 JavaScript 保留 T-004 已确认的运行总览、实时监控、设备、接入任务、运维中心五入口。设备页使用服务端 cursor 和固定 16 项页长;期望态、实际态、收敛与错误分别呈现,未知/请求失败不显示在线。接入任务明确标为未实现,不用假上传伪装交付。
- Bearer token 只保存于页面内存,输入后立即清空且刷新后会话清零;页面不使用 local/session storage、cookie、URL token 或 `innerHTML` 。只有 `video_capture + enabled + online + converged` 可选,选择和已启动预览均硬限制为 4,iframe 停止时移除 `src` 。
- Edge headless + 本地脱敏 Control API fixture 完成浏览器 QA: 1440× 900 显示 16 项和 `16 / 128` 配额,无横向溢出且 cursor 下一页可用;第五路选择被拒绝,实际 iframe 保持 4;375×812 切换为设备卡片和五入口底栏,无横向溢出、最小可见按钮 44 px;844×390 无横向溢出。刷新后连接对话框重新打开、token 输入为空、会话回到未建立。该 QA 只验证 UI/嵌入 URL,不替代真实 MediaMTX 解码验收。
- 浏览器 QA 首轮发现加载完成后分页按钮仍保留禁用态;已在 `setLoading(false)` 时重新计算前后页状态并复验通过。
- 任务验证通过:`node --check Sense/internal/console/assets/app.js` ; `python -m unittest discover -s tests -p "test_sense_console_contract.py" -v` 4 项;`go -C Sense test ./...` 、`go -C Sense vet ./...` 、`go -C Sense build ./...` ; `./init.ps1` 72 项根测试、19 项 Brain 测试及 Sense/Bell generate/test/vet/build 全绿;`git diff --check` 在提交前复核。
2026-08-11 14:42:25 +08:00
- 人工门禁已满足:项目负责人于 2026-08-11 明确回复“验收通过”,接受实际 `/sense-console/` 的五入口、设备/配额/收敛语义和 MediaMTX WebRTC 播放纵切。该确认不扩大到录像/回放、非回环生产认证、真实 16 机或生产 SLA。
### 2026-08-11 产品验收
- 项目负责人在本轮明确确认 T-018 验收通过;任务状态更新为 `DONE` ,允许合并 PR #65 并关闭 Issue #63 。
- 交付边界保持不变:这是默认关闭的 Sense 回环 NVR 管理面纵切,常态录像仍由客户既有 NVR 承担,后续 Brain→Bell ingress 仍需独立 T-019。