fischerX/docs/development/coding-standards.md

607 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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.

# 开发规范
> **文档版本**: v1.0.0
> **创建日期**: 2026-05-25
> **适用范围**: FischerX 项目开发人员
## 目录
- [代码规范](#代码规范)
- [Git 规范](#git-规范)
- [PR 规范](#pr-规范)
---
## 代码规范
### TypeScript 规范
#### 类型定义
- 使用 `type` 定义对象类型,使用 `interface` 定义类接口或需要扩展的类型
- 始终使用严格的类型检查,避免使用 `any`
- 优先使用联合类型和字面量类型
```typescript
// 好的做法
type User = {
id: string;
name: string;
email: string;
role: 'admin' | 'user' | 'guest';
};
interface Repository {
findById(id: string): Promise<User | null>;
save(user: User): Promise<User>;
}
// 避免
type User = any;
```
#### 命名规范
- 类型名使用 PascalCase
- 常量使用 UPPER_SNAKE_CASE
- 变量和函数使用 camelCase
- 类使用 PascalCase
- React 组件使用 PascalCase
```typescript
// 类型
type UserProfile = { ... };
// 常量
const MAX_RETRY_COUNT = 3;
const API_BASE_URL = 'https://api.example.com';
// 变量和函数
const userName = 'John';
function calculateTotal(price: number, quantity: number): number { ... }
// 类
class UserService { ... }
// React 组件
function UserProfileCard() { ... }
```
#### 文件组织
- 一个文件一个主要导出
- 使用 index.ts 作为模块入口
- 按功能组织文件,而不是按类型
```
// 好的做法
user/
├── index.ts
├── types.ts
├── service.ts
├── repository.ts
└── hooks.ts
```
---
### React/Next.js 规范
#### 组件设计
- 使用函数组件,避免类组件
- 组件文件使用 `.tsx` 扩展名
- 组件名与文件名保持一致
```tsx
// components/UserCard.tsx
interface UserCardProps {
user: User;
onEdit?: (user: User) => void;
}
export function UserCard({ user, onEdit }: UserCardProps) {
return (
<div className="user-card">
<h3>{user.name}</h3>
<p>{user.email}</p>
{onEdit && <button onClick={() => onEdit(user)}>Edit</button>}
</div>
);
}
```
#### Hooks 规范
- 自定义 Hook 以 `use` 开头
- Hook 应该只负责单一职责
- 使用 React Query 进行数据获取
- 使用 Zustand 进行状态管理
```tsx
// hooks/useUser.ts
import { useQuery } from '@tanstack/react-query';
import { userApi } from '@/lib/api';
export function useUser(userId: string) {
return useQuery({
queryKey: ['user', userId],
queryFn: () => userApi.getById(userId),
enabled: !!userId,
});
}
```
#### 表单处理
- 使用 React Hook Form
- 使用 Zod 进行验证
- 显示友好的错误信息
```tsx
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod';
const formSchema = z.object({
name: z.string().min(2, 'Name too short'),
email: z.string().email('Invalid email'),
});
type FormValues = z.infer<typeof formSchema>;
function UserForm() {
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
});
const onSubmit = (data: FormValues) => {
console.log(data);
};
return <form onSubmit={form.handleSubmit(onSubmit)}>{/* ... */}</form>;
}
```
#### 样式规范
- 使用 Tailwind CSS
- 组件内部样式放在 `className`
- 复杂样式使用 `clsx``tailwind-merge`
```tsx
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
function cn(...inputs: any[]) {
return twMerge(clsx(inputs));
}
function Button({
children,
variant = 'primary',
className,
}: {
children: React.ReactNode;
variant?: 'primary' | 'secondary' | 'danger';
className?: string;
}) {
const variants = {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
danger: 'bg-red-600 text-white hover:bg-red-700',
};
return (
<button
className={cn(
'px-4 py-2 rounded font-medium transition-colors',
variants[variant],
className
)}
>
{children}
</button>
);
}
```
---
### NestJS 规范
#### 模块结构
- 按功能组织模块
- 每个模块包含 Controller、Service、Module
- 使用 Prisma 作为数据访问层
```
user/
├── user.module.ts
├── user.controller.ts
├── user.service.ts
├── dto/
│ ├── create-user.dto.ts
│ └── update-user.dto.ts
└── entities/
└── user.entity.ts
```
#### 控制器规范
- Controller 只负责请求/响应处理
- 业务逻辑委托给 Service
- 使用 DTO 进行验证
- 使用 Swagger 装饰器生成文档
```typescript
import { Controller, Get, Post, Body, Param, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
@ApiTags('users')
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post()
@ApiOperation({ summary: 'Create user' })
@ApiResponse({ status: 201, description: 'User created' })
create(@Body() createUserDto: CreateUserDto) {
return this.userService.create(createUserDto);
}
@Get(':id')
@UseGuards(JwtAuthGuard)
@ApiOperation({ summary: 'Get user by ID' })
findOne(@Param('id') id: string) {
return this.userService.findOne(id);
}
}
```
#### 服务规范
- Service 包含业务逻辑
- 使用依赖注入
- 抛出业务异常
```typescript
import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { CreateUserDto } from './dto/create-user.dto';
import * as bcrypt from 'bcrypt';
@Injectable()
export class UserService {
constructor(private prisma: PrismaService) {}
async create(createUserDto: CreateUserDto) {
const hashedPassword = await bcrypt.hash(createUserDto.password, 10);
return this.prisma.user.create({
data: {
...createUserDto,
password: hashedPassword,
},
});
}
async findOne(id: string) {
const user = await this.prisma.user.findUnique({ where: { id } });
if (!user) {
throw new NotFoundException(`User with ID ${id} not found`);
}
return user;
}
}
```
#### DTO 规范
- 使用 class-validator 进行验证
- 使用 class-transformer 进行转换
- DTO 放在 dto 目录下
```typescript
import { IsEmail, IsString, MinLength } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreateUserDto {
@ApiProperty()
@IsString()
@MinLength(2)
name: string;
@ApiProperty()
@IsEmail()
email: string;
@ApiProperty()
@IsString()
@MinLength(8)
password: string;
}
```
---
## Git 规范
### 分支策略
我们使用 Git Flow 工作流:
```
main (生产环境)
└── develop (开发环境)
├── feature/feature-name (功能分支)
├── bugfix/bug-name (修复分支)
├── hotfix/hotfix-name (紧急修复)
└── release/release-x.y.z (发布分支)
```
#### 分支说明
| 分支类型 | 命名规范 | 说明 |
|---------|---------|------|
| main | `main` | 生产环境代码,始终稳定 |
| develop | `develop` | 开发环境代码,集成新功能 |
| feature | `feature/xxx-yyy` | 新功能开发 |
| bugfix | `bugfix/xxx-yyy` | Bug 修复 |
| hotfix | `hotfix/xxx-yyy` | 生产环境紧急修复 |
| release | `release/x.y.z` | 发布准备 |
#### 创建分支
```bash
# 从 develop 创建功能分支
git checkout develop
git pull origin develop
git checkout -b feature/user-authentication
# 从 main 创建紧急修复分支
git checkout main
git pull origin main
git checkout -b hotfix/critical-login-bug
```
---
### 提交规范
我们使用 Conventional Commits 规范:
```
<type>(<scope>): <subject>
<body>
<footer>
```
#### Type 类型
| 类型 | 说明 |
|-----|------|
| feat | 新功能 |
| fix | Bug 修复 |
| docs | 文档更新 |
| style | 代码格式调整 |
| refactor | 重构 |
| perf | 性能优化 |
| test | 测试相关 |
| chore | 构建/工具相关 |
#### Scope 范围
- `web`: Web 应用
- `admin`: 管理后台
- `api`: API 服务
- `ui`: UI 组件库
- `core`: 核心业务包
- `types`: 类型定义
- `utils`: 工具函数
- `config`: 配置
#### 提交示例
```bash
# 新功能
git commit -m "feat(web): add user login page"
# Bug 修复
git commit -m "fix(api): handle null user in authentication"
# 文档更新
git commit -m "docs: update quick start guide"
# 重构
git commit -m "refactor(ui): restructure button component"
# 带正文的提交
git commit -m "feat(web): add password reset
- Add password reset form
- Add email verification
- Update API client
Closes #123"
```
---
## PR 规范
### PR 流程
1. 创建分支并开发
2. 提交代码
3. 推送分支到远程
4. 创建 Pull Request
5. CI 检查
6. 代码审查
7. 修改(如果需要)
8. 合并
### PR 模板
```markdown
## 描述
简要描述这个 PR 的改动。
## 类型
- [ ] feat (新功能)
- [ ] fix (Bug 修复)
- [ ] docs (文档更新)
- [ ] style (代码格式)
- [ ] refactor (重构)
- [ ] perf (性能优化)
- [ ] test (测试)
- [ ] chore (构建/工具)
## 改动范围
- [ ] apps/web
- [ ] apps/admin
- [ ] services/api
- [ ] packages/ui
- [ ] packages/core
- [ ] packages/types
- [ ] packages/utils
- [ ] 其他: ___
## 测试
- [ ] 单元测试已添加/更新
- [ ] 集成测试已添加/更新
- [ ] E2E 测试已添加/更新
- [ ] 手动测试已完成
## 截图(如果适用)
添加 UI 变化的截图。
## 相关 Issue
Closes #123, #456
## 检查清单
- [ ] 代码符合项目规范
- [ ] 已添加必要的测试
- [ ] 文档已更新
- [ ] CI 检查通过
```
### 代码审查清单
审查者应该检查以下内容:
#### 功能正确性
- [ ] 代码实现了预期功能
- [ ] 边界情况已处理
- [ ] 错误处理正确
#### 代码质量
- [ ] 代码清晰易读
- [ ] 命名有意义
- [ ] 没有重复代码
- [ ] 复杂度适中
#### 性能
- [ ] 没有明显的性能问题
- [ ] 数据库查询优化
- [ ] 缓存使用合理
#### 安全
- [ ] 输入已验证
- [ ] 没有 SQL 注入风险
- [ ] 敏感数据已保护
- [ ] 权限控制正确
#### 测试
- [ ] 测试覆盖充分
- [ ] 测试可以通过
- [ ] 测试有意义
#### 文档
- [ ] 代码注释充分
- [ ] API 文档已更新
- [ ] 使用文档已更新
### 合并策略
- **Squash Merge**: 功能分支合并到 develop保持提交历史整洁
- **Rebase Merge**: 保持线性历史
- **Merge Commit**: 保留完整提交历史(用于 main 分支)
```bash
# Squash 合并示例
git checkout develop
git merge --squash feature/user-authentication
git commit -m "feat(web): add user authentication"
```
---
## 最佳实践提示
### 开发工作流
1. **开始工作前**
```bash
git checkout develop
git pull origin develop
```
2. **创建分支**
```bash
git checkout -b feature/your-feature-name
```
3. **定期提交**
```bash
git add .
git commit -m "feat: your commit message"
```
4. **推送到远程**
```bash
git push -u origin feature/your-feature-name
```
5. **创建 PR**
- 在 GitHub/GitLab 上创建 PR
- 填写 PR 模板
- 请求审查
6. **更新分支**
```bash
git checkout develop
git pull origin develop
git checkout feature/your-feature-name
git rebase develop
```
### 避免常见错误
- ❌ 不要直接提交到 main 或 develop
- ❌ 不要提交大文件(使用 Git LFS
- ❌ 不要提交敏感信息API 密钥、密码等)
- ❌ 不要忽略测试失败
- ✅ 保持提交小而专注
- ✅ 写有意义的提交信息
- ✅ 及时更新文档
---
## 下一步
- [最佳实践](./best-practices.md) - 学习最佳实践
- [常见问题](./troubleshooting.md) - 查看常见问题
- [贡献指南](./contributing.md) - 了解如何贡献
---
> **文档维护**: 本文档由开发团队维护,如有问题或建议请提交 Issue。
> **最后更新**: 2026-05-25