# 配送对接接口规范（模拟三通一达后台 / Mock 承运方 Server）

本文档用于定义“模拟承运方后台服务（Mock Server）”的接口与行为，供平台在未接入真实承运方前完成联调与测试。

本文定位：
- 规定 Mock Server 与平台后端之间的交互（Webhook 推送 + 控制面 API）。
- 规定平台侧建议的统一事件模型（用于入库、时间线展示、监控告警）。

关联文档：
- `配送模块需求文档.md`：目标/范围/验收与必须的故障注入
- `状态映射表.md`：状态码映射建议（Mock event_code -> 平台 status_code）
- `前端字段清单.md`：安卓/Web 时间线展示字段契约

包含两类接口：
1) Mock Server -> 平台：Webhook 事件推送（模拟承运方回调）
2) 平台/测试工具 -> Mock Server：控制面 API（创建运单、追加事件、运行场景、触发推送、查询轨迹）

## 统一约定
- 时间格式：ISO 8601（示例："2026-02-05T10:30:00+08:00"）
- 所有接口请求/响应均为 JSON，Content-Type: application/json
- 写操作建议携带 `request_id` 用于幂等与排查
- 所有第三方回调应保存 `raw_payload` 用于审计

补充说明（安卓端 & Web 端使用场景）：
- 本文主要规范 Mock Server 与平台后端的交互；安卓/Web 客户端不应直接调用 Mock Server。
- Web 端联调时如需浏览器直连平台接口，应由平台网关配置 CORS（仅测试环境白名单），避免将 Mock Server 暴露给公网。

## 一、目标与约束
- 目标：用可控数据模拟关键配送节点与异常场景，覆盖验签、幂等、乱序/重复、延迟等测试。
- 约束：本规范服务于测试/预发布环境，不用于生产承运方直连。

## 二、核心数据模型（建议统一存储字段）
- `carrier`：承运方标识（例如：YUNDA、YTO、KDN）
- `tracking_no`：运单号
- `event_id`：第三方事件唯一ID（用于去重）
- `event_time`：事件时间（ISO8601）
- `event_code`：第三方原始事件码（尽量不改写，用于审计与一致性对齐）
- `event_text`：第三方原始事件文案（前端时间线默认展示）
- `status_code`：平台统一状态（ORDER_PLACED, SHIPPED, IN_TRANSIT, OUT_FOR_DELIVERY, READY_FOR_PICKUP, DELIVERED, EXCEPTION, RETURNED）
- `node_name`：节点名称（中转站/网点/城市）
- `location`：节点位置描述（城市/网点地址，注意隐私）
- `description`：事件详细描述
- `evidence_urls`：证据照片/签名链接数组
- `estimated_arrival`：ETA（若承运方提供，可选）
- `raw_payload`：原始第三方 JSON（审计）
- `last_synced_at`：本地同步时间

## 三、接入模式
- 平台接收 Mock Server 的 Webhook 推送（推荐）。
- 平台亦可主动调用 Mock Server 查询轨迹（模拟轮询补偿）。

范围说明（避免误解）：
- 若要实现“电子面单/在线下单自动获取运单号”，需要对接第三方（快递公司直连或聚合平台）提供的下单/面单接口。
- 该类“下单/面单”接口不属于本 Mock Server 接口规范范围；本文只覆盖轨迹事件的推送/查询与相关验签、幂等与字段口径。

## 四、接口定义（示例）

1) Mock Server -> 平台：事件推送（Webhook）
- URL: POST /webhook/express/status
- 描述: 承运方/聚合方主动推送运单事件（单条或批量事件）。平台应校验签名并返回 HTTP 200 表示成功接收。
- HTTP 头部（建议）:
  - `Content-Type: application/json`
  - `X-Client-Id`: 承运方或聚合方ID
  - `X-Timestamp`: 推送时间戳（防重放）
  - `X-Signature`: HMAC-SHA256(body + X-Timestamp) 使用双方共享 secret
- 回调示例（单事件）:
{
  "tracking_no":"YD123456789",
  "carrier":"YUNDA",
  "event_id":"e_20260205_0001",
  "event_code":"TRANSIT",
  "event_text":"运输中",
  "event_time":"2026-02-05T14:32:00+08:00",
  "node_name":"北京分拨中心",
  "location":"北京市朝阳区XXX",
  "evidence_urls":[],
  "raw_payload":{/* 原始承运方 JSON */}
}

