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:
297
bugs/shared_bug.md
Normal file
297
bugs/shared_bug.md
Normal 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-A01:Prettier 配置违规(使用分号)
|
||||
- **位置**:`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-01:004 文件行数记录过期
|
||||
- **位置**:`docs/architecture/004_architecture_impact_map.md:408`
|
||||
- **问题**:记录 `types/permissions.ts | 92 | 54 个权限点常量`,实际文件 114 行,含 `DataScope`、`AuthContext` 类型定义
|
||||
- **改进建议**:更新为 `114 行 | 54 个权限点 + DataScope + AuthContext`
|
||||
|
||||
### DOC-02:005 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 Agent(GLM-5.2)
|
||||
> 核查方法:人工逐行审查 + 架构图比对 + 技能规则匹配
|
||||
Reference in New Issue
Block a user