需求分析
This commit is contained in:
49
pages.json
49
pages.json
@@ -365,6 +365,55 @@
|
|||||||
"navigationBarTitleText": "设置",
|
"navigationBarTitleText": "设置",
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "test/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "配送模块测试索引",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "test/merchant-order-list",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "商家发货管理",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "test/merchant-order-detail",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "订单物流详情",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "test/platform-tracking-query",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "轨迹排障查询",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "test/platform-webhook-logs",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "Webhook日志",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "test/platform-config-center",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "配送配置中心",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "test/consumer-logistics-detail",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "用户查快递",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
59
pages/mall/delivery/doc/需求文档/README.md
Normal file
59
pages/mall/delivery/doc/需求文档/README.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# 配送模块文档目录(Mock 三通一达后台联调)
|
||||||
|
|
||||||
|
本目录聚焦“模拟三通一达后台(Mock 承运方 Server)”的联调与测试需求,用于在未签约真实承运方前验证平台侧的 Webhook 接收、验签、幂等、入库与前端时间线展示。
|
||||||
|
|
||||||
|
## 文档分层(先看什么、后看什么)
|
||||||
|
- 需求(做什么):`配送模块需求文档.md`
|
||||||
|
- 页面(后台长什么样):`后台页面设计说明.md`
|
||||||
|
- 接口(怎么对接):`接口规范.md`
|
||||||
|
- 映射(状态怎么统一):`状态映射表.md`
|
||||||
|
- 前端契约(怎么展示):`前端字段清单.md`
|
||||||
|
- 补齐清单(还缺什么):`缺口与待补充清单.md`
|
||||||
|
|
||||||
|
## 先读这个:这套文档在解决什么
|
||||||
|
你现在要做的是一个“像三通一达一样会产生物流节点并回调的平台外部系统”。真实承运方接口通常需要签约与联调周期,因此先通过 Mock 承运方 Server 把平台侧能力跑通:
|
||||||
|
- 事件接收:平台接收并处理 Webhook 回调
|
||||||
|
- 安全与可靠性:验签、防重放、幂等去重、乱序/重复/延迟处理
|
||||||
|
- 数据闭环:事件入库 -> 前端按时间线展示(类似京东/淘宝订单物流关键节点)
|
||||||
|
|
||||||
|
说明:本目录文档服务于“平台系统的一部分”(订单详情页的物流区块、客服/履约排障与对接联调)。
|
||||||
|
- 平台端通常需要在订单详情中查看与履约相关的信息(订单号、运单号、承运方、物流时间线、异常记录等)。
|
||||||
|
- 本目录不展开订单商品/支付/营销等业务字段,仅覆盖“订单详情里的物流子模块”与其对接/入库/展示规范。
|
||||||
|
|
||||||
|
## 核心思想(设计原则)
|
||||||
|
- 以“事件流”为中心:物流展示本质就是一组按时间发生的事件(揽收/中转/在途/派送/签收/异常)。
|
||||||
|
- Webhook + 控制面分层:Webhook 用来模拟“承运方回调”,控制面 API 用来“造数据/控节奏/注入故障”。
|
||||||
|
- 统一状态码 + 原文并存:平台用 `status_code` 做标签/统计/告警;用 `event_text` 展示承运方原文,并保留 `raw_payload` 便于客服核查。
|
||||||
|
- 故障注入必须:重复推送、乱序、延迟、签名错误、缺字段等是外部对接最常见问题,必须在联调阶段覆盖。
|
||||||
|
|
||||||
|
## 阅读顺序(推荐)
|
||||||
|
1) 先看 `配送模块需求文档.md`:理解 Mock Server 要做什么、有哪些验收与故障注入。
|
||||||
|
2) 再看 `后台页面设计说明.md`:明确平台后台/商家后台需要哪些页面与最小展示/权限要求。
|
||||||
|
3) 再看 `接口规范.md`:
|
||||||
|
- Mock Server -> 平台:Webhook 推送格式与验签
|
||||||
|
- 平台/测试工具 -> Mock Server:控制面 API(创建运单/追加事件/跑场景/触发推送)
|
||||||
|
4) 看 `状态映射表.md`:明确 `event_code` 如何映射到平台统一 `status_code`。
|
||||||
|
5) 看 `前端字段清单.md`:前端时间线组件到底需要哪些字段(以及 `source` 如何标注)。
|
||||||
|
6) 最后看 `缺口与待补充清单.md`:把联调验收所需材料补齐,避免漏项。
|
||||||
|
|
||||||
|
## 快速上手(联调路径)
|
||||||
|
1) 平台准备一个 Webhook 接收地址:`/webhook/express/status`,并实现 `X-Signature` 验签与幂等去重(按 `event_id`)。
|
||||||
|
2) 使用 Mock Server 控制面配置目标:设置 `target_webhook_url`、`client_id`、`secret`。
|
||||||
|
3) 创建运单(tracking_no)并运行场景(例如 `standard_delivered`),选择是否立即推送。
|
||||||
|
4) 在平台查看:事件是否按预期入库、时间线是否按 `event_time` 展示、异常注入是否触发告警/日志。
|
||||||
|
|
||||||
|
## 常见问题(为什么这么设计)
|
||||||
|
- 为什么不直接做真实韵达/圆通对接?因为联调成本高且不可控,Mock 能让你先把平台侧工程能力打牢。
|
||||||
|
- 为什么需要控制面 API?因为测试需要“可复现/可回放/可注入”,而不是只等外部推送。
|
||||||
|
- 为什么要状态映射?因为不同承运方文案与事件码不稳定,统一状态才能做稳定 UI 与统计。
|
||||||
|
|
||||||
|
文件列表:
|
||||||
|
- 配送模块需求文档.md:Mock 承运方 Server 的目标、范围、流程与验收。
|
||||||
|
- 接口规范.md:Mock Server 控制面 API + Mock -> 平台 Webhook 推送规范。
|
||||||
|
- 状态映射表.md:Mock 事件码到平台统一状态映射建议。
|
||||||
|
- 前端字段清单.md:时间线组件所需字段契约与展示规则。
|
||||||
|
|
||||||
|
数据库:
|
||||||
|
- `mall_sql/schemas/express_tracking_mock_platform.sql`:本体系建议的 Postgres 建表脚本(平台统一入库 + Mock 持久化)。
|
||||||
|
|
||||||
|
建议下一步:在平台侧实现一个可切换的“Mock 数据源”开关(仅测试环境),并在 QA 用例中覆盖重复/乱序/验签失败等注入场景。
|
||||||
294
pages/mall/delivery/doc/需求文档/express_tracking_mock_platform.sql
Normal file
294
pages/mall/delivery/doc/需求文档/express_tracking_mock_platform.sql
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
-- 物流轨迹(第三方/Mock)数据库设计(PostgreSQL / Supabase 兼容)
|
||||||
|
-- 目标:
|
||||||
|
-- 1) 平台侧:统一接收不同第三方事件 -> 幂等去重/乱序入库 -> 给前端提供稳定时间线
|
||||||
|
-- 2) Mock 承运方侧:可持久化运单/事件/场景/推送日志,支持故障注入与回放
|
||||||
|
-- 说明:本文件仅提供表结构与索引建议;RLS/权限策略按项目实际补充。
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
-- Supabase / Postgres 常用扩展
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
|
|
||||||
|
-- 通用 updated_at 维护函数(如项目已有同名函数,可忽略重复定义)
|
||||||
|
CREATE OR REPLACE FUNCTION public.set_updated_at()
|
||||||
|
RETURNS TRIGGER
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
BEGIN
|
||||||
|
NEW.updated_at = NOW();
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- =====================================================================
|
||||||
|
-- A. 平台侧(platform):统一轨迹模型入库与查询
|
||||||
|
-- =====================================================================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS platform_express_waybills (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
|
||||||
|
-- 可选:若平台订单已存在,可关联
|
||||||
|
order_id uuid NULL,
|
||||||
|
order_no varchar(64) NULL,
|
||||||
|
|
||||||
|
carrier varchar(32) NOT NULL, -- YUNDA/YTO/ZTO/STO/KDN...
|
||||||
|
tracking_no varchar(64) NOT NULL,
|
||||||
|
source varchar(16) NOT NULL DEFAULT 'mock', -- mock/carrier/aggregator
|
||||||
|
|
||||||
|
current_status_code varchar(32) NOT NULL DEFAULT 'PENDING',
|
||||||
|
current_status_text text NULL,
|
||||||
|
|
||||||
|
eta timestamptz NULL,
|
||||||
|
last_synced_at timestamptz NULL,
|
||||||
|
|
||||||
|
created_at timestamptz NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at timestamptz NOT NULL DEFAULT NOW(),
|
||||||
|
|
||||||
|
CONSTRAINT uk_platform_waybill UNIQUE (carrier, tracking_no)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_platform_waybills_updated_at
|
||||||
|
BEFORE UPDATE ON platform_express_waybills
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_platform_waybills_order_no ON platform_express_waybills(order_no);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_platform_waybills_tracking_no ON platform_express_waybills(tracking_no);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_platform_waybills_status ON platform_express_waybills(current_status_code);
|
||||||
|
|
||||||
|
|
||||||
|
-- 统一事件表:前端时间线/告警/统计的主数据来源
|
||||||
|
CREATE TABLE IF NOT EXISTS platform_express_tracking_events (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
|
||||||
|
waybill_id uuid NOT NULL REFERENCES platform_express_waybills(id) ON DELETE CASCADE,
|
||||||
|
carrier varchar(32) NOT NULL,
|
||||||
|
tracking_no varchar(64) NOT NULL,
|
||||||
|
|
||||||
|
-- 第三方事件唯一标识(可能缺失)
|
||||||
|
event_id varchar(128) NULL,
|
||||||
|
|
||||||
|
event_time timestamptz NOT NULL,
|
||||||
|
event_code varchar(64) NOT NULL,
|
||||||
|
event_text text NOT NULL,
|
||||||
|
|
||||||
|
status_code varchar(32) NOT NULL, -- 平台统一状态
|
||||||
|
|
||||||
|
node_name varchar(128) NULL,
|
||||||
|
location text NULL,
|
||||||
|
description text NULL,
|
||||||
|
|
||||||
|
evidence_urls jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||||
|
|
||||||
|
-- 原始回文(用于审计/排障;如担心体积可移到 raw 表或只存引用)
|
||||||
|
raw_payload jsonb NULL,
|
||||||
|
|
||||||
|
-- 接收侧信息
|
||||||
|
received_at timestamptz NOT NULL DEFAULT NOW(),
|
||||||
|
source varchar(16) NOT NULL DEFAULT 'webhook', -- webhook/poll/manual
|
||||||
|
|
||||||
|
-- 幂等去重键:优先 event_id;缺失时用 tracking_no+event_code+event_time(+可选字段) 构造
|
||||||
|
dedupe_key varchar(256) NOT NULL,
|
||||||
|
|
||||||
|
created_at timestamptz NOT NULL DEFAULT NOW(),
|
||||||
|
|
||||||
|
CONSTRAINT uk_platform_event_dedupe UNIQUE (waybill_id, dedupe_key)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_platform_events_waybill_time ON platform_express_tracking_events(waybill_id, event_time);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_platform_events_tracking_time ON platform_express_tracking_events(tracking_no, event_time);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_platform_events_status ON platform_express_tracking_events(status_code);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_platform_events_received_at ON platform_express_tracking_events(received_at);
|
||||||
|
CREATE INDEX IF NOT EXISTS gin_platform_events_raw_payload ON platform_express_tracking_events USING gin (raw_payload);
|
||||||
|
|
||||||
|
|
||||||
|
-- 原始接收表:记录每一次 webhook/轮询原文、验签结果与解析错误
|
||||||
|
CREATE TABLE IF NOT EXISTS platform_express_event_raw (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
|
||||||
|
received_at timestamptz NOT NULL DEFAULT NOW(),
|
||||||
|
source varchar(16) NOT NULL DEFAULT 'webhook',
|
||||||
|
|
||||||
|
-- 请求侧标识
|
||||||
|
client_id varchar(64) NULL,
|
||||||
|
carrier varchar(32) NULL,
|
||||||
|
tracking_no varchar(64) NULL,
|
||||||
|
|
||||||
|
-- 安全审计
|
||||||
|
signature_valid boolean NULL,
|
||||||
|
signature text NULL,
|
||||||
|
ts_header text NULL,
|
||||||
|
|
||||||
|
request_id varchar(64) NULL,
|
||||||
|
remote_ip inet NULL,
|
||||||
|
headers jsonb NULL,
|
||||||
|
|
||||||
|
body jsonb NULL,
|
||||||
|
parse_error text NULL,
|
||||||
|
|
||||||
|
-- 去重辅助(可选):用于识别完全重复的原始请求
|
||||||
|
dedupe_key varchar(256) NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_platform_raw_received_at ON platform_express_event_raw(received_at);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_platform_raw_tracking_no ON platform_express_event_raw(tracking_no);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_platform_raw_signature_valid ON platform_express_event_raw(signature_valid);
|
||||||
|
CREATE INDEX IF NOT EXISTS gin_platform_raw_body ON platform_express_event_raw USING gin (body);
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================================
|
||||||
|
-- B. Mock 承运方侧(mock):运单/事件/场景/推送日志
|
||||||
|
-- =====================================================================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS mock_carrier_config (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
|
||||||
|
name varchar(64) NOT NULL DEFAULT 'default',
|
||||||
|
target_webhook_url text NULL,
|
||||||
|
|
||||||
|
client_id varchar(64) NULL,
|
||||||
|
secret text NULL,
|
||||||
|
default_carrier varchar(32) NOT NULL DEFAULT 'YUNDA',
|
||||||
|
|
||||||
|
is_active boolean NOT NULL DEFAULT true,
|
||||||
|
|
||||||
|
created_at timestamptz NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at timestamptz NOT NULL DEFAULT NOW(),
|
||||||
|
|
||||||
|
CONSTRAINT uk_mock_config_name UNIQUE (name)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_mock_carrier_config_updated_at
|
||||||
|
BEFORE UPDATE ON mock_carrier_config
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS mock_waybills (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
|
||||||
|
carrier varchar(32) NOT NULL,
|
||||||
|
tracking_no varchar(64) NOT NULL,
|
||||||
|
order_no varchar(64) NULL,
|
||||||
|
|
||||||
|
created_at timestamptz NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at timestamptz NOT NULL DEFAULT NOW(),
|
||||||
|
|
||||||
|
CONSTRAINT uk_mock_waybill UNIQUE (carrier, tracking_no)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_mock_waybills_updated_at
|
||||||
|
BEFORE UPDATE ON mock_waybills
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS mock_tracking_events (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
|
||||||
|
waybill_id uuid NOT NULL REFERENCES mock_waybills(id) ON DELETE CASCADE,
|
||||||
|
carrier varchar(32) NOT NULL,
|
||||||
|
tracking_no varchar(64) NOT NULL,
|
||||||
|
|
||||||
|
event_id varchar(128) NULL,
|
||||||
|
event_time timestamptz NOT NULL,
|
||||||
|
event_code varchar(64) NOT NULL,
|
||||||
|
event_text text NOT NULL,
|
||||||
|
|
||||||
|
node_name varchar(128) NULL,
|
||||||
|
location text NULL,
|
||||||
|
description text NULL,
|
||||||
|
evidence_urls jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||||
|
|
||||||
|
raw_payload jsonb NULL,
|
||||||
|
|
||||||
|
-- 生成幂等键,便于 Mock 内部也能去重
|
||||||
|
dedupe_key varchar(256) NOT NULL,
|
||||||
|
|
||||||
|
created_at timestamptz NOT NULL DEFAULT NOW(),
|
||||||
|
|
||||||
|
CONSTRAINT uk_mock_event_dedupe UNIQUE (waybill_id, dedupe_key)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_mock_events_waybill_time ON mock_tracking_events(waybill_id, event_time);
|
||||||
|
|
||||||
|
|
||||||
|
-- 场景定义:标准签收/拒收退回/地址异常等
|
||||||
|
CREATE TABLE IF NOT EXISTS mock_scenarios (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
scenario_code varchar(64) NOT NULL,
|
||||||
|
scenario_name varchar(128) NOT NULL,
|
||||||
|
description text NULL,
|
||||||
|
|
||||||
|
is_active boolean NOT NULL DEFAULT true,
|
||||||
|
|
||||||
|
created_at timestamptz NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at timestamptz NOT NULL DEFAULT NOW(),
|
||||||
|
|
||||||
|
CONSTRAINT uk_mock_scenario_code UNIQUE (scenario_code)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_mock_scenarios_updated_at
|
||||||
|
BEFORE UPDATE ON mock_scenarios
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
|
||||||
|
|
||||||
|
|
||||||
|
-- 场景步骤:相对时间偏移 + 事件内容
|
||||||
|
CREATE TABLE IF NOT EXISTS mock_scenario_steps (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
scenario_id uuid NOT NULL REFERENCES mock_scenarios(id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
step_no int NOT NULL,
|
||||||
|
offset_seconds int NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
|
event_code varchar(64) NOT NULL,
|
||||||
|
event_text text NOT NULL,
|
||||||
|
status_code varchar(32) NULL,
|
||||||
|
|
||||||
|
node_name varchar(128) NULL,
|
||||||
|
location text NULL,
|
||||||
|
description text NULL,
|
||||||
|
evidence_urls jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||||
|
|
||||||
|
created_at timestamptz NOT NULL DEFAULT NOW(),
|
||||||
|
|
||||||
|
CONSTRAINT uk_mock_scenario_step UNIQUE (scenario_id, step_no)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
-- 场景运行记录:便于复现/回放
|
||||||
|
CREATE TABLE IF NOT EXISTS mock_scenario_runs (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
|
||||||
|
waybill_id uuid NOT NULL REFERENCES mock_waybills(id) ON DELETE CASCADE,
|
||||||
|
scenario_id uuid NOT NULL REFERENCES mock_scenarios(id),
|
||||||
|
|
||||||
|
inject jsonb NOT NULL DEFAULT '{}'::jsonb, -- delay_ms/duplicate/out_of_order/bad_signature/timestamp_skew_seconds/drop_fields...
|
||||||
|
pushed boolean NOT NULL DEFAULT false,
|
||||||
|
|
||||||
|
started_at timestamptz NOT NULL DEFAULT NOW(),
|
||||||
|
finished_at timestamptz NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_mock_runs_waybill ON mock_scenario_runs(waybill_id, started_at);
|
||||||
|
|
||||||
|
|
||||||
|
-- 推送日志:记录每次 push 的请求/响应摘要
|
||||||
|
CREATE TABLE IF NOT EXISTS mock_push_logs (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
|
||||||
|
waybill_id uuid NOT NULL REFERENCES mock_waybills(id) ON DELETE CASCADE,
|
||||||
|
event_id varchar(128) NULL,
|
||||||
|
dedupe_key varchar(256) NULL,
|
||||||
|
|
||||||
|
target_url text NULL,
|
||||||
|
request_headers jsonb NULL,
|
||||||
|
request_body jsonb NULL,
|
||||||
|
|
||||||
|
response_status int NULL,
|
||||||
|
response_body text NULL,
|
||||||
|
error_message text NULL,
|
||||||
|
|
||||||
|
created_at timestamptz NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_mock_push_waybill ON mock_push_logs(waybill_id, created_at);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
63
pages/mall/delivery/doc/需求文档/前端字段清单.md
Normal file
63
pages/mall/delivery/doc/需求文档/前端字段清单.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# 前端字段清单(订单详情页物流时间线|安卓 & Web)
|
||||||
|
|
||||||
|
说明:本清单用于平台前端展示“物流关键节点时间线”。数据来源为平台后端消费 Mock Server(或未来真实承运方)的事件后形成的统一模型。
|
||||||
|
|
||||||
|
本文定位:只定义“平台后端 -> 客户端”的展示字段契约与规则;Mock Server 的接口与字段以 `接口规范.md` 为准。
|
||||||
|
|
||||||
|
关联文档:
|
||||||
|
- `配送模块需求文档.md`:目标/范围/验收与故障注入
|
||||||
|
- `接口规范.md`:统一事件模型、平台接收 Webhook、Mock 控制面 API
|
||||||
|
- `状态映射表.md`:event_code -> status_code 映射建议
|
||||||
|
|
||||||
|
适用端:
|
||||||
|
- 安卓端(App):重点是用户体验(弱网/图片预览/快速刷新)。
|
||||||
|
- Web 端(H5/PC):重点是排障效率(筛选/搜索/原始事件折叠展示)。
|
||||||
|
|
||||||
|
1. 订单详情(delivery block)
|
||||||
|
- `order_no`:订单号
|
||||||
|
- `tracking_no` / `waybill_no`:运单号(可能为空)
|
||||||
|
- `carrier`:承运商标识(YUNDA/YTO/KDN 等)
|
||||||
|
- `status`:平台统一状态码(PENDING/IN_TRANSIT/ARRIVED_HUB/OUT_FOR_DELIVERY/DELIVERED/EXCEPTION/RETURNED)
|
||||||
|
- `status_history`:事件数组,元素结构 `{event_id, event_time, event_code, event_text, status_code, node_name, location, description, evidence_urls, source}`
|
||||||
|
- `eta`:预计到达时间(ISO8601,若承运方或 ETA 服务提供)
|
||||||
|
- `pod`:签收凭证数组,元素 `{type: photo|signature, url, timestamp, remark}`
|
||||||
|
- `receiver_name`:收件人姓名(仅客服可查看完整)
|
||||||
|
- `receiver_masked_phone`:脱敏手机号(前端展示)
|
||||||
|
- `receiver_address`:收货地址(可按需隐藏部分字段)
|
||||||
|
- `last_synced_at`:最后同步时间(平台本地)
|
||||||
|
- `source`:来源(mock / carrier / aggregator),用于 UI 标注与排障
|
||||||
|
|
||||||
|
2. 管理/调试视图字段(可选)
|
||||||
|
- `mock_enabled`:是否开启 mock 数据
|
||||||
|
- `mock_carrier`:当前模拟承运方
|
||||||
|
- `webhook_last_result`:最近一次 webhook 推送结果摘要(仅调试页面)
|
||||||
|
|
||||||
|
3. 行为与按钮映射(平台侧)
|
||||||
|
- 刷新物流 -> GET /api/v1/delivery/express/track(平台查询自身已入库事件;或平台发起轮询)
|
||||||
|
- 上报异常 -> POST /api/v1/delivery/express/report-exception
|
||||||
|
|
||||||
|
(联调阶段可选)平台侧调试按钮(调用 Mock Server 控制面 API):
|
||||||
|
- 运行标准场景 -> POST /mock/v1/waybills/{tracking_no}/run-scenario
|
||||||
|
- 触发推送 -> POST /mock/v1/waybills/{tracking_no}/push
|
||||||
|
|
||||||
|
4. 展示规则 & 隐私
|
||||||
|
- 所有时间使用 ISO8601(含时区)。
|
||||||
|
- 手机号必须脱敏(如 138****8000),完整手机号仅在客服/运维界面显示并记录访问审计。
|
||||||
|
- 证据 URL 应带鉴权或短期有效,前端需支持预览与下载。
|
||||||
|
|
||||||
|
5. 安卓端适配要点
|
||||||
|
- 缓存:将最近一次 `status_history` 缓存在本地(仅该用户的订单范围),离线可展示并提示“数据可能不是最新”。
|
||||||
|
- 图片:POD/证据图片支持大图预览与失败重试;弱网下优先加载文本节点。
|
||||||
|
- 刷新:进入页面自动拉取;下拉刷新;显示 `last_synced_at`。
|
||||||
|
|
||||||
|
6. Web 端适配要点
|
||||||
|
- 调试信息:`raw_payload` 默认折叠,仅客服/运维可展开查看。
|
||||||
|
- 筛选搜索:按 `status_code`、时间范围、承运方 `carrier` 过滤;支持按 `tracking_no` 搜索。
|
||||||
|
- 安全:避免在前端日志中打印 `raw_payload` 与敏感字段。
|
||||||
|
|
||||||
|
7. 兼容性
|
||||||
|
- 前端组件可接收 `raw_payload`(仅供客服/运维查看)并折叠显示。
|
||||||
|
- 时间线组件需支持展开单条事件详情、证据大图预览与来源标注(承运方/聚合方)。
|
||||||
|
|
||||||
|
---
|
||||||
|
(以上为前端字段与契约建议,实际字段名可与后端协商最终确认)
|
||||||
194
pages/mall/delivery/doc/需求文档/后台页面设计说明.md
Normal file
194
pages/mall/delivery/doc/需求文档/后台页面设计说明.md
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
# 后台页面设计说明(配送模块|平台对接第三方轨迹)
|
||||||
|
|
||||||
|
本文定位:
|
||||||
|
- 定义“后台应该有什么样的页面”与每个页面的最小展示/操作/权限要求。
|
||||||
|
- 本文服务于平台系统的一部分:订单详情页物流区块 + 客服/履约/对接运维排障。
|
||||||
|
|
||||||
|
口径说明:本目录文档作为实现与验收唯一口径;如页面形态与本文不一致,以本文更新为准。
|
||||||
|
|
||||||
|
关联文档:
|
||||||
|
- `配送模块需求文档.md`:范围/目标/验收与总体定位
|
||||||
|
- `接口规范.md`:Webhook/控制面接口与入库建议
|
||||||
|
- `前端字段清单.md`:订单详情页物流区块字段契约(安卓/Web)
|
||||||
|
- `状态映射表.md`:event_code/event_text -> status_code 映射与一致性治理
|
||||||
|
- `缺口与待补充清单.md`:需补齐的验收/场景/权限矩阵等
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 角色与权限(页面设计前提)
|
||||||
|
|
||||||
|
角色建议:
|
||||||
|
- 普通用户(消费者端):仅查看自己订单物流(不在本后台范围内)
|
||||||
|
- 商家(商户后台):发货与查看订单物流(不看 raw_payload)
|
||||||
|
- 客服:查看订单物流、辅助处理异常(有限查看 raw_payload,需审计)
|
||||||
|
- 履约/运营:看指标、看异常趋势、做配置(按权限)
|
||||||
|
- 对接运维:看 webhook 日志、验签结果、配置密钥与回调、排障(可看 raw_payload,需审计)
|
||||||
|
|
||||||
|
强约束:
|
||||||
|
- `raw_payload`、完整手机号/地址、签收凭证(POD)属于敏感信息:默认折叠、按角色授权、访问需审计。
|
||||||
|
|
||||||
|
### 1.1 页面拆分原则 & 权限控制原则(避免跑偏)
|
||||||
|
|
||||||
|
结论:页面是否拆分不只由“权限”决定;更主要由“工作流/信息密度/风险”决定,权限用于控制同一页面内的可见字段与可操作按钮。
|
||||||
|
|
||||||
|
页面拆分建议(什么时候需要单独页面/专区):
|
||||||
|
- 工作流不同:商家做发货/运单绑定;客服做工单/异常处理;运维做对接配置/排障。
|
||||||
|
- 信息密度不同:面向商家的页面应短而清晰;面向运维的页面需要更细的日志与诊断信息。
|
||||||
|
- 风险不同:密钥/证书、回调配置、`raw_payload` 查看等高敏能力建议放在“对接运维专区”或独立页面,降低误操作与暴露面。
|
||||||
|
|
||||||
|
权限控制建议(同一页面内怎么按角色展示):
|
||||||
|
- 字段级:例如 `raw_payload`、完整手机号/地址、POD 仅授权角色可见;默认折叠。
|
||||||
|
- 操作级:例如“触发回查/补采”“修改接入配置/密钥”“启用 Mock 开关”等仅运维可操作。
|
||||||
|
- 审计级:对敏感字段访问与关键配置变更必须记录审计。
|
||||||
|
|
||||||
|
推荐做法:
|
||||||
|
- 信息架构先按人群拆两条导航线(商家后台 vs 平台后台)。
|
||||||
|
- 在每个页面内部再做字段/按钮的权限控制(同页不同角色看到的内容不同)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 信息架构(IA)与导航建议
|
||||||
|
|
||||||
|
建议将后台拆成两条导航线:
|
||||||
|
|
||||||
|
A. 商家后台(商户侧)
|
||||||
|
- 订单
|
||||||
|
- 订单列表
|
||||||
|
- 订单详情(含物流区块 + 发货/运单绑定)
|
||||||
|
- 设置(可选)
|
||||||
|
- 默认承运方/发货偏好
|
||||||
|
|
||||||
|
B. 平台后台(客服/运维侧)
|
||||||
|
- 订单
|
||||||
|
- 订单查询
|
||||||
|
- 订单详情(含物流区块)
|
||||||
|
- 物流对接
|
||||||
|
- 运单/轨迹查询(排障)
|
||||||
|
- Webhook 接收日志
|
||||||
|
- 接入配置中心(承运方/聚合配置)
|
||||||
|
- 监控与告警
|
||||||
|
- 状态映射治理(可选增强)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 商家后台页面(最小集)
|
||||||
|
|
||||||
|
### 3.1 订单列表页(商家)
|
||||||
|
目的:商家快速定位需要发货/查看物流的订单。
|
||||||
|
|
||||||
|
最小展示:
|
||||||
|
- `order_no`、下单时间、收件人(脱敏)、订单状态、发货状态
|
||||||
|
- 物流摘要(若已发货):`carrier`、`tracking_no`、当前 `status_code`
|
||||||
|
|
||||||
|
最小操作:
|
||||||
|
- 查看订单详情
|
||||||
|
- 发货(跳转/弹窗进入“承运方选择 + 运单号绑定”)
|
||||||
|
|
||||||
|
### 3.2 订单详情页(商家,含物流区块)
|
||||||
|
目的:完成发货动作,并查看物流时间线。
|
||||||
|
|
||||||
|
物流区块展示(以 `前端字段清单.md` 为准):
|
||||||
|
- `carrier`、`tracking_no`、`status`、`status_history`、`last_synced_at`
|
||||||
|
|
||||||
|
操作:
|
||||||
|
- 发货:选择承运方 + 录入/回填 `tracking_no`
|
||||||
|
- 刷新物流:调用平台统一查询(不直连第三方)
|
||||||
|
|
||||||
|
禁止/限制:
|
||||||
|
- 不展示 `raw_payload`
|
||||||
|
- 收件信息按平台规则脱敏
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 平台后台页面(客服/履约/对接运维)
|
||||||
|
|
||||||
|
### 4.1 订单查询页(平台)
|
||||||
|
目的:客服/履约按订单维度查找并进入详情处理。
|
||||||
|
|
||||||
|
筛选:
|
||||||
|
- `order_no`、`tracking_no`、`carrier`、`status_code`、时间范围
|
||||||
|
|
||||||
|
展示:
|
||||||
|
- 订单摘要 + 物流摘要(当前状态、最后同步时间)
|
||||||
|
|
||||||
|
### 4.2 订单详情页(平台,含物流区块加强版)
|
||||||
|
目的:在订单上下文内查看完整物流与异常。
|
||||||
|
|
||||||
|
展示:
|
||||||
|
- 物流区块:同商家侧字段 + 事件来源标注(mock/承运方/聚合)
|
||||||
|
- 异常标记:长时间无更新、签收失败、退回等(按规则)
|
||||||
|
- POD(可选):签收凭证预览(按权限)
|
||||||
|
|
||||||
|
操作:
|
||||||
|
- 刷新/回查(可选增强):触发平台轮询补偿或第三方回查
|
||||||
|
- 备注/工单关联(可选):记录客服处理信息
|
||||||
|
|
||||||
|
### 4.3 运单/轨迹查询页(平台排障核心)
|
||||||
|
目的:脱离订单也能按运单快速排障。
|
||||||
|
|
||||||
|
筛选:
|
||||||
|
- `tracking_no`、`carrier`、`status_code`、时间范围、来源(mock/承运方/聚合)
|
||||||
|
|
||||||
|
展示:
|
||||||
|
- 事件时间线(入库后统一模型)
|
||||||
|
- 幂等/乱序结果提示(例如:去重命中次数、最新事件时间)
|
||||||
|
|
||||||
|
操作:
|
||||||
|
- 复制对接诊断信息(不含敏感字段)
|
||||||
|
|
||||||
|
### 4.4 Webhook 接收日志页(平台对接运维)
|
||||||
|
目的:定位“回调未到/验签失败/重复推送/入库失败”。
|
||||||
|
|
||||||
|
筛选:
|
||||||
|
- 时间范围、`carrier`、`tracking_no`、验签结果、HTTP 状态、处理结果
|
||||||
|
|
||||||
|
展示:
|
||||||
|
- 请求摘要:`X-Client-Id`、`X-Timestamp`、签名校验结果
|
||||||
|
- 处理摘要:解析成功/失败原因、幂等键、入库结果
|
||||||
|
- 原始回文:`raw_payload` 折叠展示(仅授权角色可见,且记录访问审计)
|
||||||
|
|
||||||
|
### 4.5 接入配置中心(平台对接运维)
|
||||||
|
目的:管理承运方/聚合接入与回调配置。
|
||||||
|
|
||||||
|
配置项:
|
||||||
|
- 承运方列表与状态(启用/停用)
|
||||||
|
- 验签密钥/证书、公网 IP 白名单(如需要)
|
||||||
|
- Webhook 目标地址与环境(测试/预发/生产)
|
||||||
|
- 轮询补偿策略:频率、阈值(多久无更新触发)、熔断
|
||||||
|
- 测试环境 Mock 开关(默认关闭,需显式开启)
|
||||||
|
|
||||||
|
### 4.6 监控与告警页(平台履约/运维)
|
||||||
|
目的:按承运方/接口维度观察质量。
|
||||||
|
|
||||||
|
指标建议:
|
||||||
|
- webhook 接收成功率、验签失败率、平均同步延迟
|
||||||
|
- 超过阈值未更新的运单数
|
||||||
|
- 第三方接口错误率/超时率(轮询补偿场景)
|
||||||
|
|
||||||
|
### 4.7 状态映射治理页(可选增强)
|
||||||
|
目的:让 `event_code -> status_code` 可治理、可追溯。
|
||||||
|
|
||||||
|
展示:
|
||||||
|
- 当前映射表、变更记录、(可选)映射版本
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. MVP(最小可上线范围)
|
||||||
|
|
||||||
|
商家后台:
|
||||||
|
- 订单列表 + 订单详情(含发货与物流区块)
|
||||||
|
|
||||||
|
平台后台:
|
||||||
|
- 运单/轨迹查询
|
||||||
|
- Webhook 接收日志(含验签/去重/入库结果)
|
||||||
|
- 接入配置中心(至少支持配置承运方/密钥/回调目标)
|
||||||
|
- 监控与告警(至少有基础指标与列表)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 验收要点(页面层)
|
||||||
|
|
||||||
|
- 订单详情页物流区块字段与展示规则符合 `前端字段清单.md`
|
||||||
|
- 平台后台能从运单号定位到:事件时间线 + webhook 接收记录 + 验签结果 + 入库结果
|
||||||
|
- `raw_payload` 默认不可见/折叠,且按权限展示并有审计
|
||||||
|
- Mock 开关默认关闭,且仅在测试环境允许启用
|
||||||
512
pages/mall/delivery/doc/需求文档/接口规范.md
Normal file
512
pages/mall/delivery/doc/需求文档/接口规范.md
Normal file
@@ -0,0 +1,512 @@
|
|||||||
|
# 配送对接接口规范(模拟三通一达后台 / 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`:平台统一状态(PENDING, IN_TRANSIT, ARRIVED_HUB, OUT_FOR_DELIVERY, DELIVERED, EXCEPTION)
|
||||||
|
- `node_name`:节点名称(中转站/网点/城市)
|
||||||
|
- `location`:节点位置描述(城市/网点地址,注意隐私)
|
||||||
|
- `description`:事件详细描述
|
||||||
|
- `evidence_urls`:证据照片/签名链接数组
|
||||||
|
- `estimated_arrival`:ETA(若承运方提供,可选)
|
||||||
|
- `raw_payload`:原始第三方 JSON(审计)
|
||||||
|
- `last_synced_at`:本地同步时间
|
||||||
|
|
||||||
|
## 三、接入模式
|
||||||
|
- 平台接收 Mock Server 的 Webhook 推送(推荐)。
|
||||||
|
- 平台亦可主动调用 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":"ARRIVED_HUB",
|
||||||
|
"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":"ARRIVED_HUB","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":"ARRIVED_HUB",
|
||||||
|
"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":"ARRIVED_HUB","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": "ARRIVED_HUB", "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(已收入/到达)-> ARRIVED_HUB
|
||||||
|
- 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` 故障注入)
|
||||||
64
pages/mall/delivery/doc/需求文档/状态映射表.md
Normal file
64
pages/mall/delivery/doc/需求文档/状态映射表.md
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
# 状态映射表(Mock 承运方 Server -> 平台统一状态)
|
||||||
|
|
||||||
|
本表用于将 Mock Server 产生的 `event_code/event_text` 映射为平台统一 `status_code`,以保证前端时间线与告警规则可复用。
|
||||||
|
|
||||||
|
关联文档:
|
||||||
|
- `接口规范.md`:统一事件模型与接入模式
|
||||||
|
- `前端字段清单.md`:时间线字段契约(status_history/status_code)
|
||||||
|
|
||||||
|
平台统一状态(建议):
|
||||||
|
- PENDING:待揽收
|
||||||
|
- IN_TRANSIT:运输中
|
||||||
|
- ARRIVED_HUB:到达中转/分拨中心
|
||||||
|
- OUT_FOR_DELIVERY:派送中
|
||||||
|
- DELIVERED:已签收
|
||||||
|
- EXCEPTION:异常
|
||||||
|
- RETURNED:退回
|
||||||
|
|
||||||
|
Mock 事件码(建议) -> 平台统一状态
|
||||||
|
- CREATED / ORDERED -> PENDING
|
||||||
|
- PICKED / COLLECTED -> IN_TRANSIT
|
||||||
|
- ARRIVED_HUB -> ARRIVED_HUB
|
||||||
|
- DEPARTED_HUB / IN_TRANSIT -> IN_TRANSIT
|
||||||
|
- ARRIVED_DEST_CITY -> IN_TRANSIT
|
||||||
|
- OUT_FOR_DELIVERY -> OUT_FOR_DELIVERY
|
||||||
|
- SIGNED / DELIVERED -> DELIVERED
|
||||||
|
- REJECTED -> EXCEPTION
|
||||||
|
- ADDRESS_INVALID -> EXCEPTION
|
||||||
|
- DAMAGED -> EXCEPTION
|
||||||
|
- LOST -> EXCEPTION
|
||||||
|
- RETURNED / RETURNING -> RETURNED
|
||||||
|
|
||||||
|
示例(用于 UI 文案)
|
||||||
|
- ARRIVED_HUB:到达北京分拨中心
|
||||||
|
- OUT_FOR_DELIVERY:快件正在派送中
|
||||||
|
- SIGNED:客户已签收(可带 POD 图片)
|
||||||
|
|
||||||
|
注意事项
|
||||||
|
- 平台入库请保留原始 `event_text` 与 `raw_payload`,前端默认展示 `event_text`,状态标签使用 `status_code`。
|
||||||
|
- Mock Server 应支持故障注入(重复/乱序/延迟/验签失败),平台状态映射必须在幂等入库后执行。
|
||||||
|
|
||||||
|
为尽量保证事件状态保持一致(基础要求):
|
||||||
|
- `event_code/event_text` 视为第三方“事实记录”,尽量不改写;统一口径(标签、颜色、筛选)交由 `status_code` 承担。
|
||||||
|
- 映射必须确定性:同一承运方、同一 `event_code` 在同一套映射规则下应得到同一 `status_code`。
|
||||||
|
|
||||||
|
备选方案:映射版本化(`mapping_version`)(可选增强)
|
||||||
|
|
||||||
|
为什么要做:
|
||||||
|
- 防止“状态漂移”:映射规则一旦调整,历史订单的已入库事件如果重新计算 `status_code`,可能出现“昨天运输中,今天变异常/又变回运输中”,引发用户与客服争议。
|
||||||
|
- 提升可审计性:当出现纠纷或对账问题时,需要能回答“当时按哪一版规则映射出来的”。
|
||||||
|
- 降低排障成本:多承运方/多渠道(直连+聚合)并存时,版本信息能快速定位是“第三方事件变了”还是“平台映射变了”。
|
||||||
|
|
||||||
|
什么时候启用:
|
||||||
|
- 状态映射会随运营/产品频繁调整,且希望历史展示稳定、可解释。
|
||||||
|
- 客服/售后对轨迹状态一致性有明确 SLA 或合规/审计要求。
|
||||||
|
|
||||||
|
怎么落地(从轻到重):
|
||||||
|
- 轻量做法(推荐起步):将映射表作为配置/代码资产管理,使用 Git tag/发布号作为 `mapping_version`,并在发布记录中保留变更原因与生效时间。
|
||||||
|
- 加强做法:在事件入库时把 `mapping_version` 一并存入事件记录(或运单聚合记录),对外查询接口可返回该版本用于排查。
|
||||||
|
- 变更策略建议:
|
||||||
|
- 小改动优先“仅影响未来事件”(不回刷历史)。
|
||||||
|
- 如必须修正历史映射,采用回放/回填任务,并对已对外展示的结果做备注或审计记录,避免静默改写。
|
||||||
|
|
||||||
|
代价与取舍:
|
||||||
|
- 会引入配置治理与发布流程的管理成本;若当前映射很稳定、承运方少、无强审计诉求,可以先不启用该方案。
|
||||||
82
pages/mall/delivery/doc/需求文档/缺口与待补充清单.md
Normal file
82
pages/mall/delivery/doc/需求文档/缺口与待补充清单.md
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
# 缺口与待补充清单(配送模块|第三方轨迹对接 + Mock 联调)
|
||||||
|
|
||||||
|
本文定位:
|
||||||
|
- 用“交付物清单”的方式回答:当前这套配送对接文档还缺什么、为什么缺、补了带来什么收益。
|
||||||
|
- 不改变现有方案(统一事件模型 + Adapter + 幂等乱序入库 + 前端统一契约),只补齐落地时最容易卡住的材料。
|
||||||
|
|
||||||
|
关联文档:
|
||||||
|
- `README.md`:阅读入口与联调路径
|
||||||
|
- `配送模块需求文档.md`:目标/范围/验收口径
|
||||||
|
- `接口规范.md`:Webhook + 控制面 API + 入库建议
|
||||||
|
- `状态映射表.md`:event_code/event_text -> status_code + 一致性治理(含备选方案)
|
||||||
|
- `前端字段清单.md`:安卓/Web 展示契约
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## P0(建议本期补齐,影响联调与验收能否顺利推进)
|
||||||
|
|
||||||
|
1) 联调/验收 Checklist(平台侧 + Mock 侧)
|
||||||
|
- 为什么要补:现在“验收标准”是目标描述,但缺少可勾选的操作性检查项,QA/对接会反复口头对齐。
|
||||||
|
- 补齐收益:把“验签/幂等/乱序/重复/延迟/缺字段”等要求落到可执行项,减少漏测。
|
||||||
|
- 建议产物:一份表格/列表(可以后续直接贴到测试用例/测试报告里)。
|
||||||
|
|
||||||
|
2) 场景库清单(scenario catalog)+ 每个场景的事件序列期望
|
||||||
|
- 为什么要补:当前只提了 `standard_delivered` 等示例名,但没有定义“这个场景到底要生成哪些关键节点、每个节点对应哪些 event_code/status_code、时间间隔怎样”。
|
||||||
|
- 补齐收益:前端可稳定对照 UI;后端可稳定断言幂等与排序;QA 可复现回归。
|
||||||
|
- 建议产物:
|
||||||
|
- 场景列表(标准签收/拒收退回/地址异常/破损/丢失/长时间无更新/签收失败后成功等)
|
||||||
|
- 每个场景:事件数、关键事件码、是否包含 POD、是否包含异常、是否需要乱序/重复/延迟注入。
|
||||||
|
|
||||||
|
3) Webhook 接收契约的“ACK/重试”约定(平台与第三方的边界)
|
||||||
|
- 为什么要补:目前只写“成功返回 200”,但缺少“平台什么时候返回 2xx、什么时候 4xx/5xx、第三方是否重试、重试间隔与上限”的共识。
|
||||||
|
- 补齐收益:避免线上/联调出现“平台处理慢导致第三方重推爆量”“平台 4xx 被第三方当作可重试”之类问题。
|
||||||
|
- 建议产物:在 `接口规范.md` 增补一小节:
|
||||||
|
- 验签失败/缺字段/无法解析 -> 4xx(不建议重试)
|
||||||
|
- 平台内部暂时不可用 -> 5xx(允许重试)
|
||||||
|
- 成功接收但异步入库失败 -> 2xx 还是 5xx 的取舍(建议:接收成功就 2xx,入库失败走内部告警与补偿队列)。
|
||||||
|
|
||||||
|
4) 承运方接入配置表模板(Carrier Integration Profile)
|
||||||
|
- 为什么要补:你已经发现韵达/圆通等第三方细节差异大,缺少一个“把关键信息落盘”的标准表格,后续每接一家都要重新摸索。
|
||||||
|
- 补齐收益:缩短接新承运方周期;把差异收敛到 Adapter/配置层;减少口头信息丢失。
|
||||||
|
- 建议字段(模板):
|
||||||
|
- `carrier`、接入模式(webhook/polling/both)
|
||||||
|
- 鉴权类型与签名算法、参与签名字段、是否含 timestamp/nonce
|
||||||
|
- 轨迹查询接口(URL/method/v/字段示例)、回调接口(回调验签字段/重试策略)
|
||||||
|
- 是否提供稳定 `event_id`、是否要求手机号后四位
|
||||||
|
- 时间格式/时区、地点粒度
|
||||||
|
- 状态码枚举来源与映射版本
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## P1(建议尽快补齐,影响长期维护与一致性/审计能力)
|
||||||
|
|
||||||
|
1) 权限矩阵与审计要求(谁能看 raw_payload / POD / 全量地址手机号)
|
||||||
|
- 原因:`raw_payload` 可包含敏感字段;Web 客服/运维能力需要最小权限与审计。
|
||||||
|
- 产物:角色(普通用户/商家/客服/运维/管理员)× 字段(raw/POD/手机号/地址)的可见性矩阵 + 审计日志要求。
|
||||||
|
|
||||||
|
2) 错误码与返回体统一(控制面 API)
|
||||||
|
- 原因:目前 `接口规范.md` 仅列举了示例错误码,但缺少标准响应结构。
|
||||||
|
- 产物:统一响应:`{success, code, message, request_id, data}`;并约定 HTTP 状态码与业务码的对应。
|
||||||
|
|
||||||
|
3) OpenAPI(可选)
|
||||||
|
- 原因:接口多了以后靠 Markdown 容易漂移。
|
||||||
|
- 产物:控制面 API + Webhook payload 的 OpenAPI(至少给 Mock 侧)。
|
||||||
|
|
||||||
|
4) “状态不回退/一致性”策略的明确算法(平台侧)
|
||||||
|
- 原因:`接口规范.md` 提了可选规则,但未选型;当出现终态后补到更早事件时,当前状态如何计算需要一口径。
|
||||||
|
- 产物:选定一种算法并写清:以 `event_time` 最新为准 / 状态等级只进不退 / 双轨(展示按时间,current_status 不回退)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## P2(可后补,锦上添花)
|
||||||
|
- DB 字典与 ER 图(便于新人理解 schema)
|
||||||
|
- 场景导入导出(JSON)格式规范
|
||||||
|
- 对接灰度/熔断/降级策略的配置说明
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 建议补充顺序(最省时间)
|
||||||
|
1) 先补 P0-1(Checklist)+ P0-2(场景库清单)——直接提升联调效率
|
||||||
|
2) 再补 P0-3(ACK/重试约定)——避免重复推送与误判
|
||||||
|
3) 再补 P0-4(承运方接入配置表模板)——为后续接真实承运方铺路
|
||||||
|
4) 最后补 P1 项——为线上长期治理做准备
|
||||||
251
pages/mall/delivery/doc/需求文档/配送模块需求文档.md
Normal file
251
pages/mall/delivery/doc/需求文档/配送模块需求文档.md
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
# 配送模块需求文档(模拟三通一达后台 / Mock 承运方 Server)
|
||||||
|
|
||||||
|
本文定位:定义 Mock 承运方 Server 的目标、范围、流程、故障注入与验收标准;接口与字段细节以 `接口规范.md`、`前端字段清单.md` 为准。
|
||||||
|
|
||||||
|
口径说明:本目录文档作为联调、验收与实现的唯一口径;如与口头沟通或临时讨论结论不一致,以本文档及其关联文档(接口/字段/映射)为准,并通过文档更新同步。
|
||||||
|
|
||||||
|
关联文档:
|
||||||
|
- `README.md`:阅读入口与联调路径
|
||||||
|
- `接口规范.md`:Webhook 推送规范 + Mock 控制面 API
|
||||||
|
- `状态映射表.md`:event_code/event_text -> 平台 status_code
|
||||||
|
- `前端字段清单.md`:安卓/Web 时间线字段契约
|
||||||
|
|
||||||
|
## 1. 背景
|
||||||
|
当前配送链路依赖第三方承运方(常见为“三通一达”等快递公司或聚合平台)。在真实承运方接口尚未签约/联调完成前,需要一个**可控的模拟承运方后台服务(Mock Server)**,用于开发与测试平台侧的:Webhook 接收、验签、幂等入库、时间线展示、异常处理与监控告警。
|
||||||
|
|
||||||
|
系统定位与边界:
|
||||||
|
- 本模块属于平台系统的一部分,最终呈现在“订单详情页”的物流区块,并同时服务客服/履约/对接排障。
|
||||||
|
- 平台端需要查看订单的履约详情(至少包括:`order_no`、`tracking_no`、`carrier`、物流时间线 `status_history`、异常与处理记录)。
|
||||||
|
- 但本需求不覆盖商品明细、支付、营销等订单业务域的展示与流程;这里聚焦“物流轨迹对接、入库与展示”。
|
||||||
|
|
||||||
|
多端归属与页面边界(统一口径):
|
||||||
|
- 本需求产出的“物流能力”不是一个独立的骑手/配送员端 App,而是作为同一套物流模块能力,分别嵌入到三个端(按权限展示不同颗粒度):
|
||||||
|
1) 消费者端(C 端):订单详情的物流时间线/物流详情(只读为主,展示 `event_text` + `status_code`,不展示 `raw_payload`)。
|
||||||
|
2) 商家端(B 端):发货与运单绑定(选择承运方、录入/回填 `tracking_no`)+ 查看物流(不包含对接配置与敏感调试信息)。
|
||||||
|
3) 管理端(平台后台:客服/履约/对接运维):订单/运单查询、Webhook 接收日志、接入配置、(可选)监控告警与审计能力。
|
||||||
|
- 三端展示字段口径以统一事件模型与前端字段契约为准(见 `接口规范.md`、`前端字段清单.md`),避免出现“不同端展示不一致/状态口径不一致”。
|
||||||
|
- 若未来要做“自营配送/同城骑手端”(接单、导航、到店取货、送达签收等),需单独立项与另写需求文档,不在本需求范围内。
|
||||||
|
|
||||||
|
## 2. 目标
|
||||||
|
- 适用阶段:主要用于真实第三方承运方未签约/未联调/不可控时的替代数据源;即便后续已接入真实承运方,也保留用于回归测试、故障注入与排障复现(生产环境默认关闭)。
|
||||||
|
- 提供一个可配置的 Mock 承运方服务,模拟多承运方(圆通/韵达/中通/申通)轨迹事件与签收凭证。
|
||||||
|
- 支持将轨迹事件按既定规范推送到平台 Webhook(模拟承运方 -> 平台)。
|
||||||
|
- 支持主动查询轨迹(平台轮询场景)与“预置场景脚本”快速生成整条物流生命周期。
|
||||||
|
- 支持故障注入:延迟、重复推送、乱序、签名错误、时间戳偏移、缺字段等,用于验证平台鲁棒性。
|
||||||
|
|
||||||
|
## 2.1 配送合作模式(不同解决方案)
|
||||||
|
|
||||||
|
说明:以下方案是“商城履约/配送合作关系”的产品与工程取舍;无论选哪一种,只要前端要展示稳定一致的物流时间线,平台都建议建设统一的轨迹模型与查询接口(见 `接口规范.md` 与数据库 Schema)。本 Mock 体系用于在第三方未就绪或不可控时,替代外部系统快速联调与做故障注入回归。
|
||||||
|
|
||||||
|
### 方案 A:平台统一配送(平台与第三方合作 / 统采统接)
|
||||||
|
适用:希望提供强一致的履约体验、统一客服口径、统一监控与统计;平台愿意承担对接与运维成本。
|
||||||
|
|
||||||
|
平台职责:
|
||||||
|
- 统一签约/选择承运方或聚合平台;提供平台侧发货能力(下单、订阅/回调、轨迹查询与回单能力按合同)。
|
||||||
|
- 平台统一事件模型入库(幂等去重、乱序处理、状态不回退),对客户端输出统一 `status_history`。
|
||||||
|
|
||||||
|
商家职责:
|
||||||
|
- 在平台内选择配送方案并发货;不需要自行对接承运方轨迹接口(或仅提供必要发货信息)。
|
||||||
|
|
||||||
|
优点:体验一致,平台可观测性强;扩展新承运方主要改 Adapter,不影响前端契约。
|
||||||
|
风险/成本:平台对接与运维成本高;履约兜底责任更集中在平台侧。
|
||||||
|
|
||||||
|
与 Mock 的关系:
|
||||||
|
- Mock 用于第三方未联通阶段的替代数据源与故障注入;生产环境默认关闭。
|
||||||
|
|
||||||
|
### 方案 B:商家自选配送(商家自找承运方 / 平台只做订单)
|
||||||
|
适用:平台招商、品类/区域差异大、平台希望给商家“选择承运方”的灵活性。
|
||||||
|
|
||||||
|
重要说明(商家只是平台商户的常见情况):
|
||||||
|
- 默认不要求商家自建系统或自行对接第三方 API。
|
||||||
|
- “商家自选”指商家在平台提供的承运方/聚合平台范围内进行选择,第三方对接、验签、幂等、入库与前端展示由平台统一承担。
|
||||||
|
|
||||||
|
平台职责(建议至少做到“统一展示底座”):
|
||||||
|
- 提供统一轨迹查询接口给前端;平台内部仍建议使用统一事件模型入库。
|
||||||
|
- 平台负责与第三方承运方/聚合平台对接:订阅/回调(Webhook)或轨迹查询(轮询补偿)、验签、防重放、幂等去重、乱序处理与统一入库。
|
||||||
|
- 平台提供“发货与运单绑定”的入口(承运方选择、运单号录入/回填/打单),把差异收敛在平台 Adapter/映射规则,避免前端直接适配多家第三方。
|
||||||
|
|
||||||
|
商家职责:
|
||||||
|
- 在平台选择承运方并完成发货动作:提供/回填 `tracking_no` 与必要的订单关联信息(如 `order_no`)。
|
||||||
|
- 若商家坚持使用“商家与第三方的独立合同/账号”,可向平台提交第三方对接所需材料,由平台统一配置与代接入(不要求商家自建回调服务)。
|
||||||
|
|
||||||
|
优点:平台轻、商家灵活。
|
||||||
|
风险/成本:体验碎片化风险大;如果不强制回传规范,平台客服/前端会被迫处理多样差异,长期维护成本更高。
|
||||||
|
|
||||||
|
#### 商家自选配送需要提供的内容(接入清单)
|
||||||
|
|
||||||
|
基础信息(发货侧最小闭环):
|
||||||
|
- `carrier`:承运方标识(可为直连承运方或聚合平台,如 YUNDA/YTO/ZTO/STO/KDN 等)。
|
||||||
|
- `tracking_no`:运单号生成与回传方式(商家生成/第三方返回/平台生成)。
|
||||||
|
- 订单关联信息:`order_no`(或平台侧可解析的业务单号),用于把轨迹绑定到订单详情页。
|
||||||
|
|
||||||
|
轨迹数据接入方式(平台统一接入,推荐第一种):
|
||||||
|
1) 第三方 -> 平台 Webhook 推送(推荐):
|
||||||
|
- 平台与第三方完成订阅/回调配置;第三方直接回调平台 Webhook。
|
||||||
|
- 平台统一完成:验签、防重放、字段映射、状态映射、幂等去重、乱序入库。
|
||||||
|
2) 平台 -> 第三方 轮询拉取(可选补偿):
|
||||||
|
- 平台按承运方策略轮询“长时间无更新”的运单,补齐轨迹。
|
||||||
|
- 适用于第三方不稳定、回调丢失或仅提供查询能力的场景,但平台运维成本更高。
|
||||||
|
|
||||||
|
(高级模式,可选,适用于有自建系统的大商家)
|
||||||
|
- 商家系统 -> 平台:商家按平台统一事件模型回传轨迹事件;平台仍执行幂等/乱序入库与审计。
|
||||||
|
|
||||||
|
对接材料(按商家选择的接入方式提供):
|
||||||
|
- 若商家仅在“平台已接入承运方范围内自选”,通常无需商家提供第三方接口材料。
|
||||||
|
- 若商家使用“独立合同/账号”并要求平台代接入,则需要商家提供或协助申请:
|
||||||
|
- 鉴权信息:`appKey/appSecret`、`token`、证书、公网 IP 白名单等(因第三方而异)。
|
||||||
|
- 回调能力:是否支持订阅 + Webhook(以及重试策略、签名算法、回调白名单)。
|
||||||
|
- 能力说明:是否提供 `event_id`、是否提供 POD/签收凭证、是否需要手机号后四位参与查询等。
|
||||||
|
|
||||||
|
映射配置(用于消除差异化,平台侧必须落库为配置或代码映射):
|
||||||
|
- 事件码/文案 -> 平台 `status_code` 的映射(至少覆盖:揽收/在途/派送中/签收/异常/退回)。
|
||||||
|
- 幂等去重策略:优先 `event_id`;缺失时使用组合键(见 `接口规范.md` 的入库层建议)。
|
||||||
|
|
||||||
|
#### 差异化来源与平台收敛策略
|
||||||
|
差异化来源(商家自选必然存在):
|
||||||
|
- 鉴权差异:Token/HMAC/证书/IP 白名单等。
|
||||||
|
- 字段差异:时间格式、地点粒度、是否有 `event_id`、异常字段命名等。
|
||||||
|
- 状态差异:同一状态不同叫法/码值,甚至“派送/签收/退回”的边界不同。
|
||||||
|
- 交互差异:仅查询(轮询)/订阅回调(Webhook)/两者并存;重试与乱序程度不同。
|
||||||
|
|
||||||
|
平台收敛策略(避免差异扩散到前端与数据库):
|
||||||
|
- 前端只消费平台统一查询接口与统一字段(见 `前端字段清单.md`),不得直接依赖第三方字段。
|
||||||
|
- 平台统一入库模型与幂等/乱序规则(见 `接口规范.md`),第三方差异仅在 Adapter/配置映射层处理。
|
||||||
|
- 分级能力与降级:
|
||||||
|
- 达标(可回传轨迹或可稳定拉取 + 通过验收)-> 展示完整时间线 + 可做告警统计。
|
||||||
|
- 不达标(仅能提供运单号或字段缺失严重)-> 降级为“仅展示运单号/跳转外部查询”,不承诺完整时间线。
|
||||||
|
|
||||||
|
验收建议(商家自配准入):
|
||||||
|
- 必测:重复推送、乱序、延迟、验签失败、缺字段(对应本 Mock 的故障注入项)。
|
||||||
|
- 通过后才允许全量展示/告警统计;未通过仅允许降级展示。
|
||||||
|
|
||||||
|
与 Mock 的关系:
|
||||||
|
- Mock 可作为“平台对接与回归”的验收工具:在第三方未就绪或不可控时,先用 Mock 场景验证幂等/乱序/缺字段容错等;接入真实第三方后也可用于故障注入回归。
|
||||||
|
|
||||||
|
### 方案 C:混合模式(平台默认合作 + 允许商家自配)【推荐】
|
||||||
|
适用:既要平台可控的默认体验,又要给大商家/特殊品类保留弹性。
|
||||||
|
|
||||||
|
规则建议:
|
||||||
|
- 默认:商家走平台合作承运方(覆盖大多数订单,保证体验一致)。
|
||||||
|
- 例外:允许商家自配,但必须满足平台回传规范(至少事件时间/文案/状态映射可得);否则只提供降级展示能力。
|
||||||
|
- 前端:永远只消费平台统一查询接口,不直接依赖第三方字段。
|
||||||
|
|
||||||
|
落地建议(最小闭环):
|
||||||
|
- 平台统一事件表与查询 API 先上线;Mock 先跑通联调与回归。
|
||||||
|
- Phase 1:接 1 家聚合或 1 家主力承运方(平台统一配送)。
|
||||||
|
- Phase 2:开放商家自配(按准入与验收清单接入)。
|
||||||
|
|
||||||
|
## 3. 范围
|
||||||
|
### 3.1 包含
|
||||||
|
- Mock Server 对外提供控制面 API:创建/查询运单、追加事件、运行场景、触发推送、配置回调目标。
|
||||||
|
- Mock Server 向平台推送 Webhook:按统一事件模型、支持 HMAC 验签头。
|
||||||
|
- 事件与场景数据本地持久化(最小可用可内存;建议支持文件落盘,便于复现)。
|
||||||
|
|
||||||
|
### 3.2 不包含
|
||||||
|
- 真实承运方业务能力(计费、真实网点、真实 POD 获取)
|
||||||
|
- 配送员实时定位与地图
|
||||||
|
- 平台侧业务实现(本需求仅定义 Mock Server 的接口与行为)
|
||||||
|
|
||||||
|
## 4. 目标用户
|
||||||
|
- 平台后端开发:联调 Webhook、验签、幂等与入库。
|
||||||
|
- 平台前端开发:使用固定运单/事件数据验证时间线展示。
|
||||||
|
- QA 测试:用故障注入覆盖异常链路与回归。
|
||||||
|
- 运维/对接:用于排查“回调未到/重复到/乱序到”等问题。
|
||||||
|
|
||||||
|
## 4.1 使用端(主要投放端)
|
||||||
|
- 安卓端(App):订单详情页展示物流时间线、签收凭证预览、异常上报。
|
||||||
|
- Web 端(H5/PC 管理后台或用户 Web):同样展示物流时间线,提供更完整的原始事件/审计信息(按权限)。
|
||||||
|
|
||||||
|
## 4.2 平台后台展示建议(客服/履约/对接运维最小集)
|
||||||
|
|
||||||
|
说明:本节定义“平台侧管理后台”在物流模块上建议具备的最小展示与排障能力(不等同于完整订单后台)。
|
||||||
|
|
||||||
|
1) 订单详情页(物流区块)
|
||||||
|
- 基础信息:`order_no`、`carrier`、`tracking_no`、当前 `status_code`、`last_synced_at`
|
||||||
|
- 物流时间线:`status_history`(按 `event_time` 排序,展示 `event_text`,标签使用 `status_code`)
|
||||||
|
- 异常提示:长时间无更新、签收失败、退回等(按 `status_code` 与规则触发)
|
||||||
|
|
||||||
|
2) 运单/轨迹查询页(排障入口)
|
||||||
|
- 支持按 `tracking_no/order_no/carrier/status_code` 查询
|
||||||
|
- 展示最近 N 条事件与来源(mock/承运方/聚合),便于快速定位
|
||||||
|
|
||||||
|
3) 对接日志与审计(运维/对接用)
|
||||||
|
- Webhook 接收日志:验签结果、去重命中、入库结果/错误原因(按权限)
|
||||||
|
- 原始回文:`raw_payload` 折叠展示(仅客服/运维可见,记录访问审计)
|
||||||
|
|
||||||
|
4) 配置中心(对接运维用)
|
||||||
|
- 承运方/聚合平台配置、Webhook 目标与密钥/证书、轮询补偿开关与频率
|
||||||
|
- 测试环境 Mock 开关(默认关闭,需显式开启)
|
||||||
|
|
||||||
|
(可选增强)一致性回查/纠偏入口:按需触发第三方回查,补采缺失事件并保留审计记录。
|
||||||
|
|
||||||
|
## 4.3 商家后台展示建议(商户侧最小集)
|
||||||
|
|
||||||
|
说明:商家只是平台商户时,建议仅提供“发货与运单绑定 + 物流查看”的最小能力。
|
||||||
|
|
||||||
|
- 发货:选择承运方、录入/回填 `tracking_no`、发货确认
|
||||||
|
- 订单详情(物流区块):查看时间线与当前状态(不展示 `raw_payload`)
|
||||||
|
|
||||||
|
端侧差异化要求:
|
||||||
|
- 安卓端需支持弱网/后台切换恢复后的快速刷新;证据图片需支持点击预览/下载。
|
||||||
|
- Web 端需支持表格/筛选/搜索(便于客服排障);对调试信息(raw_payload)默认折叠。
|
||||||
|
|
||||||
|
## 5. 核心概念
|
||||||
|
- 承运方(carrier):YUNDA / YTO / ZTO / STO(可扩展)
|
||||||
|
- 运单(tracking_no):可由 Mock Server 生成或由调用方指定
|
||||||
|
- 事件(event):包含 event_id、event_time、event_code、event_text、node_name、location、evidence_urls 等
|
||||||
|
- 场景(scenario):一组按时间顺序生成的事件脚本(如“标准签收”“拒收退回”“地址异常”)
|
||||||
|
|
||||||
|
## 6. 关键流程
|
||||||
|
1) 配置推送目标:设置平台 Webhook URL、`client_id`、`secret`。
|
||||||
|
2) 创建运单:选择 carrier,生成/指定 tracking_no。
|
||||||
|
3) 运行场景:Mock Server 生成一系列关键节点事件并入库。
|
||||||
|
4) 触发推送:Mock Server 按顺序(或按乱序/延迟策略)将事件推送到平台。
|
||||||
|
5) 平台侧验证:校验验签、去重、入库、前端展示与告警。
|
||||||
|
|
||||||
|
## 7. 功能需求
|
||||||
|
### 7.1 控制面 API(Mock Server)
|
||||||
|
- 配置:设置 webhook 目标、密钥、默认承运方。
|
||||||
|
- 运单:创建/查询/列表。
|
||||||
|
- 事件:追加/查询/清空;支持批量追加。
|
||||||
|
- 场景:运行预置脚本(标准流程/异常流程)。
|
||||||
|
- 推送:立即推送指定运单的全部/增量事件;支持模拟重试与重复。
|
||||||
|
|
||||||
|
### 7.2 Webhook 推送(Mock -> 平台)
|
||||||
|
- 请求头包含 `X-Client-Id`、`X-Timestamp`、`X-Signature`。
|
||||||
|
- body 结构遵循统一事件模型(见 `接口规范.md`)。
|
||||||
|
- 幂等:对同一事件可重复推送,平台需以 `event_id` 去重。
|
||||||
|
|
||||||
|
### 7.3 故障注入(必须)
|
||||||
|
- `delay_ms`:推送延迟
|
||||||
|
- `duplicate`:重复推送次数
|
||||||
|
- `out_of_order`:乱序推送
|
||||||
|
- `bad_signature`:签名错误
|
||||||
|
- `timestamp_skew_seconds`:时间戳偏移
|
||||||
|
- `drop_fields`:缺字段(用于校验平台必填校验与容错)
|
||||||
|
|
||||||
|
## 8. 非功能需求
|
||||||
|
- 易用性:一条命令启动;提供最少的配置即可发送事件。
|
||||||
|
- 可复现:场景运行应可导出/导入(或提供固定随机种子)。
|
||||||
|
- 可观测:每次推送记录 request/response 摘要与 request_id。
|
||||||
|
- 安全:仅用于内网/测试环境;支持简单 Token 或 IP 白名单(可选)。
|
||||||
|
|
||||||
|
端侧体验要求(安卓/Web):
|
||||||
|
- 刷新策略:页面进入时拉取一次平台侧轨迹;用户可手动“刷新物流”;显示 `last_synced_at`。
|
||||||
|
- 离线降级:无网络时展示上次缓存的时间线并提示“网络不可用”。
|
||||||
|
- 权限与隐私:手机号脱敏;`raw_payload` 仅客服/运维可见并记录审计;不展示配送员精确地址/定位。
|
||||||
|
|
||||||
|
## 9. 验收标准
|
||||||
|
- 能创建运单并运行“标准签收”场景,向平台推送至少 6 个关键节点(揽收/到达中转/在途/到达目的地/派送中/签收)。
|
||||||
|
- 能注入重复与乱序事件,平台侧仍能正确去重并按时间线展示。
|
||||||
|
- 能注入验签失败事件,平台侧能拒绝并记录告警。
|
||||||
|
|
||||||
|
## 10. 文档与交付物
|
||||||
|
- `接口规范.md`:Mock Server 控制面 API + Webhook 推送规范
|
||||||
|
- `状态映射表.md`:事件码/原文到平台统一状态映射建议
|
||||||
|
- `前端字段清单.md`:前端展示字段契约(供时间线组件使用)
|
||||||
|
- 数据库 Schema:`mall_sql/schemas/express_tracking_mock_platform.sql`(平台统一轨迹入库 + Mock 承运方持久化表)
|
||||||
|
|
||||||
|
## 11. 待补充项(备忘与下一步)
|
||||||
|
为保证联调、验收与后续接真实承运方不走弯路,建议按优先级补齐:
|
||||||
|
- `缺口与待补充清单.md`
|
||||||
Reference in New Issue
Block a user