处理要求：
- 平台校验 `X-Signature` 和 `X-Timestamp`；若验签失败或时间差过大返回 4xx。若成功返回 HTTP 200。接收后异步完成映射与入库。
- 幂等：基于 `event_id` 或 `tracking_no+event_code+event_time` 去重。

2) 平台 -> Mock Server：轨迹主动拉取（模拟轮询）
- URL: GET /mock/v1/track?tracking_no={tracking_no}&carrier={carrier}
- 描述: 平台主动查询单运单轨迹，返回事件数组。
- 响应示例:
{
  "tracking_no":"YD123456789",
  "carrier":"YUNDA",
  "events":[
    {"event_id":"e1","event_code":"PICKED","event_text":"已揽收","event_time":"2026-02-04T18:00:00+08:00","node_name":"门店揽收网点","location":"北京市顺义"},
    {"event_id":"e2","event_code":"ARRIVAL","event_text":"运输中","event_time":"2026-02-05T14:32:00+08:00","node_name":"北京分拨中心","location":"北京市朝阳区"}
  ]
}

3) 平台：异常上报 API（用户/客服触发，平台侧，不属于 Mock Server）
- URL: POST /api/v1/delivery/express/report-exception
- 说明: 该接口为平台自身能力，Mock Server 不强制实现。
- 请求示例:
{
  "tracking_no":"YD123456789",
  "reported_by":"user",
  "report_type":"damaged",
  "description":"包裹外包装破损，有压痕",
  "evidence_urls":["https://.../img1.jpg"]
}
- 平台可选地回传给真实承运方（若未来接入）并记录回传结果。

4) 平台/测试工具 -> Mock Server：控制面 API（建议实现）

4.1 配置回调目标
- URL: POST /mock/v1/config
- 描述: 设置 Mock Server 推送到平台的 Webhook 目标地址与验签参数。
- 请求示例:
{
  "target_webhook_url":"https://api.yourplatform.com/webhook/express/status",
  "client_id":"carrier_mock_yunda",
  "secret":"shared_secret",
  "default_carrier":"YUNDA"
}

4.2 创建运单
- URL: POST /mock/v1/waybills
- 描述: 创建一个 mock 运单，可由调用方指定或由服务生成。
- 请求示例:
{
  "carrier":"YUNDA",
  "tracking_no":"YD123456789",
  "order_no":"202602050001"
}
- 响应示例:
{
  "carrier":"YUNDA",
  "tracking_no":"YD123456789",
  "created_at":"2026-02-05T14:00:00+08:00"
}

4.3 追加事件（不推送，仅入库）
- URL: POST /mock/v1/waybills/{tracking_no}/events
- 请求示例:
{
  "event_id":"e_20260205_0002",
  "event_code":"TRANSIT",
  "event_text":"运输中",
  "event_time":"2026-02-05T14:32:00+08:00",
  "node_name":"北京分拨中心",
  "location":"北京市朝阳区",
  "evidence_urls":[]
}

4.4 运行预置场景（生成一组事件并可选立即推送）
- URL: POST /mock/v1/waybills/{tracking_no}/run-scenario
- 请求示例:
{
  "scenario":"standard_delivered",
  "push":true,
  "inject":{
    "delay_ms":300,
    "duplicate":0,
    "out_of_order":false,
    "bad_signature":false,
    "timestamp_skew_seconds":0
  }
}

4.5 触发推送（把该运单事件推到平台）
- URL: POST /mock/v1/waybills/{tracking_no}/push
- 请求示例:
{
  "mode":"all",
  "inject":{
    "delay_ms":0,
    "duplicate":1,
    "out_of_order":true
  }
}

4.6 查询运单轨迹（Mock Server 自身查询接口）
- URL: GET /mock/v1/waybills/{tracking_no}/track
- 响应示例:
{
  "carrier":"YUNDA",
  "tracking_no":"YD123456789",
  "events":[
    {"event_id":"e1","event_code":"PICKED","event_text":"已揽收","event_time":"2026-02-04T18:00:00+08:00"}
  ]
}

4.7 健康检查
- URL: GET /mock/v1/health
- 响应示例:
{"status":"ok"}

## 五、字段映射与状态对照（示例）
- 平台统一状态 `OUT_FOR_DELIVERY` 映射关系示例：
  - 韵达：承运方 `派送中` -> 平台 `OUT_FOR_DELIVERY`
  - 聚合：原始 `deliver` -> 平台 `OUT_FOR_DELIVERY`

