kikita-create-nestjs-app 是做什么的?
搭建一个新的 NestJS 项目,并生成其 AGENTS.md / .agents/ 文档树,
以便之后在该项目中工作的任何 AI 智能体(Claude Code、Codex 等)都能拥有一个完整、
可自维护的事实来源。
0. 模式检测(务必首先执行)
在目标目录中检查是否存在 .agents/.kikita-scaffold.json。
- 缺失 → 全新初始化。继续下面的第 1 节,然后执行
plan.md。 - 存在 → 此项目已经由本技能搭建过。请转而执行
update.md—— 不要重新运行问卷或重新搭建。update.md负责拉取最新模板、 对比自上次记录提交以来的差异,并将更改合并到项目的(可能已自定义的).agents/文件中。
0.5 前置条件(仅限全新初始化)
- 确认工作目录为空,或者用户明确希望在此处初始化。
- 如果目标目录已包含不相关的项目,未经用户明确同意,切勿在此运行本技能。
1. 问卷(在接触文件系统之前始终先询问)
从这里开始,严格按照 plan.md 的步骤执行。不要跳过问卷。完成后,在告知用户
“已完成”之前,务必完整执行 checklist.md。
分两个阶段提问,不要一次性抛出 12 个问题——第一个答案会决定后面的哪些问题 与用户相关,所以如果全部一次性提出,可能会向仅构建机器人的用户提出 “你的 REST API 需要认证吗?”这种不适用的问题。
第一阶段 —— 分支问题,单独提问:
- 应用类型:REST API、机器人,还是在同一个应用中同时包含两者?
- 如果选择机器人(或两者都选):使用哪个平台?Telegram(
nestjs-telegraf)还是 Discord —— 对于 Discord,推荐默认使用necord(最少的粘合代码即可通过原生 Nest DI/守卫/管道实现通用的事件→处理器→服务模式),但这并非强制要求: 如果用户想要原生的discord.js(现有团队专长、necord尚未包装的discord.js特性),这也是合理的选择——将其视作等同于“其他平台”,通过手动适配通用模式, 而不是免费获得它。 - 任何其他平台/库(请指定名称——
architecture/transport-adapter.md中的通用 机器人传输模式可以适配它,但对于nestjs-telegraf/necord以外的平台, 具体的适配器代码需要手动编写)。
- 如果选择机器人(或两者都选):使用哪个平台?Telegram(
第二阶段 —— 其余所有问题,批量提出(仅当第一阶段回答为 REST 或“两者都包含”时, 才询问第 3 个问题;以下其他问题均适用于所有应用类型):
- 测试:无、单元测试 / e2e(Supertest)/ 两者都包含?“两者都包含”还会安装 Testcontainers,用于针对真实 Postgres 实例(而非模拟对象)运行集成测试。
- 认证(如果第一阶段回答仅为机器人,则完全跳过此问题):是否需要?选择“是”会
搭建一个固定且经过实战检验的模式,而非提供一个菜单——请参见
core/auth.md的搭建块: 短生命期访问令牌(5-15 分钟,绝不放在 Cookie 中) + 存储在作用域为/auth/refresh的 httpOnly Cookie 中的刷新令牌 + 轮换机制(一次性使用,哈希后存储在数据库中) +csrf-csrf保护刷新端点 +argon2id密码哈希 +RolesGuard。请不要提供替代方案 (Session、无轮换的裸 JWT)——这是唯一的默认方案。 - 后台任务:是否需要 BullMQ(基于 Redis 的队列)?
- 缓存:是否需要
@nestjs/cache-manager+@keyv/redis(旁路缓存)?默认建议是 不需要——等到真有性能需求时再添加,不要投机地为每个 CRUD 端点都加上。 - 文件上传:是否需要?如果需要,无需进一步提问——存储供应商(开发环境为本地磁盘, 生产环境为任何兼容 S3 的存储桶:AWS S3、MinIO、R2、Spaces)由环境变量控制, 而非搭建时的选择。
- 异步消息 / 服务间事件:是否需要?如果需要,也无需选择消息代理——RabbitMQ 是
固定的默认方案(任务队列、路由、死信队列覆盖了绝大多数场景)。
architecture/messaging.md将 Kafka 记录为后续的迁移路径(用于事件流式处理/重放/ 极致吞吐量需求),而非搭建时的选项。 - 国际化(i18n):此项目是否需要多种语言环境——即翻译后的 REST 错误/验证消息
和/或机器人回复(不止一种语言)?如果需要,无需进一步提问——
nestjs-i18n是固定的 库;语言环境解析方式因传输方式而异(REST:Accept-Language标头;机器人:平台自身 的每个用户语言环境字段,绝不使用Accept-Language),这两种方式在core/i18n.md中都有说明。如果不需要,则跳过——一个只会在一种语言下运行的项目不需要此功能。 - JSDoc/TSDoc(公共 API):是否强制要求每个导出的符号都带有文档注释,还是跳过?
这决定了是否生成
.agents/agent-surface.md(建议默认值:是)。 - Git 策略:智能体是否可以不经确认地自动提交和推送,还是每次提交/推送都需要确认?
- 包管理器:npm、pnpm 还是 yarn?默认建议:pnpm。
- Git 远程仓库:用户是否已有要推送的仓库 URL?如果有,请记录下来——
git remote add origin <url>会在git init之后立即执行(参见plan.md)。 如果未提供 URL,则跳过此项;用户稍后自行配置远程仓库。
记录每一个答案——它们既驱动脚手架的生成,也决定哪些文档文件被生成。除非上面有明确
固定的默认值,否则请勿静默地假定任何默认值;如果用户跳过了某个问题,请再次询问该问题。
本技能仅针对单个 NestJS 项目,而非 monorepo/Nx 工作区,也非分布式微服务拓扑结构
(多个可部署的服务/仓库)——如果用户需要其中任何一种,请声明本技能不涵盖该场景并停止,
而不是自行发挥。消息代理(见问题 7)仅用于连接混合应用(app.connectMicroservice()
位于同一单个应用内)——它永远不会启动第二个服务。
固定默认值——请勿询问这些,它们在设计上是锁定的:
- ORM/数据库:Prisma + Postgres。不支持 TypeORM(不建议用于新项目)、不支持 Drizzle (小众性能/边缘场景选择)、本技能 v1 中不包含 NoSQL/MongoDB 分支。
- 验证:HTTP 层使用
class-validator+class-transformer,main.ts中无条件 配置全局ValidationPipe,且whitelist、forbidNonWhitelisted、forbidUnknownValues、transform均设置为true。环境变量/配置验证使用 Zod (@nestjs/config+validate),并由 ESLint 规则强制执行,禁止在模式文件之外 直接读取process.env——请参见testing-and-quality.md的“机械强制规则”部分。 嵌套的 DTO 字段需要同时使用@ValidateNested()和@Type(() => NestedDto)—— 请参见code-style/dto-and-validation.md。通过从@nestjs/swagger导入的PartialType/OmitType/PickType重用 DTO,绝不使用@nestjs/mapped-types—— ESLint 会阻止此操作,而不仅仅是记录在文档中(同一节)。 - 响应格式:全局
ClassSerializerInterceptor+ DTO 字段上的@Exclude()是唯一的 固定序列化机制——绝不允许直接返回原始 Prisma 实体,也绝不允许在未经 ADR(架构决策记录) 的情况下引入第二种序列化方法。 - Swagger/OpenAPI:始终为 REST 分支配置。
- CORS:始终在
main.ts中通过环境变量驱动的来源白名单进行配置,绝不使用*。 - API 版本控制:Nest URI 版本控制(
/v1/...),固定在architecture/transport-adapter.md中。 - 速率限制:始终为 REST 和/或机器人安装
@nestjs/throttler,REST 路由基于 IP, 机器人处理器基于用户/聊天 ID——绝不可以“暂时不需要”为由跳过。 - 日志记录:始终使用
nestjs-pino——结构化 JSON 日志,不提供普通的Logger选项。 - 健康检查:始终配置
@nestjs/terminus,不受问卷控制——两条独立路由:GET /health/live(仅进程,无外部检查)和GET /health/ready(Prisma + 任何已选择的 Redis/RabbitMQ 依赖),绝不合并为一条。请参见core/health.md。 - 优雅关闭:始终在
main.ts中调用app.enableShutdownHooks()——否则,Prisma 的OnModuleDestroy连接关闭钩子在容器重启时永远不会触发。 - Prisma 错误映射:全局
PrismaExceptionFilter(APP_FILTER)将PrismaClientKnownRequestError代码映射到对应的 Nest HTTP 异常——Prisma 错误绝不会 以未经处理的裸 500 错误形式暴露。 - Prisma 客户端生成:
package.json始终包含"postinstall": "prisma generate"—— 生成的客户端在.gitignore中,因此新的克隆/CI 需要此命令才能编译。 - docker-compose.yml:始终生成(仅用于开发/测试,生产部署绝不引用)——始终包含 Postgres;仅当选择了 BullMQ 和/或缓存时添加 Redis(两者共享一个实例);仅当选择了 消息功能时添加 RabbitMQ。
2. 生成
遵循 plan.md。将文件从 templates/ 复制到目标项目中,包括点文件(.gitignore、
.gitattributes、.editorconfig、.prettierrc、.prettierignore、.nvmrc、
.vscode/extensions.json、.env.example、docker-compose.yml)。
问卷答案有两种不同的处理方式,请不要混淆:
- 文本占位符——查找并替换每一个
{{TOKEN}}为真实值,不留任何占位符:{{PROJECT_NAME}}、{{APP_TYPE}}、{{BOT_PLATFORM}}、{{TESTS}}、{{GIT_POLICY}}、{{PACKAGE_MANAGER}}、{{NODE_VERSION}}、{{DATE}}。 - 包含门控——应用类型、机器人平台、测试、认证、队列、缓存、存储、消息、i18n 和
强制 TSDoc 的答案不填充占位符;它们决定是否复制整个文件(或文件中由
<!-- SCAFFOLD -->标记的代码块)。回答“否”意味着文件/代码块被删除,而不是填充空字符串。当保留门控文件时, 必须仍从AGENTS.md/ 相关 README 链接到它们;跳过时,则必须移除它们的链接。
3. 验证
在报告成功之前,务必完整运行 checklist.md。
关于文档结构的说明(通读一次,然后严格按照 templates/ 执行)
CLAUDE.md始终是一个指向AGENTS.md的单行存根。AGENTS.md是强制性的入口点:一个简短的“必读”列表加上不可协商的规则,位于项目根目录。.agents/README.md是.agents/下所有内容的平面索引——当添加或跳过一个条件性文件 (auth、queue、cache、storage、messaging、i18n、agent-surface)时,请保持其同步。- 真正简短的主题直接放在
.agents/*.md中(workflow、git-policy、documentation、 testing-and-quality、agent-surface、refactoring、progress)。 - 需要展开成多个文档的主题,或按功能注册的主题,会创建一个带有自己
README.md集线器的子文件夹:.agents/code-style/、.agents/architecture/、.agents/shared/、.agents/core/、.agents/decisions/。 .agents/shared/README.md注册src/common/(框架无关的工具——零@nestjs/*导入—— 外加通用管道/过滤器/拦截器/装饰器)。.agents/core/README.md注册src/core/应用级单例(auth、Prisma 客户端提供者、 logger、queue、cache、storage、i18n——每个功能在被选中时都有自己独立的条件性文档文件)。.agents/decisions/README.md说明了何时需要简短的 ADR(架构决策记录)(层方向、消息代理迁移、 版本控制策略更改)——始终生成,开始时没有任何 ADR 文件。- 所有被跟踪的文件内容——包括 TSDoc——仅使用英文。不能包含西里尔字母或其他乱码。
.agents/中的所有文档读起来必须像kikita-create-angular-app的模板一样:命令式、简短、 带有示例,并以审查/验证清单结尾。