# 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` 已具备: - 通知器配置 - 路由配置 - 分类分发 - 任务事件按分类路由 - 管理后台操作支持 - 日志与测试保障 这已经足以支撑你当前提出的“所有任务事件都支持按任务分类路由”的要求。