Files
wwjcloud-nest-v1/docs/DEVELOPMENT-GUIDE.md
2025-11-16 22:13:57 +08:00

12 KiB
Raw Permalink Blame History

WWJCloud NestJS 开发指导原则

基于 v0.1.1 版本真实项目结构分析制定
更新时间: 2025-01-27
适用范围: WWJCloud NestJS 项目开发

🎯 核心开发原则

1. 框架使用原则

  • 框架层面: 100% 使用 NestJS 的方式和特性
  • 业务层面: 与 Java 项目保持 100% 一致
  • 数据层面: 与 Java 项目数据库结构 100% 一致

2. 开发约束条件

  • 必须: 基于 Java 项目真实代码进行开发
  • 必须: 基于真实数据库表结构进行映射
  • 必须: 遵循项目既定的命名规范
  • 禁止: 自创业务逻辑或数据结构
  • 禁止: 编写骨架代码或 TODO 注释
  • 禁止: 硬编码业务数据或配置

📁 项目结构规范

目录层级

src/
├── config/                 # 配置管理层
│   ├── *.config.ts         # 各类配置文件
│   ├── config.module.ts    # 配置模块
│   └── *.entity.ts         # 配置相关实体
├── common/                 # 通用服务层
│   ├── base/               # 基础服务
│   ├── utils/              # 工具类
│   ├── interceptors/       # 拦截器
│   ├── guards/             # 守卫
│   └── pipes/              # 管道
├── core/                   # 核心基础设施层
│   └── (待开发)
└── vendor/                 # 第三方服务适配层
    ├── pay/                # 支付服务
    ├── sms/                # 短信服务
    └── upload/             # 上传服务

🏷️ 命名规范标准

文件命名规范

1. 实体文件

  • 格式: kebab-case.entity.ts
  • 示例: dynamic-config.entity.ts, sys-user.entity.ts
  • 说明: 使用短横线分隔,以 .entity.ts 结尾

2. 服务文件

  • 格式: kebab-case.service.ts
  • 示例: config-center.service.ts, pay.service.ts
  • 说明: 使用短横线分隔,以 .service.ts 结尾

3. 控制器文件

  • 格式: kebab-case.controller.ts
  • 示例: config-center.controller.ts, auth.controller.ts
  • 说明: 使用短横线分隔,以 .controller.ts 结尾

4. 工具类文件

  • 格式: kebab-case.util.ts
  • 示例: json.util.ts, string.util.ts
  • 说明: 使用短横线分隔,以 .util.ts 结尾

5. 模块文件

  • 格式: kebab-case.module.ts
  • 示例: config.module.ts, auth.module.ts
  • 说明: 使用短横线分隔,以 .module.ts 结尾

6. DTO 文件

  • 格式: PascalCaseDto.ts
  • 示例: CreateUserDto.ts, UpdateConfigDto.ts
  • 说明: 使用 PascalCaseDto.ts 结尾

类命名规范

1. 实体类

  • 格式: PascalCase
  • 示例: DynamicConfig, SysUser, MemberLevel
  • 说明: 与数据库表名对应,使用 PascalCase

2. 服务类

  • 格式: PascalCase + Service
  • 示例: ConfigCenterService, PayService, AuthService
  • 说明: 业务名称 + Service 后缀

3. 控制器类

  • 格式: PascalCase + Controller
  • 示例: ConfigCenterController, AuthController
  • 说明: 业务名称 + Controller 后缀

4. 工具类

  • 格式: PascalCase + Util
  • 示例: JsonUtil, StringUtil, DateUtil
  • 说明: 功能名称 + Util 后缀

5. DTO 类

  • 格式: 操作动词 + 业务名称 + Dto
  • 示例: CreateUserDto, UpdateConfigDto, QueryMemberDto
  • 说明: 明确表示操作类型和业务对象

方法命名规范

1. 业务方法

  • 格式: camelCase
  • 原则: 与 Java 项目方法名保持一致
  • 示例: getUserList(), addUser(), updateConfig()

2. 私有方法

  • 格式: camelCase
  • 示例: private validateUser(), private formatData()

3. 生命周期方法

  • 格式: 按 NestJS 标准
  • 示例: onModuleInit(), onApplicationBootstrap()

变量命名规范

1. 私有属性

  • 格式: private readonly camelCase
  • 示例: private readonly logger, private readonly configService

