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 個問題 — 第一個答案決定了後續哪些問題是相關的,因此一次全部詢問意味著向僅使用 Bot 的使用者提出一個「您的 REST API 的認證」問題,但這與他們無關。
第 1 階段 — 判斷分支的問題,單獨詢問:
- 應用程式類型:REST API、Bot,或在同一個應用中同時包含兩者?
- 如果是 Bot(或兩者皆有):使用哪個平台?Telegram (
nestjs-telegraf) 或 Discord — 具體來說,對於 Discord,necord是推薦的預設選項(透過原生 Nest DI/guards/pipes 滿足通用事件→處理器→服務模式所需的最小黏合程式碼),但這並非強制:如果使用者想要原始的discord.js(現有團隊的專業知識,necord尚未封裝的discord.js功能),這也是一個合法的選擇 — 將其視為下面的「其他平台」,透過手動調整通用模式來適應,而不是免費獲得。 - 任何其他平台/函式庫(請指名 —
architecture/transport-adapter.md中的通用 Bot 傳輸模式可以適應它,但對於nestjs-telegraf/necord之外的任何平台,具體的適配器程式碼需要手動編寫)。
- 如果是 Bot(或兩者皆有):使用哪個平台?Telegram (
第 2 階段 — 其他所有問題,分批詢問(僅當第 1 階段回答為 REST 或「兩者皆有」時才詢問第 3 題;以下每個問題都適用於所有應用程式類型):
- 測試:無,或單元測試 / e2e 測試(Supertest)/ 兩者皆有?選擇「兩者皆有」還會安裝 Testcontainers 來進行整合測試,以連接真實的 Postgres 實例,而不是模擬物件。
- 認證(如果第 1 階段僅為 Bot,則完全跳過):需要或不需要?回答「是」會建立一個經過實戰檢驗的固定模式,而不是一個選單 — 請參閱
core/auth.md的 scaffold 區塊:短效存取權杖(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 是固定的預設值(任務佇列、路由、DLQ 涵蓋了絕大多數情況)。
architecture/messaging.md將 Kafka 記錄為後續遷移到事件串流/重播/極高吞吐量需求的路徑,而不是建立專案時的選項。 - i18n:此專案是否需要多個地區設定 — 即翻譯過的 REST 錯誤/驗證訊息和/或 Bot 回覆,且使用多種語言?如果需要,則無需進一步的子問題 —
nestjs-i18n是固定的函式庫;地區設定解析因傳輸方式而異(REST:Accept-Language標頭;Bot:平台自己的每個使用者地區設定欄位,絕不使用Accept-Language),兩者都在core/i18n.md中說明。如果不需要,則跳過 — 一個永遠只使用一種語言的專案不需要這個。 - 公開 API 上的 JSDoc/TSDoc:強制要求每個匯出的符號都必須有文件註解,或跳過?這決定了是否產生
.agents/agent-surface.md(建議預設值:是)。 - Git 政策:Agent 是否可以每次在未詢問的情況下進行提交和推送,或者每次提交/推送都必須經過確認?
- 套件管理員:npm、pnpm 或 yarn?預設建議:pnpm。
- Git 遠端:使用者是否已有要推送到的儲存庫 URL?如果有,請記錄下來 — 在
git init之後立即執行git remote add origin <url>(請參閱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 規則強制執行,在 schema 檔案之外禁止直接讀取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 和/或 Bot,總是安裝
@nestjs/throttler,REST 路由使用 IP 金鑰,Bot 處理器使用使用者/聊天 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 忽略,所以新的 clone/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}}。 - 包含開關 — 應用程式類型、Bot 平台、測試、認證、佇列、快取、儲存、訊息傳遞、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/*匯入 — 加上通用的 pipes/filters/interceptors/decorators)。.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的範本一樣:命令式、簡短、附有範例、並以審查/驗證清單結尾。