1
0
forked from erp-dev/erp
Files
erpnew/docs/notifier_module_design.md
2026-04-14 00:03:22 +08:00

5.1 KiB
Raw Blame History

Notifier 模块实现说明

本文档面向后端维护者,描述 notifier 模块当前的实现决策、已落地范围与后续扩展注意事项。

1. 当前阶段

notifier 现已从第一阶段的“Notifier 直接绑定 event_key”升级为第二阶段的“Notifier + NotifierRoute”结构。

这样做的原因是:

  • 一个通知器可能需要绑定多个事件
  • 同一事件需要支持按任务分类路由
  • 同一事件可能同时发往多个不同通知器
  • 后续还可能出现更多路由维度

因此当前模块职责被拆成两层:

  • Notifier:通知渠道配置、模板配置、启停控制
  • NotifierRoute:事件匹配与业务路由规则

2. 当前范围

本阶段已实现:

  • 独立 appnotifier
  • Celery task 化投递
  • 企业微信 webhook 渠道
  • 模板化内容渲染
  • Admin 可配置
  • NotifierRoute 事件路由
  • mission 相关事件按任务分类路由

本阶段仍未做:

  • 旧模块静态通知逻辑迁移
  • 外部 API
  • 通知投递明细表
  • 数据库级别审计

3. 核心模型

3.1 Notifier

Notifier 负责“怎么发”:

  • merchant
  • name
  • channel
  • template_key
  • is_enabled
  • config
  • description

当前 Notifier 已不再直接持有 event_key

3.2 NotifierRoute

NotifierRoute 负责“何时发、发给谁”:

  • merchant
  • notifier
  • event_key
  • mission_category
  • is_enabled
  • description

其中:

  • mission_category = null 表示该事件的通配路由
  • mission_category != null 表示任务分类专用路由

3.3 约束设计

当前约束:

  • Notifier 在同商户下 name 唯一
  • NotifierRoute 在同一 notifier + event_key + mission_category 下唯一
  • NotifierRoute 额外限制同一 notifier + event_key 只能有一条通配路由

4. 路由匹配规则

当前 dispatch_notification_event(...) 的匹配规则为:

  1. 先按 merchant + event_key + route.is_enabled=True + notifier.is_enabled=True 查路由
  2. 如果 payload 中带有 category_id
    • 匹配该分类的专用路由
    • 也允许匹配通配路由
  3. 如果 payload 中没有 category_id
    • 只匹配通配路由
  4. 如果同一个 Notifier 同时命中专用路由和通配路由
    • 只保留一条
    • 优先保留专用路由

这样可以同时满足:

  • 分类专用通知
  • 默认兜底通知
  • 多群并发通知
  • 同一通知器不重复发送

5. 当前调用链

通知链路如下:

  1. mission.services 在事务提交后发 signal
  2. mission.handlers 构造 payload
  3. payload 中已包含 category_idcategory_name
  4. handler 调用 enqueue_notification_event(...)
  5. Celery task 调用 dispatch_notification_event(...)
  6. notifier 根据 route 匹配命中的 Notifier
  7. 渲染模板并调用 backend 发送
  8. 记录路由日志和发送日志

6. 已接入的事件

当前 mission 已接入:

  • mission.created
  • mission.replied
  • mission.completed
  • mission.reply_rejected
  • mission.reopened
  • mission.cancelled

这些事件全部支持按任务分类路由。

7. 日志策略

当前日志覆盖以下节点:

  • 事件入队
  • 没有命中任何可用路由
  • 路由命中成功
  • backend 发送成功
  • 单个通知发送失败

当前已增加 route 维度日志,重点字段包括:

  • event_key
  • merchant_id
  • route_id
  • route_mission_category_id
  • notifier_id

8. Admin 现状

当前后台提供两个对象:

  • Notifier
  • NotifierRoute

并且:

  • Notifier 页面支持 inline 维护其下路由
  • NotifierRoute 也支持单独管理

Notifier inline 场景下route 的 merchant 会自动同步为当前 notifier 的商户,避免管理人员重复录入。

9. 迁移策略

本次从旧结构迁到新结构时,做了自动回填:

  • 对每条旧 Notifier(event_key=...)
  • 自动创建一条 NotifierRoute
  • event_key 原样继承
  • mission_category = null
  • description 标记为自动迁移生成

这样旧配置不会因为结构调整而丢失。

10. 测试覆盖重点

当前测试已覆盖:

  • 模板渲染
  • backend 发送
  • 路由按事件匹配
  • 分类专用路由优先于通配路由
  • 无专用路由时回退到通配路由
  • 任务事件 handler 正常入队

11. 当前风险与注意点

11.1 当前只对 mission 做了分类路由

当前 mission_category 是显式写进 NotifierRoute 的业务字段。
这适合当前目标,但如果未来要扩展到其它业务模型的复杂路由,可能需要更抽象的路由条件模型。

11.2 config 仍是自由 JSON

后台录入错误仍可能在发送时才暴露。
当前依赖日志排查,后续可增加更强校验。

11.3 模板校验仍在发送期暴露

template_key 如果写错,会在渲染阶段报错并记录日志。
后续可在 admin 或 model clean 中增强校验。

12. 当前结论

当前 notifier 已具备:

  • 通知器配置
  • 路由配置
  • 分类分发
  • 任务事件按分类路由
  • 管理后台操作支持
  • 日志与测试保障

这已经足以支撑你当前提出的“所有任务事件都支持按任务分类路由”的要求。