refactor: fix all P0/P1/P2 bugs and architecture issues

Bug fixes (from bugs/ directory):

- Fix cross-module DB queries in 9 modules (homework, grades, parent, diagnostic, elective, proctoring, notifications, scheduling, classes) by routing through data-access functions

- Fix shared/lib <-> auth circular dependency via new session.ts module

- Fix divide-by-zero guard in grades data-access

- Fix audit export data truncation (paginated fetch for full datasets)

- Fix missing transactions in homework grading and elective lottery

- Fix missing revalidatePath in course-plans actions

- Fix frontend permission checks using requirePermission instead of requireAuth

- Fix dashboard role routing using session.user.roles

- Fix student auth pattern (migrate getDemoStudentUser to users module)

- Fix ActionState return type handling in components

Code quality fixes:

- Remove 60+ as type assertions (replace with type guards)

- Remove non-null assertions (use optional chaining or explicit checks)

- Convert dynamic imports to static imports (grades, diagnostic)

- Add React.cache() wrapping for read functions

- Parallelize independent queries with Promise.all

- Add explicit return types to 30+ arrow functions

- Replace any with unknown + type guards

- Fix import type for type-only imports

- Add Zod validation schemas for classes and diagnostic modules

- Extract duplicate code (normalizeRoleName, normalizeBcryptHash, logger IP extraction)

- Add console.error to silent catch blocks

- Fix permission naming consistency (exam:proctor_read -> exam:proctor:read)

Architecture doc sync:

- Update 004_architecture_impact_map.md and 005_architecture_data.json

- Update management-modules-audit.md for P0-7 cross-module fix

Moved deleted proctoring event route to deletes/ folder.
This commit is contained in:
SpecialX
2026-06-19 05:13:09 +08:00
parent 063baffe4c
commit 49291fcc31
114 changed files with 12548 additions and 3395 deletions

297
bugs/shared_bug.md Normal file
View File