状态一致性策略（尽量保持平台与第三方一致）：
- 一致性定义：平台保存的 `event_code/event_text` 与 `raw_payload` 应与第三方可查询到的轨迹语义一致；平台对外展示的 `status_code` 必须由映射表确定性生成（同一承运方同一 `event_code` 在同一版本映射下得到同一 `status_code`）。
- 字段保真：`event_code/event_text` 仅做透传与脱敏展示，不建议“为了统一文案”而改写原文；统一展示口径使用 `status_code` 的标签/颜色/筛选实现。
- 映射表治理：映射表变更需要版本化（例如 `mapping_version`）并走发布流程；避免在生产环境频繁调整导致历史轨迹“同码不同态”。如必须调整，建议补充回放/回填策略以保证历史一致。
- 回查纠偏（可选增强）：平台定期或按需对“关键单/争议单”触发第三方轨迹回查；若发现缺失事件则补采入库；若发现语义冲突，优先保留原始事件并追加“平台侧纠偏事件/备注”，避免静默覆盖造成审计对不上。

## 六、验签与安全
- 建议使用 HMAC-SHA256 签名，签名字段为 `body + X-Timestamp`，服务端使用共享 `secret` 校验。
- 防重放：校验 `X-Timestamp` 与当前时间差（例如 < 5 分钟），并保存最近 N 个 `X-Signature` 或 `event_id` 用于去重。

## 七、幂等与重试策略
- webhook：承运方可能重试多次，平台必须基于 `event_id` 或 (`tracking_no`+`event_code`+`event_time`) 去重。
- 主动调用承运方接口失败时采用指数退避重试；关键操作（打单）建议入队异步重试并人工告警。

入库层（幂等去重、乱序处理）建议：
- 幂等目标：同一条事件无论推送/重试多少次，最终数据库只保留一条（或同一条被安全更新），避免重复入库造成时间线膨胀。
- 幂等键优先级：
  - 优先使用第三方提供的 `event_id`。
  - 若缺少 `event_id`，使用兜底组合键：`tracking_no + event_code + event_time`（必要时可补充 `node_name/location` 以降低碰撞）。
- 数据库约束：建议在事件表上建立唯一约束（例如 `carrier + tracking_no + event_id` 或 `tracking_no + dedupe_key`），写入采用 Upsert/Insert-Ignore，应用层无需“先查再写”来保证并发安全。
- 乱序处理：允许事件乱序写入（以免晚到的历史节点被丢弃）；查询展示时按 `event_time` 排序生成时间线。
- 状态不回退（平台侧可选规则）：当先收到终态（如 `DELIVERED`）后又收到更早时间的在途事件时，不应将订单状态从终态回退；可采用“以最新 `event_time` 事件计算 current_status”或“按状态流转等级仅允许前进”的策略。

## 八、展示与 UI 要求（与前端对接点）
- 时间线按 `event_time` 展示，标注 `carrier` 来源与 `last_synced_at`。
- 节点可展开查看 `description`、`node_name`、`location`、`evidence_urls`（签收照片/回单）。若无证据则隐藏预览。
- 提供“查看第三方原文”链接，展示 `raw_payload`（仅客服/运维可见）。

平台对客户端返回建议（安卓/Web）：
- 客户端请求应面向平台统一接口（例如：`GET /api/v1/delivery/express/track?order_no=...`），由平台返回统一的 `status_history`。
- 响应中建议包含：`carrier`、`tracking_no`、`status`、`status_history`、`last_synced_at`，以及可选的 `eta`。
- `raw_payload` 不建议下发给普通用户端；仅在 Web 客服/运维界面按权限下发并记录审计。

## 九、监控与告警
- 指标：webhook 接收成功率、平均同步时延、同步失败率、超过阈值未更新的运单数。
- 告警：承运方 5xx 增加、webhook 验签失败率异常、单运单长时间无更新。

## 十、示例 cURL（Webhook 验证场景模拟）
```
curl -X POST https://api.yourplatform.com/webhook/express/status \
  -H "Content-Type: application/json" \
  -H "X-Client-Id: carrier_yunda" \
  -H "X-Timestamp: 2026-02-05T14:32:00+08:00" \
  -H "X-Signature: <hmac-signature>" \
  -d '{"tracking_no":"YD123456789","event_id":"e_20260205_0001","event_code":"TRANSIT","event_time":"2026-02-05T14:32:00+08:00","event_text":"运输中"}'
```

