294 lines
8.6 KiB
Plaintext
294 lines
8.6 KiB
Plaintext
|
|
# Competition Management System - Cursor User Rules (DEPRECATED)
|
|||
|
|
|
|||
|
|
⚠️ **此文件已废弃** - 请使用新的规则系统:
|
|||
|
|
- 项目规则:`.cursor/rules/*.mdc`
|
|||
|
|
- 快速参考:`AGENTS.md`
|
|||
|
|
- 说明文档:`.cursor/RULES_README.md`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
以下内容保留作为备份,但不再使用:
|
|||
|
|
|
|||
|
|
# Competition Management System - Cursor User Rules
|
|||
|
|
|
|||
|
|
## 项目概述
|
|||
|
|
|
|||
|
|
这是一个多租户的竞赛管理系统,采用前后端分离架构:
|
|||
|
|
- **后端**: NestJS + TypeScript + Prisma + MySQL
|
|||
|
|
- **前端**: Vue 3 + TypeScript + Vite + Ant Design Vue + Pinia
|
|||
|
|
- **认证**: JWT + RBAC (基于角色的访问控制)
|
|||
|
|
- **架构**: 多租户架构,数据完全隔离
|
|||
|
|
|
|||
|
|
## 后端开发规范
|
|||
|
|
|
|||
|
|
### 1. 模块结构
|
|||
|
|
|
|||
|
|
- 每个功能模块应包含:`module.ts`, `controller.ts`, `service.ts`, `dto/` 目录
|
|||
|
|
- 模块命名使用复数形式(如 `users`, `roles`, `contests`)
|
|||
|
|
- 子模块放在父模块目录下(如 `contests/works/`, `contests/teams/`)
|
|||
|
|
|
|||
|
|
### 2. 服务层 (Service)
|
|||
|
|
|
|||
|
|
- 所有数据库操作必须通过 PrismaService,禁止直接使用 SQL
|
|||
|
|
- 服务方法必须处理租户隔离:所有查询必须包含 `tenantId` 条件
|
|||
|
|
- 使用 `@Injectable()` 装饰器
|
|||
|
|
- 构造函数注入依赖,使用 private readonly
|
|||
|
|
- 方法命名:`create`, `findAll`, `findOne`, `update`, `remove`
|
|||
|
|
- 查询方法应支持分页:使用 `skip` 和 `take` 参数
|
|||
|
|
|
|||
|
|
### 3. 控制器层 (Controller)
|
|||
|
|
|
|||
|
|
- 使用 `@Controller()` 装饰器,路径使用复数形式
|
|||
|
|
- 所有路由默认需要认证(除非使用 `@Public()` 装饰器)
|
|||
|
|
- 使用 `@Get()`, `@Post()`, `@Put()`, `@Delete()`, `@Patch()` 装饰器
|
|||
|
|
- 从请求中获取租户ID:使用 `@CurrentTenantId()` 装饰器或从 JWT token 中提取
|
|||
|
|
- 使用 `@CurrentUser()` 装饰器获取当前用户信息
|
|||
|
|
- 权限控制:使用 `@RequirePermission()` 装饰器
|
|||
|
|
- 返回统一响应格式:使用 TransformInterceptor(自动处理)
|
|||
|
|
|
|||
|
|
### 4. DTO (Data Transfer Object)
|
|||
|
|
|
|||
|
|
- 所有 DTO 放在 `dto/` 目录下
|
|||
|
|
- 使用 `class-validator` 进行验证
|
|||
|
|
- 命名规范:
|
|||
|
|
- 创建:`CreateXxxDto`
|
|||
|
|
- 更新:`UpdateXxxDto`
|
|||
|
|
- 查询:`QueryXxxDto`
|
|||
|
|
- 必填字段使用验证装饰器(如 `@IsString()`, `@IsNumber()`)
|
|||
|
|
- 可选字段使用 `@IsOptional()`
|
|||
|
|
- 数组字段使用 `@IsArray()` 和 `@IsNumber({}, { each: true })`
|
|||
|
|
|
|||
|
|
### 5. 数据库操作 (Prisma)
|
|||
|
|
|
|||
|
|
- 所有表必须包含 `tenantId` 字段(租户隔离)
|
|||
|
|
- 所有表必须包含审计字段:`creator`, `modifier`, `createTime`, `modifyTime`
|
|||
|
|
- 使用 Prisma 的 `include` 和 `select` 优化查询
|
|||
|
|
- 关联查询使用嵌套 include,避免 N+1 问题
|
|||
|
|
- 删除操作使用软删除(`validState` 字段)或级联删除
|
|||
|
|
- 事务操作使用 `prisma.$transaction()`
|
|||
|
|
|
|||
|
|
### 6. 多租户处理
|
|||
|
|
|
|||
|
|
- **必须**:所有业务数据查询必须包含 `tenantId` 条件
|
|||
|
|
- 从 JWT token 或请求头中获取租户ID
|
|||
|
|
- 创建数据时自动设置 `tenantId`
|
|||
|
|
- 更新/删除时验证数据属于当前租户
|
|||
|
|
- 超级租户(`isSuper = 1`)可以访问所有租户数据
|
|||
|
|
|
|||
|
|
### 7. 权限控制
|
|||
|
|
|
|||
|
|
- 使用 `@RequirePermission()` 装饰器进行权限检查
|
|||
|
|
- 权限字符串格式:`模块:操作`(如 `contest:create`, `user:update`)
|
|||
|
|
- 角色权限通过 RolesGuard 自动检查
|
|||
|
|
- 权限验证失败返回 403 Forbidden
|
|||
|
|
|
|||
|
|
### 8. 错误处理
|
|||
|
|
|
|||
|
|
- 使用 NestJS 内置异常:`NotFoundException`, `BadRequestException`, `UnauthorizedException`, `ForbiddenException`
|
|||
|
|
- 自定义异常消息使用中文
|
|||
|
|
- 错误信息要清晰明确,便于调试
|
|||
|
|
|
|||
|
|
### 9. 代码风格
|
|||
|
|
|
|||
|
|
- 使用 TypeScript 严格模式
|
|||
|
|
- 使用 ESLint 和 Prettier 格式化代码
|
|||
|
|
- 导入顺序:NestJS 核心 → 第三方库 → 本地模块
|
|||
|
|
- 使用 async/await,避免 Promise.then()
|
|||
|
|
- 使用解构赋值提高代码可读性
|
|||
|
|
|
|||
|
|
## 前端开发规范
|
|||
|
|
|
|||
|
|
### 1. 组件结构
|
|||
|
|
|
|||
|
|
- 页面组件放在 `views/` 目录下,按模块组织
|
|||
|
|
- 公共组件放在 `components/` 目录下
|
|||
|
|
- 使用 `<script setup lang="ts">` 语法
|
|||
|
|
- 组件命名使用 PascalCase
|
|||
|
|
|
|||
|
|
### 2. API 调用
|
|||
|
|
|
|||
|
|
- 所有 API 调用放在 `api/` 目录下,按模块组织
|
|||
|
|
- 使用 axios 实例(已配置拦截器)
|
|||
|
|
- API 函数命名:`getXxx`, `createXxx`, `updateXxx`, `deleteXxx`
|
|||
|
|
- 使用 TypeScript 类型定义请求和响应
|
|||
|
|
|
|||
|
|
### 3. 状态管理 (Pinia)
|
|||
|
|
|
|||
|
|
- Store 文件放在 `stores/` 目录下
|
|||
|
|
- 使用 `defineStore()` 定义 store
|
|||
|
|
- Store 命名使用 camelCase + Store 后缀(如 `authStore`)
|
|||
|
|
|
|||
|
|
### 4. 路由管理
|
|||
|
|
|
|||
|
|
- 路由配置在 `router/index.ts`
|
|||
|
|
- 支持动态路由(基于菜单权限)
|
|||
|
|
- 路由路径包含租户编码:`/:tenantCode/xxx`
|
|||
|
|
- 路由 meta 包含权限信息:`permissions`, `roles`
|
|||
|
|
|
|||
|
|
### 5. 表单验证
|
|||
|
|
|
|||
|
|
- 使用 VeeValidate + Zod 进行表单验证
|
|||
|
|
- 验证规则定义在组件内或单独的 schema 文件
|
|||
|
|
- 错误提示使用中文
|
|||
|
|
|
|||
|
|
### 6. UI 组件
|
|||
|
|
|
|||
|
|
- 使用 Ant Design Vue 组件库
|
|||
|
|
- 样式使用 Tailwind CSS + SCSS
|
|||
|
|
- 响应式设计:移动端优先
|
|||
|
|
- 组件要有 loading 和 error 状态
|
|||
|
|
|
|||
|
|
### 7. 类型定义
|
|||
|
|
|
|||
|
|
- TypeScript 类型定义放在 `types/` 目录下
|
|||
|
|
- 接口类型使用 `interface`,数据模型使用 `type`
|
|||
|
|
- 导出类型供其他模块使用
|
|||
|
|
|
|||
|
|
## 数据库设计规范
|
|||
|
|
|
|||
|
|
### 1. 表结构
|
|||
|
|
|
|||
|
|
- 所有业务表必须包含 `tenantId` 字段
|
|||
|
|
- 所有表必须包含审计字段:
|
|||
|
|
- `creator`: Int? - 创建人ID
|
|||
|
|
- `modifier`: Int? - 修改人ID
|
|||
|
|
- `createTime`: DateTime @default(now()) - 创建时间
|
|||
|
|
- `modifyTime`: DateTime @updatedAt - 修改时间
|
|||
|
|
- 状态字段使用 `validState`: Int @default(1)(1-有效,2-失效)
|
|||
|
|
- 表名使用复数形式,映射使用 `@@map("table_name")`
|
|||
|
|
|
|||
|
|
### 2. 关系设计
|
|||
|
|
|
|||
|
|
- 使用 Prisma 关系定义外键
|
|||
|
|
- 级联删除:`onDelete: Cascade`
|
|||
|
|
- 可选关联:`onDelete: SetNull`
|
|||
|
|
- 一对一关系:使用 `?` 标记可选
|
|||
|
|
|
|||
|
|
### 3. 索引
|
|||
|
|
|
|||
|
|
- 主键自动索引
|
|||
|
|
- 外键字段自动索引
|
|||
|
|
- 查询频繁的字段添加索引
|
|||
|
|
- 唯一约束使用 `@unique`
|
|||
|
|
|
|||
|
|
### 4. 迁移
|
|||
|
|
|
|||
|
|
- 使用 Prisma Migrate 管理数据库迁移
|
|||
|
|
- 迁移文件命名:`YYYYMMDDHHMMSS_description`
|
|||
|
|
- 迁移前备份数据库
|
|||
|
|
- 生产环境使用 `prisma migrate deploy`
|
|||
|
|
|
|||
|
|
## 通用开发规范
|
|||
|
|
|
|||
|
|
### 1. Git 提交
|
|||
|
|
|
|||
|
|
- 提交信息使用中文
|
|||
|
|
- 格式:`类型: 描述`(如 `feat: 添加竞赛管理功能`)
|
|||
|
|
- 类型:`feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`
|
|||
|
|
|
|||
|
|
### 2. 注释
|
|||
|
|
|
|||
|
|
- 复杂逻辑必须添加注释
|
|||
|
|
- 函数注释说明参数和返回值
|
|||
|
|
- 使用中文注释
|
|||
|
|
|
|||
|
|
### 3. 测试
|
|||
|
|
|
|||
|
|
- 单元测试文件命名:`*.spec.ts`
|
|||
|
|
- 测试覆盖率要求:核心业务逻辑 > 80%
|
|||
|
|
- 使用 Jest 进行测试
|
|||
|
|
|
|||
|
|
### 4. 环境配置
|
|||
|
|
|
|||
|
|
- 使用 `.env.development` 和 `.env.production`
|
|||
|
|
- 敏感信息不要提交到 Git
|
|||
|
|
- 配置项通过 `@nestjs/config` 管理
|
|||
|
|
|
|||
|
|
### 5. 日志
|
|||
|
|
|
|||
|
|
- 使用 NestJS Logger
|
|||
|
|
- 日志级别:`error`, `warn`, `log`, `debug`, `verbose`
|
|||
|
|
- 记录关键操作和错误信息
|
|||
|
|
|
|||
|
|
## 安全规范
|
|||
|
|
|
|||
|
|
### 1. 认证授权
|
|||
|
|
|
|||
|
|
- 所有 API 默认需要 JWT 认证
|
|||
|
|
- 密码使用 bcrypt 加密(salt rounds: 10)
|
|||
|
|
- Token 过期时间合理设置
|
|||
|
|
- 敏感操作需要额外验证
|
|||
|
|
|
|||
|
|
### 2. 数据验证
|
|||
|
|
|
|||
|
|
- 前端和后端都要进行数据验证
|
|||
|
|
- 使用 DTO 和 class-validator 验证输入
|
|||
|
|
- 防止 SQL 注入:使用 Prisma(参数化查询)
|
|||
|
|
- 防止 XSS:前端转义用户输入
|
|||
|
|
|
|||
|
|
### 3. 权限控制
|
|||
|
|
|
|||
|
|
- 最小权限原则
|
|||
|
|
- 前端显示控制 + 后端权限验证
|
|||
|
|
- 租户数据隔离必须严格检查
|
|||
|
|
|
|||
|
|
## 性能优化
|
|||
|
|
|
|||
|
|
### 1. 数据库查询
|
|||
|
|
|
|||
|
|
- 避免 N+1 查询,使用 `include` 预加载
|
|||
|
|
- 使用 `select` 只查询需要的字段
|
|||
|
|
- 分页查询必须实现
|
|||
|
|
- 大表查询添加索引
|
|||
|
|
|
|||
|
|
### 2. API 响应
|
|||
|
|
|
|||
|
|
- 响应数据精简,避免返回不必要字段
|
|||
|
|
- 使用分页减少单次数据量
|
|||
|
|
- 长时间操作使用异步处理
|
|||
|
|
|
|||
|
|
### 3. 前端优化
|
|||
|
|
|
|||
|
|
- 路由懒加载
|
|||
|
|
- 组件按需加载
|
|||
|
|
- 图片使用 CDN 或压缩
|
|||
|
|
- 避免不必要的重新渲染
|
|||
|
|
|
|||
|
|
## 代码审查检查清单
|
|||
|
|
|
|||
|
|
- [ ] 所有数据库查询包含 `tenantId` 条件
|
|||
|
|
- [ ] DTO 验证规则完整
|
|||
|
|
- [ ] 错误处理完善
|
|||
|
|
- [ ] 权限检查正确
|
|||
|
|
- [ ] 代码格式符合规范
|
|||
|
|
- [ ] 注释清晰
|
|||
|
|
- [ ] 无硬编码配置
|
|||
|
|
- [ ] 类型定义完整
|
|||
|
|
- [ ] 无控制台日志(生产环境)
|
|||
|
|
|
|||
|
|
## 常见问题
|
|||
|
|
|
|||
|
|
### Q: 如何获取当前租户ID?
|
|||
|
|
A: 在控制器中使用 `@CurrentTenantId()` 装饰器,或在服务中从 JWT token 提取。
|
|||
|
|
|
|||
|
|
### Q: 如何创建新的业务模块?
|
|||
|
|
A:
|
|||
|
|
1. 在 Prisma schema 中定义模型
|
|||
|
|
2. 运行 `prisma migrate dev`
|
|||
|
|
3. 创建模块目录和文件(module, controller, service, dto)
|
|||
|
|
4. 在 `app.module.ts` 中注册模块
|
|||
|
|
5. 创建前端 API 和页面
|
|||
|
|
|
|||
|
|
### Q: 如何处理多租户数据隔离?
|
|||
|
|
A:
|
|||
|
|
- 查询时始终包含 `where: { tenantId }`
|
|||
|
|
- 创建时自动设置 `tenantId`
|
|||
|
|
- 更新/删除前验证数据属于当前租户
|
|||
|
|
|
|||
|
|
### Q: 如何添加新的权限?
|
|||
|
|
A:
|
|||
|
|
1. 在数据库中创建权限记录
|
|||
|
|
2. 在路由或控制器方法上使用 `@RequirePermission('module:action')`
|
|||
|
|
3. 在前端路由 meta 中添加 `permissions` 字段
|
|||
|
|
|