From dd588b5daab699bbcb85c9b8ef26807b73e852e9 Mon Sep 17 00:00:00 2001 From: qsc Date: Sun, 12 Jul 2026 02:42:44 +0800 Subject: [PATCH] 11 --- 开发文档/一致性决策基线.md | 123 +++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 开发文档/一致性决策基线.md diff --git a/开发文档/一致性决策基线.md b/开发文档/一致性决策基线.md new file mode 100644 index 0000000..68b534b --- /dev/null +++ b/开发文档/一致性决策基线.md @@ -0,0 +1,123 @@ +# 污水厂智能控制平台 — 一致性决策基线 + +> 本文件是 `spec-数据管理.md`、`spec-历史数据.md` 和 `code-standards.md` 的跨文档最高优先级契约。出现歧义时,先按本文件执行,再修订对应文档。 + +## 1. 文档优先级与变更规则 + +1. 本文件中的“已采纳”决策优先于其他文档中的旧表述。 +2. 任何 API、数据库或运行架构变更,必须同步修改三份关联文档和自动化契约测试。 +3. 文档示例必须是合法 JSON、SQL、Go 或 TypeScript,不得在 JSON 代码块中写注释。 +4. API 冻结后,破坏性变更必须升级 API 版本或提供兼容迁移期。 + +## 2. 已采纳决策 + +### ADR-001|运行模型与模块边界 + +- 生产环境使用单进程嵌入式模型:`cmd/server/main.go` 同时启动 Web API 和采集引擎。 +- 模块间通过公开的 Service/领域接口通信,不通过本应用自身的 HTTP,也不得直接访问其他模块的 Repository、ORM 模型或数据库表。 +- Handler 只负责参数绑定和响应转换;运行时状态、元数据聚合和权限判断均由 Service 完成。 + +### ADR-002|协议驱动与设备连接 + +- 协议注册表保存无状态 `ProtocolDriverFactory`,不保存有连接状态的驱动单例。 +- 每个设备由工厂创建独立 `ProtocolConnection`;采集和写入共享该设备连接。 +- 同一设备连接默认串行执行协议读写,除非驱动明确声明并通过并发测试证明支持并发。 +- 采集调度采用有界 worker pool;“每点位一个任务”不等于“每点位一个 goroutine”。 + +### ADR-003|UUID 与 TDengine 子表 + +- API、PostgreSQL、TDengine 普通字段和 TAG 中统一使用带连字符的 36 位标准 UUID。 +- TDengine 子表名唯一格式为 `p_`,正则为 `^p_[0-9a-f]{32}$`。 +- 请求不得传入表名;表名只能由服务端对已验证 UUID 规范化后派生。 + +### ADR-004|动态 SQL 标识符 + +- 用户值必须参数化。 +- 动态表名属于受控标识符例外:必须由服务端派生、通过固定正则白名单,并使用驱动提供的标识符引用能力;禁止直接拼接任何用户字符串。 + +### ADR-005|历史点位生命周期 + +- 历史模块默认展示活跃点位和仍有历史数据的归档点位。 +- 活跃点位:点位和设备均未删除、均启用,且 `store_history=true`。 +- 归档点位:点位或设备已禁用/逻辑删除,或当前 `store_history=false`,但 TDengine 中仍存在历史数据。 +- 归档点位只读、可查询、不可继续采集。 + +### ADR-006|历史元数据与配置变更 + +- `collection_points` 增加 `unit`、`valid_min`、`valid_max`、`history_started_at`。 +- 首次准备写入历史数据前设置 `history_started_at`;一旦非空,禁止修改 `device_id` 和 `data_type`。需要改变时必须新建点位。 +- 点位名称、设备名称、分组和单位可以修改;历史 API 使用 PostgreSQL 当前元数据展示。 +- TDengine 中的 `point_name`、`device_name` 和 `data_type` 是写入时快照,不是当前配置的权威来源。 + +### ADR-007|质量和空值模型 + +- API 质量枚举:`good | bad | none`。 +- TDengine 只存储 `good=0`、`bad=1`;`none` 表示查询无匹配记录,不落库。 +- `value` 允许为 `null`:读取失败、断线或解析失败时写入 `quality=bad`、`value=null`。 +- 读取成功但超出配置有效范围时写入 `quality=bad` 且保留数值。 +- TDengine 和 API 增加可空 `quality_reason`,使用稳定代码,例如 `timeout`、`disconnected`、`parse_error`、`out_of_range`。 +- 表格无匹配记录统一返回 `{value:null, quality:"none", quality_reason:null, matched_ts:null}`,不得返回整个元素为 `null`。 + +### ADR-008|历史查询边界与降采样 + +- 所有历史查询要求 `end_time > start_time`,最大跨度 31 天。 +- 曲线查询最多 20 个点位;`max_samples` 默认 2000,范围 100~10000。 +- 原始记录超过上限时,服务端执行自适应 min-max 降采样,保留首尾、极值、质量变化和 gap 边界。 +- 响应返回 `sampled`、`raw_count` 和 `sample_count`。 + +### ADR-009|表格最近邻匹配 + +- 匹配窗口为 `interval_minutes / 2` 的精确时长,不进行整分钟向上取整。 +- 原始查询范围扩展为 `[start_time-window, end_time+window]`。 +- 目标时间为 `start_time + n*interval` 且不晚于 `end_time`;不强制追加未对齐的 `end_time`。 +- 距离相同时选择较早的原始时间戳,避免使用未来值优先。 +- 每个目标时间独立匹配;同一原始记录允许匹配相邻目标时间,并通过 `matched_ts` 明示。 + +### ADR-010|API 响应和文件流 + +- JSON API 使用 `{code,message,data}` 包装。 +- CSV、其他文件、SSE 和 WebSocket 是明确例外:成功响应直接返回对应流;失败响应仍返回统一 JSON 错误。 +- 同步设备写入只有写入和回读均成功时返回 HTTP 200、`code=0`。 + +### ADR-011|HTTP 状态与业务错误码 + +- HTTP 状态表达错误类别;业务 `code` 表达模块内具体原因,不从数字前缀推断 HTTP 类别。 +- 模块范围:通用/鉴权 `10001~10999`、设备 `40001~40999`、采集点 `41001~41999`、写入点 `42001~42999`、历史 `43001~43999`、采集引擎 `50001~50999`、写入引擎 `51001~51999`。 + +### ADR-012|CSV 分类和文件名 + +- 配置导入导出 CSV 使用固定 `snake_case` 标题,可再次导入。 +- 用户报表 CSV 允许本地化和动态列名;重复点位名称追加 UUID 前 8 位。 +- 文件名由服务端对已解析参数重新格式化,只允许 ASCII 字母、数字、下划线、短横线和点。 + +### ADR-013|写入值和回读 + +- 写入日志数据库可用 TEXT 保存原始值,但 API 必须按 `data_type` 返回 JSON boolean/number。 +- `write_points` 增加 `readback_tolerance`;BOOL/INT 严格相等,REAL 使用绝对误差 `abs(actual-target) <= readback_tolerance`。 +- 当前阶段仅支持内部网络中的未认证人工写入,服务端固定记录 `source=manual`、`operator=null`。 + +### ADR-014|配置生效时限 + +- Service 在事务提交后发布进程内配置变更事件,正常情况下 1 秒内生效。 +- 采集引擎每 5 秒执行一次全量版本校对作为丢事件后的兜底;因此对外 SLA 为 5 秒内最终生效。 + +### ADR-015|历史图表职责 + +- 历史 API 只返回原始值和元数据。 +- 分段自适应 Y 轴由前端图表组件实现,必须标明非线性/断轴效果;不得把映射后的显示坐标冒充原始值。 + +### ADR-016|环境配置 + +- PostgreSQL 和 TDengine 的主机、端口、用户名、密码和数据库名均通过环境变量配置。 +- TDengine 数据库名使用 `TDENGINE_DATABASE`,默认值可为 `aquacontrolai`,代码和迁移不得写死生产值。 + +## 3. 当前文档版本 + +| 文档 | 版本 | +|---|---| +| `spec-数据管理.md` | v1.2 | +| `spec-历史数据.md` | v1.1 | +| `code-standards.md` | v1.2 | +| 本基线 | v1.0 | + +> 最后更新:2026-07-11