mcpField
N
nestjs-dev-guidelines

nestjs-dev-guidelines

github.com/myatminlu开发2094 次安装10 周前更新
代码仓库

关于 nestjs-dev-guidelines

为 NestJS 及采用 Nest 风格的 Node.js 后端提供开发规范,适用于代码编写、审查与架构决策。内容涵盖安全、模块边界、验证和测试,并强调小范围修改与验证结果。

主要功能

  1. 01执行纪律与决策树
  2. 02DTO 输入验证规范
  3. 03模块边界与数据库规范
  4. 04响应、分页与日志约定
  5. 05安全、多租户与测试清单

适用场景

  1. 01设计或扩展 NestJS 模块
  2. 02审查后端代码或 PR
  3. 03处理验证、授权和数据隔离
  4. 04规划测试与代码修改范围

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/myatminlu/vector-skills --skill nestjs-dev-guidelines

安装后在 Claude Code 中输入/nestjs-dev-guidelines确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
evals.json
responses.json
evals/scripts/
grade.py
references/
00-execution-discipline.md
01-folder-structure.md
02-naming-conventions.md
03-module-design.md
04-code-quality.md
05-thinking-decision-trees.md
06-api-design.md
07-standard-responses.md
08-pagination-filters-sorting.md
09-validation.md
10-error-handling.md
11-security.md
12-authentication-patterns.md
13-database-design.md
14-database-orm-patterns.md
15-migrations.md
16-cascade-rules.md
17-pipelines-interceptors-guards.md
18-events.md
19-background-jobs.md
20-configuration.md
21-logging.md
22-observability.md
23-testing.md
24-performance.md
24a-caching-patterns.md
25-documentation-swagger.md

详细介绍

NestJS 开发指南

一套完整的生产级 NestJS 和 Nest 风格 Node.js 后端规范。当处理已采用 NestJS 概念(如模块、控制器、提供者/服务、DTO、管道和守卫)的代码库,或任务明确涉及设计这些模式时,请遵循这些规则。像资深后端工程师一样思考:一致性胜过巧妙设计,明确胜过隐式,边界胜过捷径。

如何使用本指南

  1. 编写或审查代码之前,先阅读 references/00-execution-discipline.md 和下方的不可妥协事项。
  2. 对于文件放置、模块边界或重构决策,请使用决策树。
  3. 如需深入了解某个主题,请打开对应的 references/NN-<topic>.md 文件。每个文件都自成一体,包含概要、规则、正反示例、反模式和审查清单。
  4. 审查 PR 时,请结合相关主题参考资料,逐项检查 references/29-code-review-checklist.md。

适用范围与优先级

当代码库属于“后端 TypeScript”,但不明显是标准 NestJS 应用时,请参考本节。

  1. NestJS 优先适用。 如果代码库已使用 NestJS 基础构件(@Module、控制器、提供者/服务、守卫、管道、DTO),或用户要求设计 NestJS 解决方案,请直接应用本指南。
  2. 纯 Node 后端仅部分适用。 如果代码库使用纯 Express/Fastify/Hono/Koa,且不包含 NestJS 基础构件,则仅采用本指南中的跨领域指导(验证、契约、授权、数据库设计、测试、可观测性)。不要将 Nest 专属 API、装饰器或文件夹结构强加给该代码库。
  3. 先保障结果,再考虑工具。 下方的不可妥协事项首先是必须遵守的原则,其次才是实现默认方案。集中式输入验证、稳定的响应契约、经过结构化且脱敏处理的日志、所有权检查和测试覆盖,比实现这些目标时使用的具体库更重要。
  4. 遵循等效且安全的代码库惯例。 如果代码库已有不同但可靠的机制,能够维持相同的安全性/属性边界(例如使用 Zod 而非 class-validator,或使用代码库标准的结构化日志记录器而非 nestjs-pino),请遵循代码库的做法,不要在任务中途重写。
  5. 指出有害冲突并升级处理。 如果现有模式削弱了安全性、正确性、数据完整性或稳定契约,请明确指出,并在统一该模式或扩大其使用范围之前征求同意。

执行规范

