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

> 审查日期：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 消息列表搜索逻辑复杂且无分页 UI（P1）

| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [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` 执行两个独立的 UPDATE（senderDeletedAt + 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 公告模块差距

| 功能 | 行业优秀实践 | 当前状态 | 影响 |
|------|-------------|----------|------|
| 公告分类标签 | 支持自定义标签（紧急、活动、政策），可按标签筛选 | 仅 type（school/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 的单向依赖记录正确
