Input: Design documents from /specs/028-flash-delivery-push/
Prerequisites: plan.md (required), spec.md (required for user stories), research.md, data-model.md, contracts/push.md
Tests: quickstart.md「自动验证」明确要求单测(FlashDeliveryNotificationServiceTest 新建 + FlashDeliveryApplicationServiceTest 扩展),故包含测试任务且先行(红→绿)。
Organization: Tasks are grouped by user story to enable independent implementation and testing of each story.
[ID] [P?] [Story] Descriptionruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/export JAVA_HOME="C:/Users/qmj/.jdks/graalvm-jdk-21.0.7" && export PATH="$JAVA_HOME/bin:$PATH" && mvn -pl ruoyi-admin -am test -Dtest='...'Purpose: 确认基线全绿,避免把存量问题带进本特性
mvn -pl ruoyi-admin -am test -Dtest='FlashDeliveryApplicationServiceTest,FlashDeliveryStateMachineTest,FlashDeliveryControllerContractTest'(JDK21 环境变量见 Path Conventions)——基线 79 测试 1 存量失败(createRejectsUnsupportedPayType,源于在途 payType 白名单注释改动,非本特性范围,全程保持不新增失败即可)Purpose: 通知服务基础设施 + 应用服务装配,所有 user story 依赖
ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/service/FlashDeliveryNotificationService.java:@Service;构造器注入 InfoUserMapper(com.ruoyi.system.mapper)与 PushEventService(com.ruoyi.app.utils.event);私有 runAfterCommit(Runnable)(镜像 DeliveryOrderNotificationService.java:156-167);包级可见 sendToUser(FlashDeliveryOrder, String contentKey) / sendToRider(FlashDeliveryOrder, String contentKey):runAfterCommit → userMapper.selectById 取 InfoUser → AsyncManager.me().execute(TimerTask) → PayPush.userPushHandleLocal / qsPushHandleLocal,title 固定 no.message.push.message,body=OrderPushBodyDto.getJson(order.getOrderNo(), 状态串, -1, 3),ddId=order.getOrderNo();推送异常捕获仅记日志不上抛FlashDeliveryApplicationService.java:76-94 构造器追加第 10 个依赖 FlashDeliveryNotificationService 并存字段;全仓更新 new FlashDeliveryApplicationService( 调用点(ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/service/FlashDeliveryApplicationServiceTest.java 等,先 grep 定位)补 mock 参数;编译并运行 T001 测试集保持全绿Checkpoint: 通知服务骨架就绪且零行为变化(尚无 notify 入口被调用)
Goal: 骑手抢单成功后,寄件用户收到「骑手已接单,NO:{orderNo}」推送与消息中心记录
Independent Test: 对一笔 WAITING_ACCEPTANCE 订单执行 accept 成功 → 验证 notifyAccepted 被调用;抢单失败(条件更新 0 行)→ 不调用
ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/service/FlashDeliveryNotificationServiceTest.java:spy 服务 + doNothing 打断 sendToUser/sendToRider(镜像 DeliveryOrderNotificationServiceTest.java 手法),断言 notifyAccepted(order) 走 sendToUser(order, "no.message.push.delivery.personnel.receiving.order");同时在 FlashDeliveryApplicationServiceTest.java 增补:accept 成功路径 verify notifyAccepted、orderMapper.accept 返回 0 时 never 调用FlashDeliveryNotificationService.java 实现 notifyAccepted(FlashDeliveryOrder)(runAfterCommit 后推 userId,状态串 ACCEPTED);在 FlashDeliveryApplicationService.java accept(约 :485 writeLog 之后、return 之前,withLock lambda 内)调用 notificationService.notifyAccepted(target)mvn -pl ruoyi-admin -am test -Dtest='FlashDeliveryNotificationServiceTest,FlashDeliveryApplicationServiceTest' 确认由红转绿Checkpoint: MVP——抢单通知可独立演示(quickstart.md 手动场景 3)
Goal: 骑手取件、送达成功后,寄件用户分别收到「骑手配送中」「骑手已送达」推送
Independent Test: 对 ACCEPTED 订单 pickup 成功 → notifyPickedUp;对 PICKED_UP 订单 deliver 成功 → notifyDelivered;任一失败 → 不调用
FlashDeliveryNotificationServiceTest.java 增补:notifyPickedUp 走 sendToUser(order, "no.message.push.delivery.personnel.qspsz.order")、notifyDelivered 走 sendToUser(order, "no.message.push.delivery.personnel.qsysd.order");FlashDeliveryApplicationServiceTest.java 增补:transitionWithProof 成功按 next 分派对应 notify、orderMapper.transitionByRider 返回 0 时两者均 neverFlashDeliveryNotificationService.java 实现 notifyPickedUp / notifyDelivered(状态串 PICKED_UP / DELIVERED);FlashDeliveryApplicationService.java transitionWithProof(约 :781 writeLog 之后)按 next 参数分派调用(仅 PICKED_UP/DELIVERED 两值,其它忽略)Checkpoint: 履约进度通知完整(quickstart.md 手动场景 4、5)
Goal: 用户/平台取消成功且已有接单骑手时,骑手收到「订单已取消,NO:{orderNo}」推送;未接单取消零推送
Independent Test: ACCEPTED 状态 userCancel/adminCancel 成功 → notifyCancelled;WAITING_ACCEPTANCE 取消(riderId 空)→ 跳过;取消失败 → 不调用
FlashDeliveryNotificationServiceTest.java 增补:notifyCancelled(order) 在 riderId 非空时走 sendToRider(order, "no.message.push.order.cancelled")、riderId 为空时零交互;FlashDeliveryApplicationServiceTest.java 增补:userCancel/adminCancel 成功路径 verify notifyCancelled、orderMapper.cancel 返回 0 时 neverFlashDeliveryNotificationService.java 实现 notifyCancelled(riderId 判空跳过,状态串 CANCELLED,推骑手端);FlashDeliveryApplicationService.java 在 userCancel(约 :397)与 adminCancel(约 :622)的 writeLog 之后调用Checkpoint: 取消通知完整(quickstart.md 手动场景 6、7、8)
Purpose: 排除事件防回归 + 全量验证
FlashDeliveryApplicationServiceTest.java 对 complete、cancelExpiredScheduledOrder、tipAdd、create 增加 notificationService 零交互(verifyNoInteractions 或 never)断言;FlashDeliveryAutoCompleteTaskTest.java 如涉及应用服务 mock 一并核对mvn -pl ruoyi-admin -am test 455 测试仅 1 个已知存量失败(createRejectsUnsupportedPayType,在途 payType 特性所致);编译通过;git status 确认本特性改动仅 4 个代码文件(2 新建 2 增量)+ specs/028 + CLAUDE.md + feature.json,其余为并行在途特性(预约单窗口)的既有改动mvn -pl ruoyi-admin -am test(全部模块测试)+ mvn -pl ruoyi-admin -am compile 通过;grep 确认闪送模块外无文件改动(git status 仅闪送相关文件与 specs/028)updatesql/sql.md 新条目(零数据库变更)、无 i18n 文件改动(零新 key,全部复用 no.message.push.*)、ruoyi-system 零改动;工作树中 i18n/sql.md/system 变更均属并行在途特性,与 028 无关确认无 updatesql/sql.md 新条目需求(零数据库变更)、无 i18n 文件改动(零新 key)、ruoyi-system 零改动;如有偏差回填 specs/028-flash-delivery-push/research.mdFlashDeliveryApplicationService.java 与两个测试类),必须按 US1 → US2 → US3 顺序串行执行,不可并行每个 story 完成即独立可测、可部署的增量;US1 单独上线即可解决"用户不知是否被接单"的核心痛点。
/speckit-git-commit)*/ 序列;保留 CRLF;不格式化整文件