1
0
forked from erp-dev/erp
Files
erpnew/docs/notifier_module_design.md

185 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Notifier 模块实现说明
本文档面向后端维护者,描述 `notifier` 模块当前的实现决策、已落地范围与后续扩展注意事项。
## 1. 当前阶段
`notifier` 现已从第一阶段的“`Notifier` 直接绑定 `event_key`”升级为第二阶段的“`Notifier + NotifierRoute`”结构。
这样做的原因是:
- 一个通知器可能需要绑定多个事件
- 同一事件需要支持按任务分类路由
- 同一事件可能同时发往多个不同通知器
- 后续还可能出现更多路由维度
因此当前模块职责被拆成两层:
- `Notifier`:通知渠道配置、模板配置、启停控制
- `NotifierRoute`:事件匹配与业务路由规则
## 2. 当前范围
本阶段已实现:
- 独立 app`notifier`
- Celery task 化投递
- 企业微信 webhook 渠道
- `message_api` 渠道ERP 作为调用方)
- 模板化内容渲染
- Admin 可配置
- `NotifierRoute` 事件路由
- `mission` 相关事件按任务分类路由
本阶段仍未做:
- 旧模块静态通知逻辑迁移
- 通知投递明细表
- 数据库级别审计
## 3. 核心模型
### 3.1 Notifier
- `config`
- `description`
当前 `Notifier` 已不再直接持有 `event_key`
`NotifierRoute` 负责“何时发、发给谁”:
- `merchant`
- `notifier`
其中:
- `mission_category = null` 表示该事件的通配路由
- `Notifier` 在同商户下 `name` 唯一
- `NotifierRoute` 在同一 `notifier + event_key + mission_category` 下唯一
- `NotifierRoute` 额外限制同一 `notifier + event_key` 只能有一条通配路由
当前 `dispatch_notification_event(...)` 的匹配规则为:
1. 先按 `merchant + event_key + route.is_enabled=True + notifier.is_enabled=True` 查路由
- 也允许匹配通配路由
3. 如果 payload 中没有 `category_id`
- 只匹配通配路由
4. 如果同一个 `Notifier` 同时命中专用路由和通配路由
- 只保留一条
- 优先保留专用路由
- 同一通知器不重复发送
## 5. 当前调用链
通知链路如下:
1. `mission.services` 在事务提交后发 signal
## 6. 已接入的事件
当前 `mission` 已接入:
- `mission.unreplied`
- `mission.unreplied` 并非由业务 signal 直接触发,而是由后台每分钟一次的扫描任务按任务对象上的提醒配置触发
## 7. 日志策略
- 没有命中任何可用路由
- 路由命中成功
- backend 发送成功
- 单个通知发送失败
当前已增加 route 维度日志,重点字段包括:
- `event_key`
- `merchant_id`
- `route_id`
- `route_mission_category_id`
- `notifier_id`
## 8. Admin 现状
当前后台提供两个对象:
并且:
`Notifier` inline 场景下route 的 `merchant` 会自动同步为当前 notifier 的商户,避免管理人员重复录入。
## 11. Mission 上的未回复提醒状态字段
当前未回复提醒的核心状态全部放在 `Mission` 对象自身:
- `notify_if_unreplied`
- `unreplied_notify_interval_minutes`
- `unreplied_notify_max_count`
- `unreplied_notify_sent_count`
- `unreplied_last_notified_at`
这样做的原因是:
- 配置和运行态统一放在任务对象上,最容易排查
- 不需要额外的提醒计划表或提醒历史表就能支撑当前需求
- 最大提醒次数和上次提醒时间都能直接在任务详情中观察到
这样旧配置不会因为结构调整而丢失。
## 10. 测试覆盖重点
当前测试已覆盖:
- 模板渲染
- backend 发送
- 路由按事件匹配
- 分类专用路由优先于通配路由
- 无专用路由时回退到通配路由
- 任务事件 handler 正常入队
## 11. 当前风险与注意点
### 11.1 当前只对 mission 做了分类路由
当前 `mission_category` 是显式写进 `NotifierRoute` 的业务字段。
这适合当前目标,但如果未来要扩展到其它业务模型的复杂路由,可能需要更抽象的路由条件模型。
### 11.2 config 仍是自由 JSON
后台录入错误仍可能在发送时才暴露。
当前依赖日志排查,后续可增加更强校验。
### 11.3 模板校验仍在发送期暴露
`template_key` 如果写错,会在渲染阶段报错并记录日志。
后续可在 admin 或 model clean 中增强校验。
## 12. `message_api` 渠道边界
`message_api` 的定位是:
- ERP / notifier 只负责渲染结构化消息模板并调用内部 `message_api`
- ERP 不直接管理企业微信 `corp_id``secret``access_token`
- ERP 不直接调用企业微信官方 API
当前实现方式:
- `message_api` channel 使用 `.json` 模板
- backend 会校验模板渲染结果是否符合 text/news 结构
- 之后由 notifier 作为 HTTP client 调用 `MESSAGE_API_BASE_URL`
这意味着:
- `agent_id` / `agent_ids` 仍然属于 channel 级配置
- 企业微信系统级凭据属于 `message_api` 服务自身,不属于 ERP 配置
## 13. 当前结论
当前 `notifier` 已具备:
- 通知器配置
- 路由配置
- 分类分发
- 任务事件按分类路由
- 管理后台操作支持
- 日志与测试保障
这已经足以支撑你当前提出的“所有任务事件都支持按任务分类路由”的要求。