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

343 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`
## 对齐 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 条件对齐 Java`siteId/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*0``Number\(this\.requestContext\.getSiteId\(\) \|\| 0\)``RequestUtils\.channel\(\) \|\|\s*['"]h5['"]`
- 验收标准:
- 路由/方法/参数名/返回结构与 Java 100% 一致;无默认值污染;控制器不手工注入上下文字段;查询与分页排序一致;异常信息一致;类型明确无无谓 `as any`