plan.md 10 KB

用户通知 eventScene Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:executing-plans for inline execution; use superpowers:subagent-driven-development only if the user selects that method. Steps use checkbox syntax for tracking.

Goal: 只在既有用户订单通知中新增 eventScene,供前端控制前台语音,并交付接入文档。

Architecture: 使用现有 OrderPushBodyDto 增加一个可选场景及用户专用 JSON 工厂,实际成功动作明确传入枚举。用户通知入库与外部发送复用同一个 body;旧工厂和商家/骑手通知不增加场景。App、音频、云函数及声音配置均不修改。

Tech Stack: Java 21、Spring Boot、既有 JSON 工具、事务同步、JUnit 5/Mockito、uniPush/FCM/APNs。

Spec: spec.md

Date / Branch / Progress: 2026-10-09 / 当前 test-202609v2 / 已验证(本期后端测试、构建及审查修复通过;全量回归 1 项基线失败另记,未部署)。

Global Constraints

  • 原分支工作,不创建 worktree、不切换/合并/改写其他分支。
  • 只新增 eventScene,不生成事件 ID,不传语音语种、接收账号或时间,不提供替代字段/额外接口。
  • 不修改 App、原生插件、云函数、PC、数据库结构、声音/通知渠道、支付退款或配送状态机。
  • 保留 ddId/state/type/pushType;不占用 type=0,不靠中文正文或跨入口的通用 state 判断场景。
  • 只覆盖当前实际用户通知,不新增闪送用户取消、超时、退款等通知时机。
  • 文字保留当前 Locale;前端按自身设置选音频,不能保证文字/声音语种一致。
  • 无设备地址仍写用户消息;推送失败不改变业务结果,事务回滚不发成功通知。
  • 关键代码写注释,保留文件编码和换行;集成代码放 ruoyi-admin。
  • 前端采用统一接收入口;本期没有足够字段保证精准去重、乱序识别或跨账号过滤,不在文档承诺这些能力。

Review Focus

  1. 旧 JSON 和新 JSON 的差异仅 eventScene;Task 1 精确断言键集合、旧字段值。
  2. 同一动作通知用户/商家/骑手时不能污染非用户 body;Task 2/3 分别捕获参数。
  3. 无 CID/token 时不能跳过用户消息记录;Task 2/4 断言入库一次、外发零次。
  4. 自配送直接送达、闪送部分取件、失败/回滚不能虚构成功场景;Task 2 断言调用次数。
  5. 推送异常和默认声音不能因场景改动改变订单结果或渠道;Task 3/4 回归;客户端去重等限制由文档交接。

Technical Context / Constitution Check

push_message.body 已保存完整 JSON,FCM/APNs 已转发完整 payload;无需新表、SQL、顶层字段或云函数改动。.specify/memory/constitution.md 是未填写模板,按 AGENTS.md 和用户最新范围执行,无需例外。

本次实现及本地验证不运行真实支付、数据库操作或生产推送,不读取凭据。已取消此前 UserNotificationPayload 类、事件 ID/语言映射封装和用户推送重载的计划,不改 PayPush 本地化逻辑。

Project Structure / Interfaces

后端根目录 D:/QtwCode/foodie/foodie-server;以下生产路径以 ruoyi-admin/src/main/java/com/ruoyi/app/ 为基准,测试路径以 ruoyi-admin/src/test/java/com/ruoyi/app/ 为基准。

  • 新建 push/UserNotificationScene.java:七个允许值,枚举名称为协议值。
  • 修改 order/dto/OrderPushBodyDto.java:新增可选 String eventScene;新增静态工厂: getUserJson(String ddId, String state, int type, int pushType, UserNotificationScene scene): String。
  • 工厂使用原构造方式,scene 非空才设置场景。旧 getJson/getMap 保持输出,null 场景不输出该 key,不新增其他字段。
  • 闪送用户方法改为 sendToUser(InfoUser recipient, FlashDeliveryOrder order, String status, String contentKey, UserNotificationScene scene): void。
  • 自配送用户方法改为 pushSelfDeliveryStatus(PosOrder order, String contentKey, String stateStr, UserNotificationScene scene): void,按原事务存在与否在成功提交/持久化后调度。
  • 其他现有用户包装签名不变,收到带 eventScene 的 body 后照常入库/发送,不重新解释场景。
  • 文档集中在本目录 spec.md、plan.md、tasks.md、frontend-integration.md、checklists/requirements.md。

Task 1: 单字段场景契约(US2/US3)

Files: 新建 push/UserNotificationScene.java、测试 order/dto/OrderPushBodyDtoTest.java;修改 order/dto/OrderPushBodyDto.java。

Interfaces: 产出上述 getUserJson 和七场景枚举;不再创建额外 payload 封装类。

  • 写测试 preservesLegacyFieldsAndAddsOnlyEventScene:旧四字段原值不变,新键集合仅多 eventScene;oldFactoryOmitsEventScene 断言旧 getJson/getMap 无新增 key;覆盖枚举七值及 null 场景。
  • 运行 Task 1 定向测试,确认因新工厂/场景缺失的预期失败;实现可选字段、用户工厂和 enum,并加兼容注释。
  • 重跑要求零失败,核对 DTO 序列化没有额外 null 字段,检查差异和暂存范围后独立本地提交,不推送。

Task 2: 外卖、闪送、自配送和出餐(US1/US4)

