Files
NextEdu/docs/architecture/audit/announcements-messages-audit-report-v2.md
SpecialX 1fe30984b6 refactor(announcements,messaging,notifications): V1+V2 审计重构 — i18n 命名空间独立 + 通知标题 i18n 化 + 服务端过滤 + 编排下沉 + 表单错误展示 + 架构图同步
V1 改进(已完成):
- P0-4/P1-4/P1-5: 通知组件和 CRUD Action 从 messaging 迁移至 notifications 模块
- P1-5: 新增 getMessagesPageData / getAdminAnnouncementsPageData 编排函数
- P1-6: announcements schema 添加 superRefine 条件校验
- P1-7: 新增 useMessageSearch hook(防抖 + 请求竞态取消)+ 客户端分页 UI
- P1-9: deleteMessage 事务化
- P2-11: 全模块 trackEvent 埋点
- 全模块 i18n 接入 + Error Boundary + a11y 改进

V2 改进(本次完成):
- V2-P0-1: 通知 i18n 命名空间独立(notifications.json),useTranslations 从 "messages" 切换到 "notifications"
- V2-P0-2: 公告/消息通知标题 i18n 化,Server Action 中使用 getTranslations 生成通知标题
- V2-P1-1: AnnouncementList 纯服务端过滤,移除客户端 useState/useMemo
- V2-P1-2: MessageList 客户端过滤仅在初始数据时执行,搜索结果由服务端按 tab 过滤
- V2-P1-3: 消息详情页编排下沉,新增 getMessageDetailPageData 编排函数
- V2-P1-4: 表单服务端校验错误展示(fieldErrors + aria-invalid)
- V2-P2-1: 轮询间隔常量化(POLL_INTERVAL_MS)
- V2-P2-2: 架构图同步(004 + 005)
2026-06-22 18:43:12 +08:00