## 十一、日志与保留策略
- 建议保留 `raw_payload` 与入库审计日志至少 30 天以便纠纷处理，审计记录包括接收时间、IP、头部信息与处理结果。

## 十二、兼容与扩展建议
- 建议实现承运商 Adapter 层：承运方差异在 Adapter 层转换为统一模型，便于后续扩展新承运方或替换聚合方。
- 若需签收照片或更高粒度信息，应优先与承运方签订企业级合同或直连，并在 UI 端明确注明凭证来源。

### 十二点一、平台后端适配架构（推荐实现方式）

目标：当不同第三方（直连承运方/聚合平台）API 结构、鉴权方式、事件码不同的时候，平台侧**不修改核心业务与数据库结构**即可接入。

核心原则：
- **统一领域模型入库**：第三方差异在入库前完成映射；数据库保存统一事件字段 + `raw_payload`。
- **Adapter 可插拔**：每家第三方实现一个 Adapter（验签/解析/查询/映射），核心服务只处理统一模型。
- **接入入口两条线**：Webhook（推送）与 Poller（轮询补偿）最终都走同一条 `EventIngestService`。

模块划分（建议）：
- `WebhookController`：接收回调、路由到对应 Adapter、快速返回 200（业务异步处理）。
- `CarrierAdapter`（每家一个）：验签、解析、字段映射、状态映射、（可选）轨迹查询。
- `AdapterRegistry/Router`：按 `carrier` 或 `X-Client-Id` 选择 Adapter（支持灰度与多配置）。
- `EventIngestService`：幂等去重、乱序处理策略、统一入库、写审计日志。
- `TrackQueryService`：给安卓/Web 提供统一查询接口（只读），不透出第三方差异。
- `PollerJob`：定时对“长时间无更新”的运单做轮询补偿（可按承运方频率配置）。

幂等与乱序建议（平台侧）：
- 幂等键优先级：`event_id`（优先） > `tracking_no + event_code + event_time`（兜底）。
- 入库：允许乱序写入；查询展示时按 `event_time` 排序。
- 兼容缺字段：缺少 `event_id` 时必须使用兜底组合键；缺少 `location/node_name` 时 UI 降级仅展示 `event_text`。

### 架构图（Mermaid）
```mermaid
flowchart LR
  subgraph Clients[客户端]
    A[安卓 App] -->|GET 物流时间线| PAPI[平台 API]
    W[Web/H5/PC] -->|GET 物流时间线| PAPI
  end

  subgraph Platform[平台后端]
    PAPI --> TQS[TrackQueryService\n统一查询]
    TQS --> DB[(Logistics DB\nWaybill + TrackingEvent)]

    WH[WebhookController\n接收回调] --> REG[AdapterRegistry/Router\n按carrier或X-Client-Id路由]
    REG --> AD1[YUNDA Adapter]
    REG --> AD2[YTO Adapter]
    REG --> AD3[Aggregator Adapter\n(快递鸟/快递100)]

    AD1 --> ING[EventIngestService\n幂等/映射/入库]
    AD2 --> ING
    AD3 --> ING
    ING --> DB

    PJ[PollerJob\n轮询补偿] --> REG
    PJ -->|queryTrack| AD1
    PJ -->|queryTrack| AD2
    PJ -->|queryTrack| AD3
  end

  subgraph ThirdParty[第三方/Mock]
    MS[Mock Server 或真实承运方/聚合] -->|Webhook 推送| WH
  end
```

### 回调时序图（Webhook 推送 -> 入库 -> 客户端展示）
```mermaid
sequenceDiagram
  participant TP as Mock/第三方
  participant WH as WebhookController
  participant REG as AdapterRegistry
  participant AD as CarrierAdapter
  participant ING as EventIngestService
  participant DB as LogisticsDB
  participant API as 平台查询API
  participant APP as 安卓/Web

  TP->>WH: POST /webhook/express/status (headers + body)
  WH->>REG: resolveAdapter(carrier/X-Client-Id)
  REG->>AD: getAdapter()
  WH->>AD: verify + parseWebhook(rawBody)
  AD-->>WH: NormalizedEvent[]
  WH-->>TP: 200 OK (快速返回)
  WH->>ING: ingest(NormalizedEvent[])
  ING->>DB: upsert events (幂等去重)

  APP->>API: GET /api/v1/delivery/express/track?order_no=...
  API->>DB: query events (order_no/tracking_no)
  DB-->>API: events ordered by event_time
  API-->>APP: timeLine(status_history + last_synced_at)
```

