# Feature Specification: 闪送订单状态变更消息推送 **Feature Branch**: `028-flash-delivery-push` **Created**: 2026-09-17 **Status**: Draft **Input**: User description: "闪送订单状态变更消息推送:骑手抢单、已取件、已送达推送给用户端;用户/平台取消推送给骑手端。新任务发布(待抢单)不推送,加小费不推送。" ## User Scenarios & Testing *(mandatory)* ### User Story 1 - 寄件用户收到骑手接单通知 (Priority: P1) 寄件用户下单后处于等待状态,骑手抢单成功的瞬间,用户收到一条推送,告知订单已被骑手接单、骑手正在前来取件。 **Why this priority**: 用户下单后最焦虑的时段是"有没有人接单";接单通知是整个推送体系里价值最高的单条消息,没有它用户只能反复刷新订单页。 **Independent Test**: 创建一笔待接单的闪送订单,骑手账号执行抢单,验证寄件用户收到"骑手已接单"推送。 **Acceptance Scenarios**: 1. **Given** 订单状态为 WAITING_ACCEPTANCE,**When** 骑手抢单成功(状态转为 ACCEPTED),**Then** 寄件用户在短时间内收到推送,内容表明骑手已接单并包含订单标识。 2. **Given** 抢单因并发失败(订单已被他人抢走或已取消),**When** 抢单请求落空,**Then** 不产生任何推送。 --- ### User Story 2 - 寄件用户收到取件与送达通知 (Priority: P1) 履约中段,骑手确认取件、确认送达两个节点,寄件用户分别收到推送,掌握物品在途与签收进度。 **Why this priority**: 与接单通知共同构成完整的履约进度感知;送达通知同时提示用户可去确认收货。 **Independent Test**: 对一笔已接单订单依次执行取件(附凭证)、送达(附凭证),验证寄件用户先后收到两条对应推送。 **Acceptance Scenarios**: 1. **Given** 订单状态为 ACCEPTED,**When** 骑手确认取件成功(状态转为 PICKED_UP),**Then** 寄件用户收到"骑手已取件"推送。 2. **Given** 订单状态为 PICKED_UP,**When** 骑手确认送达成功(状态转为 DELIVERED),**Then** 寄件用户收到"已送达"推送。 3. **Given** 取件或送达操作因校验失败未改变订单状态,**When** 操作报错返回,**Then** 不产生推送。 --- ### User Story 3 - 骑手收到订单取消通知 (Priority: P2) 订单被取消时,已接单的骑手收到推送,及时停止履约,避免白跑。 **Why this priority**: 取消是低频事件,但漏通知会导致骑手空跑、产生纠纷;相比履约进度通知优先级略低。 **Independent Test**: 对一笔已接单订单分别走用户取消、平台取消两条路径,验证骑手收到取消推送;对未接单订单执行取消,验证不产生骑手推送。 **Acceptance Scenarios**: 1. **Given** 订单已被骑手接单(ACCEPTED/PICKED_UP),**When** 寄件用户取消订单成功(状态转为 CANCELLED),**Then** 该骑手收到"订单已取消"推送,内容含订单标识。 2. **Given** 订单已被骑手接单,**When** 平台取消订单成功,**Then** 该骑手收到取消推送。 3. **Given** 订单尚未被任何骑手接单(WAITING_ACCEPTANCE,含过期预约单自动取消),**When** 订单被取消,**Then** 不产生骑手推送(无推送对象)。 4. **Given** 用户取消请求因状态校验失败,**When** 取消未生效,**Then** 不产生推送。 ### Edge Cases - 接收方没有有效的设备推送标识(未登录过 App / 标识为空)时:跳过云端推送,但消息记录仍正常生成,且不影响订单操作结果。 - 推送服务调用失败或超时:只记录日志,不重试阻断,订单状态流转结果不受影响。 - 接收方语言设置为越南语/繁中/英语/简中之外或未设置:按平台默认语言回落(与现有订单推送行为一致)。 - 骑手抢单与用户取消并发(一方成功另一方必然失败):只对实际改变了订单状态的一方产生推送。 - 平台连续取消多笔订单:每笔独立推送,互不影响。 ## Requirements *(mandatory)* ### Functional Requirements - **FR-001**: 骑手抢单成功(WAITING_ACCEPTANCE → ACCEPTED)后,系统 MUST 向寄件用户发送"骑手已接单"推送通知。 - **FR-002**: 骑手确认取件成功(ACCEPTED → PICKED_UP)后,系统 MUST 向寄件用户发送"骑手已取件"推送通知。 - **FR-003**: 骑手确认送达成功(PICKED_UP → DELIVERED)后,系统 MUST 向寄件用户发送"已送达"推送通知。 - **FR-004**: 寄件用户取消订单成功(状态转为 CANCELLED)且订单已有接单骑手时,系统 MUST 向该骑手发送"订单已取消"推送通知。 - **FR-005**: 平台取消订单成功且订单已有接单骑手时,系统 MUST 向该骑手发送"订单已取消"推送通知。 - **FR-006**: 所有推送文案 MUST 支持四种语言(vi、zh、tw、en),按接收方用户的语言设置呈现。 - **FR-007**: 每条推送内容 MUST 包含订单标识(订单号),使接收方无需打开 App 搜索即可定位订单。 - **FR-008**: 每条推送 MUST 同步生成消息记录(复用现有消息中心机制),用户/骑手可在消息列表中回看。 - **FR-009**: 推送环节的任何失败(无设备标识、推送服务异常)MUST NOT 影响订单状态流转本身,也 MUST NOT 向操作方返回错误。 - **FR-010**: 以下事件明确不推送:新订单发布(待抢单)不向骑手推送;加小费不产生推送;超时自动完成(DELIVERED → COMPLETED)不推送;过期预约单自动取消不推送。 - **FR-011**: 推送 MUST 仅在对应状态变更实际成功后触发;操作失败或未改变状态时不得产生推送。 ### Key Entities *(include if feature involves data)* - **推送通知(Push Notification)**: 一次状态变更事件产生的一条通知,属性包括接收方(寄件用户或接单骑手)、事件类型(接单/取件/送达/取消)、标题与正文(按语言)、关联订单标识;复用现有消息记录实体落地,不新增独立数据模型。 ## Success Criteria *(mandatory)* ### Measurable Outcomes - **SC-001**: 任一在推送范围内的事件(抢单、取件、送达、取消)成功发生后,接收方在 10 秒内收到推送(推送服务正常的前提下)。 - **SC-002**: 四种语言设置的用户各抽检一批推送,文案语言与用户设置一致的比例为 100%。 - **SC-003**: 抽检的全部推送均含订单号,接收方可凭推送内容直接定位订单,达标率 100%。 - **SC-004**: 推送服务整体不可用时,抢单/取件/送达/取消接口的成功率与推送上线前持平(推送故障零传导)。 ## Assumptions - 复用项目现有推送通道(App 端云函数推送 + 消息入库),不新建推送基础设施,不新增 Android 通道。 - 推送在订单状态变更成功后异步触发,不放在订单操作的事务内。 - 平台取消按需求仅推送骑手端;寄件用户通过订单列表感知取消结果,如需同时通知用户可后续追加需求。 - 超时自动完成、过期预约单自动取消、新单发布、加小费均在范围外(FR-010)。 - 推送点击后的客户端跳转(payload 路由到闪送订单详情页)由客户端处理;服务端只保证推送携带订单标识与业务类型。 - 报文文案沿用现有订单推送的文案风格(简短状态描述 + 订单号后缀)。