在处理 NestJS 特定细节之前,请先遵循这些规则。它们旨在减少 LLM 常见的失误:默默做出假设、过度构建代码、大范围重构,以及未经验证就修复问题。

  1. 编码前先思考。 说明假设。如果任务有歧义,请先提问,或明确列出合理的解释,而不是默默选定一种。
  2. 核实易变信息。 版本、软件包 API、模型 ID、安装命令和 CLI 标志都可能变化。在提出建议前,请对照官方文档和仓库核实,切勿凭记忆作答。参见 35-source-of-truth-freshness.md。
  3. 编写新代码前先搜索。 先检查当前模块,再检查 shared/common/core 代码,看看是否已有可复用的工具函数、DTO、服务、守卫、拦截器、仓库或模式。
  4. 修复根本原因,而不是针对触发条件打补丁。 除非产品需求本身就是确定性的基于规则的路由,否则不要用一次性正则表达式、硬编码短语或手动 if/then 规则来修补广泛行为。
  5. 优先采用最小且正确的改动。 除非任务或代码库明确需要,否则不要添加臆测性的标志、抽象、辅助函数、配置或边缘情况处理。
  6. 谨慎编辑。 只修改满足请求所需的行。不要因为顺手就清理无关代码、注释或格式。
  7. 搜索并更新完整影响范围。 如果共享函数、契约、DTO、类型或行为发生变化,请扫描并更新调用方、测试、文档、示例及相关流程,直至整体保持一致。
  8. 修改共享行为前先询问。 如果复用现有代码需要改变共享语义、影响多个调用方或修改可复用契约,请停止并确认,不要默默扩大影响范围。
  9. 明确成功标准。 将模糊的请求转化为可验证的检查项:回归测试、单元测试、端到端测试、类型检查、Lint、构建,或具体的手动检查。
  10. 遇到困惑时停止。 尽早说明不确定之处。简短的澄清问题,比重写错误的代码成本更低。

打开 references/00-execution-discipline.md,查看完整清单和示例。

不可妥协事项(保障这些结果;优先采用这些模式)

每条规则都说明了原因,帮助你推理边缘情况,而不是盲目照搬。

  1. 控制器中不应包含业务逻辑。 控制器负责验证输入、委托给服务并组织响应,仅此而已。 原因: 控制器是精简的 HTTP 适配层。若在其中编写逻辑,就必须启动框架才能进行单元测试,还会把 HTTP 相关问题带入领域代码。参见 04-code-quality.md。
  2. 所有外部输入都必须经过 DTO。 请求体、查询参数和路径参数 DTO 使用 class-validator;全局启用 ValidationPipe,并设置 whitelist: true、forbidNonWhitelisted: true、transform: true。 原因: DTO 是拦截未知字段、错误类型和注入负载的唯一关卡。跳过这一步,就意味着信任客户端。参见 09-validation.md。
  3. 绝不信任客户端。 URL 中的每个 ID 都要检查其是否属于已认证用户或组织。筛选和排序字段必须加入白名单。通过 whitelist 防止批量赋值。 原因: IDOR 和批量赋值是最常见的两类应用层安全漏洞。只有在代码认为“只要令牌有效,负载就没问题”时,这些漏洞才会出现。参见 11、12。
  4. 每个模块只负责自己的表。 禁止跨模块直接读取数据库。如果模块 B 需要模块 A 的数据,应调用 A 的服务(DI)或订阅 A 的事件。 原因: 共享表访问会让每次架构变更都变成需要跨团队协调的问题。模块会通过数据库而非 API 彼此耦合。参见 03-module-design.md。
  5. 数据库使用 snake_case,代码使用 camelCase。 表名用复数,列名用 snake_case,主键为 id,外键为 <entity>_id。 原因: 每个生态系统都有自己的约定;混用会造成长期的映射错误,也会让临时 SQL 难以编写。应采用最难变更的一方(数据库)的约定。参见 13-database-design.md。
  6. 响应遵循统一且稳定的契约。 单个资源的成功响应直接返回对象本身;列表成功响应返回 { data, meta };错误响应返回 { code, message, details?, traceId },并使用正确的 HTTP 状态码。 原因: 统一的契约让客户端只需编写一个错误处理器和一个分页处理器,就能在各处使用;支持人员也能通过 traceId 排查问题。参见 07、10。
  7. 所有列表端点都必须分页。 对可变或大型数据进行顺序浏览时,选择游标/键集分页;当按页码导航或获取精确总数是实际的产品需求时,选择偏移分页。两者都要在 meta 中返回分页信息。 原因: 未分页的列表可能导致内存溢出或数据库宕机。合适的分页模型取决于用户体验、一致性要求和规模。参见 08。
  8. 密钥只能来自环境变量,并在启动时用 Zod 验证。 代码中不得包含密钥,日志中也不得记录密钥。环境变量无效时,必须在开始处理流量前崩溃。 原因: 在启动时发现缺失或格式错误的环境变量只是轻微事故;若在运行时的关键路径上才发现,就会导致客户服务中断。参见 20、11。
  9. 使用结构化日志并进行脱敏。 生产环境使用 nestjs-pino 输出 JSON;对 authorization、cookie、set-cookie、password、token 进行脱敏。每条日志都要包含关联 ID。 原因: 纯文本日志无法大规模查询;而一条未脱敏的 Authorization 标头就会造成长期凭据泄露。参见 21。
  10. 测试边界,而非内部实现。 使用模拟依赖对服务进行单元测试;通过 HTTP 层对控制器进行端到端测试;绝不模拟被测类。 原因: 模拟被测代码只是在重复断言模拟对象。测试应验证契约(HTTP、数据库、外部调用),而不是实现。参见 23。
  11. 租户身份由服务器推导,并分层校验。 在多租户应用中,租户/组织 ID 来自已认证会话/JWT,绝不来自请求体。守卫、服务和仓储都要按租户筛选;测试要证明租户 A 无法查看租户 B 的数据。 原因: 跨租户数据泄露几乎总是因为漏掉了一处 WHERE tenant_id = ?,或过早信任了客户端提供的 ID。分层校验可确保某一层出现错误时也不会泄露数据。参见 33。

