# G5 Database Sync and Room Status Aggregation Logic

## openspec-proposal
- **生态包推荐与选型**：本次需求纯粹为数据库多环境异步双写及聚合同步架构升级。我们保持着**不重复造轮子**的极简最佳实践，未引入新的冗余 npm 依赖。坚持复用项目中现有的优秀驱动包 `pg`（node-postgres）作为核心驱动来应对大量行级的高并发插入与聚合。
- **降级与扩展策略**：对现有的 `BatchProcessor` 和 `StatusBatchProcessor` 进行原生构造拆解重写，拓展 `options`（如 `omitGuid`, `dedupeByRoom` 等变量配置），以最小侵入业务的方式分离实例对象，挂载 G5 双写。

## openspec-apply

针对 `Node.js` (V8) 和异步并发模型，完成生成和执行如下实施与扩展细则：

### 1. 异步非阻塞的 Dual-Write 设计方案
- **Event Loop 友好型并行**：在执行向 G4 和 G5 环境多库分发数据时，彻底摒弃 `await g4_write; await g5_write` 的顺序堵塞请求堆栈。采用纯异步的 `Promise.all([dbActions])` 把宏任务交由事件循环底层的 I/O 线程池并行发送所有的 `INSERT 事务报文`，将两座异地数据库的返回时延并集。
- **配置隔离熔断法**：依托 `.env` 实现对每一向数据库独立挂载的生命周期（如动态通过 `ENABLE_G4_SYNC` 或 `ENABLE_G5_SYNC` 处理）。任一数据库挂掉带来的错误 `PROMISE_REJECTED` 在进程捕获后只会独立封停，不会引发系统阻塞或导致另一健康的数据库断供。

### 2. G5 字段 `omitGuid` 的剥离控制与瘦身落地
- G5 中 `rcu_action_events_g5` 表里的 `guid` 基于 `int4` `nextval`。这与原本生成的 `uuid` 类型存在截然冲突。
- **具体落地**：当连接器池检测到 `omitGuid = true`（G5 模式打开），底层的 SQL `INSERT INTO (${columns})` 将会动态清洗掉 `guid` 和所绑定的 `$n` 占位符。把主键控制权彻底返还给 PostgreSQL 内部机制，Node 层专注传输，达到结构和时效的最简合并。

### 3. Room Status: 房间聚合锁与 Upsert (ON CONFLICT DO UPDATE) 
- **去重逻辑优化与 `dedupeByRoom`**：针对 `room_status_moment_g5` 中限定 `(hotel_id, room_id)` 是唯一的联合主键特质，如果仍然通过旧结构缓存，会产生频繁覆盖导致的 JSON 散件丢失。本次通过 Node 层注入 `dedupeByRoom` 拦截校验法：缓冲器使用 `${hotel_id}:${room_id}` 的更底层维度合并哈希。同一房间内设备的任何 JSONB 数组比如 `dev_loops` 都先进行底层 `||` 合并及时间对比去重，然后一次性下发大包。
- **SQL 更新映射**：由于 `device_id` 不再具有唯一性维度，我们执行基于 PostgreSQL 的合并操作：在冲突 `EXCLUDED` 对象中强制替换最新上报设备 `$device_id = EXCLUDED.device_id`。并且彻底抽去了 Node 更新时间戳的过程，让权给表上的 `AFTER/BEFORE UPDATE` 原生触发器处理 `ts_ms`。符合强数据库型开发的完美最佳实践。

### 4. 废弃冗余数据占用 (`udp_raw` & `details`)
由于上游报文及 JSON 持久化逻辑逐步升级，对于 G4 以及后续加入的 G5 库，在映射中全量废除了直接对 `udp_raw` 回追文本和对 `details` JSONB 的业务数据的多余存储。
- **具体拦截处理**：我们在 `processor/index.js` `commonFields` 中将 `udp_raw` 强赋值为 `null`；同理对于所有的 `payload` 解析结果，`details` 也改为了强置空（`null`）。相应的单元测试套件已被更新修改以校验拦截有效性。
- **目的**：通过这两项高频臃肿字典的精减裁剪，可极大缩小单行落盘宽表的体积，减轻 PostgreSQL 序列化负担及提升 UPSERT 时延，而数据库中的字段保留以用于结构向后兼容。
