Files
NextEdu/docs/architecture/audit/announcements-messages-audit-report.md
SpecialX fde711ce46 feat(announcements,messaging): 公告与消息模块审计重构 — i18n + Error Boundary + a11y
- 新增审计报告 docs/architecture/audit/announcements-messages-audit-report.md
- 新增中英双语 i18n 字典 announcements.json / messages.json(11/13 个命名空间)
- 重构所有 announcements 和 messaging 组件接入 next-intl(useTranslations)
- 所有页面 page.tsx 使用 generateMetadata + getTranslations 替代硬编码 metadata
- 新增 7 个 error.tsx 错误边界(4 公告 + 3 消息),统一 EmptyState + i18n + 重试
- a11y 改进:announcement-card / message-list / notification-dropdown 添加 aria-label
- 同步架构图 004 和 005:i18n.messages 清单 + 已知问题修复记录
2026-06-22 16:02:07 +08:00

324 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 公告和消息模块审计报告
> 审查日期2026-06-22
> 审查范围:`src/modules/announcements/**`、`src/modules/messaging/**`、`src/modules/notifications/**`、`src/app/(dashboard)/announcements/**`、`src/app/(dashboard)/admin/announcements/**`、`src/app/(dashboard)/messages/**`
> 架构图参考:`docs/architecture/004_architecture_impact_map.md` §2.13 / §2.14 / §2.16、`docs/architecture/005_architecture_data.json`
---
## 一、现有实现概要
### 1.1 文件分布
| 层 | 路径 | 文件数 | 说明 |
|----|------|--------|------|
| 路由层 - 用户端公告 | `src/app/(dashboard)/announcements/` | 2 个 `page.tsx` + 1 个 `loading.tsx` | 列表 + 详情,所有角色共用 |
| 路由层 - 管理端公告 | `src/app/(dashboard)/admin/announcements/` | 2 个 `page.tsx` + 1 个 `loading.tsx` | 管理列表 + 编辑 |
| 路由层 - 消息 | `src/app/(dashboard)/messages/` | 3 个 `page.tsx` + 3 个 `loading.tsx` + 1 个 `error.tsx` | 列表 + 详情 + 撰写 |
| 模块层 - announcements | `src/modules/announcements/` | 4 个核心文件 + 5 个组件 | actions(296行) / data-access(197行) / types(61行) / schema(45行) |
| 模块层 - messaging | `src/modules/messaging/` | 4 个核心文件 + 6 个组件 | actions(312行) / data-access(246行) / types(52行) / schema(44行) |
| 模块层 - notifications | `src/modules/notifications/` | 6 个核心文件 + 5 个渠道文件 | actions(159行) / data-access(174行) / dispatcher(152行) / preferences(191行) / types(153行) |
### 1.2 数据流
```
[Route] /announcements/page.tsx
└─▶ announcements/data-access.getAnnouncements (status=published, audience={gradeId,classId})
└─▶ classes/data-access.getClassGradeId / getStudentActiveClassId / getStudentActiveGradeId
[Route] /admin/announcements/page.tsx
├─▶ announcements/data-access.getAnnouncements
├─▶ school/data-access.getGrades
└─▶ classes/data-access.getAdminClasses
(页面层直接编排 3 个模块的 data-access
[Route] /messages/page.tsx
├─▶ messaging/data-access.getMessages
└─▶ notifications/data-access.getNotifications
(页面层直接编排 2 个模块的 data-access
[Route] /messages/compose/page.tsx
└─▶ messaging/data-access.getRecipients
└─▶ classes/data-access.getStudentIdsByClassIds / getTeacherIdsByClassIds / getClassesByGradeId / getStudentActiveClassId
└─▶ users/data-access.getUserNamesByIds
[Action] announcements/actions.createAnnouncementAction
└─▶ notifications.sendBatchNotifications (发布公告时批量通知)
[Action] messaging/actions.sendMessageAction
└─▶ notifications.dispatcher.sendNotification (发消息时通知收件人)
```
### 1.3 架构图记录情况
`004_architecture_impact_map.md` 对三个模块的记录较为完整:
- §2.13 messaging记录了 P0-4 / P1-5 已修复的双向依赖问题,文件清单准确
- §2.14 notifications记录了渠道抽象和从 messaging 迁移的历史
- §2.16 announcements记录了模块职责和依赖关系
**但存在以下遗漏**
- 未记录 messaging 组件目录下 `notification-dropdown.tsx``unread-message-badge.tsx` 两个组件
- 未记录 announcements 模块的 `components/` 子目录5 个组件文件未在文件清单中列出)
- 未记录消息列表的客户端搜索行为(`getMessagesAction` 在客户端被调用)
- 未记录通知下拉菜单的 30 秒轮询机制
---
## 二、现存问题与原因分析
### 2.1 国际化完全缺失P0
| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [announcements/components/announcement-list.tsx](file:///e:/Desktop/CICD/src/modules/announcements/components/announcement-list.tsx) L24-29 | `"All"` / `"Published"` / `"Draft"` / `"Archived"` 硬编码 | "所有用户可见文本必须适配 i18n使用 next-intl提取翻译键" |
| [announcements/components/announcement-detail.tsx](file:///e:/Desktop/CICD/src/modules/announcements/components/announcement-detail.tsx) L29-38 | `STATUS_LABEL` / `TYPE_LABEL` 全英文硬编码 | 同上 |
| [announcements/components/announcement-card.tsx](file:///e:/Desktop/CICD/src/modules/announcements/components/announcement-card.tsx) L9-28 | `STATUS_LABEL` / `TYPE_LABEL` 重复定义且硬编码 | 同上 |
| [announcements/components/announcement-form.tsx](file:///e:/Desktop/CICD/src/modules/announcements/components/announcement-form.tsx) L86,92,98,108 | `"New Announcement"` / `"Title"` / `"Content"` 等硬编码 | 同上 |
| [messaging/components/message-list.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/message-list.tsx) L81-88 | `"Inbox"` / `"Sent"` / `"Compose"` 硬编码 | 同上 |
| [messaging/components/message-detail.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/message-detail.tsx) L38,74,99-106 | `"From"` / `"To"` / `"Message"` / `"New"` / `"Read"` / `"Sent"` 硬编码 | 同上 |
| [messaging/components/message-compose.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/message-compose.tsx) L78,84,102,113 | `"Reply"` / `"New Message"` / `"To"` / `"Subject"` 硬编码 | 同上 |
| [messaging/components/notification-list.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/notification-list.tsx) L25-30,69-70 | `TYPE_LABEL` 硬编码,`"Notifications"` 标题硬编码 | 同上 |
| [messaging/components/notification-dropdown.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/notification-dropdown.tsx) L113 | `"Notifications"` / `"Mark all read"` 硬编码 | 同上 |
| `src/shared/i18n/messages/` | **无 `announcements.json` 或 `messages.json`** | 翻译文件结构不完整 |
| [i18n/request.ts](file:///e:/Desktop/CICD/src/i18n/request.ts) L22-29 | 未加载 announcements/messages 翻译文件 | 翻译文件未注册 |
**后果**:所有用户可见文本无法切换语言,中文用户看到全英文界面,严重影响 K12 学校教师/家长/学生的使用体验。同一组件中 `STATUS_LABEL` 重复定义card 和 detail 各一份),维护成本高。
### 2.2 角色硬编码与配置驱动缺失P0
| 位置 | 代码 | 违反规则 |
|------|------|----------|
| [layout/config/navigation.ts](file:///e:/Desktop/CICD/src/modules/layout/config/navigation.ts) L39 | `NAV_CONFIG: Partial<Record<Role, NavItem[]>>` 按角色分组 | "前端权限判断统一使用 `usePermission().hasPermission()`,严禁出现 `role === 'xxx'` 硬编码" |
| 同上 L99-103, L247-251, L307-311, L343-347 | admin/teacher/student/parent 各自配置 `Announcements``Messages` 导航项 | 配置未抽象,新增角色需复制粘贴 |
**后果**:新增角色(如 `grade_head` 已存在)无法享受公告/消息导航;导航配置按角色而非权限驱动,违反"配置驱动设计"原则。
### 2.3 架构分层页面层越权编排P1
| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [admin/announcements/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/admin/announcements/page.tsx) L33-37 | 页面层 `Promise.all` 调用 announcements/school/classes 三个模块的 data-access | "app/ 只能调用 modules/ 的 Server Actions 和 data-access" — 虽语法允许,但编排逻辑应在模块 actions 层完成 |
| [messages/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/messages/page.tsx) L17-20 | 页面层并行调用 messaging 和 notifications 两个模块的 data-access | 同上 |
| [announcements/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/announcements/page.tsx) L27-76 | `resolveAudience` 函数包含 50 行业务逻辑(根据 dataScope 解析受众) | 纯逻辑应抽为 hooks 或 data-access 层函数 |
| announcements 模块无 `getAdminAnnouncementsPageData` 编排函数 | 缺失编排层 | "模块标准结构"要求 actions.ts 承担编排职责 |
**后果**:页面层臃肿、逻辑不可复用、不可测试;多个页面需要相同数据时需复制编排逻辑。
### 2.4 模块间组件耦合P1
| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [messaging/components/notification-list.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/notification-list.tsx) L16 | 直接 `import type { Notification, NotificationType } from "@/modules/notifications/types"` | "模块内部组件绝不直接 import 其他业务模块的 actions 或 data-access只能通过注入的接口调用" |
| [messaging/components/notification-dropdown.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/notification-dropdown.tsx) L27 | 同上,直接 import notifications 模块类型 | 同上 |
| [messaging/components/notification-list.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/notification-list.tsx) L15 | 直接 import `../actions` 中的 `markAllNotificationsAsReadAction` / `markNotificationAsReadAction` | messaging 模块的 actions re-export 了 notifications 的 actions造成职责混乱 |
| [messaging/actions.ts](file:///e:/Desktop/CICD/src/modules/messaging/actions.ts) L196-248 | messaging 模块定义了 6 个通知相关 Action`getNotificationsAction` / `markNotificationAsReadAction` 等) | 通知 Action 应由 notifications 模块提供messaging 仅负责私信 |
**后果**messaging 和 notifications 模块在 UI 层和 Action 层深度耦合无法独立替换或测试notifications 模块的 UI 组件无法复用到其他场景。
### 2.5 错误边界缺失P1
| 位置 | 问题 | 违反规则 |
|------|------|----------|
| `src/app/(dashboard)/announcements/error.tsx` | **缺失** | "每个独立的数据区块必须用 React Error Boundary 包裹" |
| `src/app/(dashboard)/announcements/[id]/error.tsx` | **缺失** | 同上 |
| `src/app/(dashboard)/admin/announcements/error.tsx` | **缺失** | 同上 |
| `src/app/(dashboard)/admin/announcements/[id]/error.tsx` | **缺失** | 同上 |
| `src/app/(dashboard)/messages/[id]/error.tsx` | **缺失** | 同上 |
| `src/app/(dashboard)/messages/compose/error.tsx` | **缺失** | 同上 |
| `src/app/(dashboard)/admin/announcements/loading.tsx` | **缺失**(仅有用户端 loading | 加载骨架屏不完整 |
**后果**:数据加载失败时整页崩溃,用户体验差;无权限访问时显示原始错误而非友好提示。
### 2.6 通知轮询性能问题P1
| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [notification-dropdown.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/notification-dropdown.tsx) L65-68 | 每 30 秒轮询 `getNotificationsAction` + `getUnreadNotificationCountAction` | "性能:优先使用 React Server Components 获取初始数据" |
| [unread-message-badge.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/unread-message-badge.tsx) L31-33 | 每 60 秒轮询 `getUnreadMessageCountAction` | 同上 |
| 两个组件未使用 RSC 初始数据 | 客户端首次渲染无数据,需等待轮询 | "客户端组件仅负责交互" |
**后果**:多用户同时在线时,每分钟产生大量无效请求;首屏渲染时无数据,显示空状态闪烁。
### 2.7 公告表单校验不足P1
| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [schema.ts](file:///e:/Desktop/CICD/src/modules/announcements/schema.ts) L9-10 | `targetGradeId` / `targetClassId` 为 optional未根据 `type` 做条件必填校验 | "输入使用 Zod 验证,验证失败返回结构化错误" |
| [announcement-form.tsx](file:///e:/Desktop/CICD/src/modules/announcements/components/announcement-form.tsx) L49-54 | `type === "grade"` 时不强制选择年级,`type === "class"` 时不强制选择班级 | 同上 |
| [actions.ts](file:///e:/Desktop/CICD/src/modules/announcements/actions.ts) L43-61 | `resolveTargetUserIds``type === "grade"``targetGradeId` 为空时返回空数组,公告无人接收 | 数据完整性缺失 |
**后果**:管理员可能创建无受众的公告,发布公告后无人收到通知,且无任何错误提示。
### 2.8 消息列表搜索逻辑复杂且无分页 UIP1
| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [message-list.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/message-list.tsx) L38-58 | 客户端 `useEffect` + `setTimeout` 防抖搜索,但未取消已发出的请求 | "可测试性:数据获取、计算、格式化等纯逻辑全部放入纯函数或 hooks" |
| 同上 L71-74 | `filtered` 在客户端再次过滤 `displayMessages`,与已搜索结果重复过滤 | 逻辑冗余 |
| 同上 L17 | 初始加载 `pageSize: 50`,但无分页 UI超过 50 条无法查看 | "明确处理空数据、无权限、网络异常等边界状态" |
| [messages/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/messages/page.tsx) L18 | 一次性加载 50 条消息,无虚拟滚动 | 性能问题 |
**后果**:消息超过 50 条时用户无法查看历史;搜索逻辑与 UI 混合,无法单独测试。
### 2.9 无权限与空状态处理不友好P1
| 位置 | 问题 | 违反规则 |
|------|------|----------|
| 所有页面 | `requirePermission` 抛出 `PermissionDeniedError` 后,由上层 `error.tsx` 处理,但无专门的无权限空状态 | "明确处理空数据、无权限、网络异常等边界状态" |
| [message-list.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/message-list.tsx) L116-127 | 空状态文本硬编码且未区分"无权限"与"无数据" | 同上 |
| [notification-list.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/notification-list.tsx) L80-86 | 通知空状态未提供"去设置通知偏好"等引导操作 | 用户体验不完整 |
**后果**:用户无法区分"无数据"和"无权限",无法找到下一步操作引导。
### 2.10 可访问性问题P2
| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [message-list.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/message-list.tsx) L104-110 | 搜索框无 `aria-label`,仅靠 `placeholder` | "可访问性a11y语义化标签、ARIA 属性、键盘导航" |
| [notification-dropdown.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/notification-dropdown.tsx) L139-144 | `DropdownMenuItem``onSelect` 阻止默认行为后手动调用 `handleMarkRead`,键盘导航时焦点处理不明确 | 同上 |
| [announcement-card.tsx](file:///e:/Desktop/CICD/src/modules/announcements/components/announcement-card.tsx) L66-72 | 整个 Card 作为链接,但无 `aria-label` 描述跳转目标 | 同上 |
| [notification-list.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/notification-list.tsx) L118-124 | "Mark as read" 按钮无 `aria-label`,屏幕阅读器无法识别 | 同上 |
**后果**:视障用户无法有效使用公告和消息功能,不符合 WCAG 2.1 AA 标准。
### 2.11 监控埋点缺失P2
| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [announcements/actions.ts](file:///e:/Desktop/CICD/src/modules/announcements/actions.ts) | 发布/归档/删除公告无埋点 | "监控:方案中预留关键操作埋点接口" |
| [messaging/actions.ts](file:///e:/Desktop/CICD/src/modules/messaging/actions.ts) | 发送/删除消息无埋点 | 同上 |
| [notifications/data-access.ts](file:///e:/Desktop/CICD/src/modules/notifications/data-access.ts) L167-173 | 仅 `console.info` 输出发送日志,无结构化埋点 | 同上 |
**后果**:无法追踪公告阅读率、消息回复率等关键指标;通知发送失败无法告警。
### 2.12 消息软删除无事务P2
| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [messaging/data-access.ts](file:///e:/Desktop/CICD/src/modules/messaging/data-access.ts) L180-191 | `deleteMessage` 执行两个独立的 UPDATEsenderDeletedAt + receiverDeletedAt无事务 | "安全性:所有敏感数据查询必须在 data-access 层结合当前用户权限过滤" |
| 同上 | 两个 UPDATE 之间可能部分失败,导致数据不一致 | 数据完整性问题 |
**后果**:发送方删除后接收方可能仍可见,或反之,造成数据不一致。
### 2.13 测试覆盖不足P2
| 位置 | 问题 | 违反规则 |
|------|------|----------|
| `tests/e2e/announcements.spec.ts` | 仅 2 个测试(未登录重定向 + 登录后可见),无管理端测试 | "可测试性" |
| `tests/e2e/` | **无 messaging 模块 E2E 测试** | 同上 |
| `src/modules/announcements/` | 无单元测试 | 同上 |
| `src/modules/messaging/` | 无单元测试 | 同上 |
| `src/modules/notifications/` | 无单元测试 | 同上 |
**后果**:重构时无回归保障,关键业务逻辑(权限过滤、受众解析、通知分发)错误无法及时发现。
---
## 三、行业差距对比
### 3.1 公告模块差距
| 功能 | 行业优秀实践 | 当前状态 | 影响 |
|------|-------------|----------|------|
| 公告分类标签 | 支持自定义标签(紧急、活动、政策),可按标签筛选 | 仅 typeschool/grade/class和 status无标签 | 教师无法快速筛选紧急公告 |
| 已读回执 | 显示已读/未读用户列表,支持提醒未读 | 无已读回执,仅通知发送 | 管理员无法知道公告是否被阅读 |
| 富文本编辑 | 支持富文本、图片、附件 | 仅纯文本 Textarea | 公告内容单调,无法插入图片 |
| 定时发布 | 支持指定时间自动发布 | `publishedAt` 字段存在但表单未暴露 | 管理员无法提前安排公告 |
| 公告置顶 | 支持置顶重要公告 | 无置顶功能 | 重要公告可能被新公告淹没 |
| 多渠道推送 | 站内 + 短信 + 邮件 + 微信 | 已实现多渠道notifications 模块) | ✅ 已达标 |
| 评论互动 | 支持公告下评论或确认收到 | 无互动功能 | 无法收集公告反馈 |
### 3.2 消息模块差距
| 功能 | 行业优秀实践 | 当前状态 | 影响 |
|------|-------------|----------|------|
| 消息分组 | 按联系人分组显示对话 | 仅按时间列表,无对话分组 | 教师与同一家长的来回消息散落各处 |
| 实时推送 | WebSocket / SSE 实时推送 | 30/60 秒轮询 | 消息延迟最高 30 秒,服务器压力大 |
| 消息草稿 | 支持草稿自动保存 | 无草稿功能 | 用户意外离开页面内容丢失 |
| 附件支持 | 支持发送文件附件 | 仅纯文本 | 无法发送作业截图等 |
| 消息星标 | 支持标记重要消息 | 无星标功能 | 重要消息无法快速找回 |
| 消息模板 | 支持常用消息模板 | 无模板 | 教师重复输入相同内容 |
| 群发消息 | 支持按班级/年级群发 | 仅支持单发 | 教师需逐个发送通知 |
| 消息搜索 | 全文搜索 + 按联系人/时间筛选 | 仅关键词搜索 subject + content | 无法按联系人筛选历史消息 |
| 已读回执 | 实时显示对方已读状态 | 仅 `readAt` 字段,无实时更新 | 发送方不知道消息是否被看到 |
### 3.3 通知模块差距
| 功能 | 行业优秀实践 | 当前状态 | 影响 |
|------|-------------|----------|------|
| 通知分类管理 | 支持按类型分组(作业/成绩/公告/消息) | 仅按时间列表,类型仅作为 Badge | 用户无法快速找到特定类型通知 |
| 通知静音 | 支持单类通知静音 | 有 `quietHours` 但仅全局免打扰 | 用户想静音作业通知但保留成绩通知无法实现 |
| 通知归档 | 支持归档已处理通知 | 仅标记已读,无归档 | 通知列表越来越长 |
| 通知优先级 | 支持高/中/低优先级 | 无优先级 | 紧急通知被普通通知淹没 |
| 桌面推送 | 支持浏览器桌面通知 | 仅站内下拉 | 用户不打开页面就收不到通知 |
### 3.4 多角色体验差距
| 角色 | 痛点 | 当前状态 | 影响 |
|------|------|----------|------|
| admin | 公告管理需切换到独立页面 | `/admin/announcements``/announcements` 分离 | 管理员查看用户视角需切换路由 |
| teacher | 消息收件人列表无法搜索 | `MessageCompose` 仅 Select 下拉 | 班级多时难以找到目标家长 |
| parent | 无法主动给教师发消息 | 依赖 `getRecipients` 返回的列表 | 家长需等待教师先发消息才能回复 |
| student | 公告无"确认收到"按钮 | 仅被动查看 | 学校无法确认学生是否看到公告 |
---
## 四、改进优先级建议
### P0紧急影响核心功能与安全
1. **i18n 全覆盖**:创建 `announcements.json``messages.json` 翻译文件,重构所有组件使用 `useTranslations` 替换硬编码文本,更新 `i18n/request.ts` 加载新文件。
2. **消除角色硬编码**:将 `NAV_CONFIG` 改为权限驱动配置,公告和消息导航项仅声明 `permission`,不按角色分组。
3. **补充错误边界**:为所有缺失的页面添加 `error.tsx`,区分"无权限"、"未找到"、"网络错误"三种状态。
### P1重要影响架构与体验
4. **解耦 messaging 与 notifications**:将通知相关组件(`notification-list.tsx``notification-dropdown.tsx`)迁移至 notifications 模块messaging 模块仅保留私信组件;通过 Context 注入数据服务接口。
5. **页面编排下沉**:在 announcements 和 messaging 模块新增 `getAdminAnnouncementsPageData` / `getMessagesPageData` 编排函数,页面层仅调用单一函数。
6. **公告表单条件校验**:使用 Zod `superRefine` 根据 `type` 强制要求 `targetGradeId` / `targetClassId`
7. **消息列表分页与虚拟滚动**:添加分页 UI超过 50 条时支持加载更多;搜索逻辑抽离为 `useMessageSearch` hook。
8. **通知实时推送**:将 30 秒轮询替换为 SSE 或 WebSocket减少无效请求首屏使用 RSC 获取初始数据。
9. **消息软删除事务化**:使用数据库事务包裹 `senderDeletedAt``receiverDeletedAt` 更新。
### P2优化提升完整性与可维护性
10. **a11y 改进**:为搜索框、按钮、链接添加 `aria-label`;确保键盘导航完整。
11. **监控埋点**:在关键 Action 中预留 `trackEvent` 接口,记录发布公告、发送消息、标记已读等操作。
12. **测试覆盖**:补充 messaging 模块 E2E 测试;为 `resolveTargetUserIds``getRecipients``selectChannels` 等纯函数添加单元测试。
13. **行业功能补齐**:公告已读回执、消息分组对话、消息草稿、通知优先级(按业务优先级逐步实施)。
14. **架构图同步**:补充 announcements 组件目录、messaging 的 notification-dropdown/unread-message-badge 组件、客户端搜索行为、轮询机制。
---
## 五、架构图同步说明
本次审计发现架构图存在以下遗漏,需补充:
### 5.1 `004_architecture_impact_map.md` 需补充
**§2.13 messaging 模块文件清单**
- 当前记录:`actions.ts` 276 行 / `data-access.ts` / `schema.ts` 41 行
- 实际状态:`actions.ts` 312 行 / `data-access.ts` 246 行 / `schema.ts` 44 行 / `types.ts` 52 行
- **遗漏组件**`components/notification-dropdown.tsx``components/unread-message-badge.tsx` 未在文件清单中列出
- **遗漏行为**`notification-dropdown.tsx` 每 30 秒轮询、`unread-message-badge.tsx` 每 60 秒轮询
**§2.16 announcements 模块文件清单**
- 当前记录:仅列出 actions/data-access/schema/types
- **遗漏组件目录**`components/` 下 5 个组件(`admin-announcements-view.tsx``announcement-card.tsx``announcement-detail.tsx``announcement-form.tsx``announcement-list.tsx`)未列出
**§2.13 messaging 依赖关系**
- **遗漏**`messaging/components/notification-list.tsx``notification-dropdown.tsx` 直接 import `@/modules/notifications/types`,存在跨模块 UI 类型依赖
### 5.2 `005_architecture_data.json` 需补充
- `modules.messaging.components` 数组缺少 `notification-dropdown.tsx``unread-message-badge.tsx` 两个节点
- `modules.announcements.components` 数组完全缺失5 个组件节点未记录)
- `modules.messaging.exports` 缺少 `UnreadMessageBadge` 组件导出
- `routes` 节点中 `/messages` 路由的 `dataAccess` 字段未记录客户端搜索行为(`getMessagesAction` 在客户端被调用)
### 5.3 无需修改的部分
- §2.14 notifications 模块记录完整准确
- P0-4 / P1-5 修复历史记录准确
- 依赖矩阵§3中 messaging → notifications 的单向依赖记录正确