高级工程师思维(决策树)

完整决策树位于 references/05-thinking-decision-trees.md。简要版:

这个文件应该放在哪里?

  • 业务功能 → modules/<feature>/
  • 应用级基础设施(auth、redis、mail)→ core/<name>/
  • 通用工具(管道、装饰器、类型)→ common/<kind>/
  • 外部 API 客户端(Stripe、AWS)→ integrations/<provider>/
  • CLI/CRON 任务 → commands/<name>.command.ts
  • 领域事件发布器/监听器 → events/<event-name>/

我应该创建新模块吗?

  • 它有自己的数据库表吗?→ 是,创建新模块。
  • 它有自己的生命周期/领域逻辑吗?→ 是,创建新模块。
  • 它只是某个模块使用的辅助工具吗?→ 否,放进该模块的 utils/。
  • 它被 2 个或更多模块使用,但不拥有数据吗?→ common/ 工具。

我现在应该重构吗?

  • 我已经在编辑这段代码了吗?→ 是,边做边清理。
  • 它会阻碍我当前的功能吗?→ 是,尽量少量重构。
  • 它只是“难看”吗?→ 否,记下来,然后继续。

我应该跳过测试吗?

  • 它是控制器吗?→ 否,始终编写 E2E 测试。
  • 它是含有分支逻辑的服务吗?→ 否,始终编写单元测试。
  • 它是没有逻辑的简单透传(例如 findById)吗?→ 可以跳过;控制器的 e2e 测试会覆盖它。
  • 它是 DTO/类型吗?→ 无需测试;编译器就是测试。

规则索引(每条参考资料一行)

需要了解详情时,请阅读完整的参考文件。数字前缀用于保持顺序稳定。