160 lines
9.0 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.
# 公告和消息模块审计报告 V2
> 审查日期2026-06-22
> 审查范围V1 改进后的 `src/modules/announcements/**`、`src/modules/messaging/**`、`src/modules/notifications/**`、对应路由层
> 前置文档:`announcements-messages-audit-report.md`V114 项改进已全部完成或标记超出范围)
> 架构图参考:`docs/architecture/004_architecture_impact_map.md` §2.13 / §2.14 / §2.16
---
## 一、V1 完成情况复核
| V1 编号 | 标题 | 状态 |
|---------|------|------|
| P0-1 | i18n 全覆盖 | ✅ 已完成 |
| P0-2 | 消除角色硬编码 | ✅ 已完成COMMON_NAV_ITEMS 提取) |
| P0-3 | 补充错误边界 | ✅ 已完成7 个 error.tsx |
| P1-4 | 解耦 messaging 与 notifications | ✅ 已完成(通知组件迁移) |
| P1-5 | 页面编排下沉 | ✅ 已完成getAdminAnnouncementsPageData / getMessagesPageData |
| P1-6 | 公告表单条件校验 | ✅ 已完成superRefine |
| P1-7 | 消息列表分页与搜索 hook | ✅ 已完成useMessageSearch + 分页 UI |
| P1-8 | 通知实时推送 | ⚠️ 超出范围(需 SSE/WebSocket 基础设施) |
| P1-9 | 消息软删除事务化 | ✅ 已完成db.transaction |
| P2-10 | a11y 改进 | ✅ 已完成aria-label |
| P2-11 | 监控埋点 | ✅ 已完成trackEvent 接口) |
| P2-12 | 测试覆盖 | ⚠️ 超出范围(需独立测试计划) |
| P2-13 | 行业功能补齐 | ⚠️ 超出范围(需产品规划) |
| P2-14 | 架构图同步 | ✅ 已完成 |
V1 共 11 项已实施3 项标记超出范围。
---
## 二、V2 新发现问题
### 2.1 通知 i18n 命名空间越界P0
| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [notifications/components/notification-list.tsx](file:///e:/Desktop/CICD/src/modules/notifications/components/notification-list.tsx) L29 | `useTranslations("messages")` 通知组件使用 messages 命名空间 | "模块标准结构" — notifications 模块应有独立 i18n 资源 |
| [notifications/components/notification-dropdown.tsx](file:///e:/Desktop/CICD/src/modules/notifications/components/notification-dropdown.tsx) L39 | 同上 | 同上 |
| `src/shared/i18n/messages/` | 无 `notifications.json` 翻译文件 | 翻译文件结构不完整 |
| [i18n/request.ts](file:///e:/Desktop/CICD/src/i18n/request.ts) | 未加载 notifications 翻译文件 | 翻译文件未注册 |
**后果**:通知相关文案(`notificationType.*``empty.noNotifications*``actions.markAllRead` 等)散落在 messages 命名空间,模块边界混乱,维护困难。
### 2.2 通知标题硬编码P0
| 位置 | 代码 | 违反规则 |
|------|------|----------|
| [announcements/actions.ts](file:///e:/Desktop/CICD/src/modules/announcements/actions.ts) L75 | `title: \`新公告:${announcement.title}\`` | "所有用户可见文本必须适配 i18n" |
| [messaging/actions.ts](file:///e:/Desktop/CICD/src/modules/messaging/actions.ts) L70-71 | `title: input.subject ? \`New message: ${input.subject}\` : "New message"` | 同上 |
**后果**:通知标题语言固定(公告通知中文、消息通知英文),无法随 locale 切换。
### 2.3 AnnouncementList 过滤模式不一致P1
| 位置 | 问题 |
|------|------|
| [announcement-list.tsx](file:///e:/Desktop/CICD/src/modules/announcements/components/announcement-list.tsx) L48-59 | 客户端 `useMemo` 过滤 + URL `?status=` 更新混合模式 |
**问题分析**
- L48-51客户端 `filtered` 按 `filter` 状态过滤 `announcements` prop
- L53-59`handleFilterChange` 同时更新 `filter` 状态和 URL `?status=`
- 父页面 `admin/announcements/page.tsx` 根据 `?status=` 服务端查询并传入 `announcements` prop
**后果**:数据被双重过滤(服务端 + 客户端逻辑冗余URL 刷新时客户端 `filter` 状态可能与服务端 `initialStatus` 不同步。
### 2.4 MessageList 客户端过滤冗余P1
| 位置 | 问题 |
|------|------|
| [message-list.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/message-list.tsx) L50-53 | `filtered` 在客户端再次过滤 `displayMessages`,但 `getMessagesAction` 已按 `type` 参数过滤 |
**问题分析**
- `useMessageSearch` 调用 `getMessagesAction({ type: tab, ... })`,服务端已按 `tab` 过滤
- L50-53 又在客户端按 `m.receiverId === currentUserId` / `m.senderId === currentUserId` 过滤
- 当 `tab === "inbox"` 时,服务端返回 `receiverId === userId` 的消息,客户端再过滤一次相同条件
**后果**:逻辑冗余,且当服务端逻辑变化时客户端过滤可能不一致。
### 2.5 消息详情页编排未下沉P1
| 位置 | 问题 |
|------|------|
| `src/app/(dashboard)/messages/[id]/page.tsx` | 页面层直接调用 `getMessageById` 和 `getMessageThread`,未使用编排函数 |
**后果**:与 V1-P1-5 的编排下沉原则不一致;多个页面需要相同数据时无法复用。
### 2.6 表单未展示服务端校验错误P1
| 位置 | 问题 |
|------|------|
| [announcement-form.tsx](file:///e:/Desktop/CICD/src/modules/announcements/components/announcement-form.tsx) L70-76 | 仅显示 `res.message`,未消费 `res.errors` 字段级错误 |
| [message-compose.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/message-compose.tsx) L57-63 | 同上 |
**问题分析**
- Server Action 返回 `{ success: false, message, errors: { title: ["..."], content: ["..."] } }`
- 表单仅 `toast.error(res.message)`,用户无法看到具体字段错误
- V1-P1-6 添加的 `superRefine` 条件校验错误无法有效传达给用户
**后果**用户不知道哪个字段出错体验差Zod 校验形同虚设。
### 2.7 轮询间隔硬编码P2
| 位置 | 代码 |
|------|------|
| [notification-dropdown.tsx](file:///e:/Desktop/CICD/src/modules/notifications/components/notification-dropdown.tsx) L71 | `30_000` 硬编码 |
| [unread-message-badge.tsx](file:///e:/Desktop/CICD/src/modules/messaging/components/unread-message-badge.tsx) | `60_000` 硬编码 |
**后果**:调整轮询频率需修改多个文件,无统一配置点。
### 2.8 架构图未记录 V2 新增内容P2
V2 新增的编排函数、i18n 文件、常量等需同步到架构图。
---
## 三、V2 改进优先级
### V2-P0紧急影响 i18n 完整性)
1. **通知 i18n 命名空间独立**:创建 `notifications.json` 翻译文件,将通知相关文案从 `messages.json` 迁移;更新 `i18n/request.ts` 加载新文件;通知组件改用 `useTranslations("notifications")`。
2. **通知标题 i18n 化**:在 `announcements/actions.ts` 和 `messaging/actions.ts` 中使用 `getTranslations` 获取通知标题翻译。
### V2-P1重要影响代码质量与体验
3. **AnnouncementList 过滤模式统一**:移除客户端 `useMemo` 过滤,改为纯服务端过滤(通过 URL `?status=` 触发 RSC 重新渲染)。
4. **MessageList 过滤冗余移除**:移除客户端 `filtered` 过滤,直接使用 `displayMessages`(服务端已按 `type` 过滤)。
5. **消息详情页编排下沉**:新增 `getMessageDetailPageData` 编排函数。
6. **表单服务端校验错误展示**:在 `AnnouncementForm` 和 `MessageCompose` 中展示 `res.errors` 字段级错误。
### V2-P2优化提升可维护性
7. **轮询间隔常量化**:提取 `NOTIFICATION_POLL_INTERVAL_MS` 和 `MESSAGE_POLL_INTERVAL_MS` 常量。
8. **架构图同步**:补充 V2 新增内容到 004/005 架构文档。
---
## 四、实施计划
| 编号 | 文件 | 变更类型 |
|------|------|----------|
| V2-P0-1 | `src/shared/i18n/messages/{zh-CN,en}/notifications.json` | 新建 |
| V2-P0-1 | `src/i18n/request.ts` | 修改(加载 notifications |
| V2-P0-1 | `src/shared/i18n/messages/{zh-CN,en}/messages.json` | 修改(移除通知相关键) |
| V2-P0-1 | `src/modules/notifications/components/notification-list.tsx` | 修改useTranslations 命名空间) |
| V2-P0-1 | `src/modules/notifications/components/notification-dropdown.tsx` | 修改(同上) |
| V2-P0-2 | `src/modules/announcements/actions.ts` | 修改getTranslations |
| V2-P0-2 | `src/modules/messaging/actions.ts` | 修改getTranslations |
| V2-P1-1 | `src/modules/announcements/components/announcement-list.tsx` | 修改(移除客户端过滤) |
| V2-P1-2 | `src/modules/messaging/components/message-list.tsx` | 修改(移除 filtered |
| V2-P1-3 | `src/modules/messaging/data-access.ts` | 修改(新增编排函数) |
| V2-P1-3 | `src/app/(dashboard)/messages/[id]/page.tsx` | 修改(使用编排函数) |
| V2-P1-4 | `src/modules/announcements/components/announcement-form.tsx` | 修改(展示 errors |
| V2-P1-4 | `src/modules/messaging/components/message-compose.tsx` | 修改(展示 errors |
| V2-P2-1 | `src/modules/notifications/components/notification-dropdown.tsx` | 修改(常量化) |
| V2-P2-1 | `src/modules/messaging/components/unread-message-badge.tsx` | 修改(常量化) |
| V2-P2-2 | `docs/architecture/004_architecture_impact_map.md` | 修改(同步) |
| V2-P2-2 | `docs/architecture/005_architecture_data.json` | 修改(同步) |