1
0
forked from erp-dev/erp
Files
erpnew/docs/notifier_module_design.md
2026-04-13 12:30:33 +08:00

6.4 KiB
Raw Blame History

Notifier 模块实现说明

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

1. 背景与目标

项目原有的通知能力主要以企业微信机器人为主,并且配置集中在 settings.py 中,属于静态配置方案。
新的 mission 模块希望从一开始就采用:

  • 独立 Django app
  • task 化投递
  • 后台可配置
  • signal 与 notifier 动态绑定
  • 为后续增加其它通知渠道预留统一接口

因此本次新增独立模块 notifier,并先将 mission 的新信号通知接入该模块。

2. 当前范围

本次实现属于 Phase 1范围有意收敛

  • 已新增独立 appnotifier
  • 已支持后台配置 Notifier
  • 已支持按 event_key + merchant 动态匹配通知器
  • 已支持 Celery task 化派发
  • 已支持模板化内容渲染
  • 已支持第一种渠道:企业微信机器人 webhook
  • 已接入 mission 的 6 个业务信号

本次没有做的内容:

  • 没有改造旧模块的静态通知逻辑
  • 没有引入通知订阅/端点拆表
  • 没有引入通知投递明细表(如 NotificationDelivery
  • 没有做数据库级别审计
  • 没有提供对外 API

3. 核心模型

当前模型只有一个主模型:notifier.Notifier

字段职责如下:

  • merchant: 多商户隔离
  • name: 通知器名称,仅要求在同商户内唯一
  • event_key: 事件标识,用于和业务 signal 对接
  • channel: 通知渠道,当前仅实现 wecom_webhook
  • template_key: 模板标识,对应固定目录中的模板文件
  • is_enabled: 启用/停用
  • config: 渠道配置,当前主要存放企业微信 webhook key、msgtype、timeout 等
  • description: 备注

当前将 event_key 直接放在 Notifier 上,而没有拆成“事件订阅 + 通知端点”两层,原因是现阶段追求低复杂度、可快速上线。
后续如果一个通知端点需要订阅多个事件,或者一个事件需要更复杂的启停/优先级/路由策略,再考虑拆模。

4. 目录结构

关键文件如下:

  • notifier/models.py
  • notifier/admin.py
  • notifier/services.py
  • notifier/tasks.py
  • notifier/backends.py
  • notifier/registry.py
  • notifier/templates/notifier/events/

模板固定目录为:

notifier/templates/notifier/events/

当前已提供的模板:

  • mission_created.md
  • mission_replied.md
  • mission_completed.md
  • mission_reply_rejected.md
  • mission_reopened.md
  • mission_cancelled.md

template_key 与模板文件名一一对应,例如:

  • template_key="mission_created"
  • 模板路径 notifier/events/mission_created.md

5. 调用链路

当前通知链路为:

  1. mission.services 在事务提交后发送业务 signal
  2. mission.handlers 监听 signal
  3. handler 将业务对象整理为纯字典 payload
  4. handler 调用 notifier.services.enqueue_notification_event(...)
  5. notifier 通过 Celery task 异步执行投递
  6. task 内部调用 dispatch_notification_event(...)
  7. merchant_id + event_key + is_enabled=True 查询匹配的 Notifier
  8. 逐个渲染模板并调用对应 backend 的 notify(...)
  9. 写详细日志

这里有两个关键约束:

  • handler 只做 payload 组装和入队,不做实际发送
  • task 层才做真正的通知投递

这样可以保持业务事务与外部通知解耦。

6. 渠道抽象

当前 backend 接口约定为:

  • BaseNotifierBackend.notify(notifier, content, context) -> dict

当前已实现:

  • WeComWebhookNotifierBackend

其复用了现有工具:

  • api_v1.utils.wecom_webhook.send_wecom_webhook_message

这样做的原因:

  • 避免重复实现 webhook 发送逻辑
  • 保持旧工具可复用
  • 新模块只负责“编排”和“动态配置”

7. Mission 已接入事件

当前 mission 已接入以下事件:

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

对应 handler 在:

  • mission/handlers.py

当前 handler 不再只是打日志,而是会构造 payload 并投递到 notifier task。

8. Admin 配置方式

Notifier 已接入 Django Admin可进行

  • 添加
  • 编辑
  • 删除
  • 启用/停用

当前推荐的使用方式:

  1. 在 admin 中新建 Notifier
  2. 选择所属商户
  3. 选择 event_key
  4. 选择 channel=wecom_webhook
  5. 填写 template_key
  6. config 中填写 webhook key 等参数
  7. 启用 is_enabled

当前 config 示例:

{
  "key": "企业微信机器人key",
  "msgtype": "markdown",
  "timeout_seconds": 10
}

9. 日志策略

本阶段没有引入数据库投递明细表,因此发送明细主要依赖日志。

当前日志覆盖以下节点:

  • 任务入队
  • backend 发送成功
  • 单个 notifier 发送成功
  • 单个 notifier 发送失败
  • 某事件无匹配 notifier

这满足当前“先可用、后增强”的目标,也符合“暂不做数据库级审计”的约束。

10. 当前风险与注意点

10.1 配置合法性主要依赖管理规范

当前 config 是自由 JSON没有做更强的结构化校验。
优点是灵活,缺点是后台录入错误会在发送时才暴露。

10.2 模板标识依赖文件存在

template_key 对应的模板文件如果不存在,会在发送阶段报错并记录日志。
这在当前阶段是可接受的,但后续可以考虑在 admin 或 model clean 中增加校验。

10.3 目前仍是“单对象订阅”模型

一个 Notifier 对应一个 event_key
如果后续出现“一个群同时订阅多个事件”的强需求,可以考虑抽象出 Subscription 层。

10.4 旧通知逻辑尚未迁移

当前仅 mission 新通知走 notifier
printingshipment 等旧逻辑仍保留原来的静态方式,不应在本次改动中混改。

11. 后续建议

按优先级建议如下:

  1. 在 admin 使用中观察 configtemplate_key 是否已足够稳定
  2. 若 notifier 数量增多,再决定是否拆分“通知端点”与“事件订阅”
  3. 若需要追踪投递历史,再增加 NotificationDelivery
  4. 当 mission 通知稳定后,再考虑逐步迁移新业务节点到 notifier

12. 当前结论

当前方案已经满足:

  • 独立模块
  • admin 配置
  • task 化通知
  • 模板化内容
  • 动态 signal -> notifier 路由
  • 后续可扩展到多渠道

同时复杂度仍控制在较低水平,适合作为第一阶段正式实现。