#文件一句话规则
0000-execution-discipline.md先思考,再根据文档核实易变事实(版本/API/模型 ID);保持改动精简,精准编辑,定义成功标准,并在声称完成前进行验证
0101-folder-structure.mdsrc/{core,common,integrations,modules,events,commands} — 每类代码各有一个专属位置
0202-naming-conventions.md变量使用 camelCase,类使用 PascalCase,数据库使用 snake_case,文件使用 kebab-case.ts,环境变量使用 SCREAMING_SNAKE
0303-module-design.md每个有界上下文对应一个模块;仅对真正的全应用基础设施使用 @Global()
0404-code-quality.md遵循 SOLID、使用构造函数 DI、编写纯工具函数和小函数;没有合理理由时不要使用 any
0505-thinking-decision-trees.md如何做出判断:代码放在哪里、何时重构、何时跳过测试
0606-api-design.mdREST、使用复数名词、动词与语义相符、URI 版本控制 /v1/...、幂等键
0707-standard-responses.md单条成功响应返回普通对象;列表返回 { data, meta };错误返回 { code, message, details?, traceId }
0808-pagination-filters-sorting.md顺序浏览使用游标/键集分页;确有页码/精确总数需求时使用偏移分页;使用 filter[field]=、sort=-createdAt;字段使用白名单
0909-validation.md使用 class-validator DTO + 全局 ValidationPipe;使用 Zod 校验环境变量 + 解析运行时 JSON
1010-error-handling.md混合分类体系:HTTP 状态码 + 命名空间代码 + traceId;领域错误继承语义明确的 Nest 异常;使用一个全局过滤器,并添加 host.getType() + headersSent 检查,通过 PinoLogger 记录日志
1111-security.md安全审查流程:OWASP Top 10、传输/CORS、注入/SSRF、密码哈希、速率限制、PII/审计,以及指向身份验证/webhook/上传规则的链接
1212-authentication-patterns.md使用会话 Cookie(浏览器)或 Bearer JWT(移动端/服务端);静态存储时对会话/刷新令牌进行哈希;轮换刷新令牌;使用 revoked_before;Cookie 优先,且无效 Cookie 必须默认拒绝;身份验证错误使用 { code, message }
1313-database-design.md使用 snake_case、复数表名、外键 <entity>_id;在外键和查询路径上建立索引;使用 deleted_at、UUIDv7 或 bigint
1414-database-orm-patterns.mdraw pg / TypeORM / Prisma / Drizzle — 并列展示各种模式
1515-migrations.md生产环境始终只允许向前迁移;未经两步发布,不得进行破坏性变更
1616-cascade-rules.md自有数据使用 ON DELETE CASCADE;共享引用使用 RESTRICT;可选数据使用 SET NULL
1717-pipelines-interceptors-guards.md顺序:Guard → Interceptor(前置)→ Pipe → Handler → Interceptor(后置)→ Filter
1818-events.md进程内使用 EventEmitter2;跨服务或队列时使用 outbox 模式
1919-background-jobs.md默认使用 BullMQ;处理器保持幂等;采用带退避的重试;为有毒消息设置 DLQ
2020-configuration.mdConfigModule 设为全局;使用 Zod 模式;环境变量无效时在启动阶段快速失败
2121-logging.md使用 nestjs-pino;生产环境使用 JSON;对机密信息进行脱敏;为每个请求生成关联 ID
2222-observability.md使用 OpenTelemetry 跟踪 + 指标;使用 Langfuse/Helicone 跟踪大模型调用
2323-testing.md单元测试放在实现文件旁(*.spec.ts);端到端测试放在 test/;在边界处进行模拟;集成测试使用真实数据库
2424-performance.md避免 N+1;合理设置连接池大小;有选择地缓存;以流式方式处理大型负载
24a24a-caching-patterns.md审慎使用缓存;使用稳定的命名空间键、TTL + 失效机制,并防止缓存击穿;缓存绝不能成为身份验证/配额/计费的唯一依据
2525-documentation-swagger.md使用 @ApiTags / @ApiOperation / @ApiResponse;通过 @ApiProperty 自动生成 DTO 模式
2626-ai-product-patterns.md使用具备提供方抽象、重试、回退和超时机制的大模型网关
2727-ai-streaming-sse.md使用 SSE 端点;支持取消(中止上游请求);发送心跳;使用类型化事件词汇;重新连接后无法恢复
2828-ai-usage-metering-cost.md为每次调用记录 token + 成本;按用户/组织/模型汇总;强制执行配额
2929-code-review-checklist.md涵盖以上所有规则的 PR 审查清单
3030-code-review-anti-patterns.md反模式目录,包含正反示例片段
3131-rules-rationale-examples.md跨规则的规则、理由和正反示例,便于快速查阅
3232-modern-nestjs-stack.md用于现代化/启动 NestJS 服务的决策清单;启动顺序、模块系统检查;不包含固定的版本矩阵
3333-multi-tenancy-patterns.md由服务端推导租户身份,并在身份验证、guard、服务和仓库层强制执行;通过测试证明租户隔离
3434-health-shutdown.md存活状态与就绪状态;使用一个关闭协调器;关闭前排空请求;单独排空工作进程
3535-source-of-truth-freshness.md持久不变的规则留在本地;根据官方文档和仓库核实易变的 API/版本/模型
3636-webhooks.md对原始字节验证签名(raw-body 配置 + timingSafeEqual);根据 (provider, event_id) 去重;入队后返回 2xx 确认(包括未处理的类型);对高风险事件重新获取权威状态;从已验证的负载中解析租户
3737-file-uploads.md优先使用预签名的直接上传至存储桶(客户端使用 PUT,浏览器使用 POST 策略);在边界处限制大小/MIME;检测文件魔数;使用不透明且带租户前缀的存储键;由服务端计算哈希/大小/MIME;公开文件前进行 AV 扫描;对上传端点进行速率限制
3838-decorators-scopes-dynamic-modules.md参数装饰器只从请求中提取数据;默认使用单例作用域;使用动态模块配置基础设施;forwardRef 是一种异味
3939-exception-filters.md使用一个全局过滤器,将所有错误统一为 { code, message, details?, traceId };抛出类型明确的 HttpException 子类;绝不泄露内部信息
4040-ddd-layered-architecture.md可选的三层 DDD 分层(经典分层 → 分层特性模块 → 六边形端口/适配器);依赖指向内层;领域层不依赖框架;对于 CRUD,默认的六类目录结构仍然更合适
4141-n-plus-one-elimination.md通过统计查询次数证明 N+1(绝不靠猜测);除显而易见的循环外,还有六种模式;选择 JOIN、两次查询批量加载或每请求一个 DataLoader;绝不在联接集合上使用 SQL LIMIT;通过查询次数测试锁定修复

