Files
wwjcloud-nest-v1/docs/DEVELOPMENT-GUIDE.md

311 lines
9.6 KiB
Markdown
Raw Normal View 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`
- **说明**: 使用 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<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;
}
```
## 📋 开发检查清单
### 开发前检查
- [ ] 已查看对应的 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`