2. 业务变量

  • 格式: camelCase
  • 原则: 与 Java 项目变量名保持一致
  • 示例: userId, userName, configKey

3. 常量

  • 格式: UPPER_SNAKE_CASE
  • 示例: DEFAULT_PAGE_SIZE, MAX_RETRY_COUNT

数据库相关命名

1. 表名映射

  • 原则: 与 Java 项目表名 100% 一致
  • 示例: nc_sys_config, nc_sys_user, nc_member_level
  • 说明: 不能修改任何表名或前缀

2. 字段名映射

  • 原则: 与 Java 项目字段名 100% 一致
  • 示例: site_id, config_key, create_time, update_time
  • 说明: 不能修改任何字段名或类型

🔧 开发最佳实践

Nest DI 与导入规范(重要)

  • DI 相关类(如 MetricsServiceCacheServiceLockService)统一使用深路径导入:@wwjcloud/wwjcloud-boot/infra/...
  • 禁止在 AI 模块中通过聚合路径 @wwjcloud/wwjcloud-boot 导入上述 DI 类,避免符号不一致导致依赖解析失败。
  • 优先使用“按类型注入”,仅在确有抽象需要时使用令牌,并确保令牌在提供方模块中唯一、稳定导出。
  • 避免在运行期使用 ModuleRef.get 动态解析,除非处理循环依赖或跨域解耦的极端场景。
  • 约定Boot 层模块负责提供与导出,业务模块仅按类型消费,不再重复定义别名提供者。

1. 依赖注入

@Injectable()
export class UserService {
  constructor(
    private readonly userRepository: Repository<User>,
    private readonly configService: ConfigService,
    private readonly logger: Logger,
  ) {}
}

2. 装饰器使用

@Controller('api/user')
@UseGuards(JwtAuthGuard)
export class UserController {
  @Get('list')
  @UseInterceptors(ResponseInterceptor)
  async getUserList(@Query() query: QueryUserDto) {
    // 实现逻辑
  }
}

3. 异常处理

@Injectable()
export class UserService {
  async findUser(id: number) {
    const user = await this.userRepository.findOne({ where: { id } });
    if (!user) {
      throw new NotFoundException('用户不存在');
    }
    return user;
  }
}

4. 数据验证

export class CreateUserDto {
  @IsString()
  @IsNotEmpty()
  username: string;

  @IsEmail()
  email: string;

  @IsOptional()
  @IsString()
  nickname?: string;
}

📋 开发检查清单

开发前检查

  • 已查看对应的 Java 源码文件
  • 已查看相关的数据库表结构
  • 已理解真实的业务逻辑
  • 已确认所有依赖关系

开发中检查

  • 文件命名符合项目规范
  • 类命名符合项目规范
  • 方法命名与 Java 项目一致
  • 数据库字段映射准确
  • 业务逻辑与 Java 项目一致

开发后检查

  • 代码可以正常编译
  • 所有依赖正确注入
  • 数据库操作正常
  • API 接口功能正确
  • 异常处理完善

🚫 常见错误避免

1. 命名错误

  • 错误: userController.ts (camelCase)
  • 正确: user.controller.ts (kebab-case)

2. 文件结构错误

  • 错误: 按技术层级划分目录
  • 正确: 按业务模块划分目录

3. 业务逻辑错误

  • 错误: 自创业务逻辑
  • 正确: 基于 Java 项目真实代码

4. 数据库映射错误

  • 错误: 修改表名或字段名
  • 正确: 与 Java 项目 100% 一致

📚 参考资源


本文档基于项目真实结构制定,请严格遵循以确保代码质量和项目一致性。

🔧 AI 恢复模块集成与测试

模块挂载

  • 根应用:AI_ENABLED=true 时动态导入 AiModule
  • apps/api:直接导入 AiModule,受 GLOBAL_PREFIX=api 影响
  • 开发阶段:AiController 使用 @Public() 便于无令牌验证;生产需加守卫或网关策略

路由与前缀

  • 推荐统一使用 GLOBAL_PREFIX=api 以避免基础设施路由状态码异常
  • 端点示例:
    • GET /api/ai/recovery/status
    • GET /api/ai/recovery/simulate-failure?taskId=T1&severity=high&reason=dev
    • POST /api/ai/recovery/process-one
    • POST /api/ai/recovery/drain

