Skip to content
bitzorcas
中EN

Concept

Notifications 通知与模板

源码校验的 Notifications 模块说明书,覆盖个人收件箱、通知状态、偏好、CAP 扇出、外部渠道、版本化模板、渲染、安全与归档。

Last updated

Notifications 包含两组目前尚未闭环的能力:一组是 SysNotification 个人收件箱与外部渠道扇出,另一组是 UniversalTemplate 多表模板、版本、变量、渲染和渠道内容适配。两组代码共处同一模块,却没有在 CreateNotification 中自动串联:创建通知直接接收 Title/Body,模板渲染必须单独调用。

1. 模块实际拥有的边界

当前已实现:

  • 当前用户收件箱、未读数、Read/Unread/Archived 状态;
  • 个人级全局/通知代码偏好;
  • CAP notification.created 事件和严重级别默认渠道;
  • SMS、企业邮件、企微、钉钉、飞书投递端口;
  • 租户模板、版本历史、变量声明、Scriban 编译缓存;
  • Email、IM、SMS、Inbox、HTML 内容适配;
  • SQL Server 通知热表/归档表合并读取。

当前未实现:模板驱动的通知创建、跨模块稳定通知意图契约、批量收件人、发送计划、投递尝试持久化、重试/补偿、去重、退订强制通知规则、Webhook/Push、附件、退信反馈、送达/打开回执和通知 Feature catalog。

2. 当前端到端结构

true任意值调用方需自行渲染并传Title/Body

HTTP 当前用户或内部 NotificationService

Notification 聚合

InboxEnabled 决策

SysNotification 热表

CAP notification.created

NotificationCreatedConsumer

按 Id 回读通知

严重级别 + 偏好选择渠道

SMS / Mail / WeCom / DingTalk / Feishu

独立模板 API
当前未接入 CreateNotification

NotificationService.CreateAsync 先解析偏好;InboxEnabled=true 才保存聚合,随后总会发布事件。消费者只读取 notificationId,不使用事件中的 tenantId、userId、code 或 skipExternalDelivery。因而事件载荷与消费逻辑并不对称。

3. 两组 HTTP 表面

个人通知

方法与路由用例权限动作关键语义
POST /api/notificationsCreateNotificationCreate给当前 UserId 创建,Title/Body 由客户端直传
GET /api/notificationsGetNotificationInboxView状态过滤、1..100 页、默认合并归档
GET /api/notifications/unread-countGetUnreadCountView当前租户当前用户未读数
POST .../{id}/readMarkNotificationReadUpdate幂等;Archived 保持 Archived
POST .../{id}/unreadMarkNotificationUnreadUpdateArchived 返回 Conflict
POST .../{id}/archiveArchiveNotificationUpdate只是状态归档,不搬表
POST .../read-allMarkAllNotificationsReadUpdate加载全部未读并逐项 SaveRange
GET/PUT .../preferencesGet/UpdatePreferenceView/Update精确 Code 或全局空 Code

权限目录只声明 notifications.notification.view 和 .update,但 CreateNotification 请求使用 AuthorizationAction.Create。目录没有 .create 定义,是必须通过授权契约测试确认并修复的治理漂移。

模板

模板提供 Create、Update、Delete、Get、Search、Versions、Activate、Render、Preview、Validate 共 11 条生成端点。Create/Update/Delete 使用对应通用动作,Activate 却仍使用 Update,Preview/Validate/Render 使用 View;目录中单独声明的 .activate 与 .preview 当前未被这些请求引用。

4. 核心存储模型

SysNotification
统一聚合热表

SysNotification_Archive
只读历史

SysNotificationPreference
用户 + Code

SysUniversalTemplate
模板根

SysUniversalTemplateVersion
不可删除版本历史

SysTemplateVariable
当前变量集合

Notification 是统一 TenantAggregateRoot;模板则是已登记的多表非对称例外,由显式 projector 在根、版本、变量三表间转换。模板子表的读写都带 TenantId+TemplateId,但以 TemplateId 查询根时依赖全局租户过滤,没有在方法签名中显式传租户。

SQL Server 默认保留策略把超过 365 天的通知从热表事务迁入 SysNotification_Archive,归档保留配置为 1095 天、Action=ColdStorage。公开收件箱默认 IncludeArchived=true,会分别读取热/冷窗口后合并排序;这不是 ArchiveNotification 命令的即时行为。

5. 创建通知的真实方式

为当前用户创建一条站内通知
POST /api/notifications HTTP/1.1
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9
Content-Type: application/json
{
"code": "tickets.assignment.changed",
"title": "工单已转派给你",
"body": "工单 T-20260715-0042 已由一线支持转派。",
"type": "Todo",
"category": "Tickets",
"severity": "Warning",
"linkUrl": "/tickets/T-20260715-0042",
"metadataJson": "{\"email\":\"agent@example.com\",\"phone\":\"13800000000\"}"
}

HTTP handler 从 CurrentUser 取得 TenantId 和 UserId;客户端不能指定别的收件人。无 UserId 时写字符串 "0"。聚合只验证 TenantId/UserId/Code/Title 非空,不提前校验数据库长度、MetadataJson JSON 格式或 LinkUrl scheme。

内部业务模块可以直接调用 NotificationService 指定目标 userId,但必须保证 ambient EffectiveTenant 与传入 tenantId 一致,并自行决定模板、正文、幂等键和敏感数据最小化。

6. 主要实现缺口

  1. CreateNotification 与模板系统完全分离,不会按 Code 查模板或语言。
  2. Notification 权限目录缺少 Create;Template Activate/Preview 权限存在但请求不用。
  3. 所有 HTTP handler 使用 User.TenantId/UserId=0 回退,不使用统一 EffectiveTenant/User requirement。
  4. 通知创建没有业务幂等键;重复事件或请求会创建多行。
  5. InboxEnabled=false 时不保存,但消费者必须回读,外部投递断路。
  6. CAP 消费者忽略 tenantId 和 skipExternalDelivery,也未显式建立 tenant context。
  7. 消费与渠道异常被吞掉,失败无可查询状态、重试或对账。
  8. EnabledChannels 被保存却不参与 ResolveChannels;用户也可同时关闭全部渠道,没有 mandatory 规则。
  9. 模板渲染使用空 TenantId,CallerModule 不校验,非 Scriban 引擎名不改变编译器。
  10. 双语 Identity 种子复用同一 Tenant+TemplateKey,唯一索引使第二语言被跳过;Identity 当前仍用内联正文。
  11. 模板 Update 的 Description 入参未进入 manager;导入忽略导出 JSON 中的历史版本和变量。
  12. HTML/Email/Inbox 的正文安全边界不足以作为生产级 allowlist sanitizer。

7. 阅读路径

  1. 收件箱、状态机与归档读取
  2. 偏好、CAP 与多渠道投递
  3. 模板、版本、变量与多表持久化
  4. 渲染、渠道适配与内容安全
  5. 测试、运营与 GA 门禁

关联章节:Authorization、Multitenancy、Auditing 和 Operations。

8. 源码核对

Terminal window
# 全部通知/模板路由与权限动作。
rg -n 'GenerateEndpoint|AuthorizationAction' \
src/Platform/Notifications -g '*.cs'
# 创建、发布、消费和异常处理真实链路。
rg -n 'notification.created|skipExternalDelivery|FindByIdAsync|catch \(Exception' \
src/Platform/Notifications -g '*.cs'
# 模板租户、引擎、调用模块和版本号缺口。
rg -n 'GetByKeyAsync\(|CallerModule|TemplateEngine|OrderByDescending' \
src/Platform/Notifications -g '*.cs'

返回平台模块目录

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%