RS School App 通知系统完全指南:通知类型、Telegram/Email 订阅渠道与底层实现解析
2026/9/24 14:31:31 网站建设 项目流程

RS School App 通知系统完全指南:通知类型、Telegram/Email 订阅渠道与底层实现解析

【免费下载链接】rsschool-appAn application for the RS School education process项目地址: https://gitcode.com/gh_mirrors/rs/rsschool-app

本指南基于 RS School App 官方通知文档,全面讲解 RS School App 中通知系统的两类核心通知(导师审批通过、作业批改完成)、Telegram 与 Email 两种推送渠道的订阅/退订操作,并结合仓库源码剖析通知的底层实现:从数据库模型、Handlebar 模板渲染到 AWS 通知网关的完整调用链。阅读完本文,你将掌握在个人资料中正确配置并管理通知订阅的完整实战流程,同时理解通知“无需订阅强制送达”与“按订阅投递”两类机制的实现区别。

通知类型(Notification types)

RS School App 的通知系统目前主要面向导师(Mentor)学员(Student)推送两类关键事件,原文档明确列举如下:

1. 导师审批通过通知

  • 触发场景:你被批准参加课程(As a mentor, you are approved to take part in the course)。
  • 内容:包含审批通过的链接。
  • 重要特性不需要订阅(does not require subscription)——即使用户没有为某个渠道开启订阅,这条消息也会强制送达。

