Files
NextEdu/bugs/shared_bug.md
SpecialX 49291fcc31 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.
2026-06-19 05:13:34 +08:00

298 lines
14 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.
# `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
> 核查方法:人工逐行审查 + 架构图比对 + 技能规则匹配