12 KiB
12 KiB
| 1 | ID | Title | Description | Acceptance | Test_Method | Tools | Dev_Status | Review1_Status | Regression_Status | Files | Dependencies | Notes |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2 | A1 | R50 执行合同建档与范围冻结 | 创建并校验 R50 通知渠道实际推送执行合同 CSV,冻结范围仅包含 NotificationDelivery 模型、同步 notificationDispatcher、目标 15 类业务通知接入、投递记录查询与个人外部推送开关;明确本轮不改邮件逻辑、不改通知模板结构、不改 outbox worker。 | issues/2026-04-04_r50-notification-push.csv 列完整、Dependencies 为 JSON 数组字符串、Test_Method 可复现;范围仅覆盖 R50,不混入 R49 合同台账增强或新的权限码设计。 | 命令:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-04-04_r50-notification-push.csv。检查:1) 对照 AGENTS.md 与 issues/README.md 确认 12 列完整;2) A2-A8 依赖链符合 backend→frontend→reviewer→qa 收口;3) 方案明确目标事件改为同步 dispatcher,不再继续调用现有 enqueueImNotifications 以避免重复投递。 | manual | DONE | DONE | DONE | issues/2026-04-04_r50-notification-push.csv | [] | 回滚路径:删除本次 CSV 不影响业务。2026-04-04:Issue CSV 已创建并通过 validate_issues_csv.py 校验,范围与依赖已冻结。 |
| 3 | A2 | 通知投递模型与个人偏好迁移 | 在 Prisma schema 中新增 NotificationDelivery 模型与 Employee.notification_push_enabled 字段,补齐关联、索引与迁移脚本,保证默认值兼容存量员工。 | Prisma schema 与迁移可通过校验;Employee.notification_push_enabled 默认 true;NotificationDelivery 可记录 notification_id、channel_id、status、attempt_no、result_code、error_message、response_body、attempted_at;索引满足通知和渠道维度查询。 | 命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd server && npx prisma validate。检查:1) schema.prisma 可通过 validate;2) migration.sql 能创建新表和字段;3) Notes 写明回滚时先下线代码再回滚迁移。 | manual | DONE | DONE | DONE | server/prisma/schema.prisma|server/prisma/migrations | ["A1"] | 回滚路径:先回退应用代码,再执行反向迁移移除 notification_deliveries 表与 employees.notification_push_enabled 字段。2026-04-04:R50 迁移与 schema 已落地,npx prisma validate 通过。2026-04-05:公网 smoke 回归通过,迁移与个人推送偏好链路验收完成。 |
| 4 | A3 | 同步 dispatcher 与投递持久化 | 新增 server/src/services/notificationDispatcher.js,复用现有渠道路由、模板和企微发送逻辑,实现提交事务后的同步外部推送、3 次内重试、delivery 落库与脱敏日志。 | dispatcher 能按 roleCodes/domainScopes/allowedTypes 聚合匹配渠道;过滤 notification_push_enabled=false 的员工;mock、wecom_webhook、429/5xx/timeout、非 retryable 失败、无匹配渠道、IM 总开关关闭等路径均有明确结果;delivery 每次尝试先写 pending 后更新 success/failed。 | 命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd server && node --check src/services/notificationDispatcher.js && npm test -- tests/unit/services/notificationDispatcher.test.js。业务:1) mock 渠道成功落一条 success 记录;2) retryable 错误最多尝试 3 次;3) opt-out 员工不会触发外推;4) 日志不输出标题、正文、金额等敏感内容。 | manual | DONE | DONE | DONE | server/src/services/notificationDispatcher.js|server/src/services/notifications/index.js|server/src/services/notifications/channels.js|server/src/services/notifications/imRouting.js|server/tests/unit/services/notificationDispatcher.test.js | ["A2"] | 回滚路径:恢复到仅站内通知 + 旧 outbox IM 路由,删除 dispatcher 调用。response_body 入库但前端不原样透出。2026-04-04:dispatcher、detailUrl 复用与 delivery 落库已实现;node --check 与 notificationDispatcher.test.js 通过。2026-04-05:公网 smoke 回归通过,dispatcher 投递与重试链路验收完成。 |
| 5 | A4 | 目标业务事件切换到同步外推 | 将 workflow、reimbursements、purchaseRequests、travelRequests、assetMovements、inventoryChecks 六组目标流程从“createNotifications + enqueueImNotifications”切到“createNotifications + notificationDispatcher”,并保持邮件逻辑与业务事务边界不变。 | 15 类目标通知类型全部通过同步 dispatcher 发送;外部推送失败不会回滚业务单据;现有 sendNotificationEmailSafe 行为不回归;auth.js 与 todos.js 保持原行为。 | 命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd server && node --check src/routes/workflow.js && node --check src/routes/reimbursements.js && node --check src/routes/purchaseRequests.js && node --check src/routes/travelRequests.js && node --check src/routes/assetMovements.js && node --check src/routes/inventoryChecks.js && npm test -- tests/unit/routes/reimbursement.submit-side-effects.test.js tests/unit/routes/purchase.submit-side-effects.test.js。业务:1) 审批待办分配仍创建站内通知并同步尝试外推;2) 报销付款、资产分配、盘点完成主流程成功时,即使 webhook 失败也不回滚接口成功结果。 | manual | DONE | DONE | DONE | server/src/routes/workflow.js|server/src/routes/reimbursements.js|server/src/routes/purchaseRequests.js|server/src/routes/travelRequests.js|server/src/routes/assetMovements.js|server/src/routes/inventoryChecks.js|server/tests/unit/routes/reimbursement.submit-side-effects.test.js|server/tests/unit/routes/purchase.submit-side-effects.test.js | ["A3"] | 回滚路径:恢复目标流程中的 enqueueImNotifications 调用并移除 dispatcher 接入。2026-04-04:六组目标路由已切换到事务后同步 dispatcher;相关 node --check 与两组 side-effects 单测通过。2026-04-05:公网 smoke 回归通过,目标业务事件外推链路验收完成。 |
| 6 | A5 | 投递记录查询 API 与个人偏好 API | 扩展 /api/me 响应,新增 PATCH /api/me/notification-preferences 与 GET /api/notifications/deliveries,保证本人只能修改自己的外部推送开关,通知渠道管理员可查询最近投递记录。 | /api/me 返回 notificationPushEnabled;PATCH /api/me/notification-preferences 仅接受 { notificationPushEnabled: boolean };GET /api/notifications/deliveries 支持 notificationId/channelId/status 过滤且权限固定为 notification.channel.manage;返回最近记录含状态、尝试次数、结果码与错误摘要。 | 命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd server && node --check src/routes/me.js && node --check src/routes/notifications.js && npm test -- tests/unit/routes/me.test.js tests/unit/routes/notifications.test.js。业务:1) 登录员工可开关自己的 notificationPushEnabled;2) 无 notification.channel.manage 权限访问 deliveries 返回 403;3) channelId/status 过滤返回正确记录。 | manual | DONE | DONE | DONE | server/src/routes/me.js|server/src/routes/notifications.js|server/tests/unit/routes/me.test.js|server/tests/unit/routes/notifications.test.js | ["A2","A3"] | 回滚路径:恢复 /api/me 原响应并删除新偏好接口与 deliveries 查询接口。2026-04-04:/api/me 与 deliveries 查询已实现;node --check、me.test.js 与 notifications.test.js 通过。2026-04-05:公网 smoke 回归通过,投递记录查询与个人偏好接口验收完成。 |
| 7 | A6 | 通知渠道页投递记录 UI | 扩展 client/src/api/notificationChannels.ts 与 NotificationChannelsPage,新增最近投递记录区域和按渠道/状态筛选,不影响现有渠道 CRUD 与测试发送。 | 通知渠道页能展示最近 delivery 汇总记录,支持 channelId/status 筛选;列表展示渠道名、锚定通知标题摘要、状态、尝试次数、结果码、最近尝试时间、错误摘要;测试发送结果仍只在现有即时结果卡片展示。 | 命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd client && npm run typecheck && npm run build。业务:1) 打开通知渠道页可见 delivery 区域;2) 选择状态或渠道筛选后列表刷新;3) 现有新建/编辑/测试渠道流程不回归。 | manual | DONE | DONE | DONE | client/src/api/notificationChannels.ts|client/src/pages/NotificationChannelsPage.tsx | ["A5"] | 回滚路径:移除 delivery UI 与前端 API 封装,不影响既有渠道配置功能。2026-04-04:NotificationChannelsPage 已新增 recent deliveries 区域和筛选;client typecheck/build 通过。2026-04-05:公网 smoke 回归通过,通知渠道页投递记录展示验收完成。 |
| 8 | A7 | 个人设置页外部推送开关与 auth 状态同步 | 扩展 MeResponse/AuthContext/ProfilePage,新增外部通知推送总开关,并在修改后同步刷新当前会话里的 me 状态。 | 个人设置页可看到外部通知推送说明与 checkbox;保存后当前页面和 AuthContext 中的 notificationPushEnabled 同步更新;关闭后仅停止外部渠道推送,站内通知与企业微信绑定入口不受影响。 | 命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd client && npm run typecheck && npm run build。业务:1) 个人设置页勾选开关后提示成功并刷新当前状态;2) 重新进入页面仍保持后端返回值;3) 个人设置页其余完整档案入口、企业微信绑定卡片不回归。 | manual | DONE | DONE | DONE | client/src/api/auth.ts|client/src/api/types.ts|client/src/auth/AuthContext.tsx|client/src/pages/ProfilePage.tsx | ["A5"] | 回滚路径:删除 notificationPushEnabled 前端字段与开关区块,恢复 ProfilePage 原状。2026-04-04:ProfilePage 已新增外部推送总开关,AuthContext 增加 refreshMe;client typecheck/build 通过。2026-04-05:公网 smoke 回归通过,个人设置页推送开关验收完成。 |
| 9 | A8 | R50 reviewer QA 与收口 | 完成 reviewer 风格复核、后端/前端 post-check、关键业务回归和 CSV 状态回填,确认不存在重复投递、事务回滚误用、权限泄露与隐私日志问题。 | A2-A7 的实现、review 与 regression 证据完整;后端语法/单测、前端 typecheck/build 全部通过;关键业务事件在 mock 或异常 webhook 下均能看到正确的 delivery 结果与个人开关隔离效果。 | 命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd server && npx prisma validate && node --check src/routes/notifications.js && node --check src/routes/me.js && node --check src/services/notificationDispatcher.js && npm test -- tests/unit/services/notificationDispatcher.test.js tests/unit/routes/notifications.test.js tests/unit/routes/me.test.js tests/unit/routes/reimbursement.submit-side-effects.test.js tests/unit/routes/purchase.submit-side-effects.test.js && cd ../client && npm run typecheck && npm run build。业务:1) 启用 mock 渠道后审批/付款/资产/盘点事件产生 delivery 记录;2) webhook 异常时看到最多 3 次尝试并最终 failed;3) 员工关闭外推后相关业务仍保留站内通知。 | manual | DONE | DONE | DONE | issues/2026-04-04_r50-notification-push.csv|server/src/services/notificationDispatcher.js|server/src/routes/notifications.js|server/src/routes/me.js|client/src/pages/NotificationChannelsPage.tsx|client/src/pages/ProfilePage.tsx | ["A4","A6","A7"] | 回滚路径:若发现重复投递或权限问题,先关闭 IM_NOTIFIER_ENABLED/相关渠道并回退本轮代码,再按 A2 Notes 处理迁移回滚。2026-04-04:已完成本地 reviewer 风格复核、git diff --check、Prisma validate、5 组后端单测、client typecheck/build。2026-04-05:公网 smoke 测试通过(OpenClaw 验收 2026-04-05),R50 通知推送主链路回归完成。 |