Files
AquaControlAI/开发文档/一致性决策基线.md
T
2026-07-13 14:31:49 +08:00

7.1 KiB
Raw Blame History

污水厂智能控制平台 — 一致性决策基线

本文件是 spec-数据管理.mdspec-历史数据.mdcode-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-003UUID 与 TDengine 子表

  • API、PostgreSQL、TDengine 普通字段和 TAG 中统一使用带连字符的 36 位标准 UUID。
  • TDengine 子表名唯一格式为 p_<uuid32>,正则为 ^p_[0-9a-f]{32}$
  • 请求不得传入表名;表名只能由服务端对已验证 UUID 规范化后派生。

ADR-004|动态 SQL 标识符

  • 用户值必须参数化。
  • 动态表名属于受控标识符例外:必须由服务端派生、通过固定正则白名单,并使用驱动提供的标识符引用能力;禁止直接拼接任何用户字符串。

ADR-005|历史点位生命周期

  • 历史模块默认展示活跃点位和仍有历史数据的归档点位。
  • 活跃点位:点位和设备均未删除、均启用,且 store_history=true
  • 归档点位:点位或设备已禁用/逻辑删除,或当前 store_history=false,但 TDengine 中仍存在历史数据。
  • 归档点位只读、可查询、不可继续采集。

ADR-006|历史元数据与配置变更

  • collection_points 保留 unithistory_started_atvalid_minvalid_max 已移除。
  • 首次准备写入历史数据前设置 history_started_at。当前实现允许后续修改 device_iddata_type;历史展示以 PostgreSQL 当前元数据为准,TDengine 旧行保留写入时快照。
  • 点位名称、设备名称、分组和单位可以修改;历史 API 使用 PostgreSQL 当前元数据展示。
  • TDengine 中的 point_namedevice_namedata_type 是写入时快照,不是当前配置的权威来源。

ADR-007|质量和空值模型

  • API 质量枚举:good | bad | none
  • TDengine 只存储 good=0bad=1none 表示查询无匹配记录,不落库。
  • value 允许为 null:读取失败、断线或解析失败时写入 quality=badvalue=null
  • 采集质量不再执行有效范围判断;协议读取和解析成功即为 good
  • TDengine 和 API 增加可空 quality_reason,使用稳定代码,例如 timeoutdisconnectedparse_errorread_error
  • 表格无匹配记录统一返回 {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 边界。
  • 响应返回 sampledraw_countsample_count

ADR-009|表格最近邻匹配

  • 匹配窗口为 interval_minutes / 2 的精确时长,不进行整分钟向上取整。
  • 原始查询范围扩展为 [start_time-window, end_time+window]
  • 目标时间为 start_time + n*interval 且不晚于 end_time;不强制追加未对齐的 end_time
  • 距离相同时选择较早的原始时间戳,避免使用未来值优先。
  • 每个目标时间独立匹配;同一原始记录允许匹配相邻目标时间,并通过 matched_ts 明示。

ADR-010API 响应和文件流

  • JSON API 使用 {code,message,data} 包装。
  • CSV、其他文件、SSE 和 WebSocket 是明确例外:成功响应直接返回对应流;失败响应仍返回统一 JSON 错误。
  • 同步设备写入只有写入和回读均成功时返回 HTTP 200、code=0

ADR-011HTTP 状态与业务错误码

  • HTTP 状态表达错误类别;业务 code 表达模块内具体原因,不从数字前缀推断 HTTP 类别。
  • 模块范围:通用/鉴权 10001~10999、设备 40001~40999、采集点 41001~41999、写入点 42001~42999、历史 43001~43999、采集引擎 50001~50999、写入引擎 51001~51999

ADR-012CSV 分类和文件名

  • 配置导入导出 CSV 使用固定 snake_case 标题,可再次导入。
  • 用户报表 CSV 允许本地化和动态列名;重复点位名称追加 UUID 前 8 位。
  • 文件名由服务端对已解析参数重新格式化,只允许 ASCII 字母、数字、下划线、短横线和点。

ADR-013|写入值和回读

  • 写入日志数据库可用 TEXT 保存原始值,但 API 必须按 data_type 返回 JSON boolean/number。
  • write_points 仅保留 write_enabled 写入权限开关;enabledreadback_tolerance 已移除。
  • BOOL/INT 回读严格相等;REAL 使用固定协议精度 abs(actual-target) <= 0.0001
  • 当前阶段仅支持内部网络中的未认证人工写入,服务端固定记录 source=manualoperator=null

ADR-014|配置生效时限

  • 当前实现不使用独立配置事件总线。
  • 采集调度器每秒重新读取活动采集点,点位配置通常在下一个调度周期生效。
  • 设备配置保存成功后立即使旧连接失效,下一次采集或写入按新配置重新建连。

ADR-015|历史图表职责

  • 历史 API 只返回原始值和元数据。
  • 分段自适应 Y 轴由前端图表组件实现,必须标明非线性/断轴效果;不得把映射后的显示坐标冒充原始值。

ADR-016|环境配置

  • PostgreSQL 和 TDengine 的主机、端口、用户名、密码和数据库名均通过环境变量配置。
  • TDengine 数据库名使用 TDENGINE_DATABASE,默认值可为 aquacontrolai,代码和迁移不得写死生产值。

3. 当前文档版本

文档 版本
spec-数据管理.md v1.3
spec-历史数据.md v1.2
code-standards.md v1.2
本基线 v1.1

最后更新:2026-07-13