何时深入阅读

你正在进行……阅读……
开始任何实现或 Bug 修复00、05
开始新的功能模块01、03、04
使用 DDD 分层 / 六边形架构 / 端口-适配器架构进行组织40、01、03
启动或现代化改造一项服务32、34、20
设计新的端点06、07、08、09
统一返回错误10
设计数据库表13、14、15、16
为端点添加身份验证11、12、17
添加多租户隔离33、11、12、14
添加列表端点07、08、41
添加缓存24、24a
修复响应缓慢的端点、N+1 问题或查询次数过多的问题41、24、14、13
添加后台任务19、34
编写测试23
添加可观测性21、22
添加健康检查 / 就绪检查 / 关闭处理34、32
构建大模型功能26、27、28、22
处理来自第三方的 Webhook36、11、19、21、33
接受文件上传37、11、24
设计自定义装饰器 / 作用域提供程序 / 动态模块38、03、17
设计全局异常筛选器 / 错误在线格式39、07、10
提供版本 / 命令 / 模型方面的建议35
审查 PR29、30,以及与差异相关的任何主题

代码审查模式

当用户要求你审查 PR、更改或差异时:

  1. 先从头到尾阅读差异,理解意图后再提出批评。
  2. 按照 29-code-review-checklist.md 检查每一项,并标记通过 / 未通过 / 不适用。
  3. 对每个未通过项,引用相关参考文件中的具体章节(例如,“控制器中的业务逻辑——参见 04-code-quality.md → 分层 / 反模式”)。
  4. 区分阻塞项(安全问题、数据丢失风险、违反不可妥协的规则)和建议(风格、轻微的命名问题、可选重构)。不要因建议而阻止通过。
  5. 如果发现反模式,请链接到 30-code-review-anti-patterns.md,并引用正确的写法。
  6. 审查结束时列出:(a) 阻塞项(编号列表),(b) 建议(项目符号列表),(c) 仅在解决阻塞项后才批准。

AI 产品附录

如果项目是 AI 产品后端(大模型、Agent、RAG、向量存储、流式传输、按用量计费),还要阅读:

  • 26-ai-product-patterns.md — 与提供商无关的大模型网关、重试 / 回退
  • 27-ai-streaming-sse.md — SSE 端点模式、取消、心跳
  • 28-ai-usage-metering-cost.md — 令牌和成本计量、配额执行
  • 22-observability.md — 使用 Langfuse / Helicone 进行大模型追踪

其他所有内容(身份验证、数据库、错误处理、测试)对 AI 产品同样适用——AI 部分是一个模块,而非框架。

其他说明

  • 框架细节之前先遵守执行纪律。 小而明确且经过验证的更改,胜过快速、宽泛而巧妙的更改。
  • 规则 > 风格偏好。 这些是规则,因为它们能避免实际 Bug,或提升可维护性。本文不涉及风格争论。
  • 一致性 > 巧妙。 如果仓库中已有一种功能等效但与此技能不同的成熟模式,只要该模式没有明显危害,就遵循仓库的模式。
  • 不确定时,保持简单。 简单的代码易于审查、易于上手,也易于替换。这正是重点。

评论

支持 Markdown