# 设置和个人信息模块审计报告

> 审查日期：2026-06-22
> 审查范围：`src/modules/settings/**`、`src/app/(dashboard)/settings/**`、`src/app/(dashboard)/admin/settings/**`、`src/app/(dashboard)/profile/**`
> 架构图参考：`docs/architecture/004_architecture_impact_map.md` §2.23、`docs/architecture/005_architecture_data.json`

---

## 一、现有实现概要

### 1.1 文件分布

| 层 | 路径 | 文件数 | 说明 |
|----|------|--------|------|
| 路由层 - 通用设置 | `src/app/(dashboard)/settings/` | 1 个 `page.tsx` + `error.tsx` + `loading.tsx` | 角色分发到 4 个 SettingsView |
| 路由层 - 管理员系统设置 | `src/app/(dashboard)/admin/settings/` | 1 个 `page.tsx` | 仅 admin 可访问，渲染 `AdminSettingsView` |
| 路由层 - 安全设置 | `src/app/(dashboard)/settings/security/` | 1 个 `page.tsx` + `error.tsx` + `loading.tsx` | 独立密码修改页 |
| 路由层 - 个人资料 | `src/app/(dashboard)/profile/` | 1 个 `page.tsx` + `error.tsx` + `loading.tsx` | 个人资料展示页（317 行） |
| 模块层 - actions | `src/modules/settings/actions.ts`（160 行） | AI Provider CRUD + test | ✅ 使用 `requirePermission(AI_CONFIGURE)` |
| 模块层 - actions-password | `src/modules/settings/actions-password.ts`（87 行） | 修改密码 | ✅ 使用 `requirePermission(USER_PROFILE_UPDATE)` + Zod + 限流 |
| 模块层 - data-access | `src/modules/settings/data-access.ts`（158 行） | AI Provider + 密码 DB 操作 | ✅ `server-only` |
| 模块层 - types | `src/modules/settings/types.ts`（16 行） | AI Provider 类型 | |
| 模块层 - 组件 | `src/modules/settings/components/` | 10 个组件 | 见下表 |
| i18n | **缺失** | 0 | 无 `settings.json` / `profile.json` 翻译文件 |

**组件清单**：

| 组件 | 行数 | 职责 |
|------|------|------|
| [settings-view.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/settings-view.tsx) | 179 | 统一设置页布局（5 标签页 + 角色差异 props 注入 + Tab URL 持久化） |
| [admin-settings-view.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/admin-settings-view.tsx) | 185 | **mock 实现**：4 个 Card（学校信息/安全策略/文件上传/通知配置），`setTimeout` 模拟保存 |
| [ai-provider-settings-card.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/ai-provider-settings-card.tsx) | 357 | AI Provider 管理（选择/新建/测试/保存） |
| [notification-preferences-form.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/notification-preferences-form.tsx) | 326 | 通知偏好（渠道/类别/免打扰时段） |
| [password-change-form.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/password-change-form.tsx) | 169 | 修改密码（强度指示器 + 显示切换） |
| [profile-settings-form.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/profile-settings-form.tsx) | 146 | 个人资料编辑表单 |
| [theme-preferences-card.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/theme-preferences-card.tsx) | 55 | 主题切换（system/light/dark） |
| [parent-settings-view.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/parent-settings-view.tsx) | 60 | 家长设置视图（复用 SettingsView + 快捷链接） |
| [teacher-settings-view.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/teacher-settings-view.tsx) | 66 | 教师设置视图（同上） |
| [student-settings-view.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/student-settings-view.tsx) | 54 | 学生设置视图（同上） |

### 1.2 数据流

