cursor-init/.cursor/rules/elysia-rules.mdc
HeXiaoLong:Suanier 1195aa335e docs: 更新rules
2025-07-04 19:37:31 +08:00

682 lines
20 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

---
description: "全局规则"
globs: ["**/*"]
alwaysApply: true
---
# Bun Elysia框架业务开发规则
## 0. 概览
这是一个基于 **Bun + Elysia** 的现代化后端API项目采用TypeScript开发集成了MySQL、Redis、JWT认证、Swagger文档等功能。
- **运行时**Bun
- **框架**Elysia
- **语言**TypeScript
- **数据库**MySQL + Drizzle ORM
- **缓存**Redis
- **认证**JWT
- **测试**Vitest
- **文档**Swagger
- **日志**Winston
- **代码规范**ESLint + Prettier
- 📂 根目录结构
```
project/
├── 📋 配置文件(config/)
├── 📁 源代码 (src/)
├── 📁 文档 (docs/)
├── 📁 需求文档 (prd/)
├── 📁 任务管理 (tasks/)
├── 📁 AI对话记录 (aiChat/)
└── 📁 静态资源 (public/)
```
- 🔧 配置文件
| 文件 | 说明 |
|------|------|
| `package.json` | 项目依赖和脚本配置 |
| `tsconfig.json` | TypeScript编译配置 |
| `tsconfig.test.json` | 测试环境TypeScript配置 |
| `vitest.config.ts` | Vitest测试框架配置 |
| `eslint.config.js` | ESLint代码规范配置 |
| `bunfig.toml` | Bun运行时配置 |
| `bun.lock` | Bun依赖锁定文件 |
| `README.md` | 项目说明文档 |
- 应用入口
```
src/
├── app.ts # Elysia应用主入口
└── server.ts # 服务器启动文件
```
- 配置管理 (config/)
```
src/config/
├── index.ts # 配置总入口
├── db.config.ts # 数据库配置
├── redis.config.ts # Redis配置
├── jwt.config.ts # JWT配置
└── logger.config.ts # 日志配置
```
- 数据实体 (eneities/)
```
src/eneities/
├── index.ts # 实体总入口
└── users.ts # 用户实体定义
```
- 业务模块 (modules/)
```
src/modules/
├── index.ts # 模块总入口
├── tags.ts # Swagger标签定义
├── example/ # 示例模块
│ ├── example.schema.ts # Schema定义
│ ├── example.response.ts # 响应格式
│ ├── example.service.ts # 业务逻辑
│ ├── example.controller.ts # 路由控制器
│ └── example.test.ts # 测试用例
├── health/ # 健康检查模块
│ ├── health.controller.ts
│ └── health.service.ts
├── user/ # 用户模块
│ └── user.controller.ts
└── test/ # 测试模块
└── test.controller.ts
```
- 插件系统 (plugins/)
```
src/plugins/
├── index.ts # 插件总入口
├── drizzle/ # 数据库ORM插件
│ ├── drizzle.config.ts
│ ├── drizzle.plugins.ts
│ ├── drizzle.service.ts
│ └── README.md
├── errorHandle/ # 错误处理插件
│ └── errorHandler.plugins.ts
├── jwt/ # JWT认证插件
│ ├── jwt.plugins.ts
│ └── jwt.service.ts
├── logger/ # 日志插件
│ ├── logger.plugins.ts
│ └── logger.service.ts
├── redis/ # Redis插件
│ ├── redis.plugins.ts
│ └── redis.service.ts
└── swagger/ # API文档插件
└── swagger.plugins.ts
```
- 类型定义 (type/)
```
src/type/
├── config.type.ts # 配置相关类型
├── drizzle.type.ts # 数据库相关类型
├── error.type.ts # 错误相关类型
├── jwt.type.ts # JWT相关类型
├── logger.type.ts # 日志相关类型
└── redis.type.ts # Redis相关类型
```
- 工具函数 (utils/)
```
src/utils/
├── deviceInfo.ts # 设备信息工具
├── formatFileSize.ts # 文件大小格式化
├── formatRoute.ts # 路由格式化
├── jwt.helper.ts # JWT工具函数
├── mysql.ts # MySQL工具
├── randomChalk.ts # 随机颜色工具
├── redis.ts # Redis工具
├── text.ts # 文本处理工具
└── response.helper.ts # 响应格式工具 (新增)
```
- 验证器 (validators/)
```
src/validators/
└── global.response.ts # 全局响应格式验证
```
- 测试文件 (tests/)
```
src/tests/
├── app.test.ts # 应用测试
├── health.test.ts # 健康检查测试
├── mysql.test.ts # MySQL测试
├── redis.test.ts # Redis测试
├── swagger.test.ts # Swagger测试
└── demo/
└── testLogger.ts # 日志测试演示
```
- 常量定义 (constants/)
```
src/constants/
└── error-codes.ts # 统一错误码定义 (新增)
```
## 1. 文件组织规范
### 1.1 必须的文件结构
每个业务模块必须包含以下5个文件**按照固定顺序**
```
src/modules/[module]/
├── [module].schema.ts # 1⃣ 数据结构定义(优先级最高)
├── [module].response.ts # 2⃣ 响应格式定义
├── [module].service.ts # 3⃣ 业务逻辑实现
├── [module].controller.ts # 4⃣ 路由控制器
└── [module].test.ts # 5⃣ 测试用例
```
### 1.2 文件命名约定
- 模块名使用 **单数形式**`user`、`product`、`order`(不是 users、products
- 文件名格式:`[模块名].[类型].ts`
- 导出名格式:`[模块名][类型名]`
## 2. Schema & 类型系统(🔥 重点)
### 2.1 Schema定义规范
```typescript
// ✅ 正确示例 - user.schema.ts
import { t, type Static } from 'elysia';
// 1. 定义Schema运行时验证
export const CreateUserSchema = t.Object({
username: t.String({
minLength: 2,
maxLength: 50,
description: '用户名2-50字符',
examples: ['admin', 'testuser']
}),
email: t.String({
format: 'email',
description: '用户邮箱',
examples: ['user@example.com']
}),
password: t.String({
minLength: 6,
description: '密码至少6位',
examples: ['123456']
}),
});
// 2. 导出TypeScript类型编译时类型检查
export type CreateUserRequest = Static<typeof CreateUserSchema>;
// 3. 数据模型Schema
export const UserSchema = t.Object({
id: t.Number({ description: '用户ID' }),
username: t.String({ description: '用户名' }),
email: t.String({ description: '邮箱' }),
createdAt: t.String({ description: '创建时间' }),
updatedAt: t.String({ description: '更新时间' }),
});
export type User = Static<typeof UserSchema>;
```
### 2.2 类型导出规范
**必须遵循的命名模式:**
- Request类型`[动作][模块]Request` → `CreateUserRequest`
- Response类型`[动作][模块]Response` → `GetUserResponse`
- 数据模型:`[模块]` → `User`、`Product`
- Schema名`[动作][模块]Schema` → `CreateUserSchema`
## 3. Response定义规范
### 3.1 统一响应格式
```typescript
// ✅ 正确示例 - user.response.ts
import { t, type Static } from 'elysia';
import { globalResponseWrapperSchema } from '@/validators/global.response';
import { UserSchema } from './user.schema';
// 成功响应
export const GetUserSuccessResponseSchema = globalResponseWrapperSchema(UserSchema);
export type GetUserSuccessResponse = Static<typeof GetUserSuccessResponseSchema>;
// 错误响应
export const UserNotFoundResponseSchema = t.Object({
code: t.Literal('USER_NOT_FOUND'),
message: t.String({ examples: ['用户不存在'] }),
data: t.Null(),
});
export type UserNotFoundResponse = Static<typeof UserNotFoundResponseSchema>;
// 组合响应供controller使用
export const GetUserResponses = {
200: GetUserSuccessResponseSchema,
404: UserNotFoundResponseSchema,
401: t.Object({
code: t.Literal('UNAUTHORIZED'),
message: t.String(),
data: t.Null(),
}),
};
```
## 4. Service层规范
### 4.1 Service类定义
```typescript
// ✅ 正确示例 - user.service.ts
import type { CreateUserRequest, User } from './user.schema';
import type { GetUserSuccessResponse, UserNotFoundResponse } from './user.response';
import { Logger } from '@/plugins/logger/logger.service';
import { ERROR_CODES } from '@/constants/error-codes';
export class UserService {
/**
* 创建用户
* @param request 创建用户请求参数
* @returns Promise<GetUserSuccessResponse>
*/
async createUser(request: CreateUserRequest): Promise<GetUserSuccessResponse> {
try {
Logger.info(`创建用户请求:${JSON.stringify(request)}`);
// 业务逻辑实现
const user: User = {
id: 1,
username: request.username,
email: request.email,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
// 进行数据库操作逻辑...
Logger.info(`用户创建成功:${user.id}`);
return {
code: ERROR_CODES.SUCCESS,
message: '用户创建成功',
data: user,
};
} catch (error) {
Logger.error(new Error(`创建用户失败:${error}`));
throw error;
}
}
/**
* 根据ID查询用户
* @param id 用户ID
* @returns Promise<GetUserSuccessResponse | UserNotFoundResponse>
*/
async getUserById(id: number): Promise<GetUserSuccessResponse | UserNotFoundResponse> {
// 实现逻辑...
}
}
// 导出单例实例
export const userService = new UserService();
```
### 4.2 Service层要求
- ✅ 所有方法必须有完整的类型注解
- ✅ 所有方法必须有JSDoc注释
- ✅ 必须有详细的日志记录
- ✅ 必须有错误处理
- ✅ 导出单例实例供controller使用
## 5. Controller层规范
### 5.1 Controller定义
```typescript
// ✅ 正确示例 - user.controller.ts
import { Elysia } from 'elysia';
import { jwtAuthPlugin } from '@/plugins/jwt/jwt.plugins';
import { CreateUserSchema } from './user.schema';
import { GetUserResponses } from './user.response';
import { userService } from './user.service';
import { tags } from '@/modules/tags';
export const userController = new Elysia({ prefix: '/user' })
/**
* 创建用户
* @route POST /api/user
*/
.post(
'/',
({ body }) => userService.createUser(body);,
{
body: CreateUserSchema,
detail: {
summary: '创建用户',
description: '创建新用户账户',
tags: [tags.user],
},
response: GetUserResponses,
}
)
/**
* 获取用户信息(需要认证)
* @route GET /api/user/:id
*/
.use(jwtAuthPlugin)
.get(
'/:id',
async ({ params }) => userService.getUserById(Number(params.id));,
{
params: t.Object({
id: t.Numeric({ description: '用户ID' })
}),
detail: {
summary: '获取用户信息',
description: '根据用户ID获取用户详细信息',
tags: [tags.user],
security: [{ bearerAuth: [] }],
},
response: GetUserResponses,
}
);
```
## 6. 错误处理规范
### 6.1 统一错误码
```typescript
// src/constants/error-codes.ts
export const ERROR_CODES = {
SUCCESS: 'SUCCESS',
VALIDATION_ERROR: 'VALIDATION_ERROR',
UNAUTHORIZED: 'UNAUTHORIZED',
FORBIDDEN: 'FORBIDDEN',
NOT_FOUND: 'NOT_FOUND',
BUSINESS_ERROR: 'BUSINESS_ERROR',
INTERNAL_ERROR: 'INTERNAL_ERROR',
} as const;
```
### 6.2 错误处理模式
```typescript
// Service层
try {
// 业务逻辑
const result = await someOperation();
return successResponse(result);
} catch (error) {
Logger.error(new Error(`操作失败:${error}`));
if (error instanceof ValidationError) {
throw new BusinessError('参数验证失败', ERROR_CODES.VALIDATION_ERROR);
}
throw new InternalError('内部服务错误', ERROR_CODES.INTERNAL_ERROR);
}
// Controller层
try {
const result = await service.method();
return result;
} catch (error) {
if (error instanceof BusinessError) {
set.status = 400;
return errorResponse(error.code, error.message);
}
set.status = 500;
return errorResponse(ERROR_CODES.INTERNAL_ERROR, '服务器内部错误');
}
```
## 7. 测试规范
### 7.1 测试文件结构
```typescript
// ✅ 正确示例 - user.test.ts
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { app } from '@/app';
import type { CreateUserRequest } from './user.schema';
describe('User API', () => {
let authToken: string;
beforeAll(async () => {
// 设置测试环境
authToken = 'test-jwt-token';
});
describe('POST /api/user', () => {
it('应该成功创建用户', async () => {
const payload: CreateUserRequest = {
username: 'testuser',
email: 'test@example.com',
password: '123456',
};
const response = await app
.handle(new Request('http://localhost/api/user', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
}));
expect(response.status).toBe(200);
const result = await response.json();
expect(result.code).toBe('SUCCESS');
expect(result.data.username).toBe(payload.username);
});
it('应该验证必填字段', async () => {
const payload = { username: 'test' }; // 缺少email和password
const response = await app
.handle(new Request('http://localhost/api/user', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
}));
expect(response.status).toBe(400);
});
});
});
```
## 8. AI助手协作规范
### 8.1 注释规范(关键❗️)
#### 1. 文件头部注释
每个源文件开头应包含如下信息:
```javascript
/**
* @file 文件简要说明
* @author 创建者姓名(如:张三 <zhangsan@example.com>
* @date 创建时间2024-06-01
* @lastEditor 最后修改人
* @lastEditTime最后修改时间
* @description 文件详细描述(可选)
*/
```
#### 2. 函数/方法/请求注释JSDoc
- 每个公开函数、类、接口都应有 JSDoc 注释
- 增加修改记录,包含修改人、修改时间、修改描述
**推荐标签:**
- `@param` 参数说明
- `@returns` 返回值说明
- `@throws` 可能抛出的异常
- `@deprecated` 弃用说明
- `@example` 使用示例
- `@modification` 修改记录(格式:修改人 修改时间 修改描述)
**示例:**
```typescript
/**
* 计算两个数的和
* @param a 第一个加数
* @param b 第二个加数
* @returns 两数之和
* @example
* add(1, 2) // 3
* @modification 李四 2024-06-05 优化了参数校验
*/
function add(a: number, b: number): number {
return a + b;
}
```
```typescript
/**
* 方法功能说明
* @route HTTP方法 路径
* @description 详细描述
* @param 参数名 参数说明
* @returns 返回值类型和说明
* @throws 可能抛出的异常
* @example 使用示例
* @modification 作者 日期 修改说明
*/
```
#### 3. 注释类型与风格
- 单行注释:`//`,用于简短说明
- 多行注释:`/* ... */`,用于较长描述
- 文档注释JSDoc`/** ... */`,用于结构化说明
- 注释应简洁明了,避免废话和重复代码内容
- 注释内容使用中文或英文均可,但需统一
- 代码变更时同步更新相关注释,避免注释与代码不符
- 不要注释掉无用代码,直接删除,必要时可通过版本管理找回
#### 4. 特殊标记
- `TODO:` 需要补充或优化的内容
- `FIXME:` 需要修复的问题
- `HACK:` 临时解决方案,需后续优化
**示例:**
```javascript
// TODO: 优化此处的性能
// FIXME: 这里有边界条件未处理
// HACK: 临时绕过接口校验
```
#### 5. 变量注释
- 每一个变量遵照JSDoc添加注释携带描述、用途
参照
```ts
/**
* MySQL数据库连接配置
* @property {string} host - 数据库主机地址
* @property {number} port - 数据库端口号
* @property {string} user - 数据库用户名
* @property {string} password - 数据库密码
* @property {string} database - 数据库名称
*/
export const dbConfig = {
/** 数据库主机地址 */
host: process.env.DB_HOST || 'localhost',
/** 数据库端口号 */
port: Number(process.env.DB_PORT) || 3306,
/** 数据库用户名 */
user: process.env.DB_USER || 'root',
/** 数据库密码 */
password: process.env.DB_PASSWORD || '',
/** 数据库名称 */
database: process.env.DB_NAME || 'test',
};
```
#### 6. 规范补充建议
- 注释应随代码同步更新,避免"注释失效"或误导他人。
- 代码评审时,建议同时检查注释的准确性和完整性。
- 复杂算法、业务逻辑、边界处理、特殊依赖等务必详细注释。
- 简单、易懂的代码无需过度注释,避免注释冗余。
- 团队应约定注释统一使用中文或英文,避免混杂,提升协作效率。
- 推荐使用 ESLint、TSLint 等工具结合注释相关插件(如 eslint-plugin-jsdoc进行注释规范自动校验。
- 可使用 IDE 插件(如 VSCode 的 JSDoc Generator自动生成注释模板提升效率。
- 建议在项目根目录下提供注释模板(如 `.comment-templates`),便于新成员快速上手。
- 注释中严禁出现密码、密钥、用户隐私等敏感信息。
- 重要模块、核心业务建议将注释内容同步到项目文档,便于知识传承和查阅。
### 8.2 代码组织原则
1. **单一职责**:每个文件只负责一个清晰的功能
2. **依赖注入**:通过构造函数或导入明确依赖关系
3. **类型优先**先定义Schema和类型再实现逻辑
4. **错误优先**:优先考虑错误处理和边界情况
5. **测试驱动**:每个功能都有对应的测试用例
### 8.3 命名约定总结
| 类型 | 格式 | 示例 |
|------|------|------|
| 文件名 | `[module].[type].ts` | `user.controller.ts` |
| Schema | `[Action][Module]Schema` | `CreateUserSchema` |
| Type | `[Action][Module][Type]` | `CreateUserRequest` |
| Service类 | `[Module]Service` | `UserService` |
| Service实例 | `[module]Service` | `userService` |
| Controller | `[module]Controller` | `userController` |
## 9. 快速检查清单
开发新功能时,按此顺序检查:
- [ ] 1. Schema定义完整包含验证规则和示例
- [ ] 2. 类型导出正确Request/Response类型
- [ ] 3. Response格式统一成功/错误响应)
- [ ] 4. Service类型注解完整
- [ ] 5. Controller错误处理完整
- [ ] 6. 测试用例覆盖主要场景
- [ ] 7. JSDoc注释完整
- [ ] 8. 日志记录到位
## 10. 最佳实践
### 10.1 性能优化
- 使用连接池管理数据库连接
- 实现合理的缓存策略
- 避免N+1查询问题
### 10.2 安全考虑
- 输入验证和清理
- 适当的认证和授权
- 敏感信息不记录日志
### 10.3 监控和日志
- 关键操作必须有日志
- 错误信息要有足够上下文
- 性能敏感操作要有监控
这套规则确保了代码的一致性、可维护性和AI友好性让我能够更高效地理解和协助你的开发工作。
## 11. 模块引入
- 全部使用路径别名,如`@/app` `@/config/db.config`
- 注意更新 tsconfig.json bunfig.toml 等配置中关于路径别名的配置
---
**请所有开发者严格遵守以上规范,保障 Elysia 接口的一致性、后端服务的健壮性、安全性与可维护性。**