2. 作业批改完成通知

  • 触发场景:你的作业已被导师或 Cross-Check(交叉互评)检查完毕(Your task has been checked by mentor/cross-check)。
  • 内容:包含本次得分(score)、作业满分(task's maximum score)以及作业权重(weight of the task)。

从源码看,通知在数据库中通过NotificationType枚举区分两类语义:nestjs/src/models/notification.ts 定义了event(事件)与message(消息)两种类型,并在Notification实体上通过type字段与enabled开关管理。NotificationId联合类型则完整列举了系统当前支持的通知标识:

通知 ID语义
mentorRegistrationApproval导师注册/报名获批
mentorRegistrationApproval:submit导师注册提交确认
taskGrade作业评分(对应文档中的批改完成通知)
courseCertificate课程证书
courseScheduleChange课程日程变更
taskDeadline作业截止日期提醒
crossCheckDeadlineCross-Check 截止日期提醒
interviewerAssigned面试官分配
emailConfirmation邮箱确认
mentor:assigned导师分配
messages站内消息
mentorsInvitation导师邀请

可见mentorRegistrationApprovaltaskGrade正是原文档描述的两类核心通知在后端的正式标识,其余 ID 则为系统预留/其他模块使用的扩展类型。

通知渠道(Channels)

原文档说明通知支持两种投递渠道:

  • Telegram:通知来自@rsschool_bot机器人。
  • Email:通知发送到用户填写的邮箱。

结合源码,渠道由NotificationChannelId联合类型定义:nestjs/src/models/notificationChannel.ts 中声明type NotificationChannelId = 'telegram' | 'email' | 'discord',即后端基础能力实际覆盖Telegram、Email、Discord三种渠道,前端 notifications.ts 同样定义了NotificationChannel枚举(email / telegram / discord)。

每种渠道都有对应的消息模板结构,定义在 nestjs/src/models/notificationChannelSettings.ts:

  • EmailTemplate{ subject, body }—— 邮件包含主题正文
  • TelegramTemplate{ body }—— Telegram 仅有正文;
  • DiscordTemplate{ body }—— Discord 仅有正文。

模板以simple-json类型存储,并允许为每条通知按渠道分别配置。

如何订阅与退订通知

原文档给出了完整的订阅/退订流程,核心要点是先建立“联系渠道”,再在个人资料中勾选“同意(Consents)”。

第一步:填写联系信息

在个人资料的Contacts(联系信息)卡片中填写emailTelegram字段。注意:

  • Telegram 字段填写时不要带@前缀(without@),只需填用户名本身;
  • 注册时联系信息是互相关联的(Contacts are interconnected when registered),即注册阶段填写的联系方式会自动用于通知投递。

前端Consents组件(Consents.tsx)会根据联系信息状态展示引导提示:

  • 若未填写邮箱:提示“请在个人资料页填写邮箱以设置邮件通知”;
  • 若已填写邮箱但未验证:展示邮箱确认组件(EmailConfirmation),并可点击触发发送确认链接(调用UserService.sendEmailConfirmationLink());
  • 若未启用 Telegram:提示打开@rsschool_bot并点击Start按钮完成初始化(机器人连接链接为https://t.me/rsschool_bot?start=connect);
  • 若未授权 Discord:提示先完成 Discord 授权(discordIntegration.api.auth)。

第二步:在个人资料中开启订阅

  1. 进入个人资料的编辑(edit)模式https://app.rs.school/profile#edit
  2. Consents(同意)卡片中,在你希望订阅的渠道前面打勾(set a checkmark)即可完成订阅。

前端对应的设置入口位于Notifications用户设置页(UserNotificationsSettingsPage.tsx):页面加载时通过NotificationsService.getUserNotificationSettings()拉取用户当前各渠道的连接状态(connections)与通知设置列表;对于未建立连接的渠道(如未绑定 Telegram),该渠道会进入disabledChannels列表,其对应的勾选会被禁用。用户完成勾选后点击Save,前端会按notificationId + channelId + enabled的结构批量提交(saveUserNotifications),成功后提示“New notification settings saved.”。

第三步(Telegram 专有):改变订阅状态需通过机器人操作

原文档特别强调:要改变 Telegram 订阅的开关状态,必须在@rsschool_bot中执行订阅/退订操作(To change the state of Telegram subscription in the profile, it is necessary to subscribe/unsubscribe with@rsschool_bot)。

也就是说,对于 Telegram 渠道,个人资料页的勾选与机器人的订阅状态需要保持一致:你需要在 Telegram 中打开@rsschool_bot,点击Start完成订阅,或在机器人对话中执行退订;个人资料中的Consents勾选更多体现的是“允许通过该渠道接收通知”的意愿声明。

底层实现:通知如何从服务端送达用户

理解上述操作背后的数据与调用链路,有助于排查“为什么没收到通知”等问题。

数据模型:四张核心表

实体文件职责
Notificationnestjs/src/models/notification.ts通知定义:ID、名称、类型(event/message)、是否启用(enabled)、关联渠道设置、可选的父通知(parent
NotificationChannelnestjs/src/models/notificationChannel.ts渠道定义:telegram / email / discord
NotificationChannelSettingsnestjs/src/models/notificationChannelSettings.ts“通知 × 渠道”模板配置:以notificationId+channelId为复合主键,存对应渠道的模板 JSON
NotificationUserSettingsnestjs/src/models/notificationUserSettings.ts用户订阅设置:以notificationId+userId+channelId为复合主键,enabled布尔字段标记该用户是否订阅了该通知的该渠道

其中NotificationUserSettings正是“Consents 勾选”在后端的落库位置:用户每勾选一个“通知 × 渠道”组合,就对应一行enabled = true的记录。

服务端发送链路(notifications.service.ts)

后端核心发送逻辑分为三个方法:

  1. sendMessage(强制投递,不检查订阅):方法注释明确写道 “Messages to users regardless on user subscription status to specific channel”,这正是原文档中“导师审批通知不需要订阅”的实现基础。调用方只需提供notificationIduserIddatachannelIdchannelValue(用户在该渠道的 ID),即可直接构造消息并投递,不查询NotificationUserSettings
  2. buildChannelMessage(模板渲染):使用 Handlebars 的compile对渠道模板进行编译,将data渲染进模板正文;对 Email 渠道,还会用全局编译的 HTML 邮件外壳(email-template.ts中的compiledEmailTemplate,编译参数为noEscape: true)包裹正文,并设置邮件subject
  3. publishNotification(投递到网关):将渲染结果打包为NotificationPayload(含notificationIdchannelId[]userIddata),通过 HTTP POST 发送到 AWS 通知网关 REST API(地址与密钥来自ConfigServiceawsServices配置,请求头携带x-api-key)。注意:当configService.isDev为真时(开发环境)不会真正发送,避免开发环境骚扰真实用户。

管理端维护(notifications.controller.ts)

通知本身由管理员维护:NotificationsController挂载在/notifications路由下,使用DefaultGuard + RoleGuard并强制Role.Admin权限,提供:

  • GET /:列出全部通知(含渠道设置与父通知,按名称排序);
  • PUT /:更新通知(支持设置parentId建立父子层级);
  • POST /:创建通知(ID 冲突时返回BadRequestException);
  • DELETE /:id:删除通知。

前端管理页 AdminNotificationsSettingsPage.tsx 与 NotificationsService 中的getNotifications/saveNotification/createNotification/deleteNotification分别对应这些接口。

常见问题与排查建议

  • 为什么勾选了 Consents 却收不到 Telegram 通知?检查是否已在 Telegram 中打开@rsschool_bot并点击Start,Telegram 的订阅状态需通过机器人本身维护;同时在Contacts卡片中确认 Telegram 用户名填写正确且不带@前缀
  • 邮件通知没收到?确认邮箱已填写并完成验证(Consents组件会提示发送确认链接),并检查垃圾邮件箱;邮件投递依赖 AWS 通知网关,服务端在开发环境(isDev)下不会真实外发。
  • 哪些通知强制送达?mentorRegistrationApproval为代表的通知走sendMessage路径,不依赖用户订阅状态;以taskGrade为代表的通知则遵循用户在NotificationUserSettings中的订阅勾选。
  • 想关闭某类通知?在个人资料编辑模式的Consents卡片取消对应渠道勾选,或进入通知设置页(Notifications用户设置页)逐项调整并点击Save保存。

如需进一步了解通知模板、渠道设置的完整字段定义,可继续阅读 nestjs/src/models/notificationChannelSettings.ts 与 nestjs/src/notifications/notifications.service.spec.ts 中的测试用例,它们完整覆盖了buildChannelMessage对 Telegram/Email/Discord 模板的渲染行为。

【免费下载链接】rsschool-appAn application for the RS School education process项目地址: https://gitcode.com/gh_mirrors/rs/rsschool-app

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询