7.1 KiB
7.1 KiB
污水厂智能控制平台 — 一致性决策基线
本文件是
spec-数据管理.md、spec-历史数据.md和code-standards.md的跨文档最高优先级契约。出现歧义时,先按本文件执行,再修订对应文档。
1. 文档优先级与变更规则
- 本文件中的“已采纳”决策优先于其他文档中的旧表述。
- 任何 API、数据库或运行架构变更,必须同步修改三份关联文档和自动化契约测试。
- 文档示例必须是合法 JSON、SQL、Go 或 TypeScript,不得在 JSON 代码块中写注释。
- 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_<uuid32>,正则为^p_[0-9a-f]{32}$。 - 请求不得传入表名;表名只能由服务端对已验证 UUID 规范化后派生。
ADR-004|动态 SQL 标识符
- 用户值必须参数化。
- 动态表名属于受控标识符例外:必须由服务端派生、通过固定正则白名单,并使用驱动提供的标识符引用能力;禁止直接拼接任何用户字符串。
ADR-005|历史点位生命周期
- 历史模块默认展示活跃点位和仍有历史数据的归档点位。
- 活跃点位:点位和设备均未删除、均启用,且
store_history=true。 - 归档点位:点位或设备已禁用/逻辑删除,或当前
store_history=false,但 TDengine 中仍存在历史数据。 - 归档点位只读、可查询、不可继续采集。
ADR-006|历史元数据与配置变更
collection_points保留unit、history_started_at;valid_min、valid_max已移除。- 首次准备写入历史数据前设置
history_started_at。当前实现允许后续修改device_id和data_type;历史展示以 PostgreSQL 当前元数据为准,TDengine 旧行保留写入时快照。 - 点位名称、设备名称、分组和单位可以修改;历史 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。- 采集质量不再执行有效范围判断;协议读取和解析成功即为
good。 - TDengine 和 API 增加可空
quality_reason,使用稳定代码,例如timeout、disconnected、parse_error、read_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 边界。
- 响应返回
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仅保留write_enabled写入权限开关;enabled和readback_tolerance已移除。- BOOL/INT 回读严格相等;REAL 使用固定协议精度
abs(actual-target) <= 0.0001。 - 当前阶段仅支持内部网络中的未认证人工写入,服务端固定记录
source=manual、operator=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