```
[Route] /settings/page.tsx
   ├─▶ users/data-access.getUserProfile          (跨模块 data-access，类型导入)
   ├─▶ notifications/preferences.getNotificationPreferences  (跨模块 data-access)
   └─▶ 按 roles.includes("admin"|"student"|"parent") 分发
         ├─ admin    → SettingsView（无 generalExtra）
         ├─ student  → StudentSettingsView → SettingsView
         ├─ parent   → ParentSettingsView  → SettingsView
         └─ teacher  → TeacherSettingsView → SettingsView

[Route] /admin/settings/page.tsx
   └─▶ AdminSettingsView（mock，无数据流）

[Route] /settings/security/page.tsx
   └─▶ PasswordChangeForm → settings/actions-password.changePasswordAction

[Route] /profile/page.tsx
   ├─▶ users/data-access.getUserProfile
   ├─▶ classes/data-access.getStudentClasses / getStudentSchedule       (学生分支)
   ├─▶ homework/data-access.getStudentHomeworkAssignments / getStudentDashboardGrades  (学生分支)
   ├─▶ classes/data-access.getTeacherClasses / getTeacherTeachingSubjects  (教师分支)
   └─▶ 页面层内联 80+ 行业务计算（weekday 转换、作业状态统计、排序切片）

[Component] ProfileSettingsForm
   └─▶ users/actions.updateUserProfile  ❌ 跨模块 action 直调

[Component] NotificationPreferencesForm
   └─▶ messaging/actions.updateNotificationPreferencesAction  ❌ 跨模块 action 直调

[Component] AiProviderSettingsCard
   └─▶ settings/actions.getAiProviderSummaries / upsertAiProviderAction / testAiProviderAction  ✅ 模块内
```

### 1.3 架构图记录情况

`004_architecture_impact_map.md` §2.23 记录了 settings 模块的基本结构，但存在以下遗漏和不一致：

- **未记录 `profile/page.tsx` 的数据流**：profile 页面编排了 users/classes/homework 三个模块的 data-access，但架构图未记录
- **未记录跨模块 action 直调问题**：`profile-settings-form.tsx` 直调 `users/actions.updateUserProfile`、`notification-preferences-form.tsx` 直调 `messaging/actions.updateNotificationPreferencesAction`，架构图标注为"已修复"但实际仍存在
- **未记录 `AdminSettingsView` 是 mock 实现**：架构图描述其有 4 个 Card 但未说明无真实数据持久化
- **未记录 i18n 缺失**：架构图未标注 settings 模块所有文本均为硬编码
- **通知偏好归属不一致**：架构图 §2.17 称通知偏好已迁移至 notifications 模块，但 `notification-preferences-form.tsx` 仍从 `messaging/actions` 导入 action

---

## 二、现存问题与原因分析

### 2.1 国际化完全缺失（P0）

| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [settings-view.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/settings-view.tsx) L96-104 | "Settings"、"Back to dashboard" 等硬编码英文 | "所有用户可见文本必须适配 i18n（使用 next-intl），提取翻译键" |
| [admin-settings-view.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/admin-settings-view.tsx) 全文 | "系统设置"、"学校信息"、"安全策略" 等硬编码中文 | 同上 |
| [profile-settings-form.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/profile-settings-form.tsx) L80-82 | "Profile Information"、"Update your personal information." 硬编码 | 同上 |
| [notification-preferences-form.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/notification-preferences-form.tsx) L47-99 | CHANNELS/CATEGORIES 数组中 label/description 全部硬编码 | 同上 |
| [password-change-form.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/password-change-form.tsx) L72-76 | "Change Password"、"Choose a strong password..." 硬编码 | 同上 |
| [theme-preferences-card.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/theme-preferences-card.tsx) L24-28 | "Theme"、"Choose how the admin console looks..." 硬编码（且写死 "admin console"） | 同上 |
| [ai-provider-settings-card.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/ai-provider-settings-card.tsx) L251-257 | "AI Providers"、"Manage AI vendors..." 硬编码 | 同上 |
| [profile/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/profile/page.tsx) 全文 | "Profile"、"Personal Information"、"Account Information" 等硬编码 | 同上 |
| [settings/loading.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/settings/loading.tsx) 等错误页 | "页面加载失败" 中文硬编码，与英文页面不统一 | 同上 |
| `src/shared/i18n/messages/{zh-CN,en}/` | **无 settings.json / profile.json** | i18n 命名空间缺失 |
| `src/i18n/request.ts` | 未加载 settings/profile 命名空间 | 同上 |

