Files
NextEdu/docs/architecture/audit/archive/announcements-messages-audit-report-v3.md

12 KiB
Raw Blame History

公告和消息模块审计报告 V3

审查日期2026-06-22 审查范围V2 改进后的 src/modules/announcements/**src/modules/messaging/**src/modules/notifications/**、对应路由层、i18n 翻译文件 前置文档:announcements-messages-audit-report.mdV1announcements-messages-audit-report-v2.mdV2 架构图参考:docs/architecture/004_architecture_impact_map.md §2.13 / §2.14 / §2.16


一、V2 完成情况复核

V2 编号 标题 状态
V2-P0-1 通知 i18n 命名空间独立 已完成
V2-P0-2 通知标题 i18n 化 已完成
V2-P1-1 AnnouncementList 过滤模式统一 已完成
V2-P1-2 MessageList 过滤冗余移除 已完成
V2-P1-3 消息详情页编排下沉 已完成
V2-P1-4 表单服务端校验错误展示 已完成
V2-P2-1 轮询间隔常量化 已完成
V2-P2-2 架构图同步 已完成
V2-P2-13b 通知优先级和归档 已完成
V2-P2-13c 通知分类筛选 + 桌面推送 已完成
V2-P2-13d 公告置顶 + 已读回执 已完成

V2 共 11 项已全部实施。


二、V3 新发现问题

2.1 saveMessageDraftActionas 断言违规P0

位置 代码 违反规则
messaging/actions.ts L279-283 formData.get("draftId") as string | null 等 5 处断言 "禁止 as 断言(除非从 unknown 转换)"

问题分析

  • FormData.get() 返回类型为 string | File | null
  • 代码直接断言为 string | null,若字段为 File 类型会导致运行时错误
  • 应使用类型守卫或 Zod 校验进行安全转换

后果:类型不安全,上传场景下可能运行时崩溃;违反 TypeScript 严格模式规则。

2.2 公告列表页 resolveAudience 业务逻辑未下沉P0

位置 问题 违反规则
announcements/page.tsx L29-78 resolveAudience 函数 50 行业务逻辑在路由层 "app/ 只能调用 modules 的 Server Actions 和 data-access不直接访问数据库" + "页面层编排应下沉"

问题分析

  • resolveAudience 包含根据 dataScope 解析受众的复杂业务逻辑5 种 dataScope 分支)
  • 直接调用 classes 模块的 3 个 data-access 函数(getStudentActiveClassIdgetStudentActiveGradeIdgetClassGradeId
  • V2-P1-5 已为管理端和编辑页创建编排函数,但用户端列表页遗漏

后果:路由层承担业务逻辑,违反三层架构;逻辑无法复用;测试困难。

2.3 通知偏好 Action 放置位置错误P1

位置 问题 违反规则
messaging/actions.ts L334-396 getNotificationPreferencesAction / updateNotificationPreferencesAction 在 messaging 模块 "模块标准结构" — 通知偏好属于 notifications 模块

问题分析

  • V1-P0-4 已将通知偏好 data-access 迁移到 notifications/preferences.ts
  • 但对应的 Server Action 仍留在 messaging/actions.ts,使用 MESSAGE_READ 权限
  • 消费方settings 模块)通过 SettingsService 接口注入,但 Action 实现仍在 messaging

后果模块边界混乱messaging 模块承担了不属于它的通知偏好职责;权限语义不正确。

2.4 sendBatchNotifications 重复日志P1

位置 代码 违反规则
notifications/dispatcher.ts L128 + L149 sendNotification 内部调用 logNotificationSendBatchsendBatchNotifications 又调用一次 "代码质量规则" — 重复逻辑

问题分析

  • L128sendNotification 末尾调用 logNotificationSendBatch(results, ...)
  • L149sendBatchNotifications 末尾再次调用 logNotificationSendBatch(flatResults)
  • 批量发送时每条通知的日志被记录两次

后果:日志数据重复,影响监控准确性;浪费存储。

2.5 腾讯云短信 SmsSdkAppId 配置混淆P1

位置 代码 违反规则
sms-channel.ts L201, L203 SmsSdkAppId: this.config.templateCodeTemplateId: this.config.templateCode "类型安全" — 配置语义错误

问题分析

  • 腾讯云 SMS API 要求 SmsSdkAppId(应用 IDTemplateId(模板 ID是两个不同值
  • 代码中两者都使用 this.config.templateCode(来自 SMS_TEMPLATE_CODE 环境变量)
  • getSmsConfig() 缺少 smsSdkAppId 字段

后果腾讯云短信发送必然失败SmsSdkAppId 不等于模板 ID生产环境无法使用腾讯云短信。

2.6 内联类型导入P1

位置 代码 违反规则
messaging/actions.ts L260 Promise<ActionState<import("./types").MessageDraft[]>> "TypeScript 规则 — 仅用于类型的导入必须使用 import type"
messaging/data-access.ts L285 import("@/modules/notifications/types").Notification[] 同上

后果:可读性差,不符合 TypeScript 规范。

2.7 组件层 as 断言轻微违规P2

位置 代码 违反规则
message-list.tsx L66 setTab(v as Tab) "禁止 as 断言"
notification-list.tsx L106 Object.keys(TYPE_ICON) as NotificationType[] 同上

后果:类型不安全;应使用类型守卫。

2.8 logNotificationSend 使用 consoleP2

位置 代码 违反规则
notifications/data-access.ts L210, L230 console.info / console.error "监控" — 应使用统一日志服务

后果:生产环境日志分散,无法集中监控。


三、行业差距对比

结合 K12 教育系统特点,对比钉钉教育、企业微信教育版、智学网、班级小管家等产品:

功能 我们 行业标杆 影响
消息已读回执 钉钉/企微支持 教师无法确认家长是否已读重要通知
消息模板 智学网预设模板 教师每次手写消息效率低
公告定时发布 仅即时发布 钉钉支持定时 无法提前编排非工作时间发布
公告附件 企微/钉钉支持 无法附带 PDF/图片等材料
公告分类标签 智学网分类 公告列表无法按类型快速筛选
消息群发多班级 单收件人 钉钉群发 教师需逐个发送,效率低
公告评论/确认 仅已读回执 钉钉确认回执 无法收集家长确认反馈
消息搜索 有(按主题) 按内容搜索 基本满足
通知优先级 V2-P2-13b 已对齐
通知归档 V2-P2-13b 已对齐
桌面推送 V2-P2-13c 已对齐
SSE 实时推送 V2-P3 已对齐

主要差距:消息已读回执、公告定时发布、公告附件为高价值缺失功能,直接影响家校沟通效率。


四、改进优先级建议

P0紧急影响类型安全与架构合规

  1. 修复 saveMessageDraftActionas 断言:使用类型守卫替代 formData.get() as string | null,安全处理 File 类型。
  2. 公告列表页 resolveAudience 下沉:将受众解析逻辑迁移到 announcements/data-access.ts,新增 getUserAnnouncementsPageData 编排函数。

P1重要影响模块边界与功能正确性

  1. 通知偏好 Action 迁移:将 getNotificationPreferencesAction / updateNotificationPreferencesActionmessaging/actions.ts 迁移到 notifications/actions.ts,使用通知相关权限。
  2. 修复 sendBatchNotifications 重复日志:移除 sendBatchNotifications 中的重复 logNotificationSendBatch 调用。
  3. 修复腾讯云短信 SmsSdkAppId 配置:新增 SMS_SDK_APP_ID 环境变量和 smsSdkAppId 配置字段。
  4. 消除内联类型导入:改为顶部 import type

P2优化提升代码质量

  1. 组件 as 断言清理:使用类型守卫替代。
  2. 日志服务统一logNotificationSend 改用统一日志接口(预留接口,当前保持 console 但加注释标记为 TODO

五、架构图同步说明

本次审计发现以下架构图需更新:

  1. §2.13 messaging

    • 移除 getNotificationPreferencesAction / updateNotificationPreferencesAction(迁移至 notifications
    • 更新 actions.ts 行数(减少约 60 行)
    • 新增 saveMessageDraftAction 类型安全改进说明
  2. §2.14 notifications

    • 新增 getNotificationPreferencesAction / updateNotificationPreferencesAction
    • 更新 actions.ts 行数(增加约 60 行)
    • 修复 sendBatchNotifications 重复日志说明
    • 新增 smsSdkAppId 配置字段说明
  3. §2.16 announcements

    • 新增 getUserAnnouncementsPageData 编排函数
    • 更新 data-access.ts 行数
    • 更新用户端列表页说明(使用编排函数)
  4. 附录 A 依赖矩阵

    • messaging 对 notifications 的依赖减少(不再包含通知偏好 Action
    • announcements 对 classes 的依赖改为通过编排函数间接调用

六、实施记录

以下为 V3 审计报告的实施记录,所有修复均已完成并通过 npx tsc --noEmitnpm run lint 验证。

V3-P0-1修复 saveMessageDraftActionas 断言

文件src/modules/messaging/actions.ts

变更:将 L279-283 的 5 处 formData.get("xxx") as string | null 替换为类型守卫函数 getStringFromFormData,安全处理 File 类型。

V3-P0-2公告列表页 resolveAudience 下沉

文件

  • src/modules/announcements/data-access.ts:新增 getUserAnnouncementsPageData 编排函数
  • src/app/(dashboard)/announcements/page.tsx:移除 resolveAudience,改用编排函数

V3-P1-3通知偏好 Action 迁移

文件

  • src/modules/notifications/actions.ts:新增 getNotificationPreferencesAction / updateNotificationPreferencesAction
  • src/modules/messaging/actions.ts:移除上述 2 个 Action 及相关 import

V3-P1-4修复 sendBatchNotifications 重复日志

文件src/modules/notifications/dispatcher.ts

变更:移除 sendBatchNotifications 中的重复 logNotificationSendBatch 调用L149

V3-P1-5修复腾讯云短信 SmsSdkAppId 配置

文件src/modules/notifications/channels/sms-channel.ts

变更getSmsConfig() 新增 smsSdkAppId 字段(来自 SMS_SDK_APP_ID 环境变量),SmsSdkAppId 使用独立配置值。

V3-P1-6消除内联类型导入

文件

  • src/modules/messaging/actions.tsL260 内联 import 改为顶部 import type
  • src/modules/messaging/data-access.tsL285 内联 import 改为顶部 import type

V3-P2-7组件 as 断言清理

文件

  • src/modules/messaging/components/message-list.tsxL66 setTab(v as Tab) 改为类型守卫
  • src/modules/notifications/components/notification-list.tsxL106 Object.keys(TYPE_ICON) as NotificationType[] 改为类型守卫

V3-P2-8日志服务统一预留

文件src/modules/notifications/data-access.ts

变更console.info / console.error 添加 TODO 注释标记,预留统一日志服务接入点。

架构图同步

文件

  • docs/architecture/004_architecture_impact_map.md§2.13 / §2.14 / §2.16 同步更新
  • docs/architecture/005_architecture_data.json:对应节点同步更新