From d332797fcb02d10a72eaf6d803fed592b5339841 Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Fri, 7 Aug 2026 17:29:16 +0800 Subject: [PATCH] docs(task): define T-009 PostgreSQL foundation --- docs/tasks/T-009.md | 86 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 docs/tasks/T-009.md diff --git a/docs/tasks/T-009.md b/docs/tasks/T-009.md new file mode 100644 index 0000000..716389d --- /dev/null +++ b/docs/tasks/T-009.md @@ -0,0 +1,86 @@ +--- +id: T-009 +title: 建立 PostgreSQL 双 Schema 与 Bell 配额投影基础 +phase: 2 +deps: [T-008] +status: TODO +created: 2026-08-07 +issue: null +context_ref: null +claim_branch: null +work_branch: null +write_paths: + - docs/tasks/T-009.md + - deploy/postgres/ + - scripts/test_postgres.ps1 + - Sense/internal/store/ + - Sense/internal/config/ + - Sense/cmd/sense-api/main.go + - Sense/go.mod + - Sense/go.sum + - Sense/README.md + - docs/03-tech-stack.md + - docs/04-architecture.md + - docs/06-tasks.md + - docs/api.md + - docs/current-state.md + - tests/test_postgres_contract.py +--- + +## 问题 / 背景 + +T-008 已冻结 Sense Control API v1 和 `bell.site_quota_v1` 只读投影,但当前 Sense 仍只使用 M1 SQLite,Bell 也没有 PostgreSQL 源表、schema、角色或 migration。若直接实现 HTTP handler,tenant、配额读取、并发准入和事务语义仍会绑定 SQLite,后续迁移必然返工。 + +项目负责人指定使用本机现有 `D:\pgsql17`,已核实二进制与服务版本为 PostgreSQL `17.10`、默认端口 `5432`。现有实例要求 SCRAM 且当前执行环境没有管理员密码,因此自动验收必须使用同一套本机二进制启动隔离临时集群;不得修改现有实例的认证、角色、数据库或数据。生产/共享实例安装只有在操作者显式提供管理员连接信息时才执行。 + +## 关联需求与交互(如适用) + +- 用户故事:US-001、US-002、US-008、US-009、US-010。 +- 交互清单:IX-001~IX-004、IX-013~IX-016、IX-019、IX-020;本任务是数据基础,不修改已确认原型或实现 HTTP 页面交互。 +- 前置契约:`docs/contracts/sense-control-v1.openapi.json`、`docs/contracts/site-quota-v1.sql` 和 `docs/contracts/README.md`。 + +## 方案 + +1. 冻结 PostgreSQL `17.10` 与 Go PostgreSQL driver;增加可审计、顺序执行的初始化 SQL,创建 NOLOGIN 权限角色 `bell_app`/`sense_app`、`bell`/`sense` schema、Bell Site 配额源表和 Sense 设备/能力/调和表。 +2. migration 创建与 T-008 完全一致的 `bell.site_quota_v1(tenant_id, site_id, max_video_channels, source_version, source_updated_at)`;Bell 拥有源表和视图,Sense 只有 Bell schema `USAGE` 与视图 `SELECT`,没有 Bell 源表或写权限。 +3. Bell Site 在数据库层执行默认 16、范围 1~128、逻辑删除和单调版本;配额更新通过 trigger 增加版本,不能由 Sense 修改。 +4. 新增 Sense PostgreSQL repository,覆盖现有 SQLite 被对账/探活使用的全部 port;设备新增/启用在同一事务内按 tenant/site 读取配额投影、串行化同站点准入、统计 `enabled + video_capture`,并拒绝投影缺失、越界或版本回退。 +5. Sense 进程增加显式 `SENSE_DB_DRIVER=sqlite|postgres`;默认继续使用 SQLite 保持单摄像头开发路径,生产选择 PostgreSQL 时必须显式提供 DSN。不得把 DSN、密码或完整连接串写入日志、错误、任务证据或仓库。 +6. 使用 `D:\pgsql17\bin` 的 `initdb/pg_ctl/psql` 启动仅绑定回环地址的隔离临时集群,执行 migration、权限断言和 PostgreSQL repository 集成测试,结束后验证目标路径再清理临时数据目录;不停止或重启现有 Windows PostgreSQL 服务。 +7. 增加无 PostgreSQL 也能运行的静态契约测试,校验 migration 顺序、角色权限、配额视图签名、范围、版本 trigger 和禁止的宽权限;同步技术栈、架构、API、路线图、Sense 启动说明与当前状态。 + +## 不可变约束 + +- 阈值 / 数值边界:`max_video_channels` 默认 16、有效范围 1~128;16/128 不是单机承载保证。只统计 `desired_state=enabled` 且具有 `video_capture` capability 的设备;同站点并发创建/启用不能突破配额。 +- 判定式 / 状态转换:配额行缺失、读取失败、值越界或 `source_version` 回退时,PostgreSQL repository 只拒绝相关视频新增/启用,不停已有设备、不修改期望态;降低配额不会自动停用已有流。相同期望态重复提交不增加 generation。 +- 数据所有权:Bell 是 Tenant/Site/配额真相源;Sense 不建立可写 Site 真相副本,不写 Bell schema、不读取 `bell.sites` 源表。Sense 设备和调和状态只写 `sense` schema;两个 schema 只以 tenant/site 逻辑 ID 关联。 +- 安全边界:仓库、测试输出、Issue/PR 和日志不得出现 PostgreSQL 密码、DSN 凭据或私有数据。自动测试只使用临时 trust 集群且只绑定 `127.0.0.1`;现有 `D:\pgsql17\data`、Windows 服务和其他数据库严格只读。 +- 兼容与恢复:M1 SQLite 默认路径和现有五路集成工具继续可用;T-009 不搬迁或删除现有 SQLite 数据。生产切换失败时可回到 SQLite 配置;初始 PostgreSQL schema 不提供自动破坏性 down migration,清理由管理员在备份/确认后限定到 YoVision 专用数据库执行。 +- 既有契约:不修改 T-008 OpenAPI 路径、字段、错误语义、配额视图列签名或 Brain 事件 v0.1;PostgreSQL repository 的出现不表示 Sense HTTP handler、认证或 Bell 管理服务已经实现。 + +## 验收要点 + +- 任务相关验证:在本机执行 `./scripts/test_postgres.ps1 -PgRoot D:\pgsql17`,必须完成隔离集群启动、migration 重放、权限断言、tenant/配额/并发/版本回退 repository 集成测试和自动清理;运行 `python -m unittest tests/test_postgres_contract.py` 或对应 discovery 命令,静态负例能够拦截 Bell 写权限与契约漂移。 +- 完整门禁:运行 `./init.ps1`、`python scripts/validate_agent_context.py`、`python -m unittest discover -s tests -p "test_*.py"`、`python scripts/validate_harness_governance.py`、`go -C Sense test ./...`、`go -C Sense vet ./...`、`go -C Sense build ./...` 和 `git diff --check`,全部通过。 +- 人工 / 设备验收:不需要摄像头、UI 或客户现场;任务所有者必须核对隔离集群确实没有使用 `D:\pgsql17\data`,现有服务 PID/端口在测试前后保持运行,且共享实例未新增 YoVision 对象。 +- 构建产物:PostgreSQL migration、权限/迁移断言、本机隔离测试入口、Sense PostgreSQL repository 和配置/运维文档;不提交临时数据目录、数据库 dump 或秘密。 + +## 边界(不改什么) + +不实现 Sense Control API HTTP handler、Bearer 认证、RBAC、幂等收据、ETag/cursor/batch operation、Area/capture policy 投影、Bell Go 服务、SQLite→PostgreSQL 数据搬迁、WireGuard、孤儿删除、16 路容量压测或 T-007 现场验收;不修改 Brain、MediaMTX API、摄像头适配器、事件契约或已确认 UI 原型。 + +## 协作约束 + +- 责任 Agent:由 dispatcher 分配。 +- 唯一写入者:同责任 Agent。 +- 委派:默认不启用。 +- Gitea:任务文件先进入默认分支,再创建唯一 Issue 并回填编号;领取时记录 `context_ref`、claim 与工作分支。 + +任何新增写路径先检查与其他活跃任务是否重叠;同一时刻只有一个 Agent 修改本任务的 `write_paths`。 + +## 执行记录 + +### 2026-08-07 任务定义 + +- 项目负责人批准创建并实施 T-009,并指定复用本机 `D:\pgsql17`;核实版本为 PostgreSQL `17.10`。 +- 当前实例监听 `5432` 且 SCRAM 认证有效,执行环境未持有管理员密码;任务据此选择“本机同版二进制 + 隔离临时集群”作为自动验收,不触碰现有数据目录和服务。