队列驱动策略

  • 开发:QUEUE_DRIVER=memory,避免 Kafka/Redis 干扰,快速闭环
  • 生产:推荐 redis 或企业内部 kafka,实现跨进程/跨实例协同

依赖注入规范(与 DI 章节一致)

  • Boot 层 DI 使用深路径导入:@wwjcloud/wwjcloud-boot/infra/...
  • 业务模块按类型消费,避免重复定义令牌与别名
  • 事件监听器与服务在 AiModule 内提供并导出:AiSelfHealListenerAiRecoveryService

本地端到端验证

# 查看初始队列大小
curl -s http://localhost:3001/api/ai/recovery/status
# 模拟失败(入队)
curl -s "http://localhost:3001/api/ai/recovery/simulate-failure?taskId=T1&severity=high&reason=dev"
# 再次查看(应增长)
curl -s http://localhost:3001/api/ai/recovery/status
# 处理一个(收敛)
curl -s -X POST http://localhost:3001/api/ai/recovery/process-one
# 清空队列(可选)
curl -s -X POST http://localhost:3001/api/ai/recovery/drain

测试建议

  • e2e覆盖失败事件触发 → 入队 → 处理 → 收敛的闭环
  • 异常过滤:GLOBAL_PREFIX=api/api/metrics/api/health 保留原始状态码
  • 队列驱动兼容:memoryrediskafka 三模式最小用例

参考

  • 详细指南:docs/AI-RECOVERY-DEV.md
  • 工作流规范:docs/AI-WORKFLOW-GUIDE.md

对齐 Java 迁移规则(强约束)

  • 只替换为 NestJS/boot 写法,不改变任何业务逻辑与数据流。
  • 路由/方法/参数/返回结构必须与 Java 1:1 对齐;禁止新增/删改字段与键名。
  • 参数与上下文来源:
    • siteId/memberId 统一由 RequestContextService.getSiteId()RequestContextService.memberId 获取,或由上层传入 param.siteId/param.memberId;控制器禁止手动写入上下文字段。
    • Channel 仅在 Java 明确默认值的场景保留默认Header Channel 默认 h5),否则禁止使用 || 'h5'
  • 默认值与返回:
    • 禁止新增默认值(如 getSiteId() || 0|| ''|| 0);仅保留与 Java 对齐的配置/JSON 读取默认(等价 getStr(...,"" )getInt(...,0))。
    • 返回结构与 Java 对齐(例如 { data: '<json-string>' }),禁止附加额外键。
  • 路由与方法:
    • 路径/HTTP 方法严格一致(如 GET /api/verify_detail/{code}),参数名对齐(如 out_trade_no)。
    • 不新增非 Java 的调试/演示接口。
  • 服务层与控制器职责:
    • 登录/权限校验由守卫处理;服务层不做“未登录”等过度校验。
    • 服务层使用传参 param.* 或上下文读取,禁止在服务层覆盖传入值。
    • VO 构建与 Java 一致(如提现 transfer 子对象),仅映射必要字段。
  • 查询与分页:
    • where 条件对齐 JavasiteId/memberId/id 组合等),排序与分页一致(同字段/顺序/limit/skip
  • 异常与校验:
    • 异常信息与 Java 文案一致;参数校验放在 DTO/管道/验证器,不在服务层硬编码。
  • 类型与结构:
    • 避免 as any 类型逃逸;保持 DTO/VO 类型清晰JSON/VO 转换遵循 Java 结构(等效 BeanUtils.copyProperties 行为)。
  • 变更流程(必须遵循):
    • 先“扫描 → 标记 → 按批次改动 → 验证”,不得边看边改。
    • 批次 A清理 Number(this.requestContext.getSiteId() || 0)getSiteId() || 0
    • 批次 B清理 RequestUtils.channel() || 'h5'(保留方法内部默认)。
    • 批次 C控制器移除手工注入上下文字段siteId)。
    • 批次 D参数名/路由/返回结构对齐(如 out_trade_no、VO 子对象)。
    • 批次完成后,用关键模式自检:getSiteId\(\)\s*\|\|\s*0Number\(this\.requestContext\.getSiteId\(\) \|\| 0\)RequestUtils\.channel\(\) \|\|\s*['"]h5['"]
  • 验收标准:
    • 路由/方法/参数名/返回结构与 Java 100% 一致;无默认值污染;控制器不手工注入上下文字段;查询与分页排序一致;异常信息一致;类型明确无无谓 as any