# 项目规则 ## 架构图优先规则 **任何任务开始前,必须先查阅架构影响地图,通过图定位代码和模块。** 1. **先图后码**:执行任何分析、修改、搜索任务时,首先阅读 `docs/architecture/004_architecture_impact_map.md` 或 `docs/architecture/005_architecture_data.json`,从图中定位目标模块、函数、依赖关系,再按图索骥读取源码 2. **图未覆盖则先补图**:如果发现项目中存在架构图未记录的模块、函数、表、路由等,**必须优先完善架构图信息**,然后再继续后续工作 3. **改码必同步图**:对源码的任何修改完成后,必须同步更新 004 和 005 两个架构文档 ### 架构文档清单 | 文档 | 用途 | |------|------| | `docs/architecture/004_architecture_impact_map.md` | 人类可读的架构影响地图 | | `docs/architecture/005_architecture_data.json` | AI 友好格式的结构化数据 | | `docs/architecture/006_k12_feature_checklist.md` | 标准功能模块清单 | | `docs/architecture/007_gap_audit_report.md` | 差距审计报告 | | `docs/architecture/audit/01_decoupling_roadmap.md` | 解耦路线图 | ### 需要同步图的场景 - 新增/删除/重命名导出函数、组件、Hook、类型 - 修改函数签名(参数、返回类型) - 修改权限点(Permissions 常量)或角色-权限映射 - 新增/删除数据库表 - 新增/删除路由页面或 API 路由 - 修改模块间依赖关系 - 新增模块 ### 同步方式 - 修改 Markdown 文档中对应的模块章节 - 修改 JSON 文档中对应的节点(`modules.*.exports`、`permissions`、`dependencyMatrix`、`routes`、`dbTables` 等) - 确保两个文档内容一致 ## 编码规范 **详细规范见 `docs/standards/coding-standards.md`,以下为核心强制规则。** ### 代码质量规则 - 每次修改后运行 `npm run lint` 和 `npx tsc --noEmit` 确保零错误 - Server Action 必须使用 `requirePermission()` 进行权限校验 - 前端组件禁止使用 `role === "xxx"` 硬编码,统一使用 `usePermission().hasPermission()` - 单文件行数遵循企业级规范: - 配置文件、常量文件、类型定义文件:无限制 - React 组件:建议 ≤ 500 行(复杂表单/大型表格可放宽至 800 行) - Server Actions / Data Access 模块:建议 ≤ 800 行 - 工具函数:建议 ≤ 40 行 - 自定义 Hook:建议 ≤ 80 行 - 超过建议行数时应考虑拆分(如 data-access 拆分为多个按职责划分的文件) - 硬性上限:任何文件不超过 1000 行,超过必须拆分 ### 架构分层规则 - 严格三层架构,依赖方向单向:`app → modules → shared` - `app/` 只能调用 `modules/` 的 Server Actions 和 data-access,不直接访问 DB - `modules/` 之间通过对方 data-access 通信,**不直接查询对方 DB 表** - `shared/` 是被依赖方,**不得反向依赖** `@/auth`、`@/proxy` 或任何 `modules/*` ### 模块标准结构 ``` src/modules/[module]/ ├─ actions.ts # Server Actions(编排层) ├─ data-access.ts # 数据访问层(可拆分为 data-access-*.ts) ├─ schema.ts # Zod 验证(可选) ├─ types.ts # 类型定义 ├─ components/ # 模块专属组件 └─ hooks/ # 模块专属 Hook(可选) ``` ### TypeScript 规则 - **禁止 `any`**:未知类型用 `unknown` 并做类型守卫 - **禁止 `as` 断言**(除非从 `unknown` 转换或测试中,需注释原因) - **函数返回值必须显式标注**,特别是 `Promise` - **仅用于类型的导入必须使用 `import type`** - **可选链后禁止跟非空断言 `!`** ### 命名规范 - 目录:kebab-case(`user-profile/`) - 组件文件:PascalCase(`UserProfile.tsx`) - Hook 文件:camelCase(`useAuth.ts`) - 变量/函数:camelCase,布尔值用 `is/has/can/should` 前缀 - 常量:UPPER_SNAKE_CASE(`MAX_RETRY_COUNT`) - 类/接口:PascalCase,接口不加 `I` 前缀 ### 组件规范 - 组件必须为纯函数,使用 `function` 声明 - 页面组件(`page.tsx`)使用默认导出;其余组件使用具名导出 - 默认服务端组件,需要交互时才添加 `"use client"`(必须位于文件第一行) - **不使用 `React.FC`**,直接用函数声明 + 显式标注 props 类型 ### Server Action 规范 - 每个 Action 必须调用 `requirePermission()` 进行权限校验 - 输入使用 Zod 验证,验证失败返回结构化错误 - 返回值统一采用 `ActionState` 类型 - 使用 `revalidatePath` 精确刷新缓存 ### Tailwind 规范 - 使用 `cn()` 工具函数管理条件类名 - **禁止**字符串拼接动态类名(`bg-${color}-500`) - **禁止**使用任意值(`w-[137px]`),除非有充分理由并注释 - 设计令牌在 `src/app/styles/tokens/` 目录中分层定义,通过 `@theme inline` 暴露为 Tailwind 类 ### 设计令牌规范(强制) - **禁止硬编码颜色**: TSX/TS/CSS 中不得出现 `#hex` 颜色字面量,统一使用 `hsl(var(--*))` 或 Tailwind 类 `bg-*` - **禁止硬编码字体**: 不得出现 `'Inter'`/`'Fraunces'`/`'JetBrains Mono'` 字面量,使用 `var(--font-family-sans/serif/mono)` - **禁止硬编码字号**: 不得出现 `font-size: Npx`,使用 `var(--font-size-1~9)` - **禁止 Tailwind 任意值**: 不得使用 `w-[Npx]`/`h-[Npx]`/`p-[Npx]` 等,映射到 `--space-*` 或 Tailwind 默认阶梯 - **豁免场景**(需 `// eslint-disable-next-line no-restricted-syntax -- ` 注释): - PWA manifest(`src/app/manifest.ts`) - 邮件 HTML 内联样式(`src/modules/notifications/channels/email-channel.ts`) - 图表 SVG 固定画布尺寸(recharts 选择器中的 `#ccc`/`#fff`) - loading.tsx 占位骨架 - Dialog 固定宽度等无法令牌化的设计固定尺寸 - **令牌文件分布**: `src/app/styles/tokens/`(primitive/semantic-light/semantic-dark/lesson-preparation/tailwind-theme/index) - **令牌分层**: - Layer 1 Primitive(`primitive.css`):原始色板/字号/间距/阴影,业务代码不直接引用 - Layer 2 Semantic(`semantic-light.css` + `semantic-dark.css`):语义令牌,业务代码唯一引用入口 - 模块命名空间(`lesson-preparation.css`):`--lp-*` 令牌,明暗双份 - Tailwind 暴露(`tailwind-theme.css`):`@theme inline` 将 Semantic 令牌暴露为 `bg-*`/`text-*`/`font-*` 类 - **改令牌必同步图**: 修改令牌定义后,同步更新 `docs/architecture/004` 与 `005` - **ESLint 强制约束**: - `no-restricted-syntax`: 禁止 `#hex` 字面量 - `design-tokens/no-hardcoded-fonts`: 禁止 `'Inter'`/`'Fraunces'`/`'JetBrains Mono'` 字面量(单词边界匹配,不影响 `Interval`/`Interactive` 等标识符) - 白名单:`primitive.css`(令牌定义)、`email-channel.ts`(邮件 HTML)、`manifest.ts`(PWA) ### 安全规范 - **禁止 `dangerlySetInnerHTML`**(如必须使用,先用 DOMPurify 清洗) - JWT/session ID 存储在 httpOnly + Secure + SameSite=Strict 的 Cookie 中 - 服务端环境变量不加 `NEXT_PUBLIC_` 前缀 - 环境变量使用 `@t3-oss/env-nextjs` + Zod 校验(已实现于 `src/env.mjs`) ### 提交规范 - 使用 Conventional Commits 格式:`feat(scope): description` - 类型:`feat`, `fix`, `chore`, `docs`, `style`, `refactor`, `test`, `perf`, `ci` - 提交前必须运行 `npm run lint` 和 `npx tsc --noEmit` 确保零错误 ## 问题记录规则 **所有工作完成后,必须将遇到的问题记录到 `docs/troubleshooting/known-issues.md`(速查手册格式)。** ### 必须记录的场景 | 场景 | 记录要求 | |------|---------| | 构建报错(dev/build/lint/tsc) | 记录错误现象 + 正确写法 | | 运行时异常(白屏/API 报错/数据加载失败) | 记录错误现象 + 正确写法 | | 框架/库版本兼容问题 | 记录错误现象 + 正确写法 | | 依赖配置问题(serverExternalPackages/webpackIgnore 等) | 记录错误现象 + 正确写法 | | 架构约束违规 | 记录错误现象 + 正确写法 | ### 记录格式 以**规则表**形式记录,指明正确做法,无需详细解释原因: ```markdown ## 问题分类标题 | 规则 | 正确写法 | 错误写法 | |------|---------|---------| | 简述规则 | 代码示例 | 代码示例 | ``` ### 记录要求 - **速查手册风格**:只指明方向,不做新手指导 - **去重**:同类问题在原条目补充,不重复创建 - **可操作**:正确写法需具体到代码示例