-
.env
读取 & ConfigModule 全局配置模块 - 统一错误处理模块
- 统一返回格式模块
- 基础日志使用示例
- Cluster 多进程模块
- 本地文件日志 (还不确定是否必要)
- 请求记录打点
- 用户模块
- JWT模块 & 跳过鉴权装饰器
- Prisma 模块
- Swagger 模块
- Metrics 模块
- 健康检测 & 优雅关闭
- 全局验证管道, 验证请求参数
- RESTful Resource 示例
- TypeORM 模块
- 暴露 HTTPS 端口
src/
├── app.module.ts # 主模块文件
├── main.ts # 应用入口文件
├── common/ # 通用模块和工具
│ ├── decorators/ # 自定义装饰器
│ ├── filters/ # 全局异常过滤器
│ ├── interceptors/ # 拦截器
│ ├── guards/ # 守卫
│ ├── pipes/ # 管道
│ ├── utils/ # 工具函数
├── config/ # 配置相关
│ ├── app.config.ts # 应用配置
│ ├── database.config.ts # 数据库配置
├── modules/ # 功能模块
│ ├── users/ # 用户模块
│ │ ├── users.controller.ts
│ │ ├── users.service.ts
│ │ ├── users.module.ts
│ │ ├── dto/ # 数据传输对象
│ │ ├── entities/ # 数据实体
│ ├── auth/ # 认证模块
│ ├── auth.controller.ts
│ ├── auth.service.ts
│ ├── auth.module.ts
│ ├── strategies/ # 策略(如 JWT 或 Local)
│ ├── guards/ # 模块级守卫
├── database/ # 数据库相关
│ ├── entities/ # 实体类(若使用 TypeORM 或 Prisma)
│ ├── migrations/ # 数据库迁移文件
│ ├── seeds/ # 数据库种子文件
├── interfaces/ # 公共接口
│ ├── user.interface.ts
│ ├── auth.interface.ts
├── middleware/ # 中间件
│ ├── logger.middleware.ts
├── tests/ # 测试文件夹
│ ├── e2e/ # 端到端测试
│ ├── unit/ # 单元测试
│ ├── mocks/ # 测试用的 Mock 数据
└── shared/ # 共享模块
├── cache/ # 缓存模块(如 Redis)
├── mailer/ # 邮件模块
├── logging/ # 日志模块
-
在 NestJS 社区和官方文档中,middleware 通常是单独管理的。这种实践为开发者提供了更加模块化和标准化的代码结构,尤其在大型项目中,有助于新开发者快速熟悉代码。
-
common/interceptors
放的是那种具体模块无关的拦截器, 如果某个拦截器和模块强关联, 那么和模块放在一起, 例如 metrics 模块的拦截器。 -
在一些项目中,modules/users/entities 和 database/entities 同时存在是为了平衡模块化和全局性需求, 模块中的实体可以通过 extends 或 组合 的方式扩展全局实体。例如:
// database/entities/user.entity.ts @Entity('users') export class UserEntity { @PrimaryGeneratedColumn() id: number; @Column() name: string; } // modules/users/entities/user.entity.ts import { UserEntity } from 'database/entities/user.entity'; export class User extends UserEntity { // 模块特定字段或方法 isActive: boolean; }
// NODE_ENV 环境变量
Env.get()
// 其他配置
this.configSvc.get<string>('app.name')
// 非注入获取其他配置
appConfig().app.name
// 尽量不直接使用 process.env
Env.is(EnvType.DEVELOPMENT)
Env.isDev()
private readonly logger = new Logger(this.constructor.name);
# 初始化
npx prisma init
# 首次创建 schema.prisma 时
# DB -> schema.prisma
npx db pull
# 每次修改 schema.prisma 后
# schema.prisma -> Prisma Client
npx prisma generate
# 启动 Prisma Studio
npx prisma studio
# ================== 数据库迁移 ==================
# 开发模式下的迁移: 生成迁移文件并直接执行
# --name: 指定迁移文件的名称。
# --create-only: 只创建迁移文件,不应用迁移。
# --dry-run: 模拟迁移,但不实际执行 SQL。
npx prisma migrate dev --name init
# 重置数据库
prisma migrate reset # 清空数据库并重新应用迁移(会有交互式提示)
prisma migrate reset -f # 清空数据库并重新应用迁移 (不会提示)
# 生产环境下的迁移
# - 它会检查数据库中已应用的迁移,并应用所有尚未应用的迁移文件,将数据库更新到最新版本。
# - 非交互式,不会提示
# --skip-generate: 跳过代码生成
prisma migrate deploy # 应用所有未应用的迁移
prisma migrate deploy --skip-generate # 跳过代码生成, 不重新生成 Prisma Client
# 查看迁移状态
# 用于查看当前数据库的迁移状态,包括已应用的迁移和未应用的迁移
prisma migrate status # 显示迁移状态
# 解决迁移冲突 (危险操作)
# 当你手动修改数据库结构后,可能会导致迁移冲突,你可以使用 prisma migrate resolve 将迁移标记为已应用,即使它没有实际执行。
prisma migrate resolve --applied <migration_name> # 标记 <migration_name> 为已应用
# 比较迁移状态
prisma migrate diff
# 手动创建迁移, 手动创建一个空的迁移文件
prisma migrate create
# 注册为
# consumer.apply(LoggerMiddleware).forRoutes('*'); // 对所有路由生效
# 请求 localhost:3001/app/test/1?a=1
console.log(req.originalUrl); # /app/test/1?a=1
console.log(req.baseUrl); # /app/test/1
console.log(req.url); # /?a=1
console.log(req.path); # /
# 是不太符合预期的
# 注册为
# consumer.apply(LoggerMiddleware).forRoutes('/'); // 对所有路由生效
# 请求 localhost:3001/app/test/1?a=1
console.log(req.originalUrl); # /app/test/1?a=1
console.log(req.baseUrl); # 空
console.log(req.url); # /app/test/1?a=1
console.log(req.path); # /app/test/1