From ee517f2b335431b26b8a949991659735b26b611b Mon Sep 17 00:00:00 2001 From: SpecialX <47072643+wangxiner55@users.noreply.github.com> Date: Wed, 17 Jun 2026 21:56:44 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=96=B0=E5=A2=9E=E6=9E=B6=E6=9E=84?= =?UTF-8?q?=E8=A7=A3=E8=80=A6=E8=B7=AF=E7=BA=BF=E5=9B=BE=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 docs/architecture/audit/01_decoupling_roadmap.md - 解耦原则: 单一职责 / 模块封装 / 分层单向依赖 - 过耦合问题清单: 6 项 P0 + 6 项 P1 + 2 项 P2 - 每项含问题/影响/解耦方案/迁移步骤 - 三阶段执行优先级与验收标准 - 更新 docs/README.md 索引加入解耦路线图 - 更新 work_log 记录本次工作 --- docs/README.md | 1 + .../audit/01_decoupling_roadmap.md | 454 ++++++++++++++++++ docs/work_log.md | 25 +- 3 files changed, 479 insertions(+), 1 deletion(-) create mode 100644 docs/architecture/audit/01_decoupling_roadmap.md diff --git a/docs/README.md b/docs/README.md index ef3be93..d537be1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -20,6 +20,7 @@ | 文档 | 用途 | |------|------| | [审查汇总](architecture/audit/00_summary.md) | 全项目架构审查汇总报告 | +| [解耦路线图](architecture/audit/01_decoupling_roadmap.md) | 过耦合问题清单与解耦执行计划(P0/P1/P2 优先级) | | [shared 层审查](architecture/audit/shared-audit.md) | 共享基础设施层审查 | | [核心业务模块审查](architecture/audit/core-business-audit.md) | exams/homework/questions/textbooks 等核心模块审查 | | [管理模块群审查](architecture/audit/management-modules-audit.md) | school/classes/users/audit 等管理模块审查 | diff --git a/docs/architecture/audit/01_decoupling_roadmap.md b/docs/architecture/audit/01_decoupling_roadmap.md new file mode 100644 index 0000000..9bae3fb --- /dev/null +++ b/docs/architecture/audit/01_decoupling_roadmap.md @@ -0,0 +1,454 @@ +# 架构解耦路线图 + +> 创建日期:2026-06-17 +> 依据:`docs/architecture/audit/` 下 4 份审查报告 +> 目标:消除过耦合,使每个模块/函数遵守单一职责原则,让架构文档一次阅读即可理解项目 +> 关联文档: +> - [004 架构影响地图](../004_architecture_impact_map.md) +> - [005 架构数据 JSON](../005_architecture_data.json) +> - [审查汇总报告](./00_summary.md) + +--- + +## 一、解耦原则 + +### 1.1 单一职责原则(SRP) + +- **模块**:一个模块只负责一个业务域(如 `exams` 只管考试,不管作业) +- **文件**:一个文件只承担一类职责(data-access 只做数据存取,不做业务计算) +- **函数**:一个函数只做一件事(要么查询,要么写入,要么计算,不混合) + +### 1.2 模块封装原则 + +- 模块对外只暴露 `actions.ts`(编排)和必要的 `data-access.ts` 查询函数 +- **禁止跨模块直接查询 DB 表**,必须通过对方模块的 data-access 函数 +- 模块间类型导入允许,但 DB 访问必须走 data-access + +### 1.3 分层单向依赖原则 + +``` +app/ ──▶ modules/ ──▶ shared/ + ▲ + │ + 禁止反向依赖 +``` + +- `shared/` 不得 import `@/auth`、`@/proxy` 或任何 `modules/*` +- `modules/` 不得 import `app/*` +- `app/` 不得直接 import `shared/db`(必须通过 modules 的 data-access) + +--- + +## 二、过耦合问题清单 + +### P0 严重问题(必须立即修复) + +#### P0-1 `classes/data-access.ts` 2104 行,超硬上限 2.1 倍 + +**问题**: +- 文件行数 2104,远超 1000 行硬上限 +- 混入 homework 相关逻辑(getHomeworkStats 等) +- 混入 scheduling 相关逻辑(getClassSchedule 等) +- 混入 grades 相关逻辑(getClassGradeSummary 等) + +**影响**: +- 单文件改动影响多业务域,回归风险高 +- 阅读者无法快速定位班级相关数据访问 + +**解耦方案**: +``` +src/modules/classes/ +├── data-access.ts # 班级核心 CRUD(目标 ≤500 行) +├── data-access-stats.ts # 班级统计查询(getHomeworkStats 等) +├── data-access-schedule.ts # 班级课表查询(getClassSchedule 等) +└── data-access-grades.ts # 班级成绩汇总(getClassGradeSummary 等) +``` + +**迁移步骤**: +1. 创建 3 个新文件,按职责迁移对应函数 +2. 在 `data-access.ts` 中 re-export 以保持向后兼容 +3. 逐步更新调用方 import 路径 +4. 最终移除 re-export,强制使用新路径 + +--- + +#### P0-2 `homework/data-access.ts` 1038 行,混入排名计算 + +**问题**: +- 文件行数 1038,超 1000 行硬上限 +- 混入排名计算业务逻辑(calculateClassRankings 等) +- data-access 层不应包含业务计算 + +**影响**: +- 排名算法变更需要修改 data-access 文件 +- data-access 职责不清,难以测试 + +**解耦方案**: +``` +src/modules/homework/ +├── data-access.ts # 作业 CRUD(目标 ≤800 行) +├── ranking-service.ts # 排名计算业务逻辑 +└── stats-service.ts # 作业统计业务逻辑 +``` + +**迁移步骤**: +1. 抽取 `calculateClassRankings` 到 `ranking-service.ts` +2. 抽取统计相关函数到 `stats-service.ts` +3. data-access 只保留 CRUD + 简单查询 + +--- + +#### P0-3 `shared/lib` ↔ `@/auth` 循环依赖 + +**问题**: +``` +shared/lib/audit-logger.ts ──┐ +shared/lib/change-logger.ts ──┼──▶ import { auth } from "@/auth" +shared/lib/auth-guard.ts ──┘ + +src/auth.ts ──▶ import { ... } from "@/shared/lib/permissions" + ──▶ import { ... } from "@/shared/lib/login-logger" + ──▶ import { ... } from "@/shared/lib/password-policy" + ──▶ import { ... } from "@/shared/lib/rate-limit" +``` + +**影响**: +- shared 层无法独立测试/复用 +- 架构上基础设施不应反向依赖应用层 +- 模块加载顺序不确定,潜在运行时错误 + +**解耦方案**: +- 将 `auth()` 调用改为依赖注入:logger 函数接收 `session` 参数,由调用方传入 +- 或抽取 `shared/lib/session.ts` 提供 `getCurrentSession()`,由 `auth.ts` 委托调用 + +**迁移步骤**: +1. 创建 `shared/lib/session.ts`,封装 session 获取逻辑 +2. 修改 3 个 logger 文件,改为接收 session 参数 +3. 修改所有调用方,传入 session +4. 验证 `shared/lib` 不再 import `@/auth` + +--- + +#### P0-4 `dashboard/data-access.ts` 直查 11 张跨模块表 + +**问题**: +`getAdminDashboardData` 直查 sessions/users/classes/textbooks/chapters/questions/exams/homeworkAssignments/homeworkSubmissions/usersToRoles/roles + +**影响**: +- 严重违反模块封装 +- dashboard 与 11 张表强耦合,任何表结构变更都需修改 dashboard +- 无法通过模块单元测试覆盖 + +**解耦方案**: +```typescript +// 为每个模块添加 dashboard 聚合查询函数 +// src/modules/exams/data-access.ts +export async function getExamsDashboardStats(): Promise { ... } + +// src/modules/homework/data-access.ts +export async function getHomeworkDashboardStats(): Promise { ... } + +// src/modules/dashboard/data-access.ts +export async function getAdminDashboardData() { + const [examStats, homeworkStats, ...] = await Promise.all([ + getExamsDashboardStats(), + getHomeworkDashboardStats(), + ... + ]); + return { exams: examStats, homework: homeworkStats, ... }; +} +``` + +**迁移步骤**: +1. 在各模块 data-access 添加 `get[Module]DashboardStats()` 函数 +2. dashboard 改为并行调用各模块的 stats 函数 +3. 移除 dashboard 中的直接 DB 查询 + +--- + +#### P0-5 `messaging` 绕过 `notifications` 直接写通知 + +**问题**: +`messaging/actions.ts` 第 66-72 行直接调用 `createNotification`,导致: +- 用户通知偏好失效 +- 多渠道通知(SMS/微信/邮件)无效 +- notifications 模块形同虚设 + +**影响**: +- P2 实现的通知渠道系统完全失效 +- 用户无法通过偏好设置控制通知渠道 + +**解耦方案**: +```typescript +// src/modules/messaging/actions.ts +import { dispatchNotification } from "@/modules/notifications/dispatcher"; + +// 替换 createNotification 调用 +await dispatchNotification({ + userId: recipientId, + type: "message", + title: "...", + content: "...", + channels: ["in-app"], // 由 dispatcher 根据用户偏好决定实际渠道 +}); +``` + +**迁移步骤**: +1. messaging/actions.ts 替换 `createNotification` 为 `dispatchNotification` +2. notifications/dispatcher.ts 确保支持 message 类型 +3. 测试用户通知偏好是否生效 + +--- + +#### P0-6 `classSchedule` 表三处写入口 + +**问题**: +- `classes/data-access.ts` 写入 +- `scheduling/actions.ts` 直接 transaction 写入 +- `scheduling/data-access.ts` 写入 + +**影响**: +- 数据完整性高风险 +- 三处写入逻辑可能不一致 +- 难以添加全局校验(如冲突检测) + +**解耦方案**: +- 统一写入口到 `scheduling/data-access.ts` +- `classes` 和 `scheduling/actions` 调用 `scheduling/data-access` 的函数 +- 在 `scheduling/data-access` 添加冲突检测等全局校验 + +**迁移步骤**: +1. 在 `scheduling/data-access.ts` 添加 `upsertClassSchedule()` 函数 +2. `classes/data-access.ts` 移除 classSchedule 写入,改为调用 scheduling +3. `scheduling/actions.ts` 移除直接 transaction,改为调用 data-access +4. 添加冲突检测逻辑 + +--- + +### P1 较严重问题(短期修复) + +#### P1-1 跨模块直接 DB 查询普遍存在 + +| 被访问表 | 访问次数 | 应归属模块 | 主要违规者 | +|---------|---------|-----------|-----------| +| `classes` | 8+ | classes | exams, homework, grades, dashboard | +| `classEnrollments` | 6+ | classes | homework, grades, attendance | +| `users` | 6+ | users | 多个模块 | +| `subjects` | 6+ | school | exams, homework, questions | +| `exams` | 5+ | exams | homework, grades, dashboard | + +**解耦方案**: +- 每个模块在 data-access 中导出查询函数(如 `getClassById`、`getUserById`) +- 违规模块改为调用对方 data-access 函数 +- 建立 ESLint 规则禁止跨模块 import `shared/db/schema` 中的非本模块表 + +**迁移步骤**: +1. 为高频被访问的模块(classes/users/subjects)补全查询函数 +2. 逐个模块替换直接 DB 查询 +3. 添加 ESLint 自定义规则(可选,但推荐) + +--- + +#### P1-2 actions 层混入数据访问逻辑 + +**问题**: +exams/homework/questions/announcements 的 actions.ts 中存在直接 `db.insert/update/delete` + +**影响**: +- actions 层职责不清 +- 数据访问逻辑分散,难以统一优化(如缓存) + +**解耦方案**: +- 所有 DB 操作下沉到 data-access 层 +- actions 只做:权限校验 + 调用 data-access + revalidatePath + +**迁移步骤**: +1. 识别 actions.ts 中的直接 DB 操作 +2. 迁移到对应 data-access.ts +3. actions 改为调用 data-access 函数 + +--- + +#### P1-3 `auth.ts` 混合 5 类职责 + +**问题**: +293 行,混合: +1. NextAuth 配置 +2. 密码安全 DB 操作 +3. 角色规范化 +4. bcrypt 哈希规范化 +5. IP 解析 + +**解耦方案**: +``` +src/ +├── auth.ts # 仅 NextAuth 配置(目标 ≤150 行) +└── shared/lib/ + ├── password-security-service.ts # 密码安全 DB 操作 + ├── role-utils.ts # 角色规范化 + ├── bcrypt-utils.ts # bcrypt 哈希规范化 + └── http-utils.ts # IP 解析(与 logger 共用) +``` + +--- + +#### P1-4 `users/import-export.ts` 四重职责 + +**问题**: +导入解析 + 导出 + 用户创建(含密码哈希) + 班级注册(跨模块写 classEnrollments) + +**解耦方案**: +``` +src/modules/users/ +├── import-export.ts # 仅文件解析与生成 +├── user-service.ts # 用户创建(含密码哈希) +└── class-registration.ts # 班级注册(调用 classes/data-access) +``` + +--- + +#### P1-5 `proctoring/exam-mode-config.tsx` 死代码 + +**问题**: +组件已创建但未集成到考试表单,DB schema 有 examMode 字段但表单不收集 + +**解耦方案**: +- 集成到考试创建/编辑表单 +- 或删除组件和 DB 字段(如果业务上不需要) + +--- + +#### P1-6 `notifications` 反向依赖 `messaging` + +**问题**: +notifications 模块 import messaging 的类型,形成反向依赖 + +**解耦方案**: +- 将共享类型抽取到 `shared/types/notifications.ts` +- notifications 和 messaging 都从 shared/types 导入 + +--- + +### P2 中期优化 + +#### P2-1 `schema.ts` 按业务域分节 + +**问题**: +1111 行,54 张表混合 + +**解耦方案**: +``` +src/shared/db/schema/ +├── index.ts # 聚合导出 +├── auth.ts # 用户、角色、会话 +├── academic.ts # 学校、年级、科目、教材、章节、知识点 +├── classes.ts # 班级、选课、排课、考勤 +├── exam.ts # 考试、题目、提交 +├── homework.ts # 作业、提交、答案 +├── grades.ts # 成绩 +├── ai.ts # AI 提供商、调用记录 +├── audit.ts # 审计日志、变更日志 +└── notifications.ts # 通知、偏好 +``` + +--- + +#### P2-2 `ai.ts` 拆分 + +**问题**: +218 行,混合 5 类职责 + +**解耦方案**: +``` +src/shared/lib/ai/ +├── index.ts # 聚合导出 +├── payload-parser.ts # 请求负载解析 +├── api-key-crypto.ts # API Key 加密/解密 +├── provider-config.ts # Provider 配置查询 +├── client.ts # AI 客户端创建与调用 +└── errors.ts # 错误格式化 +``` + +--- + +## 三、解耦执行优先级 + +### 第一阶段:P0 修复(建议 1-2 周) + +| 优先级 | 任务 | 预估影响范围 | 风险 | +|--------|------|-------------|------| +| 1 | P0-3 修复循环依赖 | shared/lib + auth.ts | 低 | +| 2 | P0-5 messaging 改用 dispatcher | messaging + notifications | 低 | +| 3 | P0-6 统一 classSchedule 写入口 | classes + scheduling | 中 | +| 4 | P0-2 拆分 homework/data-access | homework | 中 | +| 5 | P0-4 dashboard 改用模块 data-access | dashboard + 11 个模块 | 高 | +| 6 | P0-1 拆分 classes/data-access | classes + 多个调用方 | 高 | + +### 第二阶段:P1 修复(建议 2-4 周) + +| 优先级 | 任务 | 预估影响范围 | 风险 | +|--------|------|-------------|------| +| 7 | P1-2 actions 层下沉 DB 操作 | 4 个模块 | 中 | +| 8 | P1-1 跨模块 DB 查询改为 data-access | 全项目 | 高 | +| 9 | P1-3 拆分 auth.ts | auth + shared/lib | 中 | +| 10 | P1-4 拆分 users/import-export | users | 低 | +| 11 | P1-6 修复 notifications 反向依赖 | notifications + messaging | 低 | +| 12 | P1-5 集成或删除 proctoring 死代码 | proctoring + exams | 低 | + +### 第三阶段:P2 优化(建议 4-8 周) + +| 优先级 | 任务 | 预估影响范围 | 风险 | +|--------|------|-------------|------| +| 13 | P2-1 schema.ts 按业务域拆分 | shared/db + 全项目 | 高(需全面回归) | +| 14 | P2-2 ai.ts 拆分 | shared/lib/ai | 中 | + +--- + +## 四、解耦验收标准 + +### 4.1 文件行数 + +- [ ] 所有文件 ≤ 1000 行(硬上限) +- [ ] React 组件 ≤ 500 行(复杂表单/表格 ≤ 800 行) +- [ ] Server Actions / Data Access ≤ 800 行 + +### 4.2 模块封装 + +- [ ] 无跨模块直接 DB 查询(通过 ESLint 规则验证) +- [ ] 无循环依赖(通过 `madge` 工具验证) +- [ ] shared/ 不 import @/auth 或 modules/ + +### 4.3 职责单一 + +- [ ] actions.ts 只做编排(权限 + 调用 data-access + revalidate) +- [ ] data-access.ts 只做数据存取(无业务计算) +- [ ] 业务计算逻辑在 *-service.ts 文件中 + +### 4.4 架构文档可读性 + +- [ ] 阅读 004 文档后能说出每个模块的职责 +- [ ] 阅读 004 文档后能说出模块间的依赖关系 +- [ ] 阅读 004 文档后能说出核心业务的数据流向 +- [ ] 阅读 004 文档后能说出关键 API 的调用链路 + +--- + +## 五、解耦后的预期效果 + +### 5.1 对开发效率的提升 + +- **定位代码更快**:知道模块职责后,直接到对应模块找代码 +- **修改影响更小**:单一职责的函数修改不会影响其他业务域 +- **测试更简单**:模块封装后可独立单元测试 + +### 5.2 对架构文档的提升 + +- **一次阅读即可理解**:模块职责清晰,依赖关系明确 +- **无需查看源码**:004 文档提供足够的架构信息 +- **问题定位明确**:已知问题清单帮助快速定位技术债 + +### 5.3 对项目可维护性的提升 + +- **新人上手更快**:清晰的分层和模块边界 +- **技术债可控**:已知问题有明确修复计划 +- **演进路径清晰**:解耦后可独立演进各模块 diff --git a/docs/work_log.md b/docs/work_log.md index f6ae8ed..1d3dcc3 100644 --- a/docs/work_log.md +++ b/docs/work_log.md @@ -46,7 +46,30 @@ - 所有文档保持活跃维护与归档分离 #### 验证 -- 待验证 lint + tsc +- tsc --noEmit: 0 errors +- npm run lint: 0 errors 0 warnings +- git commit: f8dfd1d + +--- + +### 解耦路线图输出 + +#### 完成工作 +- 创建 `docs/architecture/audit/01_decoupling_roadmap.md` 解耦路线图文档 + - 解耦原则:单一职责 / 模块封装 / 分层单向依赖 + - 过耦合问题清单:6 项 P0 + 6 项 P1 + 2 项 P2,每项含问题/影响/解耦方案/迁移步骤 + - 解耦执行优先级:三阶段(P0 1-2 周 / P1 2-4 周 / P2 4-8 周) + - 验收标准:文件行数 / 模块封装 / 职责单一 / 架构文档可读性 + - 预期效果:开发效率 / 文档质量 / 项目可维护性三方面提升 +- 更新 `docs/README.md` 索引加入解耦路线图 + +#### 关键解耦项摘要 +- P0-1: classes/data-access.ts 2104 行 → 按职责拆 4 个文件 +- P0-2: homework/data-access.ts 1038 行 → 分离排名逻辑到 ranking-service.ts +- P0-3: shared/lib ↔ auth 循环依赖 → 依赖注入或抽取 session.ts +- P0-4: dashboard 直查 11 张表 → 各模块添加 getDashboardStats() 函数 +- P0-5: messaging 绕过 notifications → 改用 dispatchNotification +- P0-6: classSchedule 三处写入口 → 统一到 scheduling/data-access ---