Files
yovision/docs/03-tech-stack.md
T
QiuSW 8208118904
Harness governance / validate (pull_request) Has been cancelled
feat(bell): add alert acknowledgement vertical slice
2026-08-11 17:01:53 +08:00

183 lines
18 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.
# 技术栈
> 已决项必须遵守;标为“待定”的版本或组件不得由 agent 自行拍板,应先落 Gitea Issue 并更新本文。
## 1. 已定技术方向
| 范围 | 选择 | 状态与说明 |
| --- | --- | --- |
| 首期部署 | 客户侧私有化实例 | 保留 `tenant_id`、RBAC、schema 和 API 的 SaaS-ready 隔离边界 |
| M1–M3 视频接入 | ONVIF / RTSP | 售前盘点存量 NVR;GB/T 28181-2022 不进当前 MVP,按需另建适配任务 |
| 本地摄像头基线 | 1 台 Hikvision IP Camera + 独立合成 RTSP 源 | 海康精确型号/固件由 T-001 冻结;T-006 冻结合成 publisher 及版本。仅为开发策略,不在业务代码写死品牌,也不替代 T-007 真实多路现场验收 |
| Sense | Go | 设备、ONVIF、MediaMTX 控制与对账 |
| 媒体数据面 | MediaMTX 独立二进制 | MIT;M1 正式生产基线 |
| MediaMTX API | 从官方 OpenAPI 用 `oapi-codegen` 生成 + 薄封装 | 不依赖第三方非官方 SDK |
| Brain | Python / CUDA | 推理流水线与判定内核 |
| 推理框架主选 | Savant / NVIDIA DeepStream | M1–M3 只验证 NVIDIA x86/Jetson;具体版本与目标 GPU 待 M0/M1 压测冻结 |
| 推理框架/硬件逃生通道 | ONNX 接口 + 可替换框架适配层;Pipeless 候选 | 信创不在 M1–M3 承诺内,海光/鲲鹏/昇腾/寒武纪走独立硬件 POC 与报价 |
| 模型主选 | Ultralytics YOLO(含 pose) | 商用前必须购买 Enterprise License |
| 模型备选 | YOLOX + RTMPose | 主选授权未批或目标硬件不适配时启用 |
| 跟踪/同一性 | ByteTrack 或 BoT-SORT + ReID | 具体组合待基准测试;ReID 默认、人脸可选 |
| Bell 后端 | Go | 事件、规则、预警、租户与审计 |
| Bell 客户端 | 值班室 Web + 响应式移动 H5 | 前端框架仍须经 UI 原型和技术评审冻结;M3 不做独立原生 App |
| Bell 对外集成 | 版本化 OpenAPI / Webhook | Bell 持有事件、Alert、ack、升级链、租户与审计真相 |
| M1 本地存储 | SQLite | schema 与生产 PostgreSQL 保持一致,仅 Sense 初期使用 |
| 生产数据库 | PostgreSQL,一个实例、`sense`/`bell` schema 分离 | Brain 无业务 schema |
| 证据对象存储 | 客户侧 MinIO / S3 兼容 | 常态录像留在客户 NVR;事件片段技术默认 30 天,最终期限由客户/法务确认 |
| 通知投递 | Bell provider 接口 | 供应商待项目采购;试点使用本地声光/Web + 一条短信或语音,生产前两条独立路径并支持故障切换 |
| 边缘隧道 | WireGuard | 控制面管理 |
| 指标 | Prometheus + Grafana | 三系统统一可观测入口 |
| 追踪 | OpenTelemetry + Jaeger | 端到端事件链路 |
### 1.1 Sense M1 冻结版本(T-003)
| 组件 | 冻结版本 | 许可证 / 校验 | 升级与退出路线 |
| --- | --- | --- | --- |
| Go | `1.26.5`(`go 1.26.0` + `toolchain go1.26.5`) | BSD-3-Clause;从 `go.dev/dl` 校验,Windows amd64 ZIP SHA-256 `97e6b2a833b6d89f9ff17d25419ac0a7e3b482a044e9ab18cdef834bd834fd38` | 跟随仍受支持的 Go 小版本,先在 CI/目标平台跑全量测试再升级;标准 Go module,无私有运行时绑定 |
| SQLite driver | `modernc.org/sqlite v1.54.0` | BSD-3-Clause;module sum `h1:JCxR4qwkJvOaqAoYcgDoO25Nc+ROg6EJ2LfBVzdrgog=`,go.mod sum `h1:4ntCLuNmnH8+GNqjka1wNg7KJd5/Hi5FYp8K+XQ7GZw=` | 选择无 CGO driver 以简化 Windows/边缘部署;只经 `database/sql` 与 repository 使用,可替换 driver;生产仍迁移到 PostgreSQL `sense` schema |
| MediaMTX | `v1.19.3` | MIT;官方 release `checksums.sha256`:Windows amd64 `5d82148d1032a6a190d9909a2997d9989457aaadf49af87dd02cd4512d31bebe`、Linux amd64 `a7ba21268fccda3ebc43fdad76b87fddb85ce77e725b5cb637bca724b5394fbe`、Linux arm64 `9e5b38a5b5fcab1916341b024031b2fc5dc6a2059baed9ba3f3b0d3768d231a8` | 独立进程,不链接到 Sense;升级时先更新 vendored OpenAPI、重新生成并跑假服务契约测试;可通过 `mtx` port 更换媒体数据面 |
| oapi-codegen | `v2.8.0` | Apache-2.0;module sum `h1:s4hxMxuqtR8jPzXkBTtFwY/SBuj3gEAYikmbBSdtLMM=`,go.mod sum `h1:yae2TI9IYB5vxQ35gFrpXh9L5H1eJv4MAUK1jumGMTo=` | 仅为构建工具;版本锁在 module tool dependency,生成文件与薄封装分离;升级后必须重新生成并检查 diff |
| oapi-codegen runtime | `v1.6.0` | Apache-2.0;module sum `h1:7Xx+GlueD6nRuyKoCPzL434Jfi3BetbiJOrzCHp/VPU=`,go.mod sum `h1:GwV7hC2hviaMzj+ITfHVRESK5J2W/GefVwIND/bMGvU=` | 生成客户端的最小运行时;与生成器一起升级并跑假 HTTP 契约测试,退出时随生成客户端一并替换 |
MediaMTX 官方 `v1.19.3` OpenAPI 固定保存于 `Sense/api/vendor/mediamtx-v1.19.3.openapi.yaml`,SHA-256 为 `a2b58195f1ec76541e124b5de4ee54645e5a3e25f70c4a73acc4a44d6f2b9c52`。下载二进制后必须对照上表或官方同版 `checksums.sha256`,不得使用浮动 `latest` URL。SQLite `v1.56.0` 在本决策日刚发布,T-003 不追新;后续依赖升级单独评审。
### 1.2 Sense M2 PostgreSQL 冻结版本(T-009)
| 组件 | 冻结版本 | 许可证 / 校验 | 使用与退出路线 |
| --- | --- | --- | --- |
| PostgreSQL | `17.10` | PostgreSQL License;本机验收二进制 `D:\pgsql17\bin\postgres.exe` 与 `psql.exe` 均报告 `17.10` | 首期一个实例、`sense`/`bell` schema 分离;自动测试用同版二进制启动隔离临时集群,不改现有服务。升级 17.x 小版本须重跑 migration、权限和 repository 集成测试;跨大版本先做备份恢复演练 |
| Go PostgreSQL driver | `github.com/jackc/pgx/v5 v5.10.0` 的 `stdlib` | MIT;module sum `h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0=`,go.mod sum `h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=` | 只通过 `database/sql` 和 store port 使用;DSN 只来自进程环境且不记录。退出时可更换 `database/sql` driver,业务域与调和器不依赖 pgx 类型 |
M2 仍保留 SQLite 作为单机开发与 T-006 回归入口,但生产真相源切换目标是 PostgreSQL。运行时必须显式设置 `SENSE_DB_DRIVER=postgres` 和私有 `SENSE_DB_DSN` 才使用 PostgreSQL;仓库不提供带密码 DSN。初始 schema 由 `deploy/postgres/` 的顺序 migration 创建,不在 Sense 进程启动时使用高权限自动迁移。
T-011 复用同一套冻结的 Go、PostgreSQL、pgx 与 `oapi-codegen`,未增加第三方依赖。Sense Control API v1 从仓库 OpenAPI 生成 `net/http` server glue;首版认证是可替换 port 下的外部静态 SHA-256 注册表,公共路由默认关闭且只在 PostgreSQL 生产路径启用。T-011 首次落成 v4 schema,T-012 后进程统一要求 v5。静态适配器是私有部署启动方案,不替代后续 Bell/JWT/OIDC 身份服务。
T-012 同样未增加第三方依赖:PostgreSQL v5 使用数据库时钟租约和 fencing token 协调多实例调和/孤儿扫描;MediaMTX Path 枚举继续使用同版生成客户端。`/metrics` 由 Go 标准库输出 Prometheus 文本格式,只包含固定结果枚举、构建/实例信息和汇总 gauge/counter,不使用 tenant、Site、device 或 Path 标签。孤儿处置是 PostgreSQL 专用本地命令,默认周期任务只报告、不自动删除。
T-014 没有增加生产依赖。Windows 容量脚本冻结并核对 Sense 模块 Go 1.26.5、PostgreSQL 17.10、MediaMTX v1.19.3 与 FFmpeg 8.1.2;MediaMTX Windows amd64 ZIP 使用上表官方 SHA-256,解压后 `mediamtx.exe` 另固定为 `1cda85249312cb9463f9f94c5a712b9f160c9af3fd9490f0d4723911d7880e05`。FFmpeg 只生成无人物夹具并以 16 个独立 `-c copy` 进程发布,不进入生产镜像或 Go module。正式本机结果与限制见 [`research/sense-16-stream-capacity.md`](research/sense-16-stream-capacity.md)。
### 1.3 Bell M3 事件存储冻结版本(T-015)
| 组件 | 冻结版本 | 许可证 / 校验 | 使用与退出路线 |
| --- | --- | --- | --- |
| Go | `1.26.5`(与 Sense 相同) | BSD-3-Clause;复用 §1.1 工具链与校验 | Bell 独立 Go module;升级时同时运行两个 module 的 test/vet/build |
| PostgreSQL / pgx | `17.10` / `github.com/jackc/pgx/v5 v5.10.0` | PostgreSQL License / MIT;module sum `h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0=` | 复用 T-009 的 `database/sql` 边界;运行身份改用无 owner 权限的 `bell_runtime` 组 |
| JSON Schema | `github.com/santhosh-tekuri/jsonschema/v6 v6.0.2` | Apache-2.0;module sum `h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=` | 运行时校验 Draft 2020-12 与 format;退出时可替换 validator,但冻结 schema 和负向契约测试不变 |
| ULID | `github.com/oklog/ulid/v2 v2.1.2` | Apache-2.0;module sum `h1:IEclFb9JNvzYA6MW2SCxbLzcHTVsfqm3PrqGQJH5zec=` | 只封装在 Bell ID generator 边界后;Event 前缀为 `evt_`,T-020 Alert 前缀为 `alt_`,替换实现不得改变格式或所有权 |
T-015 不冻结 Brain→Bell transport,也不产生可部署 Bell API 二进制。内部 factory 接收不含 `id` 的候选事实,由 Bell 生成 ULID 后才形成最终 v0.1 事件;不得把该 Go 类型当成公共网络协议。
### 1.4 Sense 审计 relay(T-016)
T-016 不增加第三方依赖:两端使用 Go 标准库 HTTP、HMAC-SHA256、SHA-256、base64url 和 constant-time compare,数据库继续使用已冻结的 PostgreSQL 17.10/pgx。`cmd/bell-api` 只提供回环 health/ready 和 Sense 审计内部端点;非回环监听必须同时提供绝对路径 TLS 证书/私钥。HMAC key 使用仓库外 version 1 JSON 文件,secret 至少 32 字节;该适配器不替代未来 Bell 公共 JWT/OIDC。
### 1.5 Brain 单路工程原型(T-017)
| 组件 | 冻结版本 | 许可证 / 校验 | 使用与退出路线 |
| --- | --- | --- | --- |
| Python | `3.10.11` | PSF License;本机 `python --version` 已验证 | 仅冻结 T-017 工程原型和测试语法基线,不等于生产 Savant/DeepStream Python 版本;生产脚手架冻结时通过标准模块边界迁移 |
| NumPy | `1.26.4` | BSD-3-Clause;本机 `numpy.__version__` 已验证 | 只在 frame fixture/OpenCV 数组边界使用;不把 NumPy 类型写入事件候选或 HTTP JSON |
| OpenCV Python | `opencv-python 4.9.0.80` | wheel 构建脚本 MIT、OpenCV Apache-2.0;Windows amd64 wheel SHA-256 `3f16f08e02b2a2da44259c7cc712e779eff1dd8b55fdb0323e8cab09548086c0` | 内置 HOG/SVM 只作为可替换 `Detector` 的匿名人员检测演示,不是生产模型;生产退出时替换 detector port,区域判定、候选事实和 UI 状态不依赖 HOG 类型。不得在同一环境混装标准/headless/contrib wheel |
T-017 不冻结 CUDA、Savant/DeepStream、ONNX Runtime、Ultralytics、跟踪/ReID 或 `max_sources`。默认合成 fixture 可重复展示工程链路,并必须标识为“非模型输出”;真实流只从仓库外绝对 URL 文件读取,优先消费 Sense 管理的 MediaMTX path。`/brain-demo` 只监听显式回环地址,事件候选最多保留 100 项内存环,不形成 Brain 业务数据库。OpenCV wheel 是 CPU-only;本机存在 NVIDIA GPU 也不能据此宣称 GPU 推理已接入。
### 1.6 Sense 回环 NVR 管理面纵切(T-018)
T-018 不增加生产或前端依赖:Go 使用标准库 `embed`/`net/http` 提供自包含 HTML、CSS 和原生 JavaScript,页面直接消费已冻结的 Sense Control API v1;实时预览使用同版 MediaMTX v1.19.3 自带浏览器 WebRTC 页面,不 vendor `reader.js`、不引入 CDN/播放器库,也不让 Sense 代理媒体字节。
该选择只适用于默认关闭的回环工程控制台,不冻结 Bell 最终前端框架。页面默认 16 项 cursor 分页、最多 4 路按需预览且不自动加载视频;Sense HTTP 与 WebRTC 基地址必须同时是显式回环地址。非回环 HTTPS/JWT/OIDC、MediaMTX 外部认证、录像/回放和正式客户会话均保持待冻结,不能从 T-018 的本地演示外推为生产安全或 NVR 存储能力。
### 1.7 Brain → Bell 事件 ingress(T-019)
T-019 不增加第三方依赖。Brain 继续使用 Python 3.10.11 标准库 `sqlite3`、`urllib`、HMAC/SHA-256 和线程;SQLite Outbox 开启 WAL 与 `synchronous=FULL`,文件、配置和 key 都必须是仓库外绝对路径。内部 HTTP client 显式禁用环境代理,避免业务事件被 `HTTP(S)_PROXY` 意外转发;回环可用 HTTP,非回环只接受 HTTPS。队列最多 10,000 条待投递、单 payload 1 MiB、1~300 秒退避、最多 100 次,终态记录保留供运维核查。
Bell 复用已冻结 Go 1.26.5、PostgreSQL 17.10/pgx、JSON Schema 和 ULID,不新增消息总线或 SDK。`brain-event-ingress-v1` 是单事件、producer-bound HMAC 内部适配器;Bell 用永久来源收据和事务级 advisory lock 保证同 `(producer_id, source_event_id)` 只生成一个平台事件。该选择不冻结 Bell 公共认证、生产 Brain GPU/runtime 或未来高吞吐 transport;若容量基准证明单条 HTTP 不足,必须发布兼容迁移方案,不能绕过来源幂等键。
### 1.8 Bell 规则、Alert 与回环值班台(T-020)
T-020 不增加第三方依赖:规则/Alert 域继续使用 Bell 已冻结的 Go 1.26.5、PostgreSQL 17.10/pgx 和 ULID。规则配置是仓库外 JSON,首版只实现精确事件类型、最小严重度、可选 Site、启用状态和生效时间;canonical SHA-256 相同则幂等复用,变化只追加新版本。规则 worker 是单一可取消循环和有界空闲轮询,不按租户、站点或设备创建 goroutine;数据库 durable sweep、唯一键和事务级 advisory lock 负责多实例收敛。
回环值班台与 T-018 相同,使用 Go 标准库 `embed`/`net/http` 和自包含 HTML/CSS/原生 JavaScript,无 npm、框架、CDN 或浏览器持久存储。该选择只服务工程验收,不冻结 Bell 正式前端栈。控制台与规则 worker 分别默认关闭;控制台要求规则已启用、整个 Bell 监听地址显式回环、仓库外 token 文件及服务端 tenant/Site/actor 上下文。证据、升级/通知、JWT/OIDC/RBAC 和非回环部署不在本任务内。
## 2. 外部项目边界
- MiBeeNvr:只用于 M0 隔离实验室、ONVIF兼容性和交互参考,不作为生产依赖。
- MediaMTX:生产媒体数据面,不提供 YoVision 业务管理 UI。
- silver_pose:独立可交付仓库,是 Brain 判定内核的来源;不改名、不合并。
- `_reference/`:只读、忽略、不进入模块依赖和生产镜像。
## 3. 待冻结项
- Python、Savant/DeepStream 的精确版本;Go、MediaMTX 与 PostgreSQL 已分别为 Sense M1/M2 冻结,后续阶段可按升级流程调整。
- Bell 前端框架和组件库。
- Brain 生产推理 runtime 与更高吞吐 transport;T-019 已冻结首版 Brain→Bell 单事件内部 HTTP ingress,但不据此承诺 64/128 路吞吐或消息总线选型。
- 目标 GPU/边缘硬件、解码能力和每 worker 的 `max_sources`。
- MinIO/S3 的精确版本、加密实现,以及客户/法务确认后的最终生命周期策略。
- 短信/语音供应商及生产双路径组合;是否开发原生 App 最早在 M4 根据试点反馈决定。
这些选项必须在对应任务中记录基准、许可证、运维成本和退出路线。
## 4. 当前标准入口
Sense 骨架建立后,根目录脚本同步 Go 依赖并执行治理与 Sense 验证:
```powershell
./init.ps1
```
WSL/Linux/macOS/Git Bash:
```bash
./init.sh
```
Sense 单独执行:
```powershell
go -C Sense mod download
go -C Sense generate ./internal/mtx ./internal/controlapi
go -C Sense test ./...
go -C Sense vet ./...
go -C Sense build ./...
go -C Sense run ./cmd/sense-api
```
Bell 事件、内部 ingress 与回环 Alert 纵切单独执行:
```powershell
go -C Bell mod download
go -C Bell test ./...
go -C Bell vet ./...
go -C Bell build ./...
```
Brain 单路工程原型单独执行:
```powershell
python -m unittest discover -s Brain/tests -p "test_*.py" -v
python -m compileall -q Brain
python -m Brain.yovision_brain --source synthetic
```
直接验证:
```powershell
python scripts/validate_agent_context.py
python -m unittest discover -s tests -p "test_*.py"
python scripts/validate_harness_governance.py
```
## 5. 验证矩阵
| 改动范围 | 每次必跑 | 完整门禁触发条件 | 人工/设备门禁 |
| --- | --- | --- | --- |
| Harness 文档/任务/Gitea 模板 | 上述三条 Python 命令 | 任一治理协议、清单或任务 schema 变化 | 不适用 |
| `docs/raw/contracts/` | JSON Schema 校验 + 契约代码断言(实现后补命令) | schema/示例/mapper 任一变化 | 生产者与消费者联合评审 |
| Sense Go | `go -C Sense generate ./internal/mtx ./internal/controlapi`、`go -C Sense test ./...`、`go -C Sense vet ./...`、`go -C Sense build ./...` | ONVIF、存储、MediaMTX、对账或公共 API 变化 | T-006 使用 1 路指定实机 + 4 路独立合成源;T-007 才要求客户/借用/租赁的真实多路矩阵 |
| PostgreSQL schema/repository | `python -m unittest discover -s tests -p "test_postgres_contract.py"`;Windows 本机再运行 `./scripts/test_postgres.ps1 -PgRoot D:\pgsql17` | migration、权限、配额判定或 PostgreSQL driver 变化 | 不需要摄像头;必须核对临时集群未使用现有 data 目录,现有 5432 listener 前后不变 |
| Brain Python | 当前工程原型:`python -m unittest discover -s Brain/tests -p "test_*.py" -v`、`python -m compileall -q Brain` | source、detector port、track、判定状态机、mapper 或模型接口变化 | T-017 合成 fixture 只验工程闭环;命中真实模型任务时另用冻结数据集和目标硬件,不能用 fixture/HOG 结果替代 |
| Bell Go/Web | `go -C Bell test ./...`、`go -C Bell vet ./...`、`go -C Bell build ./...`;回环值班台静态门禁:`python -m unittest discover -s tests -p "test_bell_alert_contract.py"`;正式前端命令待脚手架冻结 | schema、RBAC、预警状态机或公共 UI 变化 | P0 正式 UI 流程由产品/值班角色验收;T-020 工程台检查 375px/桌面、键盘、错误态和 reduced-motion,不等于正式 UI 验收 |
| 容量/分片 | 任务内基准脚本;本地 16 路入口为 `./Sense/scripts/t014-capacity.ps1 -PgRoot D:\pgsql17` | 默认 16 路软件基线,以及后续 64/128 路分片里程碑 | 本地 16 路控制面可用独立合成源;真实多路、生产 SLA、64/128 路、AI/GPU、网络与存储必须使用目标环境分别验收 |
代码脚手架落地时必须把真实命令同步到本文、`init.ps1`/`init.sh`、`00-ai-start-here.md` 和 `current-state.md`。