Feature Specification: 闪送订单状态变更消息推送
Feature Branch: 028-flash-delivery-push
Created: 2026-09-17
Status: Draft
Input: User description: "闪送订单状态变更消息推送:骑手抢单、已取件、已送达推送给用户端;用户/平台取消推送给骑手端。2026-09-18 追加:立即闪送单创建后通知骑手;预约闪送单创建时不通知,进入可抢单时间窗口后再开放展示并通知;外卖和闪送使用不同的新单文案。加小费不推送。"
User Scenarios & Testing (mandatory)
User Story 1 - 寄件用户收到骑手接单通知 (Priority: P1)
寄件用户下单后处于等待状态,骑手抢单成功的瞬间,用户收到一条推送,告知订单已被骑手接单、骑手正在前来取件。
Why this priority: 用户下单后最焦虑的时段是"有没有人接单";接单通知是整个推送体系里价值最高的单条消息,没有它用户只能反复刷新订单页。
Independent Test: 创建一笔待接单的闪送订单,骑手账号执行抢单,验证寄件用户收到"骑手已接单"推送。
Acceptance Scenarios:
- Given 订单状态为 WAITING_ACCEPTANCE,When 骑手抢单成功(状态转为 ACCEPTED),Then 寄件用户在短时间内收到推送,内容表明骑手已接单并包含订单标识。
- Given 抢单因并发失败(订单已被他人抢走或已取消),When 抢单请求落空,Then 不产生任何推送。
User Story 2 - 寄件用户收到取件与送达通知 (Priority: P1)
履约中段,骑手确认取件、确认送达两个节点,寄件用户分别收到推送,掌握物品在途与签收进度。
Why this priority: 与接单通知共同构成完整的履约进度感知;送达通知同时提示用户可去确认收货。
Independent Test: 对一笔已接单订单依次执行取件(附凭证)、送达(附凭证),验证寄件用户先后收到两条对应推送。
Acceptance Scenarios:
- Given 订单状态为 ACCEPTED,When 骑手确认取件成功(状态转为 PICKED_UP),Then 寄件用户收到"骑手已取件"推送。
- Given 订单状态为 PICKED_UP,When 骑手确认送达成功(状态转为 DELIVERED),Then 寄件用户收到"已送达"推送。
- Given 取件或送达操作因校验失败未改变订单状态,When 操作报错返回,Then 不产生推送。
User Story 3 - 骑手收到订单取消通知 (Priority: P2)
订单被取消时,已接单的骑手收到推送,及时停止履约,避免白跑。
Why this priority: 取消是低频事件,但漏通知会导致骑手空跑、产生纠纷;相比履约进度通知优先级略低。
Independent Test: 对一笔已接单订单分别走用户取消、平台取消两条路径,验证骑手收到取消推送;对未接单订单执行取消,验证不产生骑手推送。
Acceptance Scenarios:
- Given 订单已被骑手接单(ACCEPTED/PICKED_UP),When 寄件用户取消订单成功(状态转为 CANCELLED),Then 该骑手收到"订单已取消"推送,内容含订单标识。
- Given 订单已被骑手接单,When 平台取消订单成功,Then 该骑手收到取消推送。
- Given 订单尚未被任何骑手接单(WAITING_ACCEPTANCE,含过期预约单自动取消),When 订单被取消,Then 不产生骑手推送(无推送对象)。
- Given 用户取消请求因状态校验失败,When 取消未生效,Then 不产生推送。
User Story 4 - 骑手及时收到可抢闪送新单通知 (Priority: P1)
符合配送资格且在线的骑手在闪送订单真正可抢时收到新单推送。立即单创建后直接开放;预约单创建时隐藏,进入预约取件时间窗后再开放并推送。
Why this priority: 新单通知决定骑手是否能及时发现任务;预约单必须保证“列表可见”和“推送触发”使用同一个原子开放动作,避免骑手先看到订单、稍后才收到推送。
Independent Test: 分别创建立即单和预约单,验证立即单 isDisplay=true 且创建后推送;预约单初始 isDisplay=false 且不推送,在时间窗内由任务原子切为 true 后只推送一次。
Acceptance Scenarios:
- Given 创建一笔立即闪送单,When 订单保存事务提交,Then 订单立即可见,并向符合配送类型、车型、距离和接单互斥规则的在线骑手发送“有新的闪送订单”。
- Given 创建一笔尚未进入时间窗的预约闪送单,When 创建事务提交,Then
isDisplay=false,骑手列表不可见且不产生新单推送。
- Given 预约单进入
scheduledPickupStartAt <= 当前时间 < scheduledPickupEndAt,When 独立任务执行,Then 以条件更新原子切换 isDisplay=false -> true,同一次成功切换后发送新单推送。
- Given 多个任务实例或连续执行同时处理同一预约单,When 竞争开放资格,Then 只有条件更新成功的一次触发推送,其他执行不重复发送。
- Given 外卖单与闪送单分别发布,When 骑手收到新单推送,Then 文案分别为“有新的外卖订单”和“有新的闪送订单”。
Edge Cases
- 接收方没有有效的设备推送标识(未登录过 App / 标识为空)时:跳过云端推送,但消息记录仍正常生成,且不影响订单操作结果。
- 推送服务调用失败或超时:只记录日志,不重试阻断,订单状态流转结果不受影响。
- 接收方语言设置为越南语/繁中/英语/简中之外或未设置:按平台默认语言回落(与现有订单推送行为一致)。
- 骑手抢单与用户取消并发(一方成功另一方必然失败):只对实际改变了订单状态的一方产生推送。
- 平台连续取消多笔订单:每笔独立推送,互不影响。
- 预约单进入窗口后的任务存在亚秒级调度延迟:在
isDisplay 原子切换前订单保持不可见,因此不会出现先看到订单、后收到推送的一分钟级错位。
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 仅在对应状态变更实际成功后触发;操作失败或未改变状态时不得产生推送。
- FR-012: 立即闪送单创建时
isDisplay MUST 为 true,并在事务提交后触发一次骑手新单通知。
- FR-013: 预约闪送单创建时
isDisplay MUST 为 false,且在开放前不得出现在骑手可抢列表、详情或抢单接口中。
- FR-014: 预约单 MUST 仅在
scheduledPickupStartAt <= 当前时间 < scheduledPickupEndAt 时通过条件更新原子切换 isDisplay=false -> true;仅更新成功者有资格发送通知。
- FR-015: 预约开放任务 MUST 使用独立任务类每秒执行,不与自动完成或预约过期取消任务耦合。
- FR-016: 新单候选骑手 MUST 在线、具备 FLASH 配送类型、车型匹配、位于配置距离内,并遵守普通/加急闪送现有接单互斥规则。
- FR-017: 外卖和闪送的新单推送 MUST 使用不同文案,分别为
no.message.push.new.food.order 与 no.message.push.new.flash.order。
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: 推送服务整体不可用时,抢单/取件/送达/取消接口的成功率与推送上线前持平(推送故障零传导)。
- SC-005: 预约单进入可抢窗口后 2 秒内开放展示并开始异步推送,且同一订单开放通知最多触发一次。
Assumptions
- 复用项目现有推送通道(App 端云函数推送 + 消息入库),不新建推送基础设施,不新增 Android 通道。
- 推送在订单状态变更成功后异步触发,不放在订单操作的事务内。
- 平台取消按需求仅推送骑手端;寄件用户通过订单列表感知取消结果,如需同时通知用户可后续追加需求。
- 超时自动完成、过期预约单自动取消、预约单创建和加小费均不推送(FR-010);立即单创建和预约单开放属于新单通知触发点。
- 推送点击后的客户端跳转(payload 路由到闪送订单详情页)由客户端处理;服务端只保证推送携带订单标识与业务类型。
- 报文文案沿用现有订单推送的文案风格(简短状态描述 + 订单号后缀)。