备注：Mermaid 图在不支持的 Markdown 渲染器中会降级为代码块，不影响内容阅读。

## 十三、附录：不同第三方 API 形态示例（用于理解差异）

说明：以下为“常见形态示例”，用于帮助团队理解不同第三方接口在鉴权、字段与能力上的差异。
- 不保证与任一承运方/聚合平台的官方文档 100% 一致；对接时必须以官方文档、沙箱与实际回文为准。
- 推荐做法：在平台侧实现 Adapter/Mapper，把第三方差异映射为本文定义的统一事件模型再入库。

### 13.1 聚合平台常见形态（如快递100/快递鸟类）

典型能力：
- 轨迹查询 API：传入 `company_code + tracking_no`（有些场景需要收件人手机号后四位）
- 订阅/推送：先订阅，后续以 Webhook 回调推送事件
- 鉴权：常见 `appKey + sign`（MD5/HMAC）或 Token

示例：轨迹查询（示例）
```http
POST https://api.aggregator.example.com/v1/track/query
Content-Type: application/json

{
  "company_code": "yunda",
  "tracking_no": "430123456789",
  "phone_last4": "8000",
  "nonce": "n_123",
  "timestamp": 1738735200,
  "sign": "md5_or_hmac_signature"
}
```

示例响应（示例）
```json
{
  "success": true,
  "tracking_no": "430123456789",
  "company_code": "yunda",
  "state": "in_transit",
  "events": [
    { "time": "2026-02-05T10:12:00+08:00", "context": "已揽收", "location": "深圳市" },
    { "time": "2026-02-05T22:01:00+08:00", "context": "到达广州分拨中心", "location": "广州市" }
  ]
}
```

差异点：
- `state` / `status` 枚举不统一；事件字段可能是 `context/desc`、`time/timestamp`。
- 不同快递公司可能要求手机号参与查询或订阅验证。

### 13.2 承运方直连常见形态（企业接口）

典型能力：
- 轨迹查询、签收回单（POD）查询可能拆成多个接口
- 鉴权更严格：HMAC、证书、IP 白名单或 OAuth2

示例：轨迹查询（示例）
```http
POST https://open.carrier.example.com/v2/route/query
Content-Type: application/json
X-Client-Id: your_client_id
X-Timestamp: 2026-02-05T10:30:00+08:00
X-Signature: hmac_sha256(body + timestamp)

{
  "tracking_no": "SF1234567890",
  "include_pod": true
}
```

示例响应（示例）
```json
{
  "tracking_no": "SF1234567890",
  "routes": [
    { "code": "PICKED", "desc": "已揽收", "time": "2026-02-05T09:10:00+08:00", "station": "深圳XX营业点" },
    { "code": "TRANSIT", "desc": "运输中", "time": "2026-02-05T21:45:00+08:00", "station": "广州分拨中心" }
  ],
  "pod": { "signed": false, "photo_url": null }
}
```

差异点：
- 字段更细（网点编码、操作员等），但不统一；POD 能力通常受权限/合同影响。

### 13.3 Webhook 推送常见形态（订阅后回调）

典型能力：
- 订阅后由第三方主动推送轨迹事件到平台
- 具备重试机制，因此平台必须做幂等去重、乱序处理

示例：回调事件（示例，字段名因第三方而异）
```json
{
  "tracking_no": "430123456789",
  "carrier": "YUNDA",
  "event_id": "evt_0001",
  "event_time": "2026-02-05T22:01:00+08:00",
  "event_text": "到达广州分拨中心",
  "location": "广州市",
  "extra": { "pod_photo": null }
}
```

接入建议：
- 无论第三方字段如何变化，平台入库前统一映射到本文“核心数据模型”，并保留 `raw_payload`。
- 平台用 `event_id`（优先）或组合键（`tracking_no+event_code+event_time`）实现幂等。

### 13.4 圆通（YTO）物流轨迹查询接口（官方文档摘要）

文档入口：
- https://open.yto.net.cn/interfaceDocument/menu251/submenu258