**原因**：settings 模块在历次重构中未纳入 i18n 改造范围，`i18n/request.ts` 只加载 6 个命名空间（common/auth/onboarding/classes/errors/dashboard）。

**后果**：无法支持中英文切换；admin 端中文、其他端英文，体验割裂；新增语言需逐文件修改。

### 2.2 跨模块 Action 直调，违反解耦原则（P0）

| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [profile-settings-form.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/profile-settings-form.tsx) L16 | `import { updateUserProfile } from "@/modules/users/actions"` | "模块内部组件绝不直接 import 其他业务模块的 actions 或 data-access（只能通过注入的接口调用）" |
| [notification-preferences-form.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/notification-preferences-form.tsx) L16 | `import { updateNotificationPreferencesAction } from "@/modules/messaging/actions"` | 同上 |
| [settings-view.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/settings-view.tsx) L28 | `import { UserProfile } from "@/modules/users/data-access"` | 类型导入，语法允许但耦合类型定义 |
| [settings-view.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/settings-view.tsx) L29 | `import type { NotificationPreferences } from "@/modules/notifications/types"` | 类型导入，可接受 |

**原因**：settings 组件直接消费 users/messaging 模块的 Server Action，未通过接口抽象 + Context 注入。

**后果**：settings 模块无法独立测试（mock users/messaging action 困难）；users/messaging action 签名变更会直接破坏 settings 组件；无法在不修改 settings 组件的前提下替换数据源。

### 2.3 AdminSettingsView 是 mock 实现（P0）

| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [admin-settings-view.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/admin-settings-view.tsx) L20-25 | `await new Promise((r) => setTimeout(r, 800))` 模拟保存，无 Server Action 调用 | "app/ 只能调用 modules/ 的 Server Actions 和 data-access，不直接访问数据库" — 这里连 action 都没调 |
| 同文件 L23 | `toast.success("设置已保存")` 撒谎，实际未保存 | 用户体验问题 |
| 同文件全文 | 4 个 Card（学校信息/安全策略/文件上传/通知配置）的输入框无 `name` 属性、无表单提交逻辑 | 表单不可用 |
| [admin/settings/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/admin/settings/page.tsx) | 与 `/settings` 页面割裂，admin 用户有两个设置入口 | 信息架构混乱 |

**原因**：初版占位实现，后续未接入真实数据层。

**后果**：admin 调整的安全策略/文件上传限制/通知配置均不生效；与 `/settings` 页面功能重叠但行为不一致。

### 2.4 角色路由硬编码，非配置驱动（P1）

| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [settings/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/settings/page.tsx) L28-44 | `if (roles.includes("admin")) ... if (roles.includes("student")) ...` 4 分支硬编码 | "采用配置驱动设计，例如通过角色配置决定该模块渲染哪些 Widget/子模块" |
| [profile/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/profile/page.tsx) L48-49 | `const isStudent = roles.includes("student")` | 同上 |

**原因**：角色分发逻辑写在页面层，未抽取为配置。

**后果**：新增角色（如 grade_head）需修改页面代码；角色与设置视图的映射关系不可配置。

### 2.5 缺少分区 Error Boundary 和 Suspense（P1）

| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [settings-view.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/settings-view.tsx) L132-184 | 5 个 TabsContent 内部组件（ProfileSettingsForm / NotificationPreferencesForm / ThemePreferencesCard / PasswordChangeForm / AiProviderSettingsCard）无独立 Error Boundary | "每个独立的数据区块必须用 React Error Boundary 包裹" |
| 同上 | AiProviderSettingsCard 在 useEffect 中异步加载 providers，无 Suspense 包裹 | "异步数据使用 React Suspense + 骨架屏" |
| [profile/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/profile/page.tsx) L229-314 | 学生概览 / 教师概览区块无独立 Error Boundary | 同上 |

**原因**：仅依赖页面级 `error.tsx` / `loading.tsx`，未做分区隔离。

**后果**：AI Provider 加载失败会导致整个 Security 标签页崩溃；ProfileSettingsForm 提交失败不会优雅降级。

### 2.6 Profile 页面职责臃肿（P1）

| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [profile/page.tsx](file:///e:/Desktop/CICD/src/app/(dashboard)/profile/page.tsx) L37-317 | 单文件 317 行，混合：用户基本信息展示 + 学生作业统计 + 课表筛选 + 教师班级展示 | "页面组件" 建议 ≤ 500 行（虽未超限，但职责过多） |
| 同文件 L51-110 | 学生分支内联 60 行业务计算（dueSoonCount / overdueCount / gradedCount / upcomingAssignments 排序） | "数据获取、计算、格式化等纯逻辑全部放入纯函数或 hooks，与 UI 分离" |
| 同文件 L27-35 | `WEEKDAY_MAP` / `toWeekday` 日期工具函数定义在页面文件内 | 同上 |

**原因**：profile 页面直接编排了 dashboard 模块的学生概览组件，未通过 service 层。

**后果**：业务逻辑不可测试、不可复用；学生/教师概览与 dashboard 模块重复。

### 2.7 类型安全与表单规范问题（P2）

| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [profile-settings-form.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/profile-settings-form.tsx) L44 | `zodResolver(profileFormSchema) as Resolver<ProfileFormValues>` 使用 `as` 断言 | "禁止 `as` 断言（除非从 `unknown` 转换或测试中）" |
| [notification-preferences-form.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/notification-preferences-form.tsx) L121 | `useActionState(updateNotificationPreferencesAction, null)` 第二参数 `null` 类型不安全 | 应为 `ActionState<null>` 初值 |
| [admin-settings-view.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/admin-settings-view.tsx) L22 | `await new Promise((r) => setTimeout(r, 800))` 参数 `r` 隐式 any | "禁止 any" |

### 2.8 可访问性缺失（P2）

| 位置 | 问题 | 违反规则 |
|------|------|----------|
| [settings-view.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/settings-view.tsx) L106-130 | Tabs 组件虽有 Radix 内置 a11y，但 TabsTrigger 仅有图标+文字，无 `aria-label` | "可访问性（a11y）：语义化标签、ARIA 属性、键盘导航" |
| [notification-preferences-form.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/notification-preferences-form.tsx) L198-205 | 隐藏 checkbox + Switch 双控件模式，屏幕阅读器可能重复朗读 | 同上 |
| [password-change-form.tsx](file:///e:/Desktop/CICD/src/modules/settings/components/password-change-form.tsx) L90-99 | 密码显示切换按钮 `tabIndex={-1}`，键盘用户无法触达 | "键盘导航" |

### 2.9 监控埋点缺失（P2）

| 位置 | 问题 | 违反规则 |
|------|------|----------|
| 全模块 | 无任何埋点接口预留（密码修改成功率、AI Provider 测试通过率、通知偏好变更频率等） | "监控：方案中预留关键操作埋点接口" |

### 2.10 行业差距：安全功能单薄（P2）

| 缺失功能 | 影响 |
|----------|------|
| 头像上传 | 用户无法个性化头像，profile 页只能显示文字 fallback |
| 两步验证（2FA/MFA） | K12 系统涉及学生隐私，仅密码保护不够 |
| 活跃会话管理 | 用户无法查看/远程登出其他设备会话 |
| 登录历史查看 | 非管理员用户无法查看自己的登录记录 |
| 账号数据导出/注销 | 不符合 GDPR-like 合规要求 |
| 通知预览 | 通知偏好表单无"发送测试通知"功能 |
| 设置搜索 | 设置项较多时无快速定位 |

---

## 三、行业差距对比

### 3.1 与优秀 K12 产品的差距

| 维度 | 优秀实践（Google Classroom / PowerSchool / Veracross） | 当前状态 | 差距影响 |
|------|--------------------------------------------------------|----------|----------|
| **设置信息架构** | 统一入口，按角色动态显示分组，支持搜索 | admin 有两个入口（`/admin/settings` mock + `/settings`），其他角色统一 | admin 体验割裂，功能不可用 |
| **个人资料** | 头像上传 + 字段级权限可见性（学生看不到自己手机号，家长可见） | 无头像上传，所有字段对本人可见 | 个性化缺失，字段级权限未实现 |
| **安全中心** | 2FA、会话列表、登录历史、密码泄露检测 | 仅密码修改 | K12 数据安全合规风险 |
| **通知偏好** | 按事件类型细分（作业/成绩/考勤/公告/消息），支持渠道矩阵 + 免打扰 | 已有基础，但无"测试通知"按钮 | 功能完整度尚可，交互反馈缺失 |
| **主题/语言** | 主题切换 + 语言切换同页 | 主题有，语言切换在 shared 但未集成到设置页 | 用户需到别处找语言切换 |
| **AI 配置** | 多 Provider + 测试 + 用量统计 | 多 Provider + 测试，无用量统计 | 教育机构无法监控 AI 成本 |
| **空状态/骨架屏** | 每个数据区块独立骨架屏 + 空状态 | 仅页面级 loading.tsx | 局部加载失败时整页白屏 |

### 3.2 多角色使用习惯差距

| 角色 | 优秀实践 | 当前状态 |
|------|----------|----------|
| **admin** | 系统设置（学校信息/策略）与个人设置在同一入口的不同分组 | 两套页面割裂，系统设置是 mock |
| **teacher** | 设置页可快速跳转常用教学功能 | ✅ 有 Quick links（TeacherSettingsView） |
| **parent** | 设置页可切换查看不同孩子的通知偏好 | 仅一套偏好，无法按孩子细分 |
| **student** | 设置页简洁，无系统配置 | ✅ 简洁 |

---

## 四、改进优先级建议

### P0（紧急，影响安全/合规/核心功能）

1. **创建 settings i18n 命名空间**：新增 `zh-CN/settings.json` + `en/settings.json`，覆盖所有设置/个人资料文本；更新 `i18n/request.ts` 加载新命名空间。
2. **消除跨模块 action 直调**：定义 `SettingsService` 接口（含 `updateProfile` / `updateNotificationPreferences` 方法），通过 React Context 注入；`ProfileSettingsForm` / `NotificationPreferencesForm` 改为消费 Context。
3. **AdminSettingsView 接入真实数据层**：将 4 个 Card（学校信息/安全策略/文件上传/通知配置）接入 `school/data-access` 或新增 `system-settings` data-access；移除 mock `setTimeout`。

### P1（重要，影响可维护性/体验）

4. **配置驱动角色路由**：新增 `settings-config.ts`，定义 `Role → SettingsViewConfig` 映射（description / backHref / generalExtra），`/settings/page.tsx` 改为查表分发。
5. **分区 Error Boundary + Suspense**：为每个 TabsContent 内部组件包裹 `<ErrorBoundary>` + `<Suspense fallback={<Skeleton/>}>`。
6. **Profile 页面拆分**：将学生概览/教师概览业务逻辑抽为 `useStudentProfileOverview` / `useTeacherProfileOverview` hooks；`WEEKDAY_MAP`/`toWeekday` 移至 `shared/lib/utils`。
7. **移除 `as` 断言**：`profile-settings-form.tsx` 的 `zodResolver(...) as Resolver<...>` 改为类型兼容写法。

### P2（优化，提升完整度）

8. **头像上传**：profile 页新增头像上传组件（复用 `files/data-access`）。
9. **2FA / 会话管理**：security 标签页新增 2FA 开关 + 活跃会话列表。
10. **通知测试按钮**：通知偏好表单新增"发送测试通知"按钮。
11. **语言切换集成**：在 Appearance 标签页集成 `LocaleSwitcher`。
12. **埋点接口**：在 `SettingsService` 接口预留 `trackEvent` 方法。
13. **a11y 修复**：密码显示切换按钮移除 `tabIndex={-1}`；通知偏好表单移除冗余隐藏 checkbox。

---

## 五、架构图同步说明

本次审计发现架构图需补充/修改以下节点：

### 5.1 `004_architecture_impact_map.md` §2.23 settings 模块

- **修改"已知问题"**：新增"跨模块 action 直调未修复"（`profile-settings-form` → `users/actions`、`notification-preferences-form` → `messaging/actions`）
- **修改"已知问题"**：新增"AdminSettingsView 为 mock 实现，无数据持久化"
- **修改"已知问题"**：新增"i18n 完全缺失，所有文本硬编码"
- **修改"依赖关系"**：明确标注 `profile-settings-form.tsx` 依赖 `users/actions`（action 级，非 data-access）
- **新增"文件清单"**：补充 `profile/page.tsx`（317 行）的归属说明（虽在 app 层，但编排 settings 相关数据）

### 5.2 `005_architecture_data.json` settings 节点

- **`modules.settings.knownIssues`**：新增 3 条（跨模块 action 直调 / AdminSettingsView mock / i18n 缺失）
- **`modules.settings.exports`**：补充 `SettingsService` 接口（重构后新增）
- **`dependencyMatrix`**：settings → users 的依赖类型从 `data-access` 改为 `action`（标注为待修复）

### 5.3 `004` §2.17 notifications 模块

- **修正不一致**：`notification-preferences-form.tsx` 仍从 `messaging/actions` 导入 action，但架构图称"通知偏好已迁移至 notifications 模块" — 需标注"表单层 action 调用未同步迁移"

---

## 六、重构方案设计

### 6.1 完全解耦：SettingsService 接口 + Context 注入

```typescript
// src/modules/settings/types.ts (新增)
export interface ProfileService {
  getProfile: () => Promise<UserProfile | null>
  updateProfile: (input: UpdateProfileInput) => Promise<ActionState<UserProfile>>
}

export interface NotificationService {
  getPreferences: () => Promise<NotificationPreferences>
  updatePreferences: (input: UpdateNotificationPreferencesInput) => Promise<ActionState<null>>
}

export interface SettingsService {
  profile: ProfileService
  notifications: NotificationService
  trackEvent?: (event: string, payload?: Record<string, unknown>) => void
}
```

```tsx
// src/modules/settings/components/settings-service-context.tsx (新增)
const SettingsServiceContext = createContext<SettingsService | null>(null)

export function SettingsServiceProvider({ service, children }: { service: SettingsService; children: ReactNode }) {
  return <SettingsServiceContext.Provider value={service}>{children}</SettingsServiceContext.Provider>
}

export function useSettingsService(): SettingsService {
  const ctx = useContext(SettingsServiceContext)
  if (!ctx) throw new Error("useSettingsService must be used within SettingsServiceProvider")
  return ctx
}
```

页面层注入实现：

```tsx
// /settings/page.tsx
const serverService: SettingsService = {
  profile: {
    getProfile: async () => getUserProfile(userId),
    updateProfile: async (input) => updateUserProfile(input),
  },
  notifications: {
    getPreferences: async () => getNotificationPreferences(userId),
    updatePreferences: async (input) => updateNotificationPreferencesAction(null, input),
  },
}
return <SettingsServiceProvider service={serverService}><SettingsView {...} /></SettingsServiceProvider>
```

### 6.2 组合优先：角色配置驱动

```typescript
// src/modules/settings/config/role-settings-config.ts (新增)
export interface RoleSettingsConfig {
  description: string
  backHref: string
  generalExtra?: ReactNode
}

export const ROLE_SETTINGS_CONFIG: Partial<Record<Role, RoleSettingsConfig>> = {
  admin: { description: "settings.admin.description", backHref: "/admin/dashboard" },
  teacher: { description: "settings.teacher.description", backHref: "/teacher/dashboard", generalExtra: <TeacherQuickLinks /> },
  student: { description: "settings.student.description", backHref: "/student/dashboard", generalExtra: <StudentQuickLinks /> },
  parent: { description: "settings.parent.description", backHref: "/parent/dashboard", generalExtra: <ParentQuickLinks /> },
}
```

### 6.3 国际化就绪：翻译文件结构

```json
// src/shared/i18n/messages/zh-CN/settings.json
{
  "title": "设置",
  "backToDashboard": "返回仪表盘",
  "tabs": {
    "general": "通用",
    "notifications": "通知",
    "appearance": "外观",
    "security": "安全",
    "ai": "AI"
  },
  "profile": {
    "title": "个人信息",
    "description": "更新您的个人资料",
    "fields": {
      "name": "姓名",
      "email": "邮箱",
      "phone": "电话",
      "address": "地址",
      "gender": "性别",
      "age": "年龄",
      "role": "角色"
    }
  },
  "notifications": {
    "title": "通知偏好",
    "channels": { "push": "推送通知", "email": "邮件", "sms": "短信" },
    "categories": { "messages": "消息", "announcements": "公告", "homework": "作业", "grades": "成绩", "attendance": "考勤" },
    "quietHours": { "title": "免打扰时段", "enable": "启用", "start": "开始时间", "end": "结束时间" }
  },
  "security": {
    "changePassword": { "title": "修改密码", "current": "当前密码", "new": "新密码", "confirm": "确认密码" },
    "session": { "title": "会话", "signOut": "退出登录" }
  },
  "appearance": { "theme": { "title": "主题", "system": "跟随系统", "light": "浅色", "dark": "深色" } },
  "ai": { "providers": { "title": "AI 服务商", "test": "测试", "save": "保存" } }
}
```

### 6.4 错误与边界处理

每个 TabsContent 内部组件用 `<ErrorBoundary>` + `<Suspense>` 包裹：

```tsx
<TabsContent value="ai">
  <ErrorBoundary fallback={<SettingsSectionError />}>
    <Suspense fallback={<AiProviderSkeleton />}>
      <AiProviderSettingsCard />
    </Suspense>
  </ErrorBoundary>
</TabsContent>
```

### 6.5 可测试性

- `SettingsService` 接口可 mock，组件单测无需真实 DB
- `WEEKDAY_MAP` / `toWeekday` 移至 `shared/lib/utils` 后可独立测试
- 学生概览计算逻辑抽为 `useStudentProfileOverview` hook，可独立测试

### 6.6 可扩展性

- 新增角色只需在 `ROLE_SETTINGS_CONFIG` 添加条目
- 新增设置标签页只需在 `settings-view.tsx` 的 tabs 配置添加条目
- 新增系统设置 Card 只需在 `AdminSettingsView` 组合新 Card

### 6.7 企业级补充

- **a11y**：密码显示切换按钮移除 `tabIndex={-1}`；通知偏好表单移除冗余隐藏 checkbox，仅用 Switch + `name` 属性
- **性能**：SettingsView 保持客户端组件（需 URL searchParams），但各标签页内容组件按需加载
- **安全**：`SettingsService` 实现在 Server Action 层调用 `requirePermission`，组件层不绕过
- **监控**：`SettingsService.trackEvent` 预留埋点接口
