Branch: 028-flash-delivery-push | Date: 2026-09-17 | Spec: spec.md
Input: Feature specification from /specs/028-flash-delivery-push/spec.md
在闪送订单五个状态变更点(骑手抢单、取件、送达、用户取消、平台取消)接入既有推送通道:新建 FlashDeliveryNotificationService(镜像 DeliveryOrderNotificationService 的 afterCommit + AsyncManager + PayPush 模式),由 FlashDeliveryApplicationService 在条件更新成功后调用。履约事件推寄件用户、取消事件推接单骑手;复用现有 i18n 文案 key 与 OrderPushBodyDto payload(pushType=3)。零新表、零新接口、零新翻译(详见 research.md)。
Language/Version: Java 21(Spring Boot + MyBatis-Plus)
Primary Dependencies: Spring 事务同步(TransactionSynchronizationManager)、AsyncManager、PayPush(uni 云函数推送)、PushEventService(push_message 入库)、fastjson(payload 序列化)
Storage: MySQL(只读 flash_delivery_order、info_user;只写既有 push_message,经由 PushEventService)
Testing: JUnit 5 + Mockito(spy+doNothing 打断网络发送,验证路由决策;仓库先例 DeliveryOrderNotificationServiceTest)
Target Platform: Windows 开发 / Linux 部署的 Spring Boot 服务
Project Type: web-service(多模块 Maven:ruoyi-admin → ruoyi-system)
Performance Goals: 推送异步执行,不增加订单接口耗时(SC-004 零传导)
Constraints: 推送失败不得影响状态流转(FR-009);仅事务提交后触发(FR-011);不新增 Android 通道
Scale/Scope: 1 个新服务类 + 1 个应用服务的 5 个方法加钩子 + 2 个测试类
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
.specify/memory/constitution.md 为未定制的占位模板,无项目级原则可引用;改按仓库 CLAUDE.md 约束逐条核对:
| 约束 | 结论 |
|---|---|
| Controller 参数规范 | 不涉及(无新 Controller/接口改动) |
| 模块边界:集成代码放 ruoyi-admin | ✅ 通知服务放 ruoyi-admin 的 com.ruoyi.app.flashdelivery.service,不进 ruoyi-system |
| 数据库变更须写 updatesql/sql.md | ✅ 本特性零数据库变更 |
| 全栈字段清单 | ✅ 无新字段 |
Java 注释安全(无 */ 序列) |
✅ 实现时遵守 |
| 前端 i18n 规范 | 不涉及(复用后端既有文案 key,无前端改动) |
| CRLF 保留、不格式化整文件 | ✅ 实现时遵守 |
无违规,无需 Complexity Tracking 条目。
specs/028-flash-delivery-push/
├── plan.md # This file (/speckit-plan command output)
├── research.md # Phase 0 output (/speckit-plan command)
├── data-model.md # Phase 1 output (/speckit-plan command)
├── quickstart.md # Phase 1 output (/speckit-plan command)
├── contracts/
│ └── push.md # 推送 payload 契约(Phase 1 output)
└── tasks.md # Phase 2 output (/speckit-tasks command - NOT created by /speckit-plan)
ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/
└── service/
├── FlashDeliveryApplicationService.java # 修改:构造器 + 5 个方法的成功路径加通知钩子
└── FlashDeliveryNotificationService.java # 新增:推送路由(afterCommit + AsyncManager + PayPush)
ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/
└── service/
├── FlashDeliveryApplicationServiceTest.java # 修改:构造器新参 + 推送触发/不触发断言
└── FlashDeliveryNotificationServiceTest.java # 新增:接收人判定与跳过逻辑
Structure Decision: 完全落在闪送模块既有目录结构内,不新增包、不动 ruoyi-system、不动 Controller 层。
notifyAccepted(order) / notifyPickedUp(order) / notifyDelivered(order) / notifyCancelled(order);入参用事务前读到的 FlashDeliveryOrder(只消费 orderNo/userId/riderId 等不可变字段,不依赖其 status 快照)。accept:withLock 内 writeLog(...) 之后、return 之前;pickup/deliver:共用 transitionWithProof 的 writeLog(...) 之后,按 next 参数分派(PICKED_UP/DELIVERED);userCancel/adminCancel:writeLog(...) 之后,notifyCancelled 内部判 riderId 判空。FlashDeliveryApplicationService 追加第 10 个依赖 FlashDeliveryNotificationService;同步更新既有测试的构造调用。runAfterCommit → userMapper.selectById 取 cid → AsyncManager.me().execute → PayPush.userPushHandleLocal / qsPushHandleLocal(title=no.message.push.message,content key 见 research.md D2,body=OrderPushBodyDto.getJson(orderNo, status, -1, 3))。create、tipAdd、complete、FlashDeliveryAutoCompleteTask、cancelExpiredScheduledOrder 一律不调用通知服务。无 Constitution Check 违规,本节为空。