定位：该文档描述“根据圆通运单号查询物流轨迹”的接口形态，典型属于“平台主动查询（轮询）”模式。

关键交互要点（按官方文档整理，具体以控制台配置与最新文档为准）：
- 传输：HTTPS，POST。
- 报文结构：请求体包含 `timestamp`、`param`、`format`、`sign`。
- `param`：以 JSON/XML 字符串承载业务参数；轨迹查询场景下包含圆通运单号字段（示例为 `NUMBER`，一次查询一个单号）。

签名规则（按文档描述抽象）：
- 参与签名的明文：`param + method + v`（其中 `method` 与 `v` 来自控制台为该接口生成的配置）。
- 将上述明文与客户密钥（`secret`）拼接后做 MD5，再对 MD5 的字节结果进行 Base64 编码，得到 `sign`。
- 伪公式：`sign = base64(md5((param + method + v) + secret))`

响应字段（按文档列举的 JSON 返回字段抽象）：
- 运单号：`waybill_No`
- 走件时间：`upload_Time`（yyyy-MM-dd HH:mm:ss）
- 物流状态码：`infoContent`（示例枚举包括 GOT/ARRIVAL/DEPARTURE/SENT_SCAN/SIGNED 等）
- 物流信息文案：`processInfo`
- 城市/区县：`city`、`district`（可选）
- 重量：`weight`（可选）

平台侧映射建议（把第三方差异收敛到统一模型）：
- 时间：`upload_Time` -> 平台 `event_time`
- 文案：`processInfo` -> 平台 `event_text`（可另存 `description`）
- 状态：`infoContent` -> 平台 `event_code`（保留原码），再映射到平台统一 `status_code`（见 `状态映射表.md`）

`infoContent` 到平台统一 `status_code` 的建议映射（示例）：
- GOT（已揽收）-> IN_TRANSIT
- ARRIVAL（已收入/到达）-> IN_TRANSIT（中转/到达节点统一视为运输中）
- DEPARTURE（已发出/离开节点）-> IN_TRANSIT
- SENT_SCAN（派件）-> OUT_FOR_DELIVERY
- INBOUND（自提柜入柜）-> IN_TRANSIT（或按业务定义为 OUT_FOR_DELIVERY）
- SIGNED（签收成功）-> DELIVERED
- FAILED（签收失败）-> EXCEPTION
- TMS_RETURN（退回）-> RETURNED

落库建议：
- 将圆通原始返回（整个数组或单条对象）保存到 `raw_payload`，便于客服/运维对照圆通官网。
- 幂等去重：若第三方无稳定 `event_id`，可用组合键 `tracking_no + infoContent + upload_Time` 生成 `dedupe_key`。

### 13.5 韵达（YUNDA）开放平台（官方文档入口与调研清单）

文档入口：
- https://open.yundaex.com/api/apiDoc

说明：韵达开放平台文档页面存在较多交互式内容（需登录/控制台配置后才能看到每个接口的 `method/v/测试地址` 等关键信息）。因此本节先固化“对接时必须确认的要点清单”，避免对接过程中遗漏。

从官方文档导航可见的能力分类（用于判断覆盖范围）：
- API 鉴权说明
- 电子面单、散件下单
- 物流轨迹
- 售后服务、国际件、基础服务等

韵达轨迹对接需要在控制台确认/落盘的信息（建议形成《承运方接入配置表》）：
- 鉴权方式：签名算法（HMAC/MD5 等）、参与签名字段、编码/排序规则、是否包含时间戳与 nonce。
- 接口要素：轨迹查询接口 URL、`method`、`v`（如平台/第三方采用“method+version+param”体系）。
- 订阅/回调能力：是否支持轨迹订阅与回调推送、回调重试策略、回调验签字段。
- 返回字段：事件时间字段、事件码/状态字段、事件文案字段、地点字段（城市/网点）与可选 POD 能力。

平台侧落地方式保持不变：
- 无论韵达返回结构如何，统一通过 Adapter 映射为平台 `TrackingEvent` 领域模型入库，并保留 `raw_payload`。

附：Mock 控制面通用错误码（示例）
- 40001: invalid_parameter
- 40002: missing_required_field
- 40901: duplicate_request
- 50001: internal_error

可选增强（非本期必需）：
- 生成 OpenAPI 文档（控制面 API + Webhook 示例）
- 补齐“字段必填矩阵/容错矩阵”（配合 `drop_fields` 故障注入）