Files: 修改 order/PosOrderQsOprateController.java、order/PosOrderController.java、order/PosOrderShOprateController.java、flashdelivery/service/FlashDeliveryNotificationService.java。扩展测试 order/PosOrderQsOprateControllerTest.java、order/PosOrderAdminStatusControllerTest.java、order/PosOrderShOprateControllerTest.java、flashdelivery/service/FlashDeliveryNotificationServiceTest.java、flashdelivery/service/FlashDeliveryMultiPickupTest.java。

Interfaces: 使用 Task 1 getUserJson,仅用户 body 带场景。现代 deliveryStatus 1/2/3 的成功动作对应 RIDER_ACCEPTED/ORDER_DELIVERING/ORDER_DELIVERED;现有有效旧入口内部 state 3/4/12 分别明确对应这三个动作,不改 state 值。

  • 写并运行预期失败测试:成功三节点场景正确、无地址消息不丢、失败/回滚零成功通知、部分取件零派送、全部取件一次派送、自配送直接完成仅送达、非用户 body 无场景。
  • 成功动作传明确枚举;自配送商家接单 MERCHANT_ACCEPTED、出餐 MERCHANT_READY、开始/完成 ORDER_DELIVERING/ORDER_DELIVERED,不误播骑手接单。
  • 移除仅针对用户入库的地址前置阻断,外发仍由原通道判断;存在事务时 afterCommit,无事务时持久化成功后发送,不扩张支付/发票/账单事务。
  • 跑 Task 2 测试捕获实际调用参数,零失败后审阅并独立本地提交,不推送。

Task 3: 现有支付成功与取消(US3/US4)

Files: 修改 pay/LinePayOrderNotificationService.java、omgpay/OmgPaymentNotifyService.java、order/DeliveryOrderNotificationService.java;扩展同目录对应三份现有测试。

Interfaces: 用户专用 getUserJson body 复用于 PublisherEvent/BusinessPushService;商家/骑手用原始独立 body。

  • 写并运行预期失败测试:用户支付 PAYMENT_SUCCEEDED、用户取消 ORDER_CANCELLED;type=0 原值不变,同动作非用户 payload 无 eventScene,无地址仍入库。
  • 仅改现有提交后用户通知,不改 OMG/LINE 验签、核销、幂等、退款、查询或通知对象;不新增闪送用户取消。016 plan 已读。
  • 跑三组定向测试,包括重复支付不新增成功通知,检查差异后独立本地提交,不推送。

Task 4: 兼容验证和文档交接(全部故事)

Files: 扩展测试 push/BusinessPushServiceTest.java、push/FcmPushSenderTest.java、push/ApnsPushSenderTest.java、utils/event/PushEventListenerTest.java,收口本目录文档。

Interfaces: 验证现有完整 payload 保留 eventScene,不增加顶层字段、不改声音。只有测试确证 uni 用户 GET 编码破坏 JSON 时,才在 utils/PayPush.java 修该路径参数编码,不改云函数。

  • 写并运行通道/入库测试:完整 JSON 场景保持、body 一致、缺地址仅入库、通道异常不补发或影响业务、旧 payload 和 default sound/qsRing/pushsound.caf 不变。
  • 对照最终代码收口接入文档;明确仅一个新增字段、前端选语言、无事件 ID 等限制,记录后端与 App 验证边界。
  • 跑下方定向测试和模块构建、diff 和暂存检查,零失败后本地提交。不要自动推送、部署或生产试发。

Verification Commands

执行时每 Task 缩小同一 -Dtest 列表,先证明预期失败再通过;既有通道透传只增加回归测试,不改发送实现。控制器公共场景/事务夹具集中在 UserOrderNotificationSceneTest。

$env:JAVA_HOME = 'C:/Users/99029/.jdks/graalvm-jdk-21.0.12+7.1'
$env:PATH = "$env:JAVA_HOME/bin;$env:PATH"
mvn -pl ruoyi-admin -am '-Dtest=OrderPushBodyDtoTest,UserOrderNotificationSceneTest,PosOrderQsOprateControllerTest,PosOrderShOprateControllerTest,PosOrderAdminStatusControllerTest,FlashDeliveryNotificationServiceTest,FlashDeliveryMultiPickupTest,LinePayOrderNotificationServiceTest,OmgPaymentNotifyServiceTest,DeliveryOrderNotificationServiceTest,BusinessPushServiceTest,FcmPushSenderTest,ApnsPushSenderTest,PushEventListenerTest' '-Dsurefire.failIfNoSpecifiedTests=false' test
mvn -pl ruoyi-admin -am -DskipTests package
git diff --check

预期测试零失败/零错误、两次 BUILD SUCCESS、diff 检查退出码 0。Java 环境只对当前进程生效,不改全局配置。实际云端场景透传及 App 真机声音由联调核验,未执行必须单独记录。

Dependencies / Handoff

Task 1 → Task 2 → Task 3 → Task 4;详单见 tasks.md。用户已确认继续,按本计划顺序实施;不创建分支或 worktree。收口时依执行计划技能安排一次只读整体审查,不分派实现任务。

最终执行结果

  • 实际业务动作明确传场景;共用旧资料编辑通知的二参 chuCan 不带场景,真正出餐入口调用私有三参版本传 MERCHANT_READY。
  • 定向测试 152/152、独立商家/场景测试 33/33、修复后模块 package BUILD SUCCESS,差异格式检查通过。
  • 一次只读整体审查仅发现上述误分类 Important,已按失败回归修复;无 Critical/Minor,不重新派发审查。
  • 扩展全模块测试的 admin 947 项中有 1 项基线泰文键集合失败,不修范围外语言包、不推送或部署。App/云端与真机验收交接前端。完整记录及实施取舍见 tasks.md。