# 生产表说明:platform_express_*(第三方快递轨迹平台侧) 本文档对应生产迁移脚本:`pages/mall/delivery/doc/需求文档/express_tracking_platform_upgrade.sql`。 ## 1. 设计目标与边界 - 目标:为第三方承运(韵达/圆通/中通等)提供统一的“运单 + 轨迹事件 + 原始回调留痕”入库模型,支撑用户端/商家端/平台后台同源展示。 - 边界: - 仅覆盖第三方快递轨迹,不包含自营骑手/配送任务(`ml_delivery_*`)。 - 生产仅使用 `platform_express_*` 三表;不包含任何 `mock_*` 测试表。 ## 2. 表关系概览 - `platform_express_waybills`(运单主表) - 1 条运单对应 N 条轨迹事件(`platform_express_tracking_events`)。 - `platform_express_tracking_events`(轨迹事件事实表) - 时间线展示、状态判断、告警统计的主来源。 - 对同一运单使用 `(waybill_id, dedupe_key)` 做幂等去重。 - `platform_express_event_raw`(原始接收留痕表) - 记录每一次 webhook/轮询/人工补录的原始请求/响应内容与验签结果、解析错误,用于审计与排障。 ## 3. 字段说明 ### 3.1 `public.platform_express_waybills`(运单主表) 用途: - 以 `(carrier, tracking_no)` 为唯一键管理“运单实体”,可选关联订单;承载“当前状态/预计到达/最近同步时间”等运单级摘要信息。 约束/触发器/索引: - 唯一约束:`uk_platform_express_waybill (carrier, tracking_no)` - 外键:`order_id -> public.ml_orders(id)`,`ON DELETE SET NULL` - `updated_at` 触发器:`trigger_platform_express_waybills_updated_at`(UPDATE 时自动刷新) - 常用索引: - `idx_platform_express_waybills_order_id (order_id)` - `idx_platform_express_waybills_order_no (order_no)` - `idx_platform_express_waybills_tracking_no (tracking_no)` - `idx_platform_express_waybills_status (current_status_code)` 字段表: | 字段 | 类型 | 可空 | 默认/约束 | 含义 | |---|---|---:|---|---| | id | UUID | 否 | PK,`uuid_generate_v4()` | 运单主键 | | order_id | UUID | 是 | FK -> `ml_orders(id)`,删除置空 | 关联订单主键(推荐) | | order_no | VARCHAR(64) | 是 | | 订单号(展示/兜底,用于无法拿到 `order_id` 的场景) | | carrier | VARCHAR(32) | 否 | 参与唯一约束 | 承运方编码(如 `YUNDA`/`YTO`/`ZTO` 等;也可接入聚合方编码) | | tracking_no | VARCHAR(64) | 否 | 参与唯一约束 | 运单号/快递单号 | | source | VARCHAR(16) | 否 | 默认 `'mock'` | 运单数据来源:`mock`/`carrier`/`aggregator` 等 | | current_status_code | VARCHAR(32) | 否 | 默认 `'SHIPPED'` | 运单当前平台状态(用于列表页/摘要),通常由最新事件映射得到 | | current_status_text | TEXT | 是 | | 运单当前状态文本(可为最新事件文本的“清洗版”或平台自定义) | | eta | TIMESTAMPTZ | 是 | | 预计送达时间(可选;来自承运方/聚合方或平台预测) | | last_synced_at | TIMESTAMPTZ | 是 | | 最近一次与承运方/聚合方同步时间(用于健康度与补偿轮询判断) | | created_at | TIMESTAMPTZ | 否 | 默认 `NOW()` | 创建时间 | | updated_at | TIMESTAMPTZ | 否 | 默认 `NOW()`;触发器维护 | 更新时间(UPDATE 自动刷新) | ### 3.2 `public.platform_express_tracking_events`(轨迹事件表) 用途: - 存储每一个轨迹节点(揽收/到站/运输中/派送/签收/异常等),作为时间线展示与状态机判断的事实来源。 - 保留第三方原文(`event_code`/`event_text`/`raw_payload`),同时写入平台统一状态(`status_code`)。 - 通过 `dedupe_key` 实现幂等:重复回调/轮询不会重复插入。 约束/索引: - 外键:`waybill_id -> platform_express_waybills(id)`,`ON DELETE CASCADE` - 唯一约束:`uk_platform_express_event_dedupe (waybill_id, dedupe_key)` - 常用索引: - `idx_platform_express_events_waybill_time (waybill_id, event_time)`(按运单查时间线) - `idx_platform_express_events_tracking_time (tracking_no, event_time)`(按运单号查) - `idx_platform_express_events_status (status_code)`(按状态统计/筛选) - `idx_platform_express_events_received_at (received_at)`(按接收时间排障) - `gin_platform_express_events_raw_payload`(`raw_payload` JSONB GIN,便于排障检索) 字段表: | 字段 | 类型 | 可空 | 默认/约束 | 含义 | |---|---|---:|---|---| | id | UUID | 否 | PK,`uuid_generate_v4()` | 事件主键 | | waybill_id | UUID | 否 | FK,级联删除 | 所属运单 | | carrier | VARCHAR(32) | 否 | | 承运方编码(冗余字段,便于查询/对账) | | tracking_no | VARCHAR(64) | 否 | | 运单号(冗余字段,便于查询/对账) | | event_id | VARCHAR(128) | 是 | | 第三方事件唯一 ID(有些承运方会提供;优先用于幂等) | | event_time | TIMESTAMPTZ | 否 | | 事件发生时间(时间线排序的主依据) | | event_code | VARCHAR(64) | 否 | | 第三方事件码/节点码(保留原值) | | event_text | TEXT | 否 | | 第三方事件文本(保留原值;展示前可做脱敏/清洗) | | status_code | VARCHAR(32) | 否 | | 平台统一状态码(由 `event_code/event_text` 规则映射得出) | | node_name | VARCHAR(128) | 是 | | 节点/网点名称(如“xx转运中心”) | | location | TEXT | 是 | | 地理位置文本(如省市区/网点地址;不建议存精确经纬度,除非明确需求) | | description | TEXT | 是 | | 平台补充说明(如“疑似退回件,已通知商家”) | | evidence_urls | JSONB | 否 | 默认 `[]` | 证据/附件 URL 列表(签收图、面单、异常凭证等) | | raw_payload | JSONB | 是 | | 第三方原始事件载荷(用于审计/排障;注意权限控制) | | received_at | TIMESTAMPTZ | 否 | 默认 `NOW()` | 平台接收时间(用于排查延迟/乱序) | | source | VARCHAR(16) | 否 | 默认 `'webhook'` | 数据进入平台的方式:`webhook`/`poll`/`manual` | | dedupe_key | VARCHAR(256) | 否 | 参与唯一约束 | 幂等去重键(建议:有 `event_id` 用 `event_id`;否则构造 `tracking_no|event_code|event_time` 并按需要拼接 `node/location`) | | created_at | TIMESTAMPTZ | 否 | 默认 `NOW()` | 入库时间 | 幂等与乱序建议: - 幂等:插入事件时以 `(waybill_id, dedupe_key)` 唯一约束兜底;遇到冲突可 `ON CONFLICT DO NOTHING`。 - 乱序:允许旧事件晚到入库;前端展示按 `event_time` 排序。 - 运单摘要(`platform_express_waybills.current_status_*`)建议由“最新事件(按 event_time)映射结果”更新,避免用 `received_at` 作为最新依据。 ### 3.3 `public.platform_express_event_raw`(原始接收留痕表) 用途: - 记录每一次 webhook 回调或轮询结果的“原始内容 + 安全审计 + 解析结果”。 - 用于:验签问题定位、第三方字段变更回溯、解析失败重放、争议审计。 索引: - `idx_platform_express_raw_received_at (received_at)` - `idx_platform_express_raw_tracking_no (tracking_no)` - `idx_platform_express_raw_signature_valid (signature_valid)` - `gin_platform_express_raw_body`(`body` JSONB GIN,便于按字段排障检索) 字段表: | 字段 | 类型 | 可空 | 默认/约束 | 含义 | |---|---|---:|---|---| | id | UUID | 否 | PK,`uuid_generate_v4()` | 原始接收记录主键 | | received_at | TIMESTAMPTZ | 否 | 默认 `NOW()` | 平台收到请求/响应的时间 | | source | VARCHAR(16) | 否 | 默认 `'webhook'` | 来源:`webhook`/`poll`/`manual` | | client_id | VARCHAR(64) | 是 | | 调用方/渠道标识(如回调应用 ID、聚合方商户号等) | | carrier | VARCHAR(32) | 是 | | 承运方编码(可从路由/请求体解析;可能为空) | | tracking_no | VARCHAR(64) | 是 | | 运单号(可能为空:如批量回调或解析失败) | | signature_valid | BOOLEAN | 是 | | 验签是否通过(解析失败或未验签可为空) | | signature | TEXT | 是 | | 签名原文(如 header 签名) | | ts_header | TEXT | 是 | | 时间戳 header(用于防重放;字段名取决于对接规范) | | request_id | VARCHAR(64) | 是 | | 请求追踪 ID(平台生成或对方传入) | | remote_ip | INET | 是 | | 来源 IP(用于安全审计/黑白名单) | | headers | JSONB | 是 | | 请求头(建议按需过滤敏感头再落库) | | body | JSONB | 是 | | 原始请求体/响应体(用于回溯与重放) | | parse_error | TEXT | 是 | | 解析错误信息(成功解析则为空) | | dedupe_key | VARCHAR(256) | 是 | | 原始请求去重辅助键(可选:如 `hash(headers+body)`) | 权限与合规建议(实现侧): - `raw_payload`、`platform_express_event_raw.body/headers` 可能包含敏感信息(手机号、地址、签名等),建议仅后台/运维具备读取权限,并记录审计日志。 ## 4. 常见查询与写入路径(建议) - 发货/绑定运单: - Upsert `platform_express_waybills`(按 `(carrier, tracking_no)`);有订单关联时写入 `order_id/order_no`。 - 接收回调/轮询: - 先插入 `platform_express_event_raw` 做留痕(无论解析成功与否)。 - 解析出事件后写入 `platform_express_tracking_events`;用 `dedupe_key` 做幂等。 - 视需要更新 `platform_express_waybills.current_status_*`、`last_synced_at`。 - 订单详情页展示: - 通过 `order_id` 查 `platform_express_waybills`。 - 再按 `waybill_id` 查 `platform_express_tracking_events`,按 `event_time` 升序组装时间线。