# 公告和消息模块审计报告 V3 > 审查日期:2026-06-22 > 审查范围:V2 改进后的 `src/modules/announcements/**`、`src/modules/messaging/**`、`src/modules/notifications/**`、对应路由层、i18n 翻译文件 > 前置文档:`announcements-messages-audit-report.md`(V1)、`announcements-messages-audit-report-v2.md`(V2) > 架构图参考:`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 `saveMessageDraftAction` 中 `as` 断言违规(P0) | 位置 | 代码 | 违反规则 | |------|------|----------| | [messaging/actions.ts](file:///e:/Desktop/CICD/src/modules/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](file:///e:/Desktop/CICD/src/app/(dashboard)/announcements/page.tsx) L29-78 | `resolveAudience` 函数 50 行业务逻辑在路由层 | "app/ 只能调用 modules 的 Server Actions 和 data-access,不直接访问数据库" + "页面层编排应下沉" | **问题分析**: - `resolveAudience` 包含根据 dataScope 解析受众的复杂业务逻辑(5 种 dataScope 分支) - 直接调用 `classes` 模块的 3 个 data-access 函数(`getStudentActiveClassId`、`getStudentActiveGradeId`、`getClassGradeId`) - V2-P1-5 已为管理端和编辑页创建编排函数,但用户端列表页遗漏 **后果**:路由层承担业务逻辑,违反三层架构;逻辑无法复用;测试困难。 ### 2.3 通知偏好 Action 放置位置错误(P1) | 位置 | 问题 | 违反规则 | |------|------|----------| | [messaging/actions.ts](file:///e:/Desktop/CICD/src/modules/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](file:///e:/Desktop/CICD/src/modules/notifications/dispatcher.ts) L128 + L149 | `sendNotification` 内部调用 `logNotificationSendBatch`,`sendBatchNotifications` 又调用一次 | "代码质量规则" — 重复逻辑 | **问题分析**: - L128:`sendNotification` 末尾调用 `logNotificationSendBatch(results, ...)` - L149:`sendBatchNotifications` 末尾再次调用 `logNotificationSendBatch(flatResults)` - 批量发送时每条通知的日志被记录两次 **后果**:日志数据重复,影响监控准确性;浪费存储。 ### 2.5 腾讯云短信 `SmsSdkAppId` 配置混淆(P1) | 位置 | 代码 | 违反规则 | |------|------|----------| | [sms-channel.ts](file:///e:/Desktop/CICD/src/modules/notifications/channels/sms-channel.ts) L201, L203 | `SmsSdkAppId: this.config.templateCode` 和 `TemplateId: this.config.templateCode` | "类型安全" — 配置语义错误 | **问题分析**: - 腾讯云 SMS API 要求 `SmsSdkAppId`(应用 ID)和 `TemplateId`(模板 ID)是两个不同值 - 代码中两者都使用 `this.config.templateCode`(来自 `SMS_TEMPLATE_CODE` 环境变量) - `getSmsConfig()` 缺少 `smsSdkAppId` 字段 **后果**:腾讯云短信发送必然失败(SmsSdkAppId 不等于模板 ID);生产环境无法使用腾讯云短信。 ### 2.6 内联类型导入(P1) | 位置 | 代码 | 违反规则 | |------|------|----------| | [messaging/actions.ts](file:///e:/Desktop/CICD/src/modules/messaging/actions.ts) L260 | `Promise>` | "TypeScript 规则 — 仅用于类型的导入必须使用 import type" | | [messaging/data-access.ts](file:///e:/Desktop/CICD/src/modules/messaging/data-access.ts) L285 | `import("@/modules/notifications/types").Notification[]` | 同上 | **后果**:可读性差,不符合 TypeScript 规范。 ### 2.7 组件层 `as` 断言轻微违规(P2) | 位置 | 代码 | 违反规则 | |------|------|----------| | [message-list.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/message-list.tsx) L66 | `setTab(v as Tab)` | "禁止 as 断言" | | [notification-list.tsx](file:///e:/Desktop/CICD/src/modules/notifications/components/notification-list.tsx) L106 | `Object.keys(TYPE_ICON) as NotificationType[]` | 同上 | **后果**:类型不安全;应使用类型守卫。 ### 2.8 `logNotificationSend` 使用 console(P2) | 位置 | 代码 | 违反规则 | |------|------|----------| | [notifications/data-access.ts](file:///e:/Desktop/CICD/src/modules/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. **修复 `saveMessageDraftAction` 的 `as` 断言**:使用类型守卫替代 `formData.get() as string | null`,安全处理 File 类型。 2. **公告列表页 `resolveAudience` 下沉**:将受众解析逻辑迁移到 `announcements/data-access.ts`,新增 `getUserAnnouncementsPageData` 编排函数。 ### P1(重要,影响模块边界与功能正确性) 3. **通知偏好 Action 迁移**:将 `getNotificationPreferencesAction` / `updateNotificationPreferencesAction` 从 `messaging/actions.ts` 迁移到 `notifications/actions.ts`,使用通知相关权限。 4. **修复 `sendBatchNotifications` 重复日志**:移除 `sendBatchNotifications` 中的重复 `logNotificationSendBatch` 调用。 5. **修复腾讯云短信 `SmsSdkAppId` 配置**:新增 `SMS_SDK_APP_ID` 环境变量和 `smsSdkAppId` 配置字段。 6. **消除内联类型导入**:改为顶部 `import type`。 ### P2(优化,提升代码质量) 7. **组件 `as` 断言清理**:使用类型守卫替代。 8. **日志服务统一**:`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 --noEmit` 和 `npm run lint` 验证。 ### V3-P0-1:修复 `saveMessageDraftAction` 的 `as` 断言 **文件**:`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.ts`:L260 内联 import 改为顶部 `import type` - `src/modules/messaging/data-access.ts`:L285 内联 import 改为顶部 `import type` ### V3-P2-7:组件 `as` 断言清理 **文件**: - `src/modules/messaging/components/message-list.tsx`:L66 `setTab(v as Tab)` 改为类型守卫 - `src/modules/notifications/components/notification-list.tsx`:L106 `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`:对应节点同步更新