@@ -0,0 +1,297 @@
# `src/shared/types` 规范核查报告
> 核查日期2026-06-18
> 核查范围:`src/shared/types/` 目录下所有前后端文件
> 依据文档:项目规则、编码规范、架构影响地图 004、架构数据 005
> 应用技能:`vercel-react-best-practices`、`web-artifacts-builder`、`web-design-guidelines`
---
## 一、核查文件清单
| 文件 | 行数 | 类型 | 用途 |
|------|------|------|------|
| [action-state.ts](../src/shared/types/action-state.ts) | 5 | 类型定义 | Server Action 统一返回类型 |
| [action-state.test.ts](../src/shared/types/action-state.test.ts) | 33 | 单元测试 | ActionState 类型测试 |
| [permissions.ts](../src/shared/types/permissions.ts) | 114 | 类型定义+常量 | 权限点常量、Permission/DataScope/AuthContext 类型 |
---
## 二、违规问题清单
### 2.1 action-state.ts — 严重度:高
#### BUG-A01Prettier 配置违规(使用分号)
- **位置**`src/shared/types/action-state.ts:1-5`
- **问题**:文件使用分号(`;`)结尾,但项目 `.prettierrc` 配置 `"semi": false`,应移除所有分号
- **现状**
```typescript
export type ActionState<T = void> = {
success: boolean;
message?: string;
errors?: Record<string, string[]>;
data?: T;
};
```
- **改进建议**:移除所有分号,与 `permissions.ts`、`action-state.test.ts` 保持一致
#### BUG-A02缺少 JSDoc 文档注释
- **位置**`src/shared/types/action-state.ts:1`
- **问题**`ActionState<T>` 类型缺少 JSDoc 注释,未说明类型用途、泛型参数、各字段含义
- **规范依据**:编码规范 5.4「必须编写 JSDoc」
- **改进建议**:补充类型级 JSDoc说明 `@template T`、各 property 语义
---
### 2.2 permissions.ts — 严重度:高
#### BUG-P01权限点命名不一致下划线 vs 驼峰)
- **位置**`src/shared/types/permissions.ts:91`
- **问题**`EXAM_PROCTOR_READ: "exam:proctor_read"` 使用下划线分隔,而其他 READ 权限均使用单词形式(如 `exam:read`、`question:read`
- **改进建议**:统一为 `exam:proctor:read`(嵌套资源用冒号分隔)
#### BUG-P02`Permissions` 常量缺少 `satisfies` 类型约束
- **位置**`src/shared/types/permissions.ts:4-96`
- **问题**:使用 `as const` 但未用 `satisfies` 验证所有值均为字符串,无法在编译期捕获值类型错误
- **规范依据**:编码规范 4.2.3「可用 `satisfies` 保持类型推导」
- **改进建议**`as const satisfies Record<string, string>`
#### BUG-P03`AuthContext.roles` 类型过于宽松
- **位置**`src/shared/types/permissions.ts:111`
- **问题**`roles: string[]` 允许任意字符串但项目角色是有限集合admin/teacher/student/parent/grade_head/teaching_head
- **影响**:拼写错误(如 `"techer"`)无法在编译期发现;与 `proxy.ts:21` 中 `resolveDefaultPath(roles: string[])` 的硬编码角色判断形成隐患
- **改进建议**:定义 `Role` 联合类型,`AuthContext.roles` 改为 `Role[]``ROLE_PERMISSIONS` 改为 `Record<Role, Permission[]>`
#### BUG-P04`DataScope` 缺少 JSDoc 与字段说明
- **位置**`src/shared/types/permissions.ts:101-107`
- **问题**6 种数据范围类型未说明各自语义、适用角色、使用场景
- **改进建议**:补充类型级 JSDoc说明每种 `type` 的适用角色与语义
#### BUG-P05`AuthContext` 接口缺少 JSDoc
- **位置**`src/shared/types/permissions.ts:109-114`
- **问题**:接口无文档说明,使用者无法快速理解字段语义
- **规范依据**:编码规范 5.4
- **改进建议**:补充接口级 JSDoc说明「认证上下文由 `getAuthContext()` 返回,贯穿所有 Server Action」
#### BUG-P06`DataScope.class_members` 缺少关联数据
- **位置**`src/shared/types/permissions.ts:104`
- **问题**`{ type: "class_members" }` 不携带 classIds导致 data-access 层每次都需要额外查询学生所在班级,存在 N+1 查询风险
- **影响**`exams/data-access.ts`、`homework/data-access.ts` 等模块在过滤时需重复查询 `classMembers` 表
- **改进建议**:在 `resolveDataScope` 中预查并携带 classIds`{ type: "class_members"; classIds: string[] }`
---
### 2.3 action-state.test.ts — 严重度:中
#### BUG-T01测试覆盖率不足
- **位置**`src/shared/types/action-state.test.ts:4-33`
- **问题**:仅测试 3 种基本状态,缺少以下场景:
1. `errors` 字段包含多个字段、每个字段多条错误消息
2. `data` 为 `null`、`undefined`、`0`、`""` 等 falsy 值时的行为
3. 同时存在 `errors` 和 `data`(虽然语义上不应出现,但类型允许)
4. `message` 为空字符串
- **规范依据**:编码规范十、测试规范「工具函数覆盖率目标 100%」
#### BUG-T02测试描述缺少行为意图
- **位置**`src/shared/types/action-state.test.ts:4`
- **问题**`describe("ActionState")` 过于宽泛,未说明被测行为
- **规范依据**:编码规范 10.2「描述应说明预期行为」
- **改进建议**`describe("ActionState 类型构造")`
---
### 2.4 跨文件违规(使用方导入问题)
#### BUG-X01`exams/actions.ts` 类型导入违规
- **位置**`src/modules/exams/actions.ts:4`
- **问题**`import { ActionState } from "@/shared/types/action-state"` — `ActionState` 仅作为类型使用,应使用 `import type`
- **规范依据**:编码规范 4.2.6「所有仅用于类型的导入必须使用 `import type`」
- **改进建议**`import type { ActionState } from "@/shared/types/action-state"`
#### BUG-X02`questions/actions.ts` 类型导入违规
- **位置**`src/modules/questions/actions.ts:7`
- **问题**:同 BUG-X01`import { ActionState }` 应为 `import type { ActionState }`
- **改进建议**`import type { ActionState } from "@/shared/types/action-state"`
---
### 2.5 tsconfig.json 配置不达标(影响类型安全)
#### BUG-C01`target` 低于规范要求
- **位置**`tsconfig.json:3`
- **问题**`"target": "ES2017"`,编码规范 4.1 要求 `"ES2022"`
- **影响**:无法使用 ES2022 特性(如 `Array.at()`、`Object.hasOwn()`
- **改进建议**`"target": "ES2022"`
#### BUG-C02缺少 `noUncheckedIndexedAccess`
- **位置**`tsconfig.json`
- **问题**:未启用 `noUncheckedIndexedAccess`,数组/对象索引访问返回 `T` 而非 `T | undefined`
- **影响**`permissions.ts:198` 中 `ROLE_PERMISSIONS[name]` 在 `name` 不存在时返回 `Permission[]` 而非 `Permission[] | undefined`,存在运行时风险
- **规范依据**:编码规范 4.1
- **改进建议**`"noUncheckedIndexedAccess": true`
#### BUG-C03缺少 `noImplicitReturns` 和 `noFallthroughCasesInSwitch`
- **位置**`tsconfig.json`
- **问题**:未启用这两个严格检查
- **规范依据**:编码规范 4.1
- **改进建议**:补充 `"noImplicitReturns": true`、`"noFallthroughCasesInSwitch": true`、`"forceConsistentCasingInFileNames": true`
---
## 三、React 性能优化(应用 `vercel-react-best-practices` 技能)
### PERF-01`use-permission.ts` 回调函数未 memoize
- **位置**`src/shared/hooks/use-permission.ts:11-25`
- **问题**`hasPermission`、`hasAnyPermission`、`hasAllPermissions`、`hasRole` 每次渲染都创建新函数引用,导致依赖这些函数的子组件不必要重渲染
- **违反规则**`rerender-functional-setstate`、`rerender-memo`
- **改进建议**:使用 `useCallback` 包裹所有回调函数
### PERF-02`permissions` 和 `roles` 数组未 memoize
- **位置**`src/shared/hooks/use-permission.ts:8-9`
- **问题**:每次渲染都执行 `?? []` 创建新数组引用,导致下游 `useEffect`/`useMemo` 依赖项失效
- **违反规则**`rerender-derived-state`、`rerender-dependencies`
- **改进建议**:使用 `useMemo` 包裹数组派生
### PERF-03`as` 断言使用
- **位置**`src/shared/hooks/use-permission.ts:8-9`
- **问题**`as Permission[]` 和 `as string[]` 使用了类型断言,违反编码规范 4.2.3
- **改进建议**:依赖 `next-auth.d.ts` 的类型增强(已存在),移除断言;或增加类型守卫
### `use-permission.ts` 完整改进示例
```typescript
import { useCallback, useMemo } from "react"
import { useSession } from "next-auth/react"
import type { Permission } from "@/shared/types/permissions"
export function usePermission() {
const { data: session } = useSession()
const permissions = useMemo(
() => (session?.user?.permissions ?? []) as Permission[],
[session?.user?.permissions]
)
const roles = useMemo(
() => (session?.user?.roles ?? []) as string[],
[session?.user?.roles]
)
const hasPermission = useCallback(
(permission: Permission): boolean => permissions.includes(permission),
[permissions]
)
const hasAnyPermission = useCallback(
(...perms: Permission[]): boolean => perms.some((p) => permissions.includes(p)),
[permissions]
)
const hasAllPermissions = useCallback(
(...perms: Permission[]): boolean => perms.every((p) => permissions.includes(p)),
[permissions]
)
const hasRole = useCallback(
(role: string): boolean => roles.includes(role),
[roles]
)
return { permissions, roles, hasPermission, hasAnyPermission, hasAllPermissions, hasRole }
}
```
---
## 四、Web 界面规范审查(应用 `web-design-guidelines` 技能)
> 说明:`src/shared/types/` 为纯类型定义文件,无直接 UI 代码。以下审查针对类型定义所支撑的 UI 实现层(`use-permission.ts`、`proxy.ts`、`auth-guard.ts`)是否符合 Web Interface Guidelines。
### UI-01权限状态可能导致 hydration mismatch
- **位置**`src/shared/hooks/use-permission.ts:7`
- **问题**`useSession()` 在服务端渲染时返回 `null`/`loading`,客户端首次渲染后才有权限数据,导致权限相关的 UI如菜单项、按钮在 hydration 后闪烁
- **违反规则**Web Interface Guidelines — Hydration Safety
- **改进建议**
1. 服务端组件应通过 `auth()` 获取权限并作为 props 传递
2. 客户端组件在 `session === null` 时渲染骨架屏或占位,避免权限相关 UI 闪烁
3. 对权限相关的动态 UI 使用 `suppressHydrationWarning` 或延迟渲染
### UI-02权限不足时的重定向未反映在 URL
- **位置**`src/proxy.ts:75-76`
- **问题**权限不足时直接重定向到默认页URL 中未携带原始路径信息,用户无法知道「为何被重定向」
- **违反规则**Web Interface Guidelines — Navigation & State「URL reflects state」
- **改进建议**:重定向时携带 `?from=originalPath&reason=forbidden` 参数,目标页显示提示
### UI-03错误消息缺少修复步骤
- **位置**`src/shared/lib/auth-guard.ts:13`
- **问题**`Permission denied: ${permission}` 仅描述问题,未提供下一步操作
- **违反规则**Web Interface Guidelines — Content & Copy「Error messages include fix/next step」
- **改进建议**`权限不足:需要 ${permission} 权限。请联系管理员授权或切换账号。`
---
## 五、架构文档同步问题
### DOC-01004 文件行数记录过期
- **位置**`docs/architecture/004_architecture_impact_map.md:408`
- **问题**:记录 `types/permissions.ts | 92 | 54 个权限点常量`,实际文件 114 行,含 `DataScope`、`AuthContext` 类型定义
- **改进建议**:更新为 `114 行 | 54 个权限点 + DataScope + AuthContext`
### DOC-02005 JSON 中 `DataScope` 定义字段顺序与代码不一致
- **位置**`docs/architecture/005_architecture_data.json:993`
- **问题**JSON 中字段顺序为 `all, owned, class_taught, grade_managed, class_members, children`,代码中为 `all, owned, class_members, grade_managed, class_taught, children`
- **改进建议**:同步 JSON 字段顺序与源码一致
### DOC-03缺少 `Role` 类型定义记录
- **问题**:若按 BUG-P03 建议新增 `Role` 类型,需在 005 JSON 的 `shared.types` 数组中补充记录
- **改进建议**:新增 `Role` 类型节点,记录 `usedBy: ["auth-guard", "permissions", "proxy"]`
---
## 六、问题汇总统计
| 严重度 | 数量 | 问题编号 |
|--------|------|----------|
| 高 | 8 | BUG-A01, BUG-A02, BUG-P01, BUG-P02, BUG-P03, BUG-P04, BUG-P05, BUG-P06 |
| 中 | 6 | BUG-T01, BUG-T02, BUG-X01, BUG-X02, BUG-C01, BUG-C02 |
| 低 | 3 | BUG-C03, DOC-01, DOC-02, DOC-03 |
| 性能 | 3 | PERF-01, PERF-02, PERF-03 |
| 界面 | 3 | UI-01, UI-02, UI-03 |
| **合计** | **23** | |
---
## 七、修复优先级建议
### P0立即修复 — 影响类型安全与一致性)
1. BUG-A01移除 `action-state.ts` 分号
2. BUG-X01、BUG-X02修正 `import type` 违规
3. BUG-C01、BUG-C02、BUG-C03升级 `tsconfig.json`
### P1本迭代修复 — 影响可维护性)
4. BUG-P01统一权限点命名
5. BUG-P02`Permissions` 添加 `satisfies`
6. BUG-P03新增 `Role` 类型
7. BUG-A02、BUG-P04、BUG-P05补充 JSDoc
8. PERF-01、PERF-02、PERF-03`use-permission.ts` 性能优化
### P2下迭代修复 — 增强健壮性)
9. BUG-T01、BUG-T02补充测试用例
10. BUG-P06`DataScope.class_members` 携带 classIds
11. UI-01、UI-02、UI-03界面规范改进
### P3文档同步
12. DOC-01、DOC-02、DOC-03同步架构文档
---
## 八、验证命令
修复完成后应运行以下命令确保零错误:
```bash
npm run lint
npx tsc --noEmit
npm run test:unit -- action-state
```
---
> 报告生成人AI AgentGLM-5.2
> 核查方法:人工逐行审查 + 架构图比对 + 技能规则匹配