Files
whale-town-end/docs/development/backend_development_guide.md
moyin 260ae2c559 docs:简化架构文档,突出四层架构核心设计
- 精简ARCHITECTURE.md,移除冗长的目录结构说明
- 突出四层架构的职责和原则
- 保留核心的架构图和依赖关系说明
- 简化双模式架构和模块依赖的描述
- 移除过于详细的扩展指南,保留核心内容
2026-01-14 15:13:54 +08:00

15 KiB
Raw Blame History

后端开发规范指南

本文档定义了基于四层架构的后端开发规范,包括架构规范、注释规范、日志规范、代码质量规范等。

📋 目录


🏗️ 架构规范

四层架构原则

项目采用 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>> {
    // 实现逻辑
  }
}

🎯 总结

遵循开发规范能够:

  1. 清晰的架构 - 四层架构确保职责分离
  2. 高质量代码 - 完整的注释和规范的实现
  3. 易于维护 - 清晰的文档和日志便于问题定位
  4. 团队协作 - 统一的规范减少沟通成本
  5. 系统稳定 - 完善的异常处理和防御性编程

记住:好的代码不仅要能运行,更要符合架构设计、易于理解、便于维护和扩展。


📚 相关文档