# 消息推送后台 —— 核心数据库表结构需求文档

> **创建日期**：2026年03月16日
> **模块归属**：商城发货与物流推送后台
> **涉及架构**：Node.js Worker + Supabase (PostgreSQL) + UniPush 2.0

为支撑高可用、防丢失、可追溯的异步消息推送架构，本消息推送系统在底层（Supabase/PostgreSQL）摒弃了传统的 Redis 中间件依赖，直接利用关系型数据库的横表与触发器机制（Transactional Outbox 事务外箱模式）完成了高并发状态下的物流事件缓冲与分发。

本需求文档详细列出了参与推送闭环的 **5 张核心数据表** 的设计规范、字段说明与职责定位，是后端/DBA 开发与日常客诉运维排障的唯一真理依据。

---

## 整体库表流转全景
消息在数据库中的物理游走路径为：
**`平台接收原生钩子`** $\rightarrow$ **`轨迹业务表入库`** $\rightarrow$ (触发器) $\rightarrow$ **`任务队列缓冲表`** $\rightarrow$ (合并订单/用户数据) $\rightarrow$ **`最终下发通知表`** $\rightarrow$ **`匹配设备表CID推送`**

---

## 一、 原始通信日志表 (`platform_express_event_raw`)

### 1. 表职责方向
保存第一手的物流商（如快递100）Webhook 推送过来的原生 JSON 报文。不做任何业务过滤。
- **核心价值**：排查“某单是不是底下的快递公司就没给我们发回调？”的第一现场。如果这里没有记录，绝不可能是本系统的 Bug。

### 2. 核心字段设计 (逻辑概述)
* `id` (UUID): 唯一自增主键。
* `raw_payload` (JSONB): 快递100推过来的纯原生报文。
* `created_at` (Timestamp): 平台接收到外网请求的确切服务器时间。

---

## 二、 规范化轨迹主表 (`platform_express_tracking_events` / `waybills`)

### 1. 表职责方向
用于商城订单域查询使用的结构化物流跟踪事件表。接收服务将 `event_raw` 里的 JSON 解包后，转化为本商城统一的枚举状态。
- **机制特点**：这张表在发生 `INSERT` (即产生新轨迹节点) 时，会触发 PostgreSQL 内置触发器 `event_to_queue_trigger`。

### 2. 核心字段要求
* `waybill_id` (UUID): 关联的运单主键。
* `status_code` (VARCHAR): 规范化的签收/派件枚举状态码。
* `event_text` (TEXT): 具体的物流节点描述文本（例：“北京市【朝阳区】，您的快递已由门卫代签收”）。

---

## 三、 异步缓冲队列表 (`notify_queue`)

### 1. 表职责方向
承接业务量暴增时的**削峰填谷**与**断电防丢**任务（本质是实现基于 DB 的 Message Queue）。
- **流程规范**：触发器把满足条件（如需要给用户弹推送的节点）的事件主键，极速插入本表待命。后台的 `notify-worker.js` (消费者) 轮询查表消费。

### 2. 核心字段定义
* `id` (UUID): 队列任务唯一标识。
* `waybill_id` (UUID): 运单号，Worker 读取后利用它去关联查询出订单里的 `user_id` 和商品信息。
* `status_code` (VARCHAR): 通知级别状态。
* **`dedupe_key` (VARCHAR)**: 防重幂等键。防止因为相同事件重复回调产生两条推送。
* **`process_status` (VARCHAR)**: 最核心的状态机！
  * `pending`: 等待 Node.js Worker 消费。
  * `processing`: Worker 消费中（乐观锁占用）。
  * `processed`: 拼接业务数据完成，已成功放入推送大表，完美结束。
  * `failed`: 服务异常或订单找不到，抛弃处理。
* `last_error` (TEXT): 消费报错时的堆栈。

---

## 四、 最终下发通知表 (`express_notifications`)

### 1. 表职责方向
面向客户端推送与“站内信展示”的实体记录表。这里存放的是已经完成业务数据组装（谁买的、买的啥、什么物流状态），只需调用第三方厂商接口往外发的纯粹“信件”内容。
- **流程规范**：`push-server.js` 轮询此表进行真实推送。

### 2. 核心字段定义
* `id` (UUID): 消息的主键ID。
* `recipient_id` (UUID): 接收用户的标识 (商城买家ID)。
* `event_text_safe` (TEXT): 已经组装好且脱敏的安全话术（例如：“[张*]，您的Nike球鞋正在派送中”）。
* **`send_status / push_status` (VARCHAR)**: 推送服务通道状态机。
  * `pending`: 已产生信件，排队等待网络 POST 请发给 UniPush 云函数。
  * `delivered`: 云函数返回 200，且厂家确认通道收录。
  * `failed`: 网络异常或设备CID已注销失效。
* `provider_response` (JSONB): 如果推送失败，此处会存储华为/小米等厂商或推服务产生的物理失败原因。

---

## 五、 设备凭证绑定表 (`push_devices`)

### 1. 表职责方向
提供从“商城系统 `user_id`” 到“手机厂家原生通道标识 `cid`” 的 KV 路由映射能力。
- **业务场景**：用户 App 在启动或大版本更新时，前端会通过 `uni.getPushClientId` 获取本设备的厂商识别码，通过接口上报并 UPSERT 写入此表。

### 2. 核心字段定义
* `id` (UUID): 映射记录主键。
* `user_id` (UUID): 系统业务逻辑里的用户身份标识。
* **`cid` (VARCHAR)**: UniPush 2.0 分配在设备当前生命周期的绝对推送识别码（至关重要，一旦清空缓存/重装系统可能会变动，必须持续覆盖更新）。
* `updated_at` (Timestamp): 用以判断该设备CID的活跃新鲜度。如果一个CID超过1年未更新导致 `push_status` 频繁 `failed`，后台可将其标记为离线沉默用户放弃网络调用。

---

## 附：业务表拓展准则 (Guidelines)
如果未来需要将这套机制从物流推送拓展至**“拼团成功通知”**或**“特价秒杀通知”**，只需要：
1. 复用 `express_notifications` 表，或者建立同层级类似的 `system_notifications` 表，保留 `push_status` 和 `recipient_id`。
2. 复用 `push_devices` 路由查找。
3. 把源头触发器挂载到新的交易表中即可。此五表闭环具备极佳的**水平扩展性**与**极低的中间件运维成本**。