2025-10-19 19:55:52 +08:00
|
|
|
|
# WWJCloud NestJS 开发指导原则
|
|
|
|
|
|
|
|
|
|
|
|
> 基于 v0.1.1 版本真实项目结构分析制定
|
|
|
|
|
|
> 更新时间: 2025-01-27
|
|
|
|
|
|
> 适用范围: WWJCloud NestJS 项目开发
|
|
|
|
|
|
|
|
|
|
|
|
## 🎯 核心开发原则
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 框架使用原则
|
|
|
|
|
|
- **框架层面**: 100% 使用 NestJS 的方式和特性
|
2025-10-26 20:40:23 +08:00
|
|
|
|
- **业务层面**: 与 Java 项目保持 100% 一致
|
|
|
|
|
|
- **数据层面**: 与 Java 项目数据库结构 100% 一致
|
2025-10-19 19:55:52 +08:00
|
|
|
|
|
|
|
|
|
|
### 2. 开发约束条件
|
2025-10-26 20:40:23 +08:00
|
|
|
|
- ✅ **必须**: 基于 Java 项目真实代码进行开发
|
2025-10-19 19:55:52 +08:00
|
|
|
|
- ✅ **必须**: 基于真实数据库表结构进行映射
|
|
|
|
|
|
- ✅ **必须**: 遵循项目既定的命名规范
|
|
|
|
|
|
- ❌ **禁止**: 自创业务逻辑或数据结构
|
|
|
|
|
|
- ❌ **禁止**: 编写骨架代码或 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`
|
2025-10-26 20:40:23 +08:00
|
|
|
|
- **原则**: 与 Java 项目方法名保持一致
|
2025-10-19 19:55:52 +08:00
|
|
|
|
- **示例**: `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`
|
2025-10-26 20:40:23 +08:00
|
|
|
|
- **原则**: 与 Java 项目变量名保持一致
|
2025-10-19 19:55:52 +08:00
|
|
|
|
- **示例**: `userId`, `userName`, `configKey`
|
|
|
|
|
|
|
|
|
|
|
|
#### 3. 常量
|
|
|
|
|
|
- **格式**: `UPPER_SNAKE_CASE`
|
|
|
|
|
|
- **示例**: `DEFAULT_PAGE_SIZE`, `MAX_RETRY_COUNT`
|
|
|
|
|
|
|
|
|
|
|
|
### 数据库相关命名
|
|
|
|
|
|
|
|
|
|
|
|
#### 1. 表名映射
|
2025-10-26 20:40:23 +08:00
|
|
|
|
- **原则**: 与 Java 项目表名 100% 一致
|
2025-10-19 19:55:52 +08:00
|
|
|
|
- **示例**: `nc_sys_config`, `nc_sys_user`, `nc_member_level`
|
|
|
|
|
|
- **说明**: 不能修改任何表名或前缀
|
|
|
|
|
|
|
|
|
|
|
|
#### 2. 字段名映射
|
2025-10-26 20:40:23 +08:00
|
|
|
|
- **原则**: 与 Java 项目字段名 100% 一致
|
2025-10-19 19:55:52 +08:00
|
|
|
|
- **示例**: `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<User>,
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 📋 开发检查清单
|
|
|
|
|
|
|
|
|
|
|
|
### 开发前检查
|
2025-10-26 20:40:23 +08:00
|
|
|
|
- [ ] 已查看对应的 Java 源码文件
|
2025-10-19 19:55:52 +08:00
|
|
|
|
- [ ] 已查看相关的数据库表结构
|
|
|
|
|
|
- [ ] 已理解真实的业务逻辑
|
|
|
|
|
|
- [ ] 已确认所有依赖关系
|
|
|
|
|
|
|
|
|
|
|
|
### 开发中检查
|
|
|
|
|
|
- [ ] 文件命名符合项目规范
|
|
|
|
|
|
- [ ] 类命名符合项目规范
|
2025-10-26 20:40:23 +08:00
|
|
|
|
- [ ] 方法命名与 Java 项目一致
|
2025-10-19 19:55:52 +08:00
|
|
|
|
- [ ] 数据库字段映射准确
|
2025-10-26 20:40:23 +08:00
|
|
|
|
- [ ] 业务逻辑与 Java 项目一致
|
2025-10-19 19:55:52 +08:00
|
|
|
|
|
|
|
|
|
|
### 开发后检查
|
|
|
|
|
|
- [ ] 代码可以正常编译
|
|
|
|
|
|
- [ ] 所有依赖正确注入
|
|
|
|
|
|
- [ ] 数据库操作正常
|
|
|
|
|
|
- [ ] API 接口功能正确
|
|
|
|
|
|
- [ ] 异常处理完善
|
|
|
|
|
|
|
|
|
|
|
|
## 🚫 常见错误避免
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 命名错误
|
|
|
|
|
|
- ❌ 错误: `userController.ts` (camelCase)
|
|
|
|
|
|
- ✅ 正确: `user.controller.ts` (kebab-case)
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 文件结构错误
|
|
|
|
|
|
- ❌ 错误: 按技术层级划分目录
|
|
|
|
|
|
- ✅ 正确: 按业务模块划分目录
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 业务逻辑错误
|
|
|
|
|
|
- ❌ 错误: 自创业务逻辑
|
2025-10-26 20:40:23 +08:00
|
|
|
|
- ✅ 正确: 基于 Java 项目真实代码
|
2025-10-19 19:55:52 +08:00
|
|
|
|
|
|
|
|
|
|
### 4. 数据库映射错误
|
|
|
|
|
|
- ❌ 错误: 修改表名或字段名
|
2025-10-26 20:40:23 +08:00
|
|
|
|
- ✅ 正确: 与 Java 项目 100% 一致
|
2025-10-19 19:55:52 +08:00
|
|
|
|
|
|
|
|
|
|
## 📚 参考资源
|
|
|
|
|
|
|
|
|
|
|
|
- **项目仓库**: wwjcloud-nsetjs
|
2025-10-26 20:40:23 +08:00
|
|
|
|
- **Java 项目**: niucloud-java
|
2025-10-19 19:55:52 +08:00
|
|
|
|
- **数据库结构**: `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`
|