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