refactor(openspec): 归档心跳数据库v2更新相关文档

将update-heartbeat-db-v2目录下的文档迁移至archive目录
更新specs目录下的相关规范文件以反映最新变更
This commit is contained in:
2026-01-14 19:38:02 +08:00
parent eb35635253
commit 7d5b9c50ea
9 changed files with 89 additions and 45 deletions

View File

@@ -0,0 +1,20 @@
# Change: 升级心跳数据库为高吞吐日分区模型v2
## Why
现有实现仅包含简化的 `heartbeat`component/status/timestamp无法满足“每分钟约 5 万条记录、按酒店/时间范围检索、按状态聚合”的高吞吐与长期存储需求。
## What Changes
- **DB**:在既有数据库(默认 `log_platform`)内新增/升级为按 `ts_ms`(毫秒 epoch日分区的心跳明细表并提供分区预创建机制
- **DB**补齐指定索引hotel_id/power_state/guest_type/device_id B-treeservice_mask BRIN与约束NOT NULL、CHECK、IP 格式)
- **Docs**:补充 Kafka 生产者推送数据结构与推送方式说明
## Impact
- Affected specs: `openspec/specs/db`, `openspec/specs/kafka`, `openspec/specs/processor`
- Affected code: 未来 `src/db/databaseManager.js` 的表初始化/写入字段将需要适配(本变更提案先聚焦 DB 结构与脚本)
## Key Decisions / Risks (需要明确)
- **分区 + 主键冲突风险**PostgreSQL 分区表的全局唯一/主键通常需要包含分区键;需求写“主键仅 id(bigserial)”。
- 本次脚本将采用 `PRIMARY KEY (ts_ms, id)` 来保证可创建与可执行。
- **device_id 类型待确认**:脚本暂定为 `varchar(64)`(兼容序列号/MAC/混合编码);若确定为纯数字,可改为 `bigint` 获得更紧凑索引。
- **中文排序规则**:不新建库时无法修改数据库级 collation若需要中文排序建议使用 ICU collation列级/表达式级)。
- **自动建分区方式**PostgreSQL 在单条 INSERT 执行过程中动态 `CREATE PARTITION` 会触发“对象正在使用”限制;因此采用“预创建分区(安装/定时任务/启动时调用)”。

View File

@@ -0,0 +1,26 @@
## MODIFIED Requirements
### Requirement: 数据库表结构管理
系统 MUST 提供数据库表结构的定义和管理机制。
#### Scenario: 表结构初始化(高吞吐分区表)
- **WHEN** 系统首次启动或部署数据库时
- **THEN** 应该存在按 `ts_ms` 日分区的心跳明细表
- **AND** 必填字段应具备 NOT NULL 约束
- **AND** 状态类字段应具备 CHECK 约束(限制取值范围)
- **AND** 必需索引应存在hotel_id/power_state/guest_type/device_id B-treeservice_mask BRIN
#### Scenario: 自动分区
- **WHEN** 写入某天数据而该日分区不存在
- **THEN** 系统应能够自动创建对应日分区或确保分区被预创建
- **AND** 不应影响持续写入(高吞吐场景)
## ADDED Requirements
### Requirement: 高吞吐写入友好
系统 MUST 在高吞吐场景(约 5 万条/分钟量级)下避免单点瓶颈。
#### Scenario: 批量写入与分区裁剪
- **WHEN** 进行批量写入
- **THEN** 写入应路由到正确日分区
- **AND** 常见查询hotel_id + 时间范围)应触发分区裁剪

View File

@@ -0,0 +1,22 @@
## ADDED Requirements
### Requirement: 心跳消息载荷格式(生产者约束)
Kafka 心跳消息 MUST 包含数据库落库所需的必填字段,并采用 UTF-8 编码。
#### Scenario: JSON 心跳消息
- **WHEN** 生产者向主题推送心跳消息
- **THEN** 消息 value 应为 JSONUTF-8
- **AND** 至少包含 ts_ms、hotel_id、room_id、device_id、ip、power_state、guest_type、cardless_state、service_mask、pms_state、carbon_state、device_count、comm_seq
- **AND** 可选包含 extrajson object
### Requirement: 分区键友好的 Kafka Key
系统 MUST 支持使用 `hotel_id:device_id` 作为 Kafka message key 以获得更好的分区与有序性。
#### Scenario: 缺失 key 仍可处理
- **WHEN** 消息未携带 key
- **THEN** 系统仍应能够消费与处理该消息
#### Scenario: 使用 device_id 作为 key
- **WHEN** 生产者发送消息
- **THEN** 建议使用 `hotel_id:device_id` 作为 Kafka message key
- **AND** 以提升同设备有序性与消费侧批量聚合效率

View File

@@ -0,0 +1,39 @@
## MODIFIED Requirements
### Requirement: 心跳数据解包
系统 MUST 能够将 Kafka 消息 value 解码/解压并还原为 JSON 对象或数组,支持两层以内的编码/压缩组合。
#### Scenario: 支持常见编码/压缩(两层以内)
- **WHEN** Kafka 消息 value 为下列任意形式时:
- UTF-8 JSON对象或数组
- base64(二进制)
- gzip / deflate(zlib) / deflate(raw) / brotli 压缩后的二进制
- **THEN** 系统应当按“最多两层”的策略尝试解码/解压
- **AND** 成功时应还原为 JSON 对象或数组
- **AND** 失败时应记录错误并丢弃该消息
#### Scenario: 支持包装结构
- **WHEN** 解包得到的 JSON 为包装结构(例如包含 `data`/`payload`/`body` 字段)
- **THEN** 系统应优先提取其中的对象作为心跳数据源
#### Scenario: 解包有效心跳数据
- **WHEN** 接收到有效格式的Kafka心跳消息时
- **THEN** 系统应该成功解包消息
- **AND** 提取出心跳数据的各个字段
#### Scenario: 解包无效心跳数据
- **WHEN** 接收到无效格式的Kafka心跳消息时
- **THEN** 系统应该返回解包错误
- **AND** 记录错误日志
### Requirement: 心跳数据转换
系统 MUST 能够将解包后的心跳数据转换为数据库存储格式。
#### Scenario: 转换为 v2 明细表字段
- **WHEN** 心跳数据验证通过时
- **THEN** 系统应输出与 v2 明细表字段一致的数据结构
- **AND** 添加必要的元数据
#### Scenario: 缺失必填字段
- **WHEN** 心跳数据缺失必填字段时
- **THEN** 系统应判定为无效数据并丢弃

View File

@@ -0,0 +1,11 @@
## 1. Implementation
- [x] 提供 PostgreSQL 建库脚本UTF-8 + 中文排序规则可选)
- [x] 提供心跳明细表结构(必填字段、可选字段、约束、索引)
- [x] 实现按 `ts_ms` 日分区与自动建分区机制
- [x] 补充性能建议(索引策略、分区影响、聚合/物化视图建议)
- [x] 产出 docsDB 表结构文档 + Kafka 生产者推送数据结构与方式
- [x] Processor实现 Kafka 心跳 value 的两层解码/解压与反序列化(需要对端样本/算法确认)
## 2. Validation
- [x] 在可访问的 PostgreSQL 环境执行脚本并验证对象创建成功
- [x] 检查约束与索引是否符合要求