forked from datawhale/whale-town-end
- 精简ARCHITECTURE.md,移除冗长的目录结构说明 - 突出四层架构的职责和原则 - 保留核心的架构图和依赖关系说明 - 简化双模式架构和模块依赖的描述 - 移除过于详细的扩展指南,保留核心内容
15 KiB
15 KiB
后端开发规范指南
本文档定义了基于四层架构的后端开发规范,包括架构规范、注释规范、日志规范、代码质量规范等。
📋 目录
🏗️ 架构规范
四层架构原则
项目采用 Gateway-Business-Core-Data 四层架构,每层职责明确:
Gateway Layer (网关层)
↓ 依赖
Business Layer (业务层)
↓ 依赖
Core Layer (核心层)
↓ 依赖
Data Layer (数据层)
各层职责
🌐 Gateway Layer(网关层)
位置: src/gateway/
职责:
- HTTP/WebSocket协议处理
- 请求参数验证(DTO)
- 路由管理
- 认证守卫
- 错误转换
规范:
// ✅ 正确:只做协议转换
@Controller('auth')
export class LoginController {
constructor(private readonly loginService: LoginService) {}
@Post('login')
async login(@Body() dto: LoginDto, @Res() res: Response) {
const result = await this.loginService.login(dto);
this.handleResponse(result, res);
}
}
// ❌ 错误:包含业务逻辑
@Controller('auth')
export class LoginController {
@Post('login')
async login(@Body() dto: LoginDto) {
const user = await this.usersService.findByEmail(dto.email);
const isValid = await bcrypt.compare(dto.password, user.password);
// ... 更多业务逻辑
}
}
🎯 Business Layer(业务层)
位置: src/business/
职责:
- 业务逻辑实现
- 服务协调
- 业务规则验证
- 事务管理
规范:
// ✅ 正确:实现业务逻辑
@Injectable()
export class LoginService {
constructor(
private readonly loginCoreService: LoginCoreService,
private readonly emailService: EmailService,
) {}
async login(dto: LoginDto): Promise<ApiResponse<LoginResponse>> {
try {
// 1. 调用核心服务验证
const user = await this.loginCoreService.validateUser(dto);
// 2. 业务逻辑:生成Token
const tokens = await this.loginCoreService.generateTokens(user);
// 3. 业务逻辑:发送登录通知
await this.emailService.sendLoginNotification(user.email);
return { success: true, data: tokens };
} catch (error) {
return { success: false, message: error.message };
}
}
}
// ❌ 错误:直接访问数据库
@Injectable()
export class LoginService {
async login(dto: LoginDto) {
const user = await this.userRepository.findOne({ email: dto.email });
// ...
}
}
⚙️ Core Layer(核心层)
位置: src/core/
职责:
- 数据访问
- 基础设施
- 外部系统集成
- 工具服务
规范:
// ✅ 正确:提供技术基础设施
@Injectable()
export class LoginCoreService {
constructor(
@Inject('IUsersService')
private readonly usersService: IUsersService,
@Inject('IRedisService')
private readonly redisService: IRedisService,
) {}
async validateUser(dto: LoginDto): Promise<User> {
const user = await this.usersService.findByEmail(dto.email);
if (!user) {
throw new UnauthorizedException('用户不存在');
}
const isValid = await bcrypt.compare(dto.password, user.password);
if (!isValid) {
throw new UnauthorizedException('密码错误');
}
return user;
}
}
// ❌ 错误:包含业务逻辑
@Injectable()
export class LoginCoreService {
async validateUser(dto: LoginDto) {
// 发送邮件通知 - 这是业务逻辑,应该在Business层
await this.emailService.sendLoginNotification(user.email);
}
}
模块组织规范
// 模块命名:功能名.module.ts
// 服务命名:功能名.service.ts
// 控制器命名:功能名.controller.ts
// 网关命名:功能名.gateway.ts
// ✅ 正确的模块结构
src/
├── gateway/
│ └── auth/
│ ├── login.controller.ts
│ ├── register.controller.ts
│ ├── jwt_auth.guard.ts
│ ├── dto/
│ └── auth.gateway.module.ts
├── business/
│ └── auth/
│ ├── login.service.ts
│ ├── register.service.ts
│ └── auth.module.ts
└── core/
└── login_core/
├── login_core.service.ts
└── login_core.module.ts
<EFBFBD> 注释规规范
文件头注释
/**
* 用户登录服务
*
* 功能描述:
* - 处理用户登录业务逻辑
* - 协调登录核心服务和邮件服务
* - 生成JWT令牌
*
* 架构层级:Business Layer
*
* 依赖服务:
* - LoginCoreService: 登录核心逻辑
* - EmailService: 邮件发送服务
*
* @author 作者名
* @version 1.0.0
* @since 2025-01-01
*/
类注释
/**
* 登录业务服务
*
* 职责:
* - 实现用户登录业务逻辑
* - 协调核心服务完成登录流程
* - 处理登录相关的业务规则
*
* 主要方法:
* - login() - 用户登录
* - verificationCodeLogin() - 验证码登录
* - refreshToken() - 刷新令牌
*/
@Injectable()
export class LoginService {
// 实现
}
方法注释(三级标准)
/**
* 用户登录
*
* 业务逻辑:
* 1. 调用核心服务验证用户凭证
* 2. 生成访问令牌和刷新令牌
* 3. 发送登录成功通知邮件
* 4. 记录登录日志
* 5. 返回登录结果
*
* @param dto 登录请求数据
* @returns 登录结果,包含用户信息和令牌
* @throws UnauthorizedException 用户名或密码错误
* @throws ForbiddenException 用户状态不允许登录
*
* @example
* ```typescript
* const result = await loginService.login({
* identifier: 'user@example.com',
* password: 'password123'
* });
* ```
*/
async login(dto: LoginDto): Promise<ApiResponse<LoginResponse>> {
// 实现
}
修改记录规范
/**
* 最近修改:
* - 2025-01-15: 架构重构 - 迁移到四层架构,分离网关层和业务层
* - 2025-01-10: 功能新增 - 添加验证码登录功能
* - 2025-01-08: Bug修复 - 修复Token刷新逻辑错误
* - 2025-01-05: 代码规范优化 - 统一异常处理格式
* - 2025-01-03: 性能优化 - 优化数据库查询性能
*
* @version 2.0.0
* @lastModified 2025-01-15
*/
修改记录原则:
- 只保留最近5次修改
- 包含日期、类型、描述
- 重大版本更新标注版本号
📊 日志规范
日志级别使用
// ERROR - 系统错误,需要立即处理
this.logger.error('用户登录失败', {
userId,
error: error.message,
stack: error.stack
});
// WARN - 警告信息,需要关注
this.logger.warn('用户多次登录失败', {
userId,
attemptCount,
ip: request.ip
});
// INFO - 重要的业务操作
this.logger.info('用户登录成功', {
userId,
loginTime: new Date(),
ip: request.ip
});
// DEBUG - 调试信息(仅开发环境)
this.logger.debug('验证用户密码', {
userId,
passwordHash: '***'
});
日志格式规范
// ✅ 正确:结构化日志
this.logger.info('操作描述', {
userId: 'user123',
action: 'login',
timestamp: new Date(),
metadata: { ip: '192.168.1.1' }
});
// ❌ 错误:字符串拼接
this.logger.info(`用户${userId}登录成功`);
敏感信息处理
// ✅ 正确:隐藏敏感信息
this.logger.info('用户注册', {
email: user.email,
password: '***', // 密码不记录
apiKey: '***' // API密钥不记录
});
// ❌ 错误:暴露敏感信息
this.logger.info('用户注册', {
email: user.email,
password: user.password, // 危险!
apiKey: user.apiKey // 危险!
});
⚠️ 异常处理规范
异常类型使用
// 400 - 客户端请求错误
throw new BadRequestException('参数格式错误');
// 401 - 未授权
throw new UnauthorizedException('用户名或密码错误');
// 403 - 禁止访问
throw new ForbiddenException('用户状态不允许此操作');
// 404 - 资源不存在
throw new NotFoundException('用户不存在');
// 409 - 资源冲突
throw new ConflictException('用户名已存在');
// 500 - 服务器内部错误
throw new InternalServerErrorException('系统内部错误');
分层异常处理
// Gateway Layer - 转换为HTTP响应
@Controller('auth')
export class LoginController {
@Post('login')
async login(@Body() dto: LoginDto, @Res() res: Response) {
const result = await this.loginService.login(dto);
if (result.success) {
res.status(HttpStatus.OK).json(result);
} else {
const statusCode = this.getErrorStatusCode(result);
res.status(statusCode).json(result);
}
}
}
// Business Layer - 返回业务响应
@Injectable()
export class LoginService {
async login(dto: LoginDto): Promise<ApiResponse<LoginResponse>> {
try {
const user = await this.loginCoreService.validateUser(dto);
const tokens = await this.loginCoreService.generateTokens(user);
return {
success: true,
data: tokens,
message: '登录成功'
};
} catch (error) {
this.logger.error('登录失败', { dto, error: error.message });
return {
success: false,
message: error.message,
error_code: 'LOGIN_FAILED'
};
}
}
}
// Core Layer - 抛出技术异常
@Injectable()
export class LoginCoreService {
async validateUser(dto: LoginDto): Promise<User> {
const user = await this.usersService.findByEmail(dto.email);
if (!user) {
throw new UnauthorizedException('用户不存在');
}
const isValid = await bcrypt.compare(dto.password, user.password);
if (!isValid) {
throw new UnauthorizedException('密码错误');
}
return user;
}
}
🔍 代码质量规范
代码检查清单
提交代码前确保:
-
架构规范
- 代码放在正确的架构层
- 没有跨层直接调用(如Gateway直接调用Core)
- 依赖方向正确(上层依赖下层)
- 模块职责单一明确
-
注释完整性
- 文件头注释包含架构层级说明
- 类注释说明职责和主要方法
- 方法注释包含业务逻辑和技术实现
- 修改记录保持最近5次
-
代码质量
- 没有未使用的导入和变量
- 常量使用正确命名(UPPER_SNAKE_CASE)
- 方法长度合理(不超过50行)
- 单一职责原则
-
日志规范
- 关键操作记录日志
- 使用结构化日志格式
- 敏感信息已隐藏
- 日志级别使用正确
-
异常处理
- 所有异常情况都处理
- 异常类型使用正确
- 错误信息清晰明确
- 记录了错误日志
💡 最佳实践
1. 遵循四层架构
// ✅ 正确:清晰的层次调用
// Gateway → Business → Core → Data
// Gateway Layer
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get(':id')
async getUser(@Param('id') id: string) {
return this.usersService.getUserById(id);
}
}
// Business Layer
@Injectable()
export class UsersService {
constructor(private readonly usersCoreService: UsersCoreService) {}
async getUserById(id: string): Promise<ApiResponse<User>> {
try {
const user = await this.usersCoreService.findUserById(id);
return { success: true, data: user };
} catch (error) {
return { success: false, message: error.message };
}
}
}
// Core Layer
@Injectable()
export class UsersCoreService {
constructor(
@Inject('IUsersService')
private readonly usersDataService: IUsersService
) {}
async findUserById(id: string): Promise<User> {
const user = await this.usersDataService.findOne(id);
if (!user) {
throw new NotFoundException('用户不存在');
}
return user;
}
}
2. 使用依赖注入接口
// ✅ 正确:使用接口依赖注入
@Injectable()
export class LoginCoreService {
constructor(
@Inject('IUsersService')
private readonly usersService: IUsersService,
@Inject('IRedisService')
private readonly redisService: IRedisService,
) {}
}
// ❌ 错误:直接依赖具体实现
@Injectable()
export class LoginCoreService {
constructor(
private readonly usersService: UsersService,
private readonly redisService: RealRedisService,
) {}
}
3. 统一响应格式
// 定义统一的响应接口
export interface ApiResponse<T = any> {
success: boolean;
data?: T;
message: string;
error_code?: string;
}
// Business Layer 返回统一格式
async login(dto: LoginDto): Promise<ApiResponse<LoginResponse>> {
try {
const result = await this.loginCoreService.validateUser(dto);
return {
success: true,
data: result,
message: '登录成功'
};
} catch (error) {
return {
success: false,
message: error.message,
error_code: 'LOGIN_FAILED'
};
}
}
4. 防御性编程
async processPayment(dto: PaymentDto): Promise<ApiResponse<PaymentResult>> {
// 1. 参数验证
if (!dto.amount || dto.amount <= 0) {
return {
success: false,
message: '支付金额必须大于0',
error_code: 'INVALID_AMOUNT'
};
}
// 2. 业务规则验证
const user = await this.usersService.findOne(dto.userId);
if (!user) {
return {
success: false,
message: '用户不存在',
error_code: 'USER_NOT_FOUND'
};
}
// 3. 状态检查
if (user.status !== UserStatus.ACTIVE) {
return {
success: false,
message: '用户状态不允许支付',
error_code: 'USER_INACTIVE'
};
}
// 4. 执行业务逻辑
return this.executePayment(dto);
}
5. 测试驱动开发
// 先写测试
describe('LoginService', () => {
it('should login successfully with valid credentials', async () => {
const dto = { identifier: 'test@example.com', password: 'password123' };
const result = await loginService.login(dto);
expect(result.success).toBe(true);
expect(result.data).toHaveProperty('accessToken');
});
it('should return error with invalid credentials', async () => {
const dto = { identifier: 'test@example.com', password: 'wrong' };
const result = await loginService.login(dto);
expect(result.success).toBe(false);
expect(result.error_code).toBe('LOGIN_FAILED');
});
});
// 再写实现
@Injectable()
export class LoginService {
async login(dto: LoginDto): Promise<ApiResponse<LoginResponse>> {
// 实现逻辑
}
}
🎯 总结
遵循开发规范能够:
- 清晰的架构 - 四层架构确保职责分离
- 高质量代码 - 完整的注释和规范的实现
- 易于维护 - 清晰的文档和日志便于问题定位
- 团队协作 - 统一的规范减少沟通成本
- 系统稳定 - 完善的异常处理和防御性编程
记住:好的代码不仅要能运行,更要符合架构设计、易于理解、便于维护和扩展。