# 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` - **说明**: 使用 PascalCase,以 `Dto.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 相关类(如 `MetricsService`、`CacheService`、`LockService`)统一使用深路径导入:`@wwjcloud/wwjcloud-boot/infra/...`。 - 禁止在 AI 模块中通过聚合路径 `@wwjcloud/wwjcloud-boot` 导入上述 DI 类,避免符号不一致导致依赖解析失败。 - 优先使用“按类型注入”,仅在确有抽象需要时使用令牌,并确保令牌在提供方模块中唯一、稳定导出。 - 避免在运行期使用 `ModuleRef.get` 动态解析,除非处理循环依赖或跨域解耦的极端场景。 - 约定:Boot 层模块负责提供与导出,业务模块仅按类型消费,不再重复定义别名提供者。 ### 1. 依赖注入 ```typescript @Injectable() export class UserService { constructor( private readonly userRepository: Repository, private readonly configService: ConfigService, private readonly logger: Logger, ) {} } ``` ### 2. 装饰器使用 ```typescript @Controller('api/user') @UseGuards(JwtAuthGuard) export class UserController { @Get('list') @UseInterceptors(ResponseInterceptor) async getUserList(@Query() query: QueryUserDto) { // 实现逻辑 } } ``` ### 3. 异常处理 ```typescript @Injectable() export class UserService { async findUser(id: number) { const user = await this.userRepository.findOne({ where: { id } }); if (!user) { throw new NotFoundException('用户不存在'); } return user; } } ``` ### 4. 数据验证 ```typescript 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% 一致 ## 📚 参考资源 - **项目仓库**: wwjcloud-nsetjs - **Java 项目**: niucloud-java - **数据库结构**: `sql/wwjcloud.sql` - **NestJS 官方文档**: https://nestjs.com/ - **TypeORM 文档**: https://typeorm.io/ --- > 本文档基于项目真实结构制定,请严格遵循以确保代码质量和项目一致性。 ## 🔧 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` 内提供并导出:`AiSelfHealListener`、`AiRecoveryService` ### 本地端到端验证 ```bash # 查看初始队列大小 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` 保留原始状态码 - 队列驱动兼容:`memory`、`redis`、`kafka` 三模式最小用例 ### 参考 - 详细指南:`docs/AI-RECOVERY-DEV.md` - 工作流规范:`docs/AI-WORKFLOW-GUIDE.md`