spoonfeeder 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +249 -0
- package/dist/generator/ai-context-assembler.d.ts +4 -0
- package/dist/generator/ai-context-assembler.js +52 -0
- package/dist/generator/ai-context-assembler.js.map +1 -0
- package/dist/generator/env-merger.d.ts +3 -0
- package/dist/generator/env-merger.js +16 -0
- package/dist/generator/env-merger.js.map +1 -0
- package/dist/generator/generator.d.ts +3 -0
- package/dist/generator/generator.js +253 -0
- package/dist/generator/generator.js.map +1 -0
- package/dist/generator/package-json-merger.d.ts +6 -0
- package/dist/generator/package-json-merger.js +29 -0
- package/dist/generator/package-json-merger.js.map +1 -0
- package/dist/generator/post-generate.d.ts +1 -0
- package/dist/generator/post-generate.js +28 -0
- package/dist/generator/post-generate.js.map +1 -0
- package/dist/generator/template-engine.d.ts +4 -0
- package/dist/generator/template-engine.js +20 -0
- package/dist/generator/template-engine.js.map +1 -0
- package/dist/generators/add-recipe/generator.d.ts +3 -0
- package/dist/generators/add-recipe/generator.js +153 -0
- package/dist/generators/add-recipe/generator.js.map +1 -0
- package/dist/generators/list-recipes/generator.d.ts +3 -0
- package/dist/generators/list-recipes/generator.js +58 -0
- package/dist/generators/list-recipes/generator.js.map +1 -0
- package/dist/generators/migrate-recipe/generator.d.ts +9 -0
- package/dist/generators/migrate-recipe/generator.js +90 -0
- package/dist/generators/migrate-recipe/generator.js.map +1 -0
- package/dist/generators/migrate-recipe/migration-guidance.d.ts +1 -0
- package/dist/generators/migrate-recipe/migration-guidance.js +159 -0
- package/dist/generators/migrate-recipe/migration-guidance.js.map +1 -0
- package/dist/generators/remove-recipe/generator.d.ts +3 -0
- package/dist/generators/remove-recipe/generator.js +176 -0
- package/dist/generators/remove-recipe/generator.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/add-ons.d.ts +3 -0
- package/dist/prompts/add-ons.js +29 -0
- package/dist/prompts/add-ons.js.map +1 -0
- package/dist/prompts/ci-cd.d.ts +2 -0
- package/dist/prompts/ci-cd.js +19 -0
- package/dist/prompts/ci-cd.js.map +1 -0
- package/dist/prompts/cloud-provider.d.ts +2 -0
- package/dist/prompts/cloud-provider.js +18 -0
- package/dist/prompts/cloud-provider.js.map +1 -0
- package/dist/prompts/confirmation.d.ts +2 -0
- package/dist/prompts/confirmation.js +29 -0
- package/dist/prompts/confirmation.js.map +1 -0
- package/dist/prompts/deployment.d.ts +2 -0
- package/dist/prompts/deployment.js +20 -0
- package/dist/prompts/deployment.js.map +1 -0
- package/dist/prompts/frontend.d.ts +2 -0
- package/dist/prompts/frontend.js +18 -0
- package/dist/prompts/frontend.js.map +1 -0
- package/dist/prompts/project-name.d.ts +5 -0
- package/dist/prompts/project-name.js +34 -0
- package/dist/prompts/project-name.js.map +1 -0
- package/dist/prompts/project-type.d.ts +2 -0
- package/dist/prompts/project-type.js +22 -0
- package/dist/prompts/project-type.js.map +1 -0
- package/dist/prompts/run-all.d.ts +3 -0
- package/dist/prompts/run-all.js +83 -0
- package/dist/prompts/run-all.js.map +1 -0
- package/dist/prompts/transport.d.ts +2 -0
- package/dist/prompts/transport.js +22 -0
- package/dist/prompts/transport.js.map +1 -0
- package/dist/recipes/definitions.d.ts +2 -0
- package/dist/recipes/definitions.js +3647 -0
- package/dist/recipes/definitions.js.map +1 -0
- package/dist/recipes/recipe.interface.d.ts +8 -0
- package/dist/recipes/recipe.interface.js +2 -0
- package/dist/recipes/recipe.interface.js.map +1 -0
- package/dist/recipes/registry.d.ts +9 -0
- package/dist/recipes/registry.js +23 -0
- package/dist/recipes/registry.js.map +1 -0
- package/dist/types.d.ts +70 -0
- package/dist/types.js +152 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/ai-context-updater.d.ts +6 -0
- package/dist/utils/ai-context-updater.js +50 -0
- package/dist/utils/ai-context-updater.js.map +1 -0
- package/dist/utils/dependency-checker.d.ts +14 -0
- package/dist/utils/dependency-checker.js +27 -0
- package/dist/utils/dependency-checker.js.map +1 -0
- package/dist/utils/env-updater.d.ts +7 -0
- package/dist/utils/env-updater.js +35 -0
- package/dist/utils/env-updater.js.map +1 -0
- package/dist/utils/main-ts-updater.d.ts +37 -0
- package/dist/utils/main-ts-updater.js +144 -0
- package/dist/utils/main-ts-updater.js.map +1 -0
- package/dist/utils/module-updater.d.ts +26 -0
- package/dist/utils/module-updater.js +167 -0
- package/dist/utils/module-updater.js.map +1 -0
- package/dist/utils/recipe-manifest.d.ts +24 -0
- package/dist/utils/recipe-manifest.js +45 -0
- package/dist/utils/recipe-manifest.js.map +1 -0
- package/dist/validation/config-validator.d.ts +13 -0
- package/dist/validation/config-validator.js +50 -0
- package/dist/validation/config-validator.js.map +1 -0
- package/dist/validation/conflict-detector.d.ts +7 -0
- package/dist/validation/conflict-detector.js +37 -0
- package/dist/validation/conflict-detector.js.map +1 -0
- package/generators.json +24 -0
- package/package.json +78 -0
- package/src/generators/add-recipe/schema.json +21 -0
- package/src/generators/list-recipes/schema.json +18 -0
- package/src/generators/migrate-recipe/schema.json +20 -0
- package/src/generators/remove-recipe/schema.json +21 -0
- package/templates/base/.env.example.ejs +3 -0
- package/templates/base/README.md.ejs +20 -0
- package/templates/base/SECURITY.md +36 -0
- package/templates/base/commitlint.config.js +15 -0
- package/templates/base/docs/adr/000-template.md +45 -0
- package/templates/base/docs/adr/001-framework-selection.md +54 -0
- package/templates/base/docs/adr/002-error-handling-strategy.md +36 -0
- package/templates/base/docs/adr/003-database-strategy.md +40 -0
- package/templates/base/docs/adr/004-authentication-architecture.md +44 -0
- package/templates/base/docs/adr/005-deployment-strategy.md +40 -0
- package/templates/base/docs/adr/006-testing-strategy.md +41 -0
- package/templates/base/docs/adr/007-scaffolder-architecture.md +64 -0
- package/templates/base/docs/adr/008-recipe-system.md +47 -0
- package/templates/base/docs/adr/009-standards-compliance.md +54 -0
- package/templates/base/docs/adr/010-ai-context-generation.md +44 -0
- package/templates/base/docs/adr/011-package-versioning.md +44 -0
- package/templates/base/docs/adr/012-monorepo-strategy.md +54 -0
- package/templates/base/docs/adr/013-http-adapter.md +63 -0
- package/templates/base/docs/adr/014-build-toolchain.md +61 -0
- package/templates/base/docs/adr/015-cloud-provider-strategy.md +49 -0
- package/templates/base/docs/adr/016-ci-cd-pipeline-strategy.md +52 -0
- package/templates/base/docs/adr/017-logging-strategy.md +63 -0
- package/templates/base/docs/adr/018-security-architecture.md +61 -0
- package/templates/base/docs/adr/019-project-type-design.md +61 -0
- package/templates/base/docs/adr/020-frontend-framework-support.md +57 -0
- package/templates/base/docs/adr/021-observability-strategy.md +68 -0
- package/templates/base/docs/adr/022-api-design-patterns.md +64 -0
- package/templates/base/docs/adr/023-error-hierarchy.md +54 -0
- package/templates/base/docs/adr/024-request-context-pattern.md +57 -0
- package/templates/base/docs/adr/025-data-patterns.md +58 -0
- package/templates/base/docs/adr/026-migration-strategy.md +57 -0
- package/templates/base/docs/adr/027-dependency-management.md +60 -0
- package/templates/base/docs/adr/028-code-quality-toolchain.md +60 -0
- package/templates/base/docs/adr/029-admin-panel.md +53 -0
- package/templates/base/docs/adr/030-performance-patterns.md +60 -0
- package/templates/base/docs/adr/031-nx-generators-roadmap.md +73 -0
- package/templates/base/docs/runbooks/000-template.md +78 -0
- package/templates/base/docs/sla-slo.md +36 -0
- package/templates/base/dot-editorconfig +12 -0
- package/templates/base/dot-github/ISSUE_TEMPLATE/bug_report.md +33 -0
- package/templates/base/dot-github/ISSUE_TEMPLATE/feature_request.md +21 -0
- package/templates/base/dot-github/pull_request_template.md +32 -0
- package/templates/base/dot-gitignore +28 -0
- package/templates/base/dot-husky/commit-msg +1 -0
- package/templates/base/dot-husky/pre-commit +1 -0
- package/templates/base/dot-husky/pre-push +2 -0
- package/templates/base/dot-npmrc +1 -0
- package/templates/base/dot-nvmrc +1 -0
- package/templates/base/dot-prettierrc +8 -0
- package/templates/base/eslint.config.mjs +35 -0
- package/templates/base/jest.config.ts +56 -0
- package/templates/base/nest-cli.json.ejs +10 -0
- package/templates/base/nx.json +3 -0
- package/templates/base/package.json.ejs +78 -0
- package/templates/base/src/app/modules/.gitkeep +0 -0
- package/templates/base/src/config/.gitkeep +0 -0
- package/templates/base/src/infrastructure/database/entities/.gitkeep +0 -0
- package/templates/base/src/infrastructure/database/migrations/.gitkeep +0 -0
- package/templates/base/src/infrastructure/database/repositories/.gitkeep +0 -0
- package/templates/base/src/infrastructure/http/.gitkeep +0 -0
- package/templates/base/src/infrastructure/notifications/.gitkeep +0 -0
- package/templates/base/src/infrastructure/queue/.gitkeep +0 -0
- package/templates/base/src/infrastructure/storage/.gitkeep +0 -0
- package/templates/base/src/shared/constants/error-codes.constant.ts +30 -0
- package/templates/base/src/shared/constants/http.constant.ts +134 -0
- package/templates/base/src/shared/constants/index.ts +2 -0
- package/templates/base/src/shared/decorators/.gitkeep +0 -0
- package/templates/base/src/shared/decorators/api-paginated-response.decorator.ts +10 -0
- package/templates/base/src/shared/errors/application.error.ts +21 -0
- package/templates/base/src/shared/errors/forbidden.error.ts +7 -0
- package/templates/base/src/shared/errors/index.ts +6 -0
- package/templates/base/src/shared/errors/invalid-request.error.ts +7 -0
- package/templates/base/src/shared/errors/not-found.error.ts +7 -0
- package/templates/base/src/shared/errors/requester.error.ts +7 -0
- package/templates/base/src/shared/errors/validation.error.ts +7 -0
- package/templates/base/src/shared/filters/http-exception.filter.ts +139 -0
- package/templates/base/src/shared/guards/.gitkeep +0 -0
- package/templates/base/src/shared/interceptors/interfaces/.gitkeep +0 -0
- package/templates/base/src/shared/interceptors/response.interceptor.ts +22 -0
- package/templates/base/src/shared/middleware/request-timeout.middleware.ts +32 -0
- package/templates/base/src/shared/pipes/parse-uuid.pipe.ts +13 -0
- package/templates/base/src/shared/utils/index.ts +2 -0
- package/templates/base/src/shared/utils/retry.util.ts +32 -0
- package/templates/base/src/shared/utils/sleep.util.ts +3 -0
- package/templates/base/tests/e2e/app.e2e-spec.ts.ejs +25 -0
- package/templates/base/tests/factories/.gitkeep +0 -0
- package/templates/base/tests/helpers/.gitkeep +0 -0
- package/templates/base/tests/integration/.gitkeep +0 -0
- package/templates/base/tests/unit/app.module.spec.ts +11 -0
- package/templates/base/tests/unit/shared/errors/error-hierarchy.spec.ts +69 -0
- package/templates/base/tests/unit/shared/filters/http-exception.filter.spec.ts +188 -0
- package/templates/base/tests/unit/shared/interceptors/response.interceptor.spec.ts +54 -0
- package/templates/base/tests/unit/shared/pipes/parse-uuid.pipe.spec.ts +14 -0
- package/templates/base/tsconfig.build.json +4 -0
- package/templates/base/tsconfig.json.ejs +26 -0
- package/templates/project-types/aws-lambda/package-fragment.json +8 -0
- package/templates/project-types/aws-lambda/src/app.module.ts.ejs +9 -0
- package/templates/project-types/aws-lambda/src/main.ts.ejs +32 -0
- package/templates/project-types/aws-lambda/tests/unit/handler.spec.ts +7 -0
- package/templates/project-types/cli-app/package-fragment.json +8 -0
- package/templates/project-types/cli-app/src/app.module.ts.ejs +11 -0
- package/templates/project-types/cli-app/src/commands/hello.command.ts.ejs +8 -0
- package/templates/project-types/cli-app/src/main.ts.ejs +8 -0
- package/templates/project-types/cli-app/tests/unit/commands/hello.command.spec.ts +17 -0
- package/templates/project-types/full-stack/apps/api/src/app.module.ts.ejs +9 -0
- package/templates/project-types/full-stack/apps/api/src/main.ts.ejs +32 -0
- package/templates/project-types/full-stack/frontend/nextjs/.cursor/rules/nextjs.mdc +12 -0
- package/templates/project-types/full-stack/frontend/nextjs/.github/copilot-instructions.md +23 -0
- package/templates/project-types/full-stack/frontend/nextjs/CLAUDE.md +25 -0
- package/templates/project-types/full-stack/frontend/nextjs/next.config.ts +9 -0
- package/templates/project-types/full-stack/frontend/nextjs/package.json +21 -0
- package/templates/project-types/full-stack/frontend/nextjs/src/app/layout.tsx +9 -0
- package/templates/project-types/full-stack/frontend/nextjs/src/app/page.tsx +8 -0
- package/templates/project-types/full-stack/frontend/nextjs/tsconfig.json +21 -0
- package/templates/project-types/full-stack/frontend/nuxt/.cursor/rules/nuxt.mdc +14 -0
- package/templates/project-types/full-stack/frontend/nuxt/.github/copilot-instructions.md +25 -0
- package/templates/project-types/full-stack/frontend/nuxt/CLAUDE.md +25 -0
- package/templates/project-types/full-stack/frontend/nuxt/app.vue +5 -0
- package/templates/project-types/full-stack/frontend/nuxt/nuxt.config.ts +6 -0
- package/templates/project-types/full-stack/frontend/nuxt/package.json +17 -0
- package/templates/project-types/full-stack/frontend/nuxt/pages/index.vue +3 -0
- package/templates/project-types/full-stack/frontend/nuxt/tsconfig.json +1 -0
- package/templates/project-types/full-stack/frontend/sveltekit/.cursor/rules/sveltekit.mdc +13 -0
- package/templates/project-types/full-stack/frontend/sveltekit/.github/copilot-instructions.md +24 -0
- package/templates/project-types/full-stack/frontend/sveltekit/CLAUDE.md +25 -0
- package/templates/project-types/full-stack/frontend/sveltekit/package.json +17 -0
- package/templates/project-types/full-stack/frontend/sveltekit/src/app.html +5 -0
- package/templates/project-types/full-stack/frontend/sveltekit/src/routes/+page.svelte +1 -0
- package/templates/project-types/full-stack/frontend/sveltekit/svelte.config.js +5 -0
- package/templates/project-types/full-stack/frontend/sveltekit/vite.config.ts +9 -0
- package/templates/project-types/full-stack/frontend/vite-react/.cursor/rules/react.mdc +12 -0
- package/templates/project-types/full-stack/frontend/vite-react/.github/copilot-instructions.md +23 -0
- package/templates/project-types/full-stack/frontend/vite-react/CLAUDE.md +24 -0
- package/templates/project-types/full-stack/frontend/vite-react/index.html +5 -0
- package/templates/project-types/full-stack/frontend/vite-react/package.json +22 -0
- package/templates/project-types/full-stack/frontend/vite-react/src/App.tsx +8 -0
- package/templates/project-types/full-stack/frontend/vite-react/src/main.tsx +9 -0
- package/templates/project-types/full-stack/frontend/vite-react/tsconfig.json +21 -0
- package/templates/project-types/full-stack/frontend/vite-react/vite.config.ts +9 -0
- package/templates/project-types/full-stack/libs/shared-types/package.json.ejs +6 -0
- package/templates/project-types/full-stack/libs/shared-types/src/index.ts.ejs +15 -0
- package/templates/project-types/full-stack/nx.json.ejs +20 -0
- package/templates/project-types/full-stack/package-fragment.json +14 -0
- package/templates/project-types/full-stack/pnpm-workspace.yaml +3 -0
- package/templates/project-types/full-stack/tsconfig.json.ejs +27 -0
- package/templates/project-types/http-api/src/app.module.ts.ejs +9 -0
- package/templates/project-types/http-api/src/main.ts.ejs +30 -0
- package/templates/project-types/http-api/tests/e2e/health.e2e-spec.ts +23 -0
- package/templates/project-types/microservice/package-fragment.json +5 -0
- package/templates/project-types/microservice/src/app.module.ts.ejs +9 -0
- package/templates/project-types/microservice/src/main.ts.ejs +15 -0
- package/templates/project-types/microservice/tests/unit/app.module.spec.ts +9 -0
- package/templates/project-types/monorepo/README.md.ejs +33 -0
- package/templates/project-types/monorepo/apps/api/src/app.module.ts.ejs +9 -0
- package/templates/project-types/monorepo/apps/api/src/main.ts.ejs +30 -0
- package/templates/project-types/monorepo/libs/common/package.json.ejs +6 -0
- package/templates/project-types/monorepo/libs/common/src/index.ts.ejs +17 -0
- package/templates/project-types/monorepo/nx.json.ejs +20 -0
- package/templates/project-types/monorepo/package-fragment.json +13 -0
- package/templates/project-types/monorepo/pnpm-workspace.yaml +3 -0
- package/templates/project-types/monorepo/tsconfig.json.ejs +27 -0
- package/templates/project-types/scheduled-worker/package-fragment.json +5 -0
- package/templates/project-types/scheduled-worker/src/app.module.ts.ejs +13 -0
- package/templates/project-types/scheduled-worker/src/jobs/example.job.ts.ejs +12 -0
- package/templates/project-types/scheduled-worker/src/main.ts.ejs +10 -0
- package/templates/project-types/scheduled-worker/tests/unit/jobs/example.job.spec.ts +17 -0
- package/templates/recipes/adminjs/README.md +145 -0
- package/templates/recipes/adminjs/src/app/modules/admin/admin.module.ts +59 -0
- package/templates/recipes/adminjs/tests/unit/app/modules/admin/admin.module.spec.ts +22 -0
- package/templates/recipes/ai-context/README.md +11 -0
- package/templates/recipes/ai-context/claude/base.md +73 -0
- package/templates/recipes/ai-context/claude/commands/add-command.md +48 -0
- package/templates/recipes/ai-context/claude/commands/add-consumer.md +58 -0
- package/templates/recipes/ai-context/claude/commands/add-endpoint.md +69 -0
- package/templates/recipes/ai-context/claude/commands/add-job.md +42 -0
- package/templates/recipes/ai-context/claude/commands/migrate.md +69 -0
- package/templates/recipes/ai-context/copilot/base.md +71 -0
- package/templates/recipes/ai-context/cursor/auth.mdc +44 -0
- package/templates/recipes/ai-context/cursor/base.mdc +44 -0
- package/templates/recipes/ai-context/cursor/prisma.mdc +43 -0
- package/templates/recipes/ai-context/cursor/swagger.mdc +48 -0
- package/templates/recipes/ai-context/cursor/testing.mdc +58 -0
- package/templates/recipes/ai-context/cursor/typeorm.mdc +49 -0
- package/templates/recipes/api-keys/README.md +44 -0
- package/templates/recipes/api-keys/src/shared/guards/api-key.guard.ts +32 -0
- package/templates/recipes/api-keys/tests/unit/shared/guards/api-key.guard.spec.ts +40 -0
- package/templates/recipes/api-versioning/README.md +63 -0
- package/templates/recipes/audit-trail/README.md +75 -0
- package/templates/recipes/audit-trail/src/shared/decorators/auditable.decorator.ts +4 -0
- package/templates/recipes/audit-trail/src/shared/interceptors/audit.interceptor.ts +46 -0
- package/templates/recipes/audit-trail/tests/unit/shared/interceptors/audit.interceptor.spec.ts +82 -0
- package/templates/recipes/auth-flows/README.md +91 -0
- package/templates/recipes/auth-flows/src/app/modules/auth/auth.controller.ts +44 -0
- package/templates/recipes/auth-flows/src/app/modules/auth/auth.module.ts +11 -0
- package/templates/recipes/auth-flows/src/app/modules/auth/auth.service.ts +194 -0
- package/templates/recipes/auth-flows/src/app/modules/auth/dto/forgot-password.dto.ts +6 -0
- package/templates/recipes/auth-flows/src/app/modules/auth/dto/login.dto.ts +9 -0
- package/templates/recipes/auth-flows/src/app/modules/auth/dto/reset-password.dto.ts +11 -0
- package/templates/recipes/auth-flows/src/app/modules/auth/dto/signup.dto.ts +16 -0
- package/templates/recipes/auth-flows/tests/unit/app/modules/auth/auth.service.spec.ts +13 -0
- package/templates/recipes/bullmq/README.md +54 -0
- package/templates/recipes/bullmq/src/infrastructure/queue/example.processor.ts +25 -0
- package/templates/recipes/bullmq/src/infrastructure/queue/queue.module.ts +26 -0
- package/templates/recipes/bullmq/tests/unit/infrastructure/queue/example.processor.spec.ts +17 -0
- package/templates/recipes/changelog/.changelogrc.json +18 -0
- package/templates/recipes/changelog/README.md +44 -0
- package/templates/recipes/ci-cd/README.md +14 -0
- package/templates/recipes/ci-cd/aws-codepipeline/README.md +30 -0
- package/templates/recipes/ci-cd/aws-codepipeline/buildspec.yml +41 -0
- package/templates/recipes/ci-cd/azure-devops/README.md +32 -0
- package/templates/recipes/ci-cd/azure-devops/azure-pipelines.yml +79 -0
- package/templates/recipes/ci-cd/gcp-cloudbuild/README.md +64 -0
- package/templates/recipes/ci-cd/gcp-cloudbuild/cloudbuild.yaml +53 -0
- package/templates/recipes/ci-cd/github-actions/.github/workflows/cd.yml +35 -0
- package/templates/recipes/ci-cd/github-actions/.github/workflows/ci.yml +62 -0
- package/templates/recipes/ci-cd/github-actions/README.md +29 -0
- package/templates/recipes/circuit-breaker/README.md +45 -0
- package/templates/recipes/circuit-breaker/src/shared/utils/circuit-breaker.ts +100 -0
- package/templates/recipes/circuit-breaker/tests/unit/shared/utils/circuit-breaker.spec.ts +28 -0
- package/templates/recipes/cloud-aws/README.md +20 -0
- package/templates/recipes/cloud-aws/cloudfront/README.md +50 -0
- package/templates/recipes/cloud-aws/cloudfront/src/infrastructure/aws/cloudfront.module.ts +8 -0
- package/templates/recipes/cloud-aws/cloudfront/src/infrastructure/aws/cloudfront.service.ts +29 -0
- package/templates/recipes/cloud-aws/cloudwatch/README.md +40 -0
- package/templates/recipes/cloud-aws/cloudwatch/src/infrastructure/aws/cloudwatch.module.ts +8 -0
- package/templates/recipes/cloud-aws/cloudwatch/src/infrastructure/aws/cloudwatch.service.ts +40 -0
- package/templates/recipes/cloud-aws/cognito/README.md +39 -0
- package/templates/recipes/cloud-aws/cognito/src/infrastructure/aws/cognito.module.ts +8 -0
- package/templates/recipes/cloud-aws/cognito/src/infrastructure/aws/cognito.service.ts +47 -0
- package/templates/recipes/cloud-aws/dynamodb/README.md +48 -0
- package/templates/recipes/cloud-aws/dynamodb/src/infrastructure/aws/dynamodb.module.ts +8 -0
- package/templates/recipes/cloud-aws/dynamodb/src/infrastructure/aws/dynamodb.service.ts +49 -0
- package/templates/recipes/cloud-aws/elasticache/README.md +45 -0
- package/templates/recipes/cloud-aws/elasticache/src/infrastructure/aws/redis.module.ts +8 -0
- package/templates/recipes/cloud-aws/elasticache/src/infrastructure/aws/redis.service.ts +47 -0
- package/templates/recipes/cloud-aws/eventbridge/README.md +46 -0
- package/templates/recipes/cloud-aws/eventbridge/src/infrastructure/aws/eventbridge.module.ts +8 -0
- package/templates/recipes/cloud-aws/eventbridge/src/infrastructure/aws/eventbridge.service.ts +48 -0
- package/templates/recipes/cloud-aws/rds/README.md +59 -0
- package/templates/recipes/cloud-aws/s3/README.md +44 -0
- package/templates/recipes/cloud-aws/s3/src/infrastructure/aws/s3.module.ts +8 -0
- package/templates/recipes/cloud-aws/s3/src/infrastructure/aws/s3.service.ts +42 -0
- package/templates/recipes/cloud-aws/secrets-manager/README.md +38 -0
- package/templates/recipes/cloud-aws/secrets-manager/src/infrastructure/aws/secrets.module.ts +8 -0
- package/templates/recipes/cloud-aws/secrets-manager/src/infrastructure/aws/secrets.service.ts +39 -0
- package/templates/recipes/cloud-aws/sns/README.md +43 -0
- package/templates/recipes/cloud-aws/sns/src/infrastructure/aws/sns.module.ts +8 -0
- package/templates/recipes/cloud-aws/sns/src/infrastructure/aws/sns.service.ts +48 -0
- package/templates/recipes/cloud-aws/sqs/README.md +47 -0
- package/templates/recipes/cloud-aws/sqs/src/infrastructure/aws/sqs.module.ts +8 -0
- package/templates/recipes/cloud-aws/sqs/src/infrastructure/aws/sqs.service.ts +58 -0
- package/templates/recipes/cloud-aws/ssm/README.md +41 -0
- package/templates/recipes/cloud-aws/ssm/src/infrastructure/aws/ssm.module.ts +8 -0
- package/templates/recipes/cloud-aws/ssm/src/infrastructure/aws/ssm.service.ts +54 -0
- package/templates/recipes/cloud-azure/README.md +18 -0
- package/templates/recipes/cloud-azure/app-insights/README.md +50 -0
- package/templates/recipes/cloud-azure/app-insights/src/infrastructure/azure/app-insights.module.ts +11 -0
- package/templates/recipes/cloud-azure/app-insights/src/infrastructure/azure/app-insights.service.ts +38 -0
- package/templates/recipes/cloud-azure/blob-storage/README.md +49 -0
- package/templates/recipes/cloud-azure/blob-storage/src/infrastructure/azure/blob-storage.module.ts +11 -0
- package/templates/recipes/cloud-azure/blob-storage/src/infrastructure/azure/blob-storage.service.ts +64 -0
- package/templates/recipes/cloud-azure/cache/README.md +47 -0
- package/templates/recipes/cloud-azure/cache/src/infrastructure/azure/redis.module.ts +11 -0
- package/templates/recipes/cloud-azure/cache/src/infrastructure/azure/redis.service.ts +41 -0
- package/templates/recipes/cloud-azure/cosmos-db/README.md +57 -0
- package/templates/recipes/cloud-azure/cosmos-db/src/infrastructure/azure/cosmos-db.module.ts +11 -0
- package/templates/recipes/cloud-azure/cosmos-db/src/infrastructure/azure/cosmos-db.service.ts +55 -0
- package/templates/recipes/cloud-azure/entra-id/README.md +42 -0
- package/templates/recipes/cloud-azure/entra-id/src/infrastructure/azure/entra-id.module.ts +11 -0
- package/templates/recipes/cloud-azure/entra-id/src/infrastructure/azure/entra-id.service.ts +55 -0
- package/templates/recipes/cloud-azure/front-door/README.md +48 -0
- package/templates/recipes/cloud-azure/functions/README.md +48 -0
- package/templates/recipes/cloud-azure/key-vault/README.md +42 -0
- package/templates/recipes/cloud-azure/key-vault/src/infrastructure/azure/key-vault.module.ts +11 -0
- package/templates/recipes/cloud-azure/key-vault/src/infrastructure/azure/key-vault.service.ts +27 -0
- package/templates/recipes/cloud-azure/service-bus/README.md +49 -0
- package/templates/recipes/cloud-azure/service-bus/src/infrastructure/azure/service-bus.module.ts +11 -0
- package/templates/recipes/cloud-azure/service-bus/src/infrastructure/azure/service-bus.service.ts +52 -0
- package/templates/recipes/cloud-azure/sql-database/README.md +54 -0
- package/templates/recipes/cloud-gcp/README.md +18 -0
- package/templates/recipes/cloud-gcp/cloud-cdn/README.md +40 -0
- package/templates/recipes/cloud-gcp/cloud-functions/README.md +42 -0
- package/templates/recipes/cloud-gcp/cloud-logging/README.md +42 -0
- package/templates/recipes/cloud-gcp/cloud-logging/src/infrastructure/gcp/logging.module.ts +10 -0
- package/templates/recipes/cloud-gcp/cloud-logging/src/infrastructure/gcp/logging.service.ts +50 -0
- package/templates/recipes/cloud-gcp/cloud-sql/README.md +53 -0
- package/templates/recipes/cloud-gcp/cloud-storage/README.md +43 -0
- package/templates/recipes/cloud-gcp/cloud-storage/src/infrastructure/gcp/storage.module.ts +10 -0
- package/templates/recipes/cloud-gcp/cloud-storage/src/infrastructure/gcp/storage.service.ts +51 -0
- package/templates/recipes/cloud-gcp/firebase-auth/README.md +38 -0
- package/templates/recipes/cloud-gcp/firebase-auth/src/infrastructure/gcp/firebase-auth.module.ts +10 -0
- package/templates/recipes/cloud-gcp/firebase-auth/src/infrastructure/gcp/firebase-auth.service.ts +41 -0
- package/templates/recipes/cloud-gcp/firestore/README.md +46 -0
- package/templates/recipes/cloud-gcp/firestore/src/infrastructure/gcp/firestore.module.ts +10 -0
- package/templates/recipes/cloud-gcp/firestore/src/infrastructure/gcp/firestore.service.ts +44 -0
- package/templates/recipes/cloud-gcp/memorystore/README.md +44 -0
- package/templates/recipes/cloud-gcp/memorystore/src/infrastructure/gcp/redis.module.ts +10 -0
- package/templates/recipes/cloud-gcp/memorystore/src/infrastructure/gcp/redis.service.ts +54 -0
- package/templates/recipes/cloud-gcp/pubsub/README.md +43 -0
- package/templates/recipes/cloud-gcp/pubsub/src/infrastructure/gcp/pubsub.module.ts +10 -0
- package/templates/recipes/cloud-gcp/pubsub/src/infrastructure/gcp/pubsub.service.ts +60 -0
- package/templates/recipes/cloud-gcp/secret-manager/README.md +40 -0
- package/templates/recipes/cloud-gcp/secret-manager/src/infrastructure/gcp/secrets.module.ts +10 -0
- package/templates/recipes/cloud-gcp/secret-manager/src/infrastructure/gcp/secrets.service.ts +41 -0
- package/templates/recipes/config-validation/README.md +61 -0
- package/templates/recipes/config-validation/src/config/env.validation.ts +28 -0
- package/templates/recipes/config-validation/tests/unit/config/env.validation.spec.ts +34 -0
- package/templates/recipes/content-digest/README.md +28 -0
- package/templates/recipes/content-digest/src/shared/guards/content-digest.guard.ts +30 -0
- package/templates/recipes/content-digest/src/shared/interceptors/content-digest.interceptor.ts +23 -0
- package/templates/recipes/content-digest/tests/unit/shared/guards/content-digest.guard.spec.ts +56 -0
- package/templates/recipes/content-digest/tests/unit/shared/interceptors/content-digest.interceptor.spec.ts +54 -0
- package/templates/recipes/correlation-id/README.md +44 -0
- package/templates/recipes/correlation-id/src/shared/middleware/correlation-id.middleware.ts +29 -0
- package/templates/recipes/correlation-id/tests/unit/shared/middleware/correlation-id.spec.ts +5 -0
- package/templates/recipes/cors/README.md +45 -0
- package/templates/recipes/cqrs/README.md +39 -0
- package/templates/recipes/cqrs/src/shared/cqrs/example.command.ts +29 -0
- package/templates/recipes/cqrs/tests/unit/shared/cqrs/example.command.spec.ts +38 -0
- package/templates/recipes/csrf/README.md +55 -0
- package/templates/recipes/data-masking/README.md +85 -0
- package/templates/recipes/data-masking/src/shared/decorators/sensitive.decorator.ts +12 -0
- package/templates/recipes/data-masking/src/shared/utils/mask.util.ts +26 -0
- package/templates/recipes/data-masking/tests/unit/shared/utils/mask.util.spec.ts +21 -0
- package/templates/recipes/database-factories/README.md +48 -0
- package/templates/recipes/database-factories/tests/factories/base.factory.ts +51 -0
- package/templates/recipes/database-seeding/README.md +40 -0
- package/templates/recipes/database-seeding/src/infrastructure/database/seed.ts +61 -0
- package/templates/recipes/database-seeding/tests/unit/infrastructure/database/seed.spec.ts +37 -0
- package/templates/recipes/dead-letter-queue/README.md +79 -0
- package/templates/recipes/dead-letter-queue/src/infrastructure/queue/dlq.service.ts +43 -0
- package/templates/recipes/dead-letter-queue/tests/unit/infrastructure/queue/dlq.service.spec.ts +46 -0
- package/templates/recipes/dependabot-renovate/.github/dependabot.yml +52 -0
- package/templates/recipes/dependabot-renovate/README.md +37 -0
- package/templates/recipes/dependabot-renovate/renovate.json +46 -0
- package/templates/recipes/deploy/README.md +13 -0
- package/templates/recipes/deploy/docker-compose/README.md +38 -0
- package/templates/recipes/deploy/docker-compose/docker-compose.yml +43 -0
- package/templates/recipes/deploy/dockerfile/Dockerfile +30 -0
- package/templates/recipes/deploy/dockerfile/README.md +30 -0
- package/templates/recipes/deploy/dockerfile/dot-dockerignore +9 -0
- package/templates/recipes/deploy/kubernetes/README.md +43 -0
- package/templates/recipes/deploy/kubernetes/k8s/configmap.yaml +7 -0
- package/templates/recipes/deploy/kubernetes/k8s/deployment.yaml +45 -0
- package/templates/recipes/deploy/kubernetes/k8s/hpa.yaml +18 -0
- package/templates/recipes/deploy/kubernetes/k8s/ingress.yaml +23 -0
- package/templates/recipes/deploy/kubernetes/k8s/service.yaml +12 -0
- package/templates/recipes/deploy/serverless-framework/README.md +39 -0
- package/templates/recipes/deploy/serverless-framework/serverless.yml.ejs +22 -0
- package/templates/recipes/deploy/terraform/README.md +99 -0
- package/templates/recipes/deploy/terraform/main.tf.ejs +13 -0
- package/templates/recipes/deploy/terraform/modules/app/alb.tf +34 -0
- package/templates/recipes/deploy/terraform/modules/app/iam.tf +30 -0
- package/templates/recipes/deploy/terraform/modules/app/main.tf +80 -0
- package/templates/recipes/deploy/terraform/modules/app/outputs.tf +11 -0
- package/templates/recipes/deploy/terraform/modules/app/security.tf +37 -0
- package/templates/recipes/deploy/terraform/modules/app/variables.tf +42 -0
- package/templates/recipes/deploy/terraform/outputs.tf +4 -0
- package/templates/recipes/deploy/terraform/variables.tf +11 -0
- package/templates/recipes/devcontainer/.devcontainer/Dockerfile +5 -0
- package/templates/recipes/devcontainer/.devcontainer/devcontainer.json +32 -0
- package/templates/recipes/devcontainer/.devcontainer/docker-compose.yml +62 -0
- package/templates/recipes/devcontainer/README.md +31 -0
- package/templates/recipes/distributed-tracing/README.md +45 -0
- package/templates/recipes/distributed-tracing/src/shared/middleware/trace-propagation.middleware.ts +68 -0
- package/templates/recipes/distributed-tracing/tests/unit/shared/middleware/trace-propagation.middleware.spec.ts +76 -0
- package/templates/recipes/docker-compose-dev/Dockerfile.dev +14 -0
- package/templates/recipes/docker-compose-dev/README.md +57 -0
- package/templates/recipes/docker-compose-dev/docker-compose.dev.yml.ejs +54 -0
- package/templates/recipes/docs-site/README.md +41 -0
- package/templates/recipes/docs-site/docs/.vitepress/config.ts.ejs +53 -0
- package/templates/recipes/dpop/README.md +37 -0
- package/templates/recipes/dpop/src/shared/guards/dpop.guard.ts +61 -0
- package/templates/recipes/dpop/tests/unit/shared/guards/dpop.guard.spec.ts +69 -0
- package/templates/recipes/drizzle-postgres/README.md +68 -0
- package/templates/recipes/drizzle-postgres/drizzle.config.ts +10 -0
- package/templates/recipes/drizzle-postgres/src/infrastructure/database/drizzle.module.ts +25 -0
- package/templates/recipes/drizzle-postgres/src/infrastructure/database/schema/example.ts +9 -0
- package/templates/recipes/drizzle-postgres/src/infrastructure/database/schema/index.ts +3 -0
- package/templates/recipes/drizzle-postgres/tests/unit/infrastructure/database/drizzle.module.spec.ts +35 -0
- package/templates/recipes/env-per-environment/.env.development +17 -0
- package/templates/recipes/env-per-environment/.env.production +20 -0
- package/templates/recipes/env-per-environment/.env.test +17 -0
- package/templates/recipes/env-per-environment/README.md +40 -0
- package/templates/recipes/feature-flags/README.md +45 -0
- package/templates/recipes/feature-flags/src/shared/services/feature-flag.service.ts +48 -0
- package/templates/recipes/feature-flags/tests/unit/shared/services/feature-flag.service.spec.ts +36 -0
- package/templates/recipes/file-upload/README.md +104 -0
- package/templates/recipes/file-upload/src/shared/interceptors/file-upload.interceptor.ts +33 -0
- package/templates/recipes/file-upload/src/shared/pipes/file-validation.pipe.ts +45 -0
- package/templates/recipes/file-upload/tests/unit/shared/pipes/file-validation.pipe.spec.ts +56 -0
- package/templates/recipes/filtering/README.md +43 -0
- package/templates/recipes/filtering/src/shared/dto/filter.dto.ts +49 -0
- package/templates/recipes/filtering/tests/unit/shared/dto/filter.dto.spec.ts +38 -0
- package/templates/recipes/graceful-shutdown/README.md +60 -0
- package/templates/recipes/graceful-shutdown/src/shared/lifecycle/shutdown.service.ts +52 -0
- package/templates/recipes/graceful-shutdown/tests/unit/shared/lifecycle/shutdown.service.spec.ts +52 -0
- package/templates/recipes/graphql-mercurius/README.md +37 -0
- package/templates/recipes/graphql-mercurius/src/infrastructure/graphql/graphql.module.ts +18 -0
- package/templates/recipes/graphql-mercurius/tests/unit/infrastructure/graphql/graphql.module.spec.ts +12 -0
- package/templates/recipes/health-checks/README.md +35 -0
- package/templates/recipes/health-checks/src/shared/health/health.controller.ts +26 -0
- package/templates/recipes/health-checks/src/shared/health/health.module.ts +9 -0
- package/templates/recipes/health-checks/tests/unit/shared/health/health.controller.spec.ts +8 -0
- package/templates/recipes/helmet/README.md +43 -0
- package/templates/recipes/http-caching/README.md +63 -0
- package/templates/recipes/http-caching/src/shared/decorators/cache-control.decorator.ts +18 -0
- package/templates/recipes/http-caching/src/shared/interceptors/cache-control.interceptor.ts +43 -0
- package/templates/recipes/http-caching/tests/unit/shared/interceptors/cache-control.interceptor.spec.ts +44 -0
- package/templates/recipes/i18n/README.md +45 -0
- package/templates/recipes/i18n/src/i18n/en/common.json +7 -0
- package/templates/recipes/i18n/src/i18n/nl/common.json +7 -0
- package/templates/recipes/i18n/src/shared/i18n/i18n.module.ts +17 -0
- package/templates/recipes/i18n/tests/unit/shared/i18n/i18n.module.spec.ts +18 -0
- package/templates/recipes/idempotency/README.md +63 -0
- package/templates/recipes/idempotency/src/shared/decorators/idempotent.decorator.ts +4 -0
- package/templates/recipes/idempotency/src/shared/middleware/idempotency.middleware.ts +63 -0
- package/templates/recipes/idempotency/tests/unit/shared/middleware/idempotency.middleware.spec.ts +56 -0
- package/templates/recipes/json-merge-patch/README.md +53 -0
- package/templates/recipes/json-merge-patch/src/shared/pipes/merge-patch.pipe.ts +11 -0
- package/templates/recipes/json-merge-patch/tests/unit/shared/pipes/merge-patch.pipe.spec.ts +30 -0
- package/templates/recipes/json-patch/README.md +54 -0
- package/templates/recipes/json-patch/src/shared/pipes/json-patch.pipe.ts +39 -0
- package/templates/recipes/json-patch/tests/unit/shared/pipes/json-patch.pipe.spec.ts +37 -0
- package/templates/recipes/jwt-auth/README.md +56 -0
- package/templates/recipes/jwt-auth/src/shared/decorators/current-user.decorator.ts +10 -0
- package/templates/recipes/jwt-auth/src/shared/decorators/public.decorator.ts +4 -0
- package/templates/recipes/jwt-auth/src/shared/guards/jwt-auth.guard.ts +24 -0
- package/templates/recipes/jwt-auth/tests/unit/shared/guards/jwt-auth.guard.spec.ts +9 -0
- package/templates/recipes/kysely/README.md +53 -0
- package/templates/recipes/kysely/src/infrastructure/database/database.module.ts +28 -0
- package/templates/recipes/kysely/src/infrastructure/database/types.ts +17 -0
- package/templates/recipes/kysely/tests/unit/infrastructure/database/database.module.spec.ts +35 -0
- package/templates/recipes/license/LICENSE.agpl3 +59 -0
- package/templates/recipes/license/LICENSE.apache +189 -0
- package/templates/recipes/license/LICENSE.bsd3 +28 -0
- package/templates/recipes/license/LICENSE.gpl3 +22 -0
- package/templates/recipes/license/LICENSE.isc +15 -0
- package/templates/recipes/license/LICENSE.mit +21 -0
- package/templates/recipes/license/LICENSE.mpl2 +24 -0
- package/templates/recipes/license/LICENSE.proprietary +76 -0
- package/templates/recipes/license/LICENSE.unlicensed +13 -0
- package/templates/recipes/license/README.md +53 -0
- package/templates/recipes/load-testing/README.md +77 -0
- package/templates/recipes/load-testing/k6/smoke.js +20 -0
- package/templates/recipes/load-testing/k6/stress.js +22 -0
- package/templates/recipes/mfa-totp/README.md +77 -0
- package/templates/recipes/mfa-totp/src/shared/auth/totp.service.ts +26 -0
- package/templates/recipes/mfa-totp/tests/unit/shared/auth/totp.service.spec.ts +65 -0
- package/templates/recipes/mikro-orm/README.md +22 -0
- package/templates/recipes/mikro-orm/src/infrastructure/database/database.module.ts +8 -0
- package/templates/recipes/mikro-orm/src/infrastructure/database/entities/.gitkeep +0 -0
- package/templates/recipes/mikro-orm/src/infrastructure/database/migrations/.gitkeep +0 -0
- package/templates/recipes/mikro-orm/src/infrastructure/database/mikro-orm.config.ts +20 -0
- package/templates/recipes/mikro-orm/tests/unit/infrastructure/database/mikro-orm.config.spec.ts +53 -0
- package/templates/recipes/mongoose/README.md +42 -0
- package/templates/recipes/mongoose/src/infrastructure/database/database.module.ts.ejs +17 -0
- package/templates/recipes/mongoose/tests/unit/infrastructure/database/database.module.spec.ts +25 -0
- package/templates/recipes/multi-tenancy/README.md +49 -0
- package/templates/recipes/multi-tenancy/src/shared/decorators/tenant.decorator.ts +14 -0
- package/templates/recipes/multi-tenancy/src/shared/middleware/tenant.middleware.ts +49 -0
- package/templates/recipes/multi-tenancy/tests/unit/shared/middleware/tenant.middleware.spec.ts +29 -0
- package/templates/recipes/nodemailer/README.md +55 -0
- package/templates/recipes/nodemailer/src/infrastructure/notifications/mail.module.ts +37 -0
- package/templates/recipes/nodemailer/tests/unit/infrastructure/notifications/mail.module.spec.ts +33 -0
- package/templates/recipes/oauth-apple/README.md +68 -0
- package/templates/recipes/oauth-apple/src/shared/auth/apple-auth.guard.ts +5 -0
- package/templates/recipes/oauth-apple/src/shared/auth/apple.strategy.ts +33 -0
- package/templates/recipes/oauth-apple/tests/unit/shared/auth/apple.strategy.spec.ts +65 -0
- package/templates/recipes/oauth-github/README.md +62 -0
- package/templates/recipes/oauth-github/src/shared/auth/github-auth.guard.ts +5 -0
- package/templates/recipes/oauth-github/src/shared/auth/github.strategy.ts +33 -0
- package/templates/recipes/oauth-github/tests/unit/shared/auth/github.strategy.spec.ts +72 -0
- package/templates/recipes/oauth-google/README.md +64 -0
- package/templates/recipes/oauth-google/src/shared/auth/google-auth.guard.ts +5 -0
- package/templates/recipes/oauth-google/src/shared/auth/google.strategy.ts +33 -0
- package/templates/recipes/oauth-google/tests/unit/shared/auth/google.strategy.spec.ts +72 -0
- package/templates/recipes/oauth2-introspection/README.md +62 -0
- package/templates/recipes/oauth2-introspection/src/shared/guards/token-introspection.guard.ts +77 -0
- package/templates/recipes/oauth2-introspection/tests/unit/shared/guards/token-introspection.guard.spec.ts +99 -0
- package/templates/recipes/opentelemetry/README.md +44 -0
- package/templates/recipes/opentelemetry/src/infrastructure/telemetry/tracing.ts +38 -0
- package/templates/recipes/opentelemetry/tests/unit/infrastructure/telemetry/tracing.spec.ts +23 -0
- package/templates/recipes/pagination/README.md +71 -0
- package/templates/recipes/pagination/src/shared/decorators/paginate.decorator.ts +25 -0
- package/templates/recipes/pagination/src/shared/dto/pagination.dto.ts +64 -0
- package/templates/recipes/pagination/src/shared/interceptors/pagination-link.interceptor.ts +31 -0
- package/templates/recipes/pagination/tests/unit/shared/dto/pagination.dto.spec.ts +56 -0
- package/templates/recipes/passport/README.md +41 -0
- package/templates/recipes/passport/src/shared/guards/local-auth.guard.ts +5 -0
- package/templates/recipes/passport/tests/unit/shared/guards/local-auth.guard.spec.ts +17 -0
- package/templates/recipes/pino/README.md +48 -0
- package/templates/recipes/pino/src/infrastructure/logging/logger.module.ts +39 -0
- package/templates/recipes/pino/tests/unit/infrastructure/logging/logger.module.spec.ts +6 -0
- package/templates/recipes/prefer-header/README.md +92 -0
- package/templates/recipes/prefer-header/src/shared/interceptors/prefer.interceptor.ts +60 -0
- package/templates/recipes/prefer-header/tests/unit/shared/interceptors/prefer.interceptor.spec.ts +44 -0
- package/templates/recipes/prisma/README.md +52 -0
- package/templates/recipes/prisma/prisma/schema.prisma.ejs +8 -0
- package/templates/recipes/prisma/src/infrastructure/database/prisma.service.ts +27 -0
- package/templates/recipes/prisma/tests/unit/infrastructure/database/prisma.service.spec.ts +21 -0
- package/templates/recipes/prometheus/README.md +54 -0
- package/templates/recipes/prometheus/src/infrastructure/metrics/metrics.controller.ts +15 -0
- package/templates/recipes/prometheus/src/infrastructure/metrics/metrics.module.ts +29 -0
- package/templates/recipes/prometheus/tests/unit/infrastructure/metrics/metrics.controller.spec.ts +22 -0
- package/templates/recipes/rabbitmq/README.md +53 -0
- package/templates/recipes/rabbitmq/src/infrastructure/queue/queue.module.ts.ejs +27 -0
- package/templates/recipes/rbac-casl/README.md +69 -0
- package/templates/recipes/rbac-casl/src/shared/auth/casl-ability.factory.ts +43 -0
- package/templates/recipes/rbac-casl/src/shared/decorators/roles.decorator.ts +5 -0
- package/templates/recipes/rbac-casl/src/shared/guards/policies.guard.ts +32 -0
- package/templates/recipes/rbac-casl/src/shared/guards/roles.guard.ts +21 -0
- package/templates/recipes/rbac-casl/tests/unit/shared/auth/casl-ability.factory.spec.ts +6 -0
- package/templates/recipes/redis-cache/README.md +55 -0
- package/templates/recipes/redis-cache/src/infrastructure/cache/cache.module.ts +26 -0
- package/templates/recipes/redis-cache/tests/unit/infrastructure/cache/cache.module.spec.ts +12 -0
- package/templates/recipes/request-context/README.md +57 -0
- package/templates/recipes/request-context/src/shared/context/request-context.module.ts +19 -0
- package/templates/recipes/request-context/tests/unit/shared/context/request-context.module.spec.ts +20 -0
- package/templates/recipes/request-logging/README.md +36 -0
- package/templates/recipes/request-logging/src/shared/middleware/request-logging.middleware.ts +40 -0
- package/templates/recipes/request-logging/tests/unit/shared/middleware/request-logging.middleware.spec.ts +64 -0
- package/templates/recipes/s3-minio/README.md +52 -0
- package/templates/recipes/s3-minio/src/infrastructure/storage/storage.module.ts +10 -0
- package/templates/recipes/s3-minio/src/infrastructure/storage/storage.service.ts +72 -0
- package/templates/recipes/s3-minio/tests/unit/infrastructure/storage/storage.service.spec.ts +23 -0
- package/templates/recipes/sdk-generation/README.md +40 -0
- package/templates/recipes/sdk-generation/openapitools.json +21 -0
- package/templates/recipes/sendgrid/README.md +45 -0
- package/templates/recipes/sendgrid/src/infrastructure/notifications/sendgrid.service.ts +60 -0
- package/templates/recipes/sendgrid/tests/unit/infrastructure/notifications/sendgrid.service.spec.ts +59 -0
- package/templates/recipes/sentry/README.md +49 -0
- package/templates/recipes/sentry/src/infrastructure/sentry/sentry.filter.ts +34 -0
- package/templates/recipes/sentry/src/infrastructure/sentry/sentry.module.ts +23 -0
- package/templates/recipes/sentry/tests/unit/infrastructure/sentry/sentry.filter.spec.ts +50 -0
- package/templates/recipes/seq2/README.md +41 -0
- package/templates/recipes/seq2/src/infrastructure/logging/seq.transport.ts +57 -0
- package/templates/recipes/seq2/tests/unit/infrastructure/logging/seq.transport.spec.ts +53 -0
- package/templates/recipes/serialization-groups/README.md +105 -0
- package/templates/recipes/serialization-groups/src/shared/interceptors/serialize.interceptor.ts +29 -0
- package/templates/recipes/serialization-groups/tests/unit/shared/interceptors/serialize.interceptor.spec.ts +48 -0
- package/templates/recipes/soft-delete/README.md +71 -0
- package/templates/recipes/soft-delete/src/shared/decorators/with-deleted.decorator.ts +4 -0
- package/templates/recipes/soft-delete/src/shared/entities/soft-deletable.entity.ts +20 -0
- package/templates/recipes/soft-delete/tests/unit/shared/entities/soft-deletable.entity.spec.ts +35 -0
- package/templates/recipes/sse/README.md +43 -0
- package/templates/recipes/sse/src/shared/gateways/events.sse.controller.ts +21 -0
- package/templates/recipes/sse/tests/unit/shared/gateways/events.sse.controller.spec.ts +32 -0
- package/templates/recipes/swagger/README.md +42 -0
- package/templates/recipes/swagger/src/main.swagger.ts.ejs +20 -0
- package/templates/recipes/swagger/tests/unit/main.swagger.spec.ts +5 -0
- package/templates/recipes/throttler/README.md +49 -0
- package/templates/recipes/throttler/src/shared/guards/throttle.config.ts +33 -0
- package/templates/recipes/throttler/tests/unit/shared/guards/throttle.spec.ts +5 -0
- package/templates/recipes/transactional-outbox/README.md +98 -0
- package/templates/recipes/transactional-outbox/src/infrastructure/outbox/outbox.entity.ts +30 -0
- package/templates/recipes/transactional-outbox/src/infrastructure/outbox/outbox.service.ts +21 -0
- package/templates/recipes/transactional-outbox/tests/unit/infrastructure/outbox/outbox.service.spec.ts +38 -0
- package/templates/recipes/typeorm-mysql/README.md +48 -0
- package/templates/recipes/typeorm-mysql/src/infrastructure/database/database.module.ts.ejs +24 -0
- package/templates/recipes/typeorm-postgres/README.md +101 -0
- package/templates/recipes/typeorm-postgres/src/infrastructure/database/data-source.ts.ejs +14 -0
- package/templates/recipes/typeorm-postgres/src/infrastructure/database/database.module.ts.ejs +24 -0
- package/templates/recipes/typeorm-postgres/src/infrastructure/database/entities/.gitkeep +0 -0
- package/templates/recipes/typeorm-postgres/src/infrastructure/database/entities/index.ts +7 -0
- package/templates/recipes/typeorm-postgres/src/infrastructure/database/migrations/.gitkeep +0 -0
- package/templates/recipes/typeorm-postgres/src/infrastructure/database/migrations/index.ts +10 -0
- package/templates/recipes/typeorm-postgres/tests/unit/infrastructure/database/database.module.spec.ts +11 -0
- package/templates/recipes/webhooks/README.md +76 -0
- package/templates/recipes/webhooks/src/infrastructure/webhooks/webhook.service.ts +53 -0
- package/templates/recipes/webhooks/tests/unit/infrastructure/webhooks/webhook.service.spec.ts +31 -0
- package/templates/recipes/websockets/README.md +44 -0
- package/templates/recipes/websockets/src/shared/gateways/events.gateway.ts +55 -0
- package/templates/recipes/websockets/tests/unit/shared/gateways/events.gateway.spec.ts +23 -0
- package/templates/recipes/winston/README.md +45 -0
- package/templates/recipes/winston/src/infrastructure/logging/logger.module.ts +34 -0
- package/templates/recipes/winston/tests/unit/infrastructure/logging/logger.module.spec.ts +12 -0
- package/templates/recipes/worker-threads/README.md +71 -0
- package/templates/recipes/worker-threads/src/shared/utils/worker-pool.ts +59 -0
- package/templates/recipes/worker-threads/tests/unit/shared/utils/worker-pool.spec.ts +36 -0
|
@@ -0,0 +1,3647 @@
|
|
|
1
|
+
const recipes = [
|
|
2
|
+
// ─── Database ───────────────────────────────────────────────────────
|
|
3
|
+
{
|
|
4
|
+
id: 'typeorm-postgres',
|
|
5
|
+
name: 'TypeORM + PostgreSQL',
|
|
6
|
+
description: 'TypeORM integration with PostgreSQL driver',
|
|
7
|
+
category: 'Database',
|
|
8
|
+
dependencies: {
|
|
9
|
+
'@nestjs/typeorm': '10.0.2',
|
|
10
|
+
typeorm: '0.3.20',
|
|
11
|
+
pg: '8.13.1',
|
|
12
|
+
},
|
|
13
|
+
devDependencies: {},
|
|
14
|
+
envVars: [
|
|
15
|
+
{ key: 'DB_HOST', defaultValue: 'localhost', description: 'PostgreSQL host' },
|
|
16
|
+
{ key: 'DB_PORT', defaultValue: '5432', description: 'PostgreSQL port' },
|
|
17
|
+
{ key: 'DB_USERNAME', defaultValue: 'postgres', description: 'PostgreSQL username' },
|
|
18
|
+
{ key: 'DB_PASSWORD', defaultValue: 'postgres', description: 'PostgreSQL password' },
|
|
19
|
+
{ key: 'DB_NAME', defaultValue: 'app', description: 'PostgreSQL database name' },
|
|
20
|
+
],
|
|
21
|
+
conflicts: ['typeorm-mysql', 'prisma', 'mongoose', 'drizzle-postgres', 'kysely', 'mikro-orm'],
|
|
22
|
+
requires: [],
|
|
23
|
+
compatibleWith: 'all',
|
|
24
|
+
templateDir: 'typeorm-postgres',
|
|
25
|
+
claudeMdSection: [
|
|
26
|
+
'## TypeORM + PostgreSQL',
|
|
27
|
+
'Entities live in `src/<module>/entities/`. Use migrations for schema changes — never `synchronize: true` in production.',
|
|
28
|
+
'Run migrations: `pnpm typeorm migration:run`. Generate: `pnpm typeorm migration:generate`.',
|
|
29
|
+
].join('\n'),
|
|
30
|
+
cursorRules: [
|
|
31
|
+
'Use TypeORM repository pattern via @InjectRepository(). Always create and run migrations for schema changes.',
|
|
32
|
+
'Place entities in the module they belong to under entities/. Use column decorators for all fields.',
|
|
33
|
+
].join('\n'),
|
|
34
|
+
copilotInstructions: [
|
|
35
|
+
'TypeORM with PostgreSQL is used for database access. Inject repositories with @InjectRepository().',
|
|
36
|
+
'Never use synchronize:true in production. Generate migrations with typeorm CLI.',
|
|
37
|
+
].join('\n'),
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: 'typeorm-mysql',
|
|
41
|
+
name: 'TypeORM + MySQL',
|
|
42
|
+
description: 'TypeORM integration with MySQL driver',
|
|
43
|
+
category: 'Database',
|
|
44
|
+
dependencies: {
|
|
45
|
+
'@nestjs/typeorm': '10.0.2',
|
|
46
|
+
typeorm: '0.3.20',
|
|
47
|
+
mysql2: '3.11.5',
|
|
48
|
+
},
|
|
49
|
+
devDependencies: {},
|
|
50
|
+
envVars: [
|
|
51
|
+
{ key: 'DB_HOST', defaultValue: 'localhost', description: 'MySQL host' },
|
|
52
|
+
{ key: 'DB_PORT', defaultValue: '3306', description: 'MySQL port' },
|
|
53
|
+
{ key: 'DB_USERNAME', defaultValue: 'root', description: 'MySQL username' },
|
|
54
|
+
{ key: 'DB_PASSWORD', defaultValue: 'root', description: 'MySQL password' },
|
|
55
|
+
{ key: 'DB_NAME', defaultValue: 'app', description: 'MySQL database name' },
|
|
56
|
+
],
|
|
57
|
+
conflicts: ['typeorm-postgres', 'prisma', 'mongoose', 'drizzle-postgres', 'kysely', 'mikro-orm'],
|
|
58
|
+
requires: [],
|
|
59
|
+
compatibleWith: 'all',
|
|
60
|
+
templateDir: 'typeorm-mysql',
|
|
61
|
+
claudeMdSection: [
|
|
62
|
+
'## TypeORM + MySQL',
|
|
63
|
+
'Entities live in `src/<module>/entities/`. Use migrations for schema changes — never `synchronize: true` in production.',
|
|
64
|
+
'Run migrations: `pnpm typeorm migration:run`. Generate: `pnpm typeorm migration:generate`.',
|
|
65
|
+
].join('\n'),
|
|
66
|
+
cursorRules: [
|
|
67
|
+
'Use TypeORM repository pattern via @InjectRepository(). Always create and run migrations for schema changes.',
|
|
68
|
+
'Place entities in the module they belong to under entities/. Use column decorators for all fields.',
|
|
69
|
+
].join('\n'),
|
|
70
|
+
copilotInstructions: [
|
|
71
|
+
'TypeORM with MySQL is used for database access. Inject repositories with @InjectRepository().',
|
|
72
|
+
'Never use synchronize:true in production. Generate migrations with typeorm CLI.',
|
|
73
|
+
].join('\n'),
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: 'prisma',
|
|
77
|
+
name: 'Prisma',
|
|
78
|
+
description: 'Prisma ORM with schema-first approach and type-safe client',
|
|
79
|
+
category: 'Database',
|
|
80
|
+
dependencies: {
|
|
81
|
+
'@prisma/client': '6.2.1',
|
|
82
|
+
},
|
|
83
|
+
devDependencies: {
|
|
84
|
+
prisma: '6.2.1',
|
|
85
|
+
},
|
|
86
|
+
envVars: [
|
|
87
|
+
{
|
|
88
|
+
key: 'DATABASE_URL',
|
|
89
|
+
defaultValue: 'postgresql://postgres:postgres@localhost:5432/app',
|
|
90
|
+
description: 'Prisma database connection URL',
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
conflicts: ['typeorm-postgres', 'typeorm-mysql', 'mongoose', 'drizzle-postgres', 'kysely', 'mikro-orm'],
|
|
94
|
+
requires: [],
|
|
95
|
+
compatibleWith: 'all',
|
|
96
|
+
templateDir: 'prisma',
|
|
97
|
+
claudeMdSection: [
|
|
98
|
+
'## Prisma',
|
|
99
|
+
'Schema lives in `prisma/schema.prisma`. Run `pnpm prisma generate` after schema changes.',
|
|
100
|
+
'Migrations: `pnpm prisma migrate dev`. Inject `PrismaService` for database access.',
|
|
101
|
+
].join('\n'),
|
|
102
|
+
cursorRules: [
|
|
103
|
+
'Use PrismaService (extends PrismaClient) for all database access. Edit prisma/schema.prisma for model changes.',
|
|
104
|
+
'Always run `prisma generate` after schema edits. Use Prisma migrate for schema migrations.',
|
|
105
|
+
].join('\n'),
|
|
106
|
+
copilotInstructions: [
|
|
107
|
+
'Prisma ORM is used. Models are defined in prisma/schema.prisma. Inject PrismaService for queries.',
|
|
108
|
+
'After modifying the schema, run `pnpm prisma generate` then `pnpm prisma migrate dev`.',
|
|
109
|
+
].join('\n'),
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: 'mongoose',
|
|
113
|
+
name: 'Mongoose',
|
|
114
|
+
description: 'MongoDB integration with Mongoose ODM',
|
|
115
|
+
category: 'Database',
|
|
116
|
+
dependencies: {
|
|
117
|
+
'@nestjs/mongoose': '10.1.0',
|
|
118
|
+
mongoose: '8.9.5',
|
|
119
|
+
},
|
|
120
|
+
devDependencies: {},
|
|
121
|
+
envVars: [
|
|
122
|
+
{
|
|
123
|
+
key: 'MONGO_URI',
|
|
124
|
+
defaultValue: 'mongodb://localhost:27017/app',
|
|
125
|
+
description: 'MongoDB connection URI',
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
conflicts: ['typeorm-postgres', 'typeorm-mysql', 'prisma', 'drizzle-postgres', 'kysely', 'mikro-orm'],
|
|
129
|
+
requires: [],
|
|
130
|
+
compatibleWith: 'all',
|
|
131
|
+
templateDir: 'mongoose',
|
|
132
|
+
claudeMdSection: [
|
|
133
|
+
'## Mongoose',
|
|
134
|
+
'Schemas live in `src/<module>/schemas/`. Use @Schema() and @Prop() decorators.',
|
|
135
|
+
'Inject models with @InjectModel(). Use lean() for read-only queries.',
|
|
136
|
+
].join('\n'),
|
|
137
|
+
cursorRules: [
|
|
138
|
+
'Use @Schema() decorator classes for Mongoose schemas. Inject models via @InjectModel(SchemaName.name).',
|
|
139
|
+
'Place schemas alongside their module. Prefer lean() queries when documents are read-only.',
|
|
140
|
+
].join('\n'),
|
|
141
|
+
copilotInstructions: [
|
|
142
|
+
'Mongoose ODM is used with NestJS decorators. Define schemas with @Schema()/@Prop() in schemas/ folders.',
|
|
143
|
+
'Inject models via @InjectModel(). Use lean() for read-only queries for better performance.',
|
|
144
|
+
].join('\n'),
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
id: 'drizzle-postgres',
|
|
148
|
+
name: 'Drizzle ORM + PostgreSQL',
|
|
149
|
+
description: 'Lightweight type-safe ORM with best-in-class performance',
|
|
150
|
+
category: 'Database',
|
|
151
|
+
dependencies: {
|
|
152
|
+
'drizzle-orm': '0.44.2',
|
|
153
|
+
pg: '8.13.1',
|
|
154
|
+
},
|
|
155
|
+
devDependencies: {
|
|
156
|
+
'drizzle-kit': '0.31.1',
|
|
157
|
+
},
|
|
158
|
+
envVars: [
|
|
159
|
+
{
|
|
160
|
+
key: 'DATABASE_URL',
|
|
161
|
+
defaultValue: 'postgres://postgres:postgres@localhost:5432/app',
|
|
162
|
+
description: 'PostgreSQL connection URL',
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
conflicts: ['typeorm-postgres', 'typeorm-mysql', 'prisma', 'mongoose', 'kysely', 'mikro-orm'],
|
|
166
|
+
requires: [],
|
|
167
|
+
compatibleWith: 'all',
|
|
168
|
+
templateDir: 'drizzle-postgres',
|
|
169
|
+
claudeMdSection: [
|
|
170
|
+
'## Drizzle ORM',
|
|
171
|
+
'Schema in `src/infrastructure/database/schema/`. Run `pnpm drizzle:generate` after schema changes, then `pnpm drizzle:migrate`.',
|
|
172
|
+
].join('\n'),
|
|
173
|
+
cursorRules: 'Use Drizzle schema definitions in src/infrastructure/database/schema/. Use drizzle-kit for migrations. Queries use the db object from drizzle().',
|
|
174
|
+
copilotInstructions: 'Drizzle ORM for database. Schema files in src/infrastructure/database/schema/. Use drizzle-kit generate and migrate for schema changes.',
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
id: 'kysely',
|
|
178
|
+
name: 'Kysely',
|
|
179
|
+
description: 'Type-safe SQL query builder with zero overhead',
|
|
180
|
+
category: 'Database',
|
|
181
|
+
dependencies: {
|
|
182
|
+
kysely: '0.27.6',
|
|
183
|
+
pg: '8.13.1',
|
|
184
|
+
},
|
|
185
|
+
devDependencies: {
|
|
186
|
+
'kysely-ctl': '0.9.0',
|
|
187
|
+
},
|
|
188
|
+
envVars: [
|
|
189
|
+
{
|
|
190
|
+
key: 'DATABASE_URL',
|
|
191
|
+
defaultValue: 'postgres://postgres:postgres@localhost:5432/app',
|
|
192
|
+
description: 'PostgreSQL connection URL',
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
conflicts: [
|
|
196
|
+
'typeorm-postgres',
|
|
197
|
+
'typeorm-mysql',
|
|
198
|
+
'prisma',
|
|
199
|
+
'mongoose',
|
|
200
|
+
'drizzle-postgres',
|
|
201
|
+
'mikro-orm',
|
|
202
|
+
],
|
|
203
|
+
requires: [],
|
|
204
|
+
compatibleWith: 'all',
|
|
205
|
+
templateDir: 'kysely',
|
|
206
|
+
claudeMdSection: '## Kysely\nType-safe SQL query builder. Define database types in `src/infrastructure/database/types.ts`. Use the db instance for queries. Migrations via kysely-ctl.',
|
|
207
|
+
cursorRules: 'Use Kysely for type-safe SQL. Define table interfaces in types.ts. Use db.selectFrom(), db.insertInto(), etc. No ORM magic — you write the SQL.',
|
|
208
|
+
copilotInstructions: 'Kysely is a type-safe SQL query builder. Database types in src/infrastructure/database/types.ts. Use selectFrom/insertInto/updateTable/deleteFrom methods.',
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
id: 'mikro-orm',
|
|
212
|
+
name: 'MikroORM + PostgreSQL',
|
|
213
|
+
description: 'Data Mapper ORM with Unit of Work and Identity Map for DDD',
|
|
214
|
+
category: 'Database',
|
|
215
|
+
dependencies: {
|
|
216
|
+
'@mikro-orm/core': '6.5.3',
|
|
217
|
+
'@mikro-orm/nestjs': '6.1.1',
|
|
218
|
+
'@mikro-orm/postgresql': '6.5.3',
|
|
219
|
+
'@mikro-orm/migrations': '6.5.3',
|
|
220
|
+
},
|
|
221
|
+
devDependencies: {
|
|
222
|
+
'@mikro-orm/cli': '6.5.3',
|
|
223
|
+
},
|
|
224
|
+
envVars: [
|
|
225
|
+
{ key: 'DB_HOST', defaultValue: 'localhost', description: 'PostgreSQL host' },
|
|
226
|
+
{ key: 'DB_PORT', defaultValue: '5432', description: 'PostgreSQL port' },
|
|
227
|
+
{ key: 'DB_NAME', defaultValue: 'app', description: 'PostgreSQL database name' },
|
|
228
|
+
{ key: 'DB_USERNAME', defaultValue: 'postgres', description: 'PostgreSQL username' },
|
|
229
|
+
{ key: 'DB_PASSWORD', defaultValue: 'postgres', description: 'PostgreSQL password' },
|
|
230
|
+
],
|
|
231
|
+
conflicts: ['typeorm-postgres', 'typeorm-mysql', 'prisma', 'mongoose', 'drizzle-postgres', 'kysely'],
|
|
232
|
+
requires: [],
|
|
233
|
+
compatibleWith: 'all',
|
|
234
|
+
templateDir: 'mikro-orm',
|
|
235
|
+
claudeMdSection: '## MikroORM\nEntities in `src/infrastructure/database/entities/`. Uses Unit of Work pattern — changes are flushed via `em.flush()`. Run `pnpm mikro-orm migration:create` for migrations.',
|
|
236
|
+
cursorRules: 'Use MikroORM entity manager (em) for queries. Entities use @Entity() decorator. Changes persist on em.flush(). Use @mikro-orm/cli for migrations.',
|
|
237
|
+
copilotInstructions: 'MikroORM with Unit of Work pattern. Use EntityManager for queries. Call em.flush() to persist. Migrations via @mikro-orm/cli.',
|
|
238
|
+
},
|
|
239
|
+
// ─── Cache ──────────────────────────────────────────────────────────
|
|
240
|
+
{
|
|
241
|
+
id: 'redis-cache',
|
|
242
|
+
name: 'Redis Cache',
|
|
243
|
+
description: 'Redis-backed caching with cache-manager',
|
|
244
|
+
category: 'Cache',
|
|
245
|
+
dependencies: {
|
|
246
|
+
'@nestjs/cache-manager': '2.3.0',
|
|
247
|
+
'cache-manager-redis-yet': '5.1.5',
|
|
248
|
+
ioredis: '5.4.2',
|
|
249
|
+
},
|
|
250
|
+
devDependencies: {},
|
|
251
|
+
envVars: [
|
|
252
|
+
{ key: 'REDIS_HOST', defaultValue: 'localhost', description: 'Redis host' },
|
|
253
|
+
{ key: 'REDIS_PORT', defaultValue: '6379', description: 'Redis port' },
|
|
254
|
+
{ key: 'REDIS_PASSWORD', defaultValue: '', description: 'Redis password (empty for local)' },
|
|
255
|
+
{ key: 'REDIS_TTL', defaultValue: '300', description: 'Default cache TTL in seconds' },
|
|
256
|
+
],
|
|
257
|
+
conflicts: [],
|
|
258
|
+
requires: [],
|
|
259
|
+
compatibleWith: [
|
|
260
|
+
'http-api',
|
|
261
|
+
'aws-lambda',
|
|
262
|
+
'microservice',
|
|
263
|
+
'scheduled-worker',
|
|
264
|
+
'monorepo',
|
|
265
|
+
'full-stack',
|
|
266
|
+
],
|
|
267
|
+
templateDir: 'redis-cache',
|
|
268
|
+
claudeMdSection: [
|
|
269
|
+
'## Redis Cache',
|
|
270
|
+
'Use @UseInterceptors(CacheInterceptor) for automatic route caching or inject CACHE_MANAGER directly.',
|
|
271
|
+
'Default TTL is configured in the CacheModule registration.',
|
|
272
|
+
].join('\n'),
|
|
273
|
+
cursorRules: [
|
|
274
|
+
'Use @CacheKey() and @CacheTTL() decorators on controller methods. Inject CACHE_MANAGER for manual cache operations.',
|
|
275
|
+
'Invalidate cache explicitly when underlying data changes.',
|
|
276
|
+
].join('\n'),
|
|
277
|
+
copilotInstructions: [
|
|
278
|
+
'Redis caching is configured via @nestjs/cache-manager. Use CacheInterceptor for automatic caching.',
|
|
279
|
+
'For manual control, inject CACHE_MANAGER token. Always invalidate stale cache on writes.',
|
|
280
|
+
].join('\n'),
|
|
281
|
+
},
|
|
282
|
+
// ─── Queue ──────────────────────────────────────────────────────────
|
|
283
|
+
{
|
|
284
|
+
id: 'rabbitmq',
|
|
285
|
+
name: 'RabbitMQ',
|
|
286
|
+
description: 'RabbitMQ message broker integration',
|
|
287
|
+
category: 'Queue',
|
|
288
|
+
dependencies: {
|
|
289
|
+
'@nestjs/microservices': '10.4.15',
|
|
290
|
+
amqplib: '0.10.5',
|
|
291
|
+
},
|
|
292
|
+
devDependencies: {
|
|
293
|
+
'@types/amqplib': '0.10.6',
|
|
294
|
+
},
|
|
295
|
+
envVars: [
|
|
296
|
+
{
|
|
297
|
+
key: 'RABBITMQ_URL',
|
|
298
|
+
defaultValue: 'amqp://guest:guest@localhost:5672',
|
|
299
|
+
description: 'RabbitMQ connection URL',
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
conflicts: [],
|
|
303
|
+
requires: [],
|
|
304
|
+
compatibleWith: [
|
|
305
|
+
'http-api',
|
|
306
|
+
'aws-lambda',
|
|
307
|
+
'microservice',
|
|
308
|
+
'scheduled-worker',
|
|
309
|
+
'monorepo',
|
|
310
|
+
'full-stack',
|
|
311
|
+
],
|
|
312
|
+
templateDir: 'rabbitmq',
|
|
313
|
+
claudeMdSection: [
|
|
314
|
+
'## RabbitMQ',
|
|
315
|
+
'Use @MessagePattern() for request/response and @EventPattern() for fire-and-forget.',
|
|
316
|
+
'Configure queues in the microservice module registration. Use durable queues in production.',
|
|
317
|
+
].join('\n'),
|
|
318
|
+
cursorRules: [
|
|
319
|
+
'Use @MessagePattern() for RPC and @EventPattern() for events. Always acknowledge messages.',
|
|
320
|
+
'Define message contracts as typed interfaces. Handle deserialization errors gracefully.',
|
|
321
|
+
].join('\n'),
|
|
322
|
+
copilotInstructions: [
|
|
323
|
+
'RabbitMQ is integrated via @nestjs/microservices. Use @MessagePattern/@EventPattern decorators.',
|
|
324
|
+
'Always define typed DTOs for message payloads. Use durable queues and handle dead-letter routing.',
|
|
325
|
+
].join('\n'),
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
id: 'bullmq',
|
|
329
|
+
name: 'BullMQ',
|
|
330
|
+
description: 'Redis-backed job queue with BullMQ',
|
|
331
|
+
category: 'Queue',
|
|
332
|
+
dependencies: {
|
|
333
|
+
'@nestjs/bullmq': '10.2.3',
|
|
334
|
+
bullmq: '5.34.8',
|
|
335
|
+
},
|
|
336
|
+
devDependencies: {},
|
|
337
|
+
envVars: [
|
|
338
|
+
{ key: 'REDIS_HOST', defaultValue: 'localhost', description: 'Redis host for BullMQ' },
|
|
339
|
+
{ key: 'REDIS_PORT', defaultValue: '6379', description: 'Redis port for BullMQ' },
|
|
340
|
+
],
|
|
341
|
+
conflicts: [],
|
|
342
|
+
requires: [],
|
|
343
|
+
compatibleWith: [
|
|
344
|
+
'http-api',
|
|
345
|
+
'aws-lambda',
|
|
346
|
+
'microservice',
|
|
347
|
+
'scheduled-worker',
|
|
348
|
+
'monorepo',
|
|
349
|
+
'full-stack',
|
|
350
|
+
],
|
|
351
|
+
templateDir: 'bullmq',
|
|
352
|
+
claudeMdSection: [
|
|
353
|
+
'## BullMQ',
|
|
354
|
+
'Define processors with @Processor() and handle jobs with @WorkerHost. Add jobs via inject Queue.',
|
|
355
|
+
'Configure concurrency and rate limiting per queue. Use named jobs for routing.',
|
|
356
|
+
].join('\n'),
|
|
357
|
+
cursorRules: [
|
|
358
|
+
'Create processors extending WorkerHost with @Processor(). Inject Queue to add jobs.',
|
|
359
|
+
'Use named jobs and handle failed jobs with @OnWorkerEvent(). Set appropriate concurrency.',
|
|
360
|
+
].join('\n'),
|
|
361
|
+
copilotInstructions: [
|
|
362
|
+
'BullMQ is used for background jobs. Extend WorkerHost with @Processor() for consumers.',
|
|
363
|
+
'Inject Queue to enqueue jobs. Handle retries and failures with @OnWorkerEvent decorators.',
|
|
364
|
+
].join('\n'),
|
|
365
|
+
},
|
|
366
|
+
// ─── Auth ───────────────────────────────────────────────────────────
|
|
367
|
+
{
|
|
368
|
+
id: 'jwt-auth',
|
|
369
|
+
name: 'JWT Authentication',
|
|
370
|
+
description: 'JWT-based authentication with Passport',
|
|
371
|
+
category: 'Auth',
|
|
372
|
+
dependencies: {
|
|
373
|
+
'@nestjs/jwt': '10.2.0',
|
|
374
|
+
'@nestjs/passport': '10.0.3',
|
|
375
|
+
'passport-jwt': '4.0.1',
|
|
376
|
+
},
|
|
377
|
+
devDependencies: {
|
|
378
|
+
'@types/passport-jwt': '4.0.1',
|
|
379
|
+
},
|
|
380
|
+
envVars: [
|
|
381
|
+
{
|
|
382
|
+
key: 'JWT_SECRET',
|
|
383
|
+
defaultValue: 'change-me-in-production',
|
|
384
|
+
description: 'JWT signing secret',
|
|
385
|
+
},
|
|
386
|
+
{ key: 'JWT_EXPIRES_IN', defaultValue: '3600s', description: 'JWT token expiration' },
|
|
387
|
+
],
|
|
388
|
+
conflicts: [],
|
|
389
|
+
requires: [],
|
|
390
|
+
compatibleWith: ['http-api', 'aws-lambda', 'microservice', 'full-stack', 'monorepo'],
|
|
391
|
+
templateDir: 'jwt-auth',
|
|
392
|
+
claudeMdSection: [
|
|
393
|
+
'## JWT Authentication',
|
|
394
|
+
'Use @UseGuards(JwtAuthGuard) on protected routes. The JWT strategy extracts and validates tokens.',
|
|
395
|
+
'Access the authenticated user with @CurrentUser() parameter decorator.',
|
|
396
|
+
].join('\n'),
|
|
397
|
+
cursorRules: [
|
|
398
|
+
'Apply JwtAuthGuard to protected endpoints. Use @CurrentUser() to access the authenticated user.',
|
|
399
|
+
'Never hardcode JWT_SECRET — always use ConfigService. Set short expiration and use refresh tokens.',
|
|
400
|
+
].join('\n'),
|
|
401
|
+
copilotInstructions: [
|
|
402
|
+
'JWT auth is configured with @nestjs/jwt and passport-jwt. Protect routes with @UseGuards(JwtAuthGuard).',
|
|
403
|
+
'Use @CurrentUser() decorator to get the authenticated user. JWT_SECRET comes from environment.',
|
|
404
|
+
].join('\n'),
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
id: 'passport',
|
|
408
|
+
name: 'Passport Strategies',
|
|
409
|
+
description: 'Passport.js with local and JWT strategies',
|
|
410
|
+
category: 'Auth',
|
|
411
|
+
dependencies: {
|
|
412
|
+
'@nestjs/passport': '10.0.3',
|
|
413
|
+
'passport-local': '1.0.0',
|
|
414
|
+
'passport-jwt': '4.0.1',
|
|
415
|
+
},
|
|
416
|
+
devDependencies: {
|
|
417
|
+
'@types/passport-local': '1.0.38',
|
|
418
|
+
'@types/passport-jwt': '4.0.1',
|
|
419
|
+
},
|
|
420
|
+
envVars: [
|
|
421
|
+
{
|
|
422
|
+
key: 'JWT_SECRET',
|
|
423
|
+
defaultValue: 'change-me-in-production',
|
|
424
|
+
description: 'JWT signing secret',
|
|
425
|
+
},
|
|
426
|
+
],
|
|
427
|
+
conflicts: [],
|
|
428
|
+
requires: [],
|
|
429
|
+
compatibleWith: ['http-api', 'aws-lambda', 'microservice', 'full-stack', 'monorepo'],
|
|
430
|
+
templateDir: 'passport',
|
|
431
|
+
claudeMdSection: [
|
|
432
|
+
'## Passport Strategies',
|
|
433
|
+
'Local strategy handles username/password login. JWT strategy validates bearer tokens.',
|
|
434
|
+
'Create custom strategies by extending PassportStrategy(Strategy).',
|
|
435
|
+
].join('\n'),
|
|
436
|
+
cursorRules: [
|
|
437
|
+
'Extend PassportStrategy for custom auth strategies. Use @UseGuards(AuthGuard("strategy-name")).',
|
|
438
|
+
'The local strategy validates credentials; JWT strategy protects subsequent requests.',
|
|
439
|
+
].join('\n'),
|
|
440
|
+
copilotInstructions: [
|
|
441
|
+
'Passport.js is integrated via @nestjs/passport with local and JWT strategies.',
|
|
442
|
+
'Use AuthGuard("local") for login and AuthGuard("jwt") for protected routes.',
|
|
443
|
+
].join('\n'),
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
id: 'auth-flows',
|
|
447
|
+
name: 'Auth Flows',
|
|
448
|
+
description: 'Complete signup, email verification, and password reset flows',
|
|
449
|
+
category: 'Auth',
|
|
450
|
+
dependencies: {
|
|
451
|
+
'@nestjs/jwt': '10.2.0',
|
|
452
|
+
bcrypt: '6.0.0',
|
|
453
|
+
uuid: '11.1.0',
|
|
454
|
+
},
|
|
455
|
+
devDependencies: {
|
|
456
|
+
'@types/bcrypt': '5.0.2',
|
|
457
|
+
},
|
|
458
|
+
envVars: [
|
|
459
|
+
{
|
|
460
|
+
key: 'AUTH_JWT_SECRET',
|
|
461
|
+
defaultValue: 'change-me-in-production',
|
|
462
|
+
description: 'JWT secret used for auth flow tokens (email verification, password reset)',
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
key: 'AUTH_EMAIL_VERIFICATION_URL',
|
|
466
|
+
defaultValue: 'http://localhost:3000/verify-email',
|
|
467
|
+
description: 'Base URL for email verification links sent to users',
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
key: 'AUTH_PASSWORD_RESET_URL',
|
|
471
|
+
defaultValue: 'http://localhost:3000/reset-password',
|
|
472
|
+
description: 'Base URL for password reset links sent to users',
|
|
473
|
+
},
|
|
474
|
+
],
|
|
475
|
+
conflicts: [],
|
|
476
|
+
requires: ['jwt-auth'],
|
|
477
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
478
|
+
templateDir: 'auth-flows',
|
|
479
|
+
claudeMdSection: [
|
|
480
|
+
'## Auth Flows',
|
|
481
|
+
'AuthService handles signup, login, email verification, and password reset.',
|
|
482
|
+
'Passwords are hashed with bcrypt. Wire in your own UserRepository and email transport.',
|
|
483
|
+
].join('\n'),
|
|
484
|
+
cursorRules: [
|
|
485
|
+
'AuthService provides signup, login, verifyEmail, forgotPassword, resetPassword.',
|
|
486
|
+
'Replace the in-memory user store with a real UserRepository. Plug in your email service for transactional emails.',
|
|
487
|
+
].join('\n'),
|
|
488
|
+
copilotInstructions: [
|
|
489
|
+
'Auth flows use bcrypt for password hashing and uuid for token generation.',
|
|
490
|
+
'Wire AuthService to a real user repository and email service before going to production.',
|
|
491
|
+
].join('\n'),
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
id: 'api-keys',
|
|
495
|
+
name: 'API Key Authentication',
|
|
496
|
+
description: 'API key-based authentication with custom guard',
|
|
497
|
+
category: 'Auth',
|
|
498
|
+
dependencies: {},
|
|
499
|
+
devDependencies: {},
|
|
500
|
+
envVars: [
|
|
501
|
+
{ key: 'API_KEY_HEADER', defaultValue: 'x-api-key', description: 'Header name for API key' },
|
|
502
|
+
],
|
|
503
|
+
conflicts: [],
|
|
504
|
+
requires: [],
|
|
505
|
+
compatibleWith: ['http-api', 'aws-lambda', 'microservice', 'full-stack', 'monorepo'],
|
|
506
|
+
templateDir: 'api-keys',
|
|
507
|
+
claudeMdSection: [
|
|
508
|
+
'## API Key Authentication',
|
|
509
|
+
'Apply @UseGuards(ApiKeyGuard) to routes requiring API key auth.',
|
|
510
|
+
'API keys are validated against stored keys. Rotate keys without downtime by supporting multiple active keys.',
|
|
511
|
+
].join('\n'),
|
|
512
|
+
cursorRules: [
|
|
513
|
+
'Use ApiKeyGuard for machine-to-machine authentication. API keys are sent in the x-api-key header.',
|
|
514
|
+
'Store hashed API keys in the database. Support key rotation with multiple active keys.',
|
|
515
|
+
].join('\n'),
|
|
516
|
+
copilotInstructions: [
|
|
517
|
+
'API key auth uses a custom guard. Apply @UseGuards(ApiKeyGuard) to protect routes.',
|
|
518
|
+
'Keys are validated from the x-api-key header. Store only hashed keys in the database.',
|
|
519
|
+
].join('\n'),
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
id: 'oauth2-introspection',
|
|
523
|
+
name: 'OAuth 2.0 Token Introspection',
|
|
524
|
+
description: 'RFC 7662 token introspection for validating opaque tokens',
|
|
525
|
+
category: 'Auth',
|
|
526
|
+
dependencies: {},
|
|
527
|
+
devDependencies: {},
|
|
528
|
+
envVars: [
|
|
529
|
+
{
|
|
530
|
+
key: 'OAUTH2_INTROSPECTION_URL',
|
|
531
|
+
defaultValue: 'https://auth.example.com/oauth2/introspect',
|
|
532
|
+
description: 'Token introspection endpoint URL',
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
key: 'OAUTH2_CLIENT_ID',
|
|
536
|
+
defaultValue: '',
|
|
537
|
+
description: 'OAuth 2.0 client ID for introspection',
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
key: 'OAUTH2_CLIENT_SECRET',
|
|
541
|
+
defaultValue: '',
|
|
542
|
+
description: 'OAuth 2.0 client secret for introspection',
|
|
543
|
+
},
|
|
544
|
+
],
|
|
545
|
+
conflicts: [],
|
|
546
|
+
requires: [],
|
|
547
|
+
compatibleWith: ['http-api', 'aws-lambda', 'microservice', 'full-stack', 'monorepo'],
|
|
548
|
+
templateDir: 'oauth2-introspection',
|
|
549
|
+
claudeMdSection: '## OAuth 2.0 Token Introspection\nUse the TokenIntrospectionGuard on routes that accept opaque OAuth tokens. The guard calls the introspection endpoint per RFC 7662.',
|
|
550
|
+
cursorRules: 'Use TokenIntrospectionGuard for opaque token validation. JWT tokens should use the jwt-auth recipe instead.',
|
|
551
|
+
copilotInstructions: 'OAuth 2.0 token introspection (RFC 7662) validates opaque tokens via the introspection endpoint.',
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
id: 'rbac-casl',
|
|
555
|
+
name: 'RBAC Authorization (CASL)',
|
|
556
|
+
description: 'Role-based access control with CASL ability factory',
|
|
557
|
+
category: 'Auth',
|
|
558
|
+
dependencies: {
|
|
559
|
+
'@casl/ability': '6.7.3',
|
|
560
|
+
},
|
|
561
|
+
devDependencies: {},
|
|
562
|
+
envVars: [],
|
|
563
|
+
conflicts: [],
|
|
564
|
+
requires: [],
|
|
565
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
566
|
+
templateDir: 'rbac-casl',
|
|
567
|
+
claudeMdSection: [
|
|
568
|
+
'## RBAC Authorization (CASL)',
|
|
569
|
+
'Use @Roles(Role.Admin) for simple role checks and @CheckPolicies(handler) for fine-grained CASL policies.',
|
|
570
|
+
'The CaslAbilityFactory defines per-role permissions. Register PoliciesGuard and RolesGuard as needed.',
|
|
571
|
+
].join('\n'),
|
|
572
|
+
cursorRules: [
|
|
573
|
+
'Use @Roles() for coarse role checks and @CheckPolicies() for attribute-based access control.',
|
|
574
|
+
'Define abilities in CaslAbilityFactory. Never hardcode permission checks — always use guards and decorators.',
|
|
575
|
+
].join('\n'),
|
|
576
|
+
copilotInstructions: [
|
|
577
|
+
'RBAC uses CASL for authorization. Apply @Roles(Role.Admin) or @CheckPolicies(handler) to endpoints.',
|
|
578
|
+
'Permissions are defined in CaslAbilityFactory. Use PoliciesGuard for policy-based and RolesGuard for role-based access.',
|
|
579
|
+
].join('\n'),
|
|
580
|
+
},
|
|
581
|
+
// ─── API Docs ───────────────────────────────────────────────────────
|
|
582
|
+
{
|
|
583
|
+
id: 'swagger',
|
|
584
|
+
name: 'Swagger / OpenAPI',
|
|
585
|
+
description: 'Auto-generated OpenAPI documentation with Swagger UI',
|
|
586
|
+
category: 'API Docs',
|
|
587
|
+
dependencies: {
|
|
588
|
+
'@nestjs/swagger': '11.4.2',
|
|
589
|
+
'@fastify/static': '8.1.0',
|
|
590
|
+
},
|
|
591
|
+
devDependencies: {},
|
|
592
|
+
envVars: [
|
|
593
|
+
{ key: 'SWAGGER_ENABLED', defaultValue: 'true', description: 'Enable Swagger UI' },
|
|
594
|
+
{ key: 'SWAGGER_PATH', defaultValue: 'api/docs', description: 'Swagger UI URL path' },
|
|
595
|
+
],
|
|
596
|
+
conflicts: [],
|
|
597
|
+
requires: [],
|
|
598
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo', 'aws-lambda'],
|
|
599
|
+
templateDir: 'swagger',
|
|
600
|
+
claudeMdSection: [
|
|
601
|
+
'## Swagger / OpenAPI',
|
|
602
|
+
'Swagger UI is available at `/{SWAGGER_PATH}`. Use @ApiTags(), @ApiOperation(), and @ApiResponse() on controllers.',
|
|
603
|
+
'DTOs are auto-documented via the Swagger plugin — ensure DTOs use class-validator decorators.',
|
|
604
|
+
].join('\n'),
|
|
605
|
+
cursorRules: [
|
|
606
|
+
'Decorate all controllers with @ApiTags() and endpoints with @ApiOperation()/@ApiResponse().',
|
|
607
|
+
'The Swagger CLI plugin auto-documents DTOs. Add @ApiProperty() only for complex/optional fields.',
|
|
608
|
+
].join('\n'),
|
|
609
|
+
copilotInstructions: [
|
|
610
|
+
'Swagger is configured with @nestjs/swagger. Decorate controllers with @ApiTags() and methods with @ApiOperation().',
|
|
611
|
+
'DTOs are auto-scanned. Use @ApiProperty() for fields that need extra documentation.',
|
|
612
|
+
].join('\n'),
|
|
613
|
+
mainTsSetup: {
|
|
614
|
+
blockId: 'swagger',
|
|
615
|
+
block: {
|
|
616
|
+
imports: [
|
|
617
|
+
{
|
|
618
|
+
namedImports: ['DocumentBuilder', 'SwaggerModule'],
|
|
619
|
+
moduleSpecifier: '@nestjs/swagger',
|
|
620
|
+
},
|
|
621
|
+
],
|
|
622
|
+
code: ` const swaggerEnabled = process.env.SWAGGER_ENABLED !== 'false';
|
|
623
|
+
if (swaggerEnabled) {
|
|
624
|
+
const config = new DocumentBuilder()
|
|
625
|
+
.setTitle('API')
|
|
626
|
+
.setDescription('API documentation')
|
|
627
|
+
.setVersion('1.0')
|
|
628
|
+
.addBearerAuth()
|
|
629
|
+
.build();
|
|
630
|
+
const document = SwaggerModule.createDocument(app, config);
|
|
631
|
+
SwaggerModule.setup(process.env.SWAGGER_PATH ?? 'api/docs', app, document);
|
|
632
|
+
}`,
|
|
633
|
+
},
|
|
634
|
+
},
|
|
635
|
+
},
|
|
636
|
+
// ─── Logging ────────────────────────────────────────────────────────
|
|
637
|
+
{
|
|
638
|
+
id: 'pino',
|
|
639
|
+
name: 'Pino Logger',
|
|
640
|
+
description: 'Structured JSON logging with Pino',
|
|
641
|
+
category: 'Logging',
|
|
642
|
+
dependencies: {
|
|
643
|
+
'nestjs-pino': '4.2.0',
|
|
644
|
+
pino: '9.6.0',
|
|
645
|
+
},
|
|
646
|
+
devDependencies: {
|
|
647
|
+
'pino-pretty': '13.0.0',
|
|
648
|
+
},
|
|
649
|
+
envVars: [
|
|
650
|
+
{
|
|
651
|
+
key: 'LOG_LEVEL',
|
|
652
|
+
defaultValue: 'info',
|
|
653
|
+
description: 'Pino log level (trace, debug, info, warn, error, fatal)',
|
|
654
|
+
},
|
|
655
|
+
],
|
|
656
|
+
conflicts: ['winston'],
|
|
657
|
+
requires: [],
|
|
658
|
+
compatibleWith: 'all',
|
|
659
|
+
templateDir: 'pino',
|
|
660
|
+
claudeMdSection: [
|
|
661
|
+
'## Pino Logger',
|
|
662
|
+
'Use `PinoLogger` (injected) for structured logging. Logs are JSON in production, pretty-printed in dev.',
|
|
663
|
+
'Set log level via LOG_LEVEL env var. Use `logger.assign()` to add context fields.',
|
|
664
|
+
].join('\n'),
|
|
665
|
+
cursorRules: [
|
|
666
|
+
'Inject PinoLogger for logging. Never use console methods — all logs go through Pino.',
|
|
667
|
+
'Use logger.assign({ key: value }) for adding context. Logs are structured JSON in production.',
|
|
668
|
+
].join('\n'),
|
|
669
|
+
copilotInstructions: [
|
|
670
|
+
'Pino is the logger. Inject PinoLogger and use .info(), .warn(), .error() methods.',
|
|
671
|
+
'Avoid console methods. Use pino-pretty in development. Logs are JSON in production.',
|
|
672
|
+
].join('\n'),
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
id: 'winston',
|
|
676
|
+
name: 'Winston Logger',
|
|
677
|
+
description: 'Flexible logging with Winston transports',
|
|
678
|
+
category: 'Logging',
|
|
679
|
+
dependencies: {
|
|
680
|
+
'nest-winston': '1.10.2',
|
|
681
|
+
winston: '3.17.0',
|
|
682
|
+
},
|
|
683
|
+
devDependencies: {},
|
|
684
|
+
envVars: [{ key: 'LOG_LEVEL', defaultValue: 'info', description: 'Winston log level' }],
|
|
685
|
+
conflicts: ['pino'],
|
|
686
|
+
requires: [],
|
|
687
|
+
compatibleWith: 'all',
|
|
688
|
+
templateDir: 'winston',
|
|
689
|
+
claudeMdSection: [
|
|
690
|
+
'## Winston Logger',
|
|
691
|
+
'Winston is configured with console and file transports. Inject `WINSTON_MODULE_PROVIDER` for the logger.',
|
|
692
|
+
'Add custom transports (e.g., Elasticsearch, CloudWatch) in the WinstonModule configuration.',
|
|
693
|
+
].join('\n'),
|
|
694
|
+
cursorRules: [
|
|
695
|
+
'Use the injected Winston logger, never console methods. Configure transports in the module setup.',
|
|
696
|
+
'Use log levels consistently: error for failures, warn for degraded, info for operations, debug for dev.',
|
|
697
|
+
].join('\n'),
|
|
698
|
+
copilotInstructions: [
|
|
699
|
+
'Winston handles logging. Inject the logger via WINSTON_MODULE_PROVIDER token.',
|
|
700
|
+
'Multiple transports are configured. Use structured metadata objects in log calls.',
|
|
701
|
+
].join('\n'),
|
|
702
|
+
},
|
|
703
|
+
// ─── Monitoring ─────────────────────────────────────────────────────
|
|
704
|
+
{
|
|
705
|
+
id: 'health-checks',
|
|
706
|
+
name: 'Health Checks',
|
|
707
|
+
description: 'Health check endpoints with Terminus',
|
|
708
|
+
category: 'Monitoring',
|
|
709
|
+
dependencies: {
|
|
710
|
+
'@nestjs/terminus': '10.2.3',
|
|
711
|
+
},
|
|
712
|
+
devDependencies: {},
|
|
713
|
+
envVars: [],
|
|
714
|
+
conflicts: [],
|
|
715
|
+
requires: [],
|
|
716
|
+
compatibleWith: ['http-api', 'microservice', 'scheduled-worker', 'full-stack', 'monorepo'],
|
|
717
|
+
templateDir: 'health-checks',
|
|
718
|
+
claudeMdSection: [
|
|
719
|
+
'## Health Checks',
|
|
720
|
+
'GET `/health` returns service health. Add custom indicators by implementing HealthIndicator.',
|
|
721
|
+
'Includes disk, memory, and database checks out of the box.',
|
|
722
|
+
].join('\n'),
|
|
723
|
+
cursorRules: [
|
|
724
|
+
'Health endpoint is at /health. Add custom checks by extending HealthIndicator.',
|
|
725
|
+
'Include checks for all external dependencies (DB, Redis, queues) the service uses.',
|
|
726
|
+
].join('\n'),
|
|
727
|
+
copilotInstructions: [
|
|
728
|
+
'Terminus health checks are at /health. Custom indicators extend HealthIndicator.',
|
|
729
|
+
'Add checks for every external dependency. Use @HealthCheck() decorator on the controller method.',
|
|
730
|
+
].join('\n'),
|
|
731
|
+
},
|
|
732
|
+
{
|
|
733
|
+
id: 'prometheus',
|
|
734
|
+
name: 'Prometheus Metrics',
|
|
735
|
+
description: 'Expose application metrics for Prometheus scraping',
|
|
736
|
+
category: 'Monitoring',
|
|
737
|
+
dependencies: {
|
|
738
|
+
'prom-client': '15.1.3',
|
|
739
|
+
},
|
|
740
|
+
devDependencies: {},
|
|
741
|
+
envVars: [
|
|
742
|
+
{
|
|
743
|
+
key: 'METRICS_PATH',
|
|
744
|
+
defaultValue: '/metrics',
|
|
745
|
+
description: 'Prometheus metrics endpoint path',
|
|
746
|
+
},
|
|
747
|
+
],
|
|
748
|
+
conflicts: [],
|
|
749
|
+
requires: [],
|
|
750
|
+
compatibleWith: 'all',
|
|
751
|
+
templateDir: 'prometheus',
|
|
752
|
+
claudeMdSection: [
|
|
753
|
+
'## Prometheus Metrics',
|
|
754
|
+
'Metrics are exposed at `/{METRICS_PATH}`. Default metrics are collected automatically.',
|
|
755
|
+
'Create custom metrics (Counter, Histogram, Gauge) in dedicated metric services.',
|
|
756
|
+
].join('\n'),
|
|
757
|
+
cursorRules: [
|
|
758
|
+
'Use prom-client to define custom metrics. Register metrics in module providers.',
|
|
759
|
+
'Use Histogram for request durations, Counter for totals, Gauge for current values.',
|
|
760
|
+
].join('\n'),
|
|
761
|
+
copilotInstructions: [
|
|
762
|
+
'Prometheus metrics are at /metrics via prom-client. Default Node.js metrics are auto-collected.',
|
|
763
|
+
'Define custom metrics as injectable services. Use histogram.observe() and counter.inc().',
|
|
764
|
+
].join('\n'),
|
|
765
|
+
},
|
|
766
|
+
// ─── Error Tracking ────────────────────────────────────────────────
|
|
767
|
+
{
|
|
768
|
+
id: 'sentry',
|
|
769
|
+
name: 'Sentry',
|
|
770
|
+
description: 'Error tracking and performance monitoring with Sentry',
|
|
771
|
+
category: 'Error Tracking',
|
|
772
|
+
dependencies: {
|
|
773
|
+
'@sentry/nestjs': '8.48.0',
|
|
774
|
+
},
|
|
775
|
+
devDependencies: {},
|
|
776
|
+
envVars: [
|
|
777
|
+
{ key: 'SENTRY_DSN', defaultValue: '', description: 'Sentry project DSN' },
|
|
778
|
+
{
|
|
779
|
+
key: 'SENTRY_ENVIRONMENT',
|
|
780
|
+
defaultValue: 'development',
|
|
781
|
+
description: 'Sentry environment tag',
|
|
782
|
+
},
|
|
783
|
+
{
|
|
784
|
+
key: 'SENTRY_TRACES_SAMPLE_RATE',
|
|
785
|
+
defaultValue: '1.0',
|
|
786
|
+
description: 'Sentry performance traces sample rate',
|
|
787
|
+
},
|
|
788
|
+
],
|
|
789
|
+
conflicts: [],
|
|
790
|
+
requires: [],
|
|
791
|
+
compatibleWith: 'all',
|
|
792
|
+
templateDir: 'sentry',
|
|
793
|
+
claudeMdSection: [
|
|
794
|
+
'## Sentry',
|
|
795
|
+
'Sentry captures unhandled exceptions and performance data. Configure via SENTRY_DSN.',
|
|
796
|
+
'Use Sentry.captureException() for manual error reporting. Add tags/context with Sentry.setTag().',
|
|
797
|
+
].join('\n'),
|
|
798
|
+
cursorRules: [
|
|
799
|
+
'Sentry is initialized at app startup. Unhandled exceptions are auto-captured.',
|
|
800
|
+
'Use Sentry.captureException() for caught errors. Add context with Sentry.setTag/setContext.',
|
|
801
|
+
].join('\n'),
|
|
802
|
+
copilotInstructions: [
|
|
803
|
+
'Sentry captures errors automatically. Use Sentry.captureException() for explicit reporting.',
|
|
804
|
+
'Set SENTRY_DSN in environment. Performance tracing is enabled by default.',
|
|
805
|
+
].join('\n'),
|
|
806
|
+
},
|
|
807
|
+
{
|
|
808
|
+
id: 'seq2',
|
|
809
|
+
name: 'Seq',
|
|
810
|
+
description: 'Structured log aggregation with Seq',
|
|
811
|
+
category: 'Error Tracking',
|
|
812
|
+
dependencies: {
|
|
813
|
+
'seq-logging': '3.0.0',
|
|
814
|
+
},
|
|
815
|
+
devDependencies: {},
|
|
816
|
+
envVars: [
|
|
817
|
+
{
|
|
818
|
+
key: 'SEQ_SERVER_URL',
|
|
819
|
+
defaultValue: 'http://localhost:5341',
|
|
820
|
+
description: 'Seq server URL',
|
|
821
|
+
},
|
|
822
|
+
{ key: 'SEQ_API_KEY', defaultValue: '', description: 'Seq API key' },
|
|
823
|
+
],
|
|
824
|
+
conflicts: [],
|
|
825
|
+
requires: [],
|
|
826
|
+
compatibleWith: 'all',
|
|
827
|
+
templateDir: 'seq2',
|
|
828
|
+
claudeMdSection: [
|
|
829
|
+
'## Seq',
|
|
830
|
+
'Structured logs are forwarded to Seq at SEQ_SERVER_URL.',
|
|
831
|
+
'Use structured properties in log messages for searchability in the Seq dashboard.',
|
|
832
|
+
].join('\n'),
|
|
833
|
+
cursorRules: [
|
|
834
|
+
'Seq receives structured logs. Always include meaningful properties in log entries.',
|
|
835
|
+
'Use message templates with named properties for Seq filtering and alerting.',
|
|
836
|
+
].join('\n'),
|
|
837
|
+
copilotInstructions: [
|
|
838
|
+
'Seq is configured for log aggregation. Logs are sent to SEQ_SERVER_URL.',
|
|
839
|
+
'Use structured logging properties for effective filtering in the Seq UI.',
|
|
840
|
+
].join('\n'),
|
|
841
|
+
},
|
|
842
|
+
// ─── Storage ────────────────────────────────────────────────────────
|
|
843
|
+
{
|
|
844
|
+
id: 's3-minio',
|
|
845
|
+
name: 'S3 / MinIO Storage',
|
|
846
|
+
description: 'Object storage with AWS S3 SDK (compatible with MinIO)',
|
|
847
|
+
category: 'Storage',
|
|
848
|
+
dependencies: {
|
|
849
|
+
'@aws-sdk/client-s3': '3.712.0',
|
|
850
|
+
'@aws-sdk/s3-request-presigner': '3.712.0',
|
|
851
|
+
},
|
|
852
|
+
devDependencies: {},
|
|
853
|
+
envVars: [
|
|
854
|
+
{
|
|
855
|
+
key: 'S3_ENDPOINT',
|
|
856
|
+
defaultValue: 'http://localhost:9000',
|
|
857
|
+
description: 'S3/MinIO endpoint',
|
|
858
|
+
},
|
|
859
|
+
{ key: 'S3_REGION', defaultValue: 'us-east-1', description: 'S3 region' },
|
|
860
|
+
{ key: 'S3_BUCKET', defaultValue: 'app-uploads', description: 'Default S3 bucket name' },
|
|
861
|
+
{ key: 'S3_ACCESS_KEY_ID', defaultValue: 'minioadmin', description: 'S3/MinIO access key' },
|
|
862
|
+
{ key: 'S3_SECRET_ACCESS_KEY', defaultValue: 'minioadmin', description: 'S3/MinIO secret key' },
|
|
863
|
+
],
|
|
864
|
+
conflicts: [],
|
|
865
|
+
requires: [],
|
|
866
|
+
compatibleWith: 'all',
|
|
867
|
+
templateDir: 's3-minio',
|
|
868
|
+
claudeMdSection: [
|
|
869
|
+
'## S3 / MinIO Storage',
|
|
870
|
+
'Use StorageService for file uploads, downloads, and presigned URLs.',
|
|
871
|
+
'MinIO is used locally; configure S3_ENDPOINT to switch to AWS S3 in production.',
|
|
872
|
+
].join('\n'),
|
|
873
|
+
cursorRules: [
|
|
874
|
+
'Use the StorageService abstraction, not S3Client directly in business code.',
|
|
875
|
+
'Generate presigned URLs for client-side uploads. Set appropriate content-type and size limits.',
|
|
876
|
+
].join('\n'),
|
|
877
|
+
copilotInstructions: [
|
|
878
|
+
'S3-compatible storage via @aws-sdk/client-s3. Use StorageService for all file operations.',
|
|
879
|
+
'MinIO is the local dev replacement. Presigned URLs are used for direct browser uploads.',
|
|
880
|
+
].join('\n'),
|
|
881
|
+
},
|
|
882
|
+
// ─── Email ──────────────────────────────────────────────────────────
|
|
883
|
+
{
|
|
884
|
+
id: 'nodemailer',
|
|
885
|
+
name: 'Nodemailer',
|
|
886
|
+
description: 'Email sending with Nodemailer and template support',
|
|
887
|
+
category: 'Email',
|
|
888
|
+
dependencies: {
|
|
889
|
+
'@nestjs-modules/mailer': '2.0.2',
|
|
890
|
+
nodemailer: '6.9.16',
|
|
891
|
+
handlebars: '4.7.8',
|
|
892
|
+
},
|
|
893
|
+
devDependencies: {
|
|
894
|
+
'@types/nodemailer': '6.4.17',
|
|
895
|
+
},
|
|
896
|
+
envVars: [
|
|
897
|
+
{ key: 'MAIL_HOST', defaultValue: 'localhost', description: 'SMTP host' },
|
|
898
|
+
{ key: 'MAIL_PORT', defaultValue: '1025', description: 'SMTP port' },
|
|
899
|
+
{ key: 'MAIL_USER', defaultValue: '', description: 'SMTP username' },
|
|
900
|
+
{ key: 'MAIL_PASSWORD', defaultValue: '', description: 'SMTP password' },
|
|
901
|
+
{
|
|
902
|
+
key: 'MAIL_FROM',
|
|
903
|
+
defaultValue: 'noreply@example.com',
|
|
904
|
+
description: 'Default sender address',
|
|
905
|
+
},
|
|
906
|
+
],
|
|
907
|
+
conflicts: ['sendgrid'],
|
|
908
|
+
requires: [],
|
|
909
|
+
compatibleWith: 'all',
|
|
910
|
+
templateDir: 'nodemailer',
|
|
911
|
+
claudeMdSection: [
|
|
912
|
+
'## Nodemailer',
|
|
913
|
+
'Inject MailerService to send emails. Templates live in `src/mail/templates/`.',
|
|
914
|
+
'Use MailHog or similar SMTP trap locally. Configure real SMTP credentials in production.',
|
|
915
|
+
].join('\n'),
|
|
916
|
+
cursorRules: [
|
|
917
|
+
'Use MailerService for sending emails. Email templates are in src/mail/templates/.',
|
|
918
|
+
'Never hardcode email credentials. Use SMTP trap (MailHog) for local development.',
|
|
919
|
+
].join('\n'),
|
|
920
|
+
copilotInstructions: [
|
|
921
|
+
'Nodemailer is integrated via @nestjs-modules/mailer. Inject MailerService to send mail.',
|
|
922
|
+
'Templates are in src/mail/templates/. Use MailHog locally for testing email delivery.',
|
|
923
|
+
].join('\n'),
|
|
924
|
+
},
|
|
925
|
+
{
|
|
926
|
+
id: 'sendgrid',
|
|
927
|
+
name: 'SendGrid',
|
|
928
|
+
description: 'Transactional email via SendGrid API',
|
|
929
|
+
category: 'Email',
|
|
930
|
+
dependencies: {
|
|
931
|
+
'@sendgrid/mail': '8.1.4',
|
|
932
|
+
},
|
|
933
|
+
devDependencies: {},
|
|
934
|
+
envVars: [
|
|
935
|
+
{ key: 'SENDGRID_API_KEY', defaultValue: '', description: 'SendGrid API key' },
|
|
936
|
+
{
|
|
937
|
+
key: 'SENDGRID_FROM_EMAIL',
|
|
938
|
+
defaultValue: 'noreply@example.com',
|
|
939
|
+
description: 'Default sender address',
|
|
940
|
+
},
|
|
941
|
+
],
|
|
942
|
+
conflicts: ['nodemailer'],
|
|
943
|
+
requires: [],
|
|
944
|
+
compatibleWith: 'all',
|
|
945
|
+
templateDir: 'sendgrid',
|
|
946
|
+
claudeMdSection: [
|
|
947
|
+
'## SendGrid',
|
|
948
|
+
'Use EmailService to send transactional emails via SendGrid. Set SENDGRID_API_KEY in env.',
|
|
949
|
+
'Use dynamic templates in the SendGrid dashboard for managed email templates.',
|
|
950
|
+
].join('\n'),
|
|
951
|
+
cursorRules: [
|
|
952
|
+
'Use the EmailService wrapper, not @sendgrid/mail directly. API key from ConfigService.',
|
|
953
|
+
'Prefer SendGrid dynamic templates over inline HTML for production emails.',
|
|
954
|
+
].join('\n'),
|
|
955
|
+
copilotInstructions: [
|
|
956
|
+
'SendGrid handles email sending. Use the EmailService abstraction layer.',
|
|
957
|
+
'Configure SENDGRID_API_KEY via environment. Use dynamic templates for production.',
|
|
958
|
+
].join('\n'),
|
|
959
|
+
},
|
|
960
|
+
// ─── WebSockets ─────────────────────────────────────────────────────
|
|
961
|
+
{
|
|
962
|
+
id: 'websockets',
|
|
963
|
+
name: 'WebSockets',
|
|
964
|
+
description: 'Real-time communication with Socket.IO',
|
|
965
|
+
category: 'WebSockets',
|
|
966
|
+
dependencies: {
|
|
967
|
+
'@nestjs/websockets': '10.4.15',
|
|
968
|
+
'@nestjs/platform-socket.io': '10.4.15',
|
|
969
|
+
'socket.io': '4.8.3',
|
|
970
|
+
},
|
|
971
|
+
devDependencies: {},
|
|
972
|
+
envVars: [{ key: 'WS_PORT', defaultValue: '3001', description: 'WebSocket server port' }],
|
|
973
|
+
conflicts: [],
|
|
974
|
+
requires: [],
|
|
975
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
976
|
+
templateDir: 'websockets',
|
|
977
|
+
claudeMdSection: [
|
|
978
|
+
'## WebSockets',
|
|
979
|
+
'Use @WebSocketGateway() for real-time gateways. Handle events with @SubscribeMessage().',
|
|
980
|
+
'Socket.IO is the underlying transport. Use rooms and namespaces for channel isolation.',
|
|
981
|
+
].join('\n'),
|
|
982
|
+
cursorRules: [
|
|
983
|
+
'Create gateways with @WebSocketGateway(). Handle events via @SubscribeMessage().',
|
|
984
|
+
'Use rooms for scoped broadcasting. Authenticate WebSocket connections in handleConnection().',
|
|
985
|
+
].join('\n'),
|
|
986
|
+
copilotInstructions: [
|
|
987
|
+
'WebSockets use Socket.IO via @nestjs/websockets. Create gateways with @WebSocketGateway().',
|
|
988
|
+
'Use @SubscribeMessage() for event handlers. Rooms and namespaces manage channel isolation.',
|
|
989
|
+
].join('\n'),
|
|
990
|
+
},
|
|
991
|
+
// ─── GraphQL ────────────────────────────────────────────────────────
|
|
992
|
+
{
|
|
993
|
+
id: 'graphql-mercurius',
|
|
994
|
+
name: 'GraphQL (Mercurius)',
|
|
995
|
+
description: 'GraphQL API with Mercurius adapter for Fastify',
|
|
996
|
+
category: 'GraphQL',
|
|
997
|
+
dependencies: {
|
|
998
|
+
'@nestjs/graphql': '12.2.1',
|
|
999
|
+
'@nestjs/mercurius': '12.2.1',
|
|
1000
|
+
mercurius: '15.0.0',
|
|
1001
|
+
graphql: '16.9.0',
|
|
1002
|
+
},
|
|
1003
|
+
devDependencies: {},
|
|
1004
|
+
envVars: [],
|
|
1005
|
+
conflicts: [],
|
|
1006
|
+
requires: [],
|
|
1007
|
+
compatibleWith: ['http-api', 'aws-lambda', 'full-stack', 'monorepo'],
|
|
1008
|
+
templateDir: 'graphql-mercurius',
|
|
1009
|
+
claudeMdSection: [
|
|
1010
|
+
'## GraphQL (Mercurius)',
|
|
1011
|
+
'Code-first approach: define @ObjectType() and @Resolver() classes. Schema is auto-generated.',
|
|
1012
|
+
'GraphQL playground is available at `/graphql` in non-production environments.',
|
|
1013
|
+
].join('\n'),
|
|
1014
|
+
cursorRules: [
|
|
1015
|
+
'Use code-first approach with @ObjectType(), @Field(), @Resolver(), @Query(), @Mutation().',
|
|
1016
|
+
'Define input types with @InputType(). Use DataLoader for N+1 query prevention.',
|
|
1017
|
+
].join('\n'),
|
|
1018
|
+
copilotInstructions: [
|
|
1019
|
+
'GraphQL uses Mercurius with code-first approach. Define resolvers with @Resolver() decorator.',
|
|
1020
|
+
'Use @ObjectType/@Field for types, @Query/@Mutation for operations. DataLoader prevents N+1.',
|
|
1021
|
+
].join('\n'),
|
|
1022
|
+
},
|
|
1023
|
+
// ─── CQRS ───────────────────────────────────────────────────────────
|
|
1024
|
+
{
|
|
1025
|
+
id: 'cqrs',
|
|
1026
|
+
name: 'CQRS',
|
|
1027
|
+
description: 'Command Query Responsibility Segregation pattern',
|
|
1028
|
+
category: 'CQRS',
|
|
1029
|
+
dependencies: {
|
|
1030
|
+
'@nestjs/cqrs': '10.2.7',
|
|
1031
|
+
},
|
|
1032
|
+
devDependencies: {},
|
|
1033
|
+
envVars: [],
|
|
1034
|
+
conflicts: [],
|
|
1035
|
+
requires: [],
|
|
1036
|
+
compatibleWith: 'all',
|
|
1037
|
+
templateDir: 'cqrs',
|
|
1038
|
+
claudeMdSection: [
|
|
1039
|
+
'## CQRS',
|
|
1040
|
+
'Separate commands (writes) and queries (reads). Use CommandBus and QueryBus for dispatching.',
|
|
1041
|
+
'Events are emitted via EventBus. Sagas handle cross-aggregate side effects.',
|
|
1042
|
+
].join('\n'),
|
|
1043
|
+
cursorRules: [
|
|
1044
|
+
'Commands go through CommandBus, queries through QueryBus. One handler per command/query.',
|
|
1045
|
+
'Events are dispatched via EventBus. Place handlers in the same module as the aggregate.',
|
|
1046
|
+
].join('\n'),
|
|
1047
|
+
copilotInstructions: [
|
|
1048
|
+
'CQRS is via @nestjs/cqrs. Dispatch commands with CommandBus, queries with QueryBus.',
|
|
1049
|
+
'Each command/query has exactly one handler. Use events for side effects across modules.',
|
|
1050
|
+
].join('\n'),
|
|
1051
|
+
},
|
|
1052
|
+
// ─── Security ───────────────────────────────────────────────────────
|
|
1053
|
+
{
|
|
1054
|
+
id: 'throttler',
|
|
1055
|
+
name: 'Rate Limiting',
|
|
1056
|
+
description: 'Request rate limiting with Throttler',
|
|
1057
|
+
category: 'Security',
|
|
1058
|
+
dependencies: {
|
|
1059
|
+
'@nestjs/throttler': '6.3.0',
|
|
1060
|
+
},
|
|
1061
|
+
devDependencies: {},
|
|
1062
|
+
envVars: [
|
|
1063
|
+
{
|
|
1064
|
+
key: 'THROTTLE_TTL',
|
|
1065
|
+
defaultValue: '60000',
|
|
1066
|
+
description: 'Rate limit window in milliseconds',
|
|
1067
|
+
},
|
|
1068
|
+
{ key: 'THROTTLE_LIMIT', defaultValue: '100', description: 'Max requests per window' },
|
|
1069
|
+
],
|
|
1070
|
+
conflicts: [],
|
|
1071
|
+
requires: [],
|
|
1072
|
+
compatibleWith: 'all',
|
|
1073
|
+
templateDir: 'throttler',
|
|
1074
|
+
claudeMdSection: [
|
|
1075
|
+
'## Rate Limiting',
|
|
1076
|
+
'Global rate limiting is applied via ThrottlerGuard. Override per-route with @Throttle().',
|
|
1077
|
+
'Skip rate limiting on specific routes with @SkipThrottle().',
|
|
1078
|
+
].join('\n'),
|
|
1079
|
+
cursorRules: [
|
|
1080
|
+
'ThrottlerGuard is applied globally. Use @Throttle() to customize per-route limits.',
|
|
1081
|
+
'Use @SkipThrottle() for internal/health endpoints. Configure via THROTTLE_TTL and THROTTLE_LIMIT.',
|
|
1082
|
+
].join('\n'),
|
|
1083
|
+
copilotInstructions: [
|
|
1084
|
+
'Rate limiting uses @nestjs/throttler. Global guard is applied. Override with @Throttle() per route.',
|
|
1085
|
+
'Use @SkipThrottle() to exempt specific endpoints like health checks.',
|
|
1086
|
+
].join('\n'),
|
|
1087
|
+
},
|
|
1088
|
+
{
|
|
1089
|
+
id: 'helmet',
|
|
1090
|
+
name: 'Helmet',
|
|
1091
|
+
description: 'HTTP security headers with Fastify Helmet',
|
|
1092
|
+
category: 'Security',
|
|
1093
|
+
dependencies: {
|
|
1094
|
+
'@fastify/helmet': '13.0.2',
|
|
1095
|
+
},
|
|
1096
|
+
devDependencies: {},
|
|
1097
|
+
envVars: [],
|
|
1098
|
+
conflicts: [],
|
|
1099
|
+
requires: [],
|
|
1100
|
+
compatibleWith: 'all',
|
|
1101
|
+
templateDir: 'helmet',
|
|
1102
|
+
claudeMdSection: [
|
|
1103
|
+
'## Helmet',
|
|
1104
|
+
'Helmet sets security headers (CSP, X-Frame-Options, etc.) automatically.',
|
|
1105
|
+
'Customize header policies in the Helmet registration options.',
|
|
1106
|
+
].join('\n'),
|
|
1107
|
+
cursorRules: [
|
|
1108
|
+
'Helmet is registered as a Fastify plugin. Customize CSP and other policies as needed.',
|
|
1109
|
+
'Ensure CSP allows required script/style sources when using Swagger UI or frontends.',
|
|
1110
|
+
].join('\n'),
|
|
1111
|
+
copilotInstructions: [
|
|
1112
|
+
'Helmet applies security headers via @fastify/helmet. Configured in main.ts.',
|
|
1113
|
+
'Adjust CSP directives if Swagger UI or external resources are blocked.',
|
|
1114
|
+
].join('\n'),
|
|
1115
|
+
mainTsSetup: {
|
|
1116
|
+
blockId: 'helmet',
|
|
1117
|
+
block: {
|
|
1118
|
+
imports: [
|
|
1119
|
+
{
|
|
1120
|
+
defaultImport: 'helmet',
|
|
1121
|
+
namedImports: [],
|
|
1122
|
+
moduleSpecifier: '@fastify/helmet',
|
|
1123
|
+
},
|
|
1124
|
+
],
|
|
1125
|
+
code: ` await app.register(helmet as any, {
|
|
1126
|
+
contentSecurityPolicy: {
|
|
1127
|
+
directives: {
|
|
1128
|
+
defaultSrc: ["'self'"],
|
|
1129
|
+
styleSrc: ["'self'", "'unsafe-inline'"],
|
|
1130
|
+
imgSrc: ["'self'", 'data:', 'validator.swagger.io'],
|
|
1131
|
+
scriptSrc: ["'self'", "'unsafe-inline'"],
|
|
1132
|
+
},
|
|
1133
|
+
},
|
|
1134
|
+
});`,
|
|
1135
|
+
},
|
|
1136
|
+
},
|
|
1137
|
+
},
|
|
1138
|
+
{
|
|
1139
|
+
id: 'cors',
|
|
1140
|
+
name: 'CORS',
|
|
1141
|
+
description: 'Cross-Origin Resource Sharing configuration',
|
|
1142
|
+
category: 'Security',
|
|
1143
|
+
dependencies: {},
|
|
1144
|
+
devDependencies: {},
|
|
1145
|
+
envVars: [
|
|
1146
|
+
{
|
|
1147
|
+
key: 'CORS_ORIGIN',
|
|
1148
|
+
defaultValue: 'http://localhost:3000',
|
|
1149
|
+
description: 'Allowed CORS origin(s), comma-separated',
|
|
1150
|
+
},
|
|
1151
|
+
],
|
|
1152
|
+
conflicts: [],
|
|
1153
|
+
requires: [],
|
|
1154
|
+
compatibleWith: 'all',
|
|
1155
|
+
templateDir: 'cors',
|
|
1156
|
+
claudeMdSection: [
|
|
1157
|
+
'## CORS',
|
|
1158
|
+
'CORS is configured in main.ts. Allowed origins are set via CORS_ORIGIN env var.',
|
|
1159
|
+
'Use comma-separated values for multiple origins. Never use `*` in production.',
|
|
1160
|
+
].join('\n'),
|
|
1161
|
+
cursorRules: [
|
|
1162
|
+
'CORS origins come from CORS_ORIGIN env var. Never wildcard in production.',
|
|
1163
|
+
'Configure credentials, methods, and headers in the CORS options in main.ts.',
|
|
1164
|
+
].join('\n'),
|
|
1165
|
+
copilotInstructions: [
|
|
1166
|
+
'CORS is configured in main.ts via Fastify CORS plugin. Origins from CORS_ORIGIN env var.',
|
|
1167
|
+
'Support comma-separated origins. Never use wildcard (*) in production environments.',
|
|
1168
|
+
].join('\n'),
|
|
1169
|
+
},
|
|
1170
|
+
{
|
|
1171
|
+
id: 'csrf',
|
|
1172
|
+
name: 'CSRF Protection',
|
|
1173
|
+
description: 'Cross-Site Request Forgery protection for Fastify',
|
|
1174
|
+
category: 'Security',
|
|
1175
|
+
dependencies: {
|
|
1176
|
+
'@fastify/csrf-protection': '7.0.1',
|
|
1177
|
+
'@fastify/cookie': '11.0.1',
|
|
1178
|
+
},
|
|
1179
|
+
devDependencies: {},
|
|
1180
|
+
envVars: [],
|
|
1181
|
+
conflicts: [],
|
|
1182
|
+
requires: [],
|
|
1183
|
+
compatibleWith: 'all',
|
|
1184
|
+
templateDir: 'csrf',
|
|
1185
|
+
claudeMdSection: [
|
|
1186
|
+
'## CSRF Protection',
|
|
1187
|
+
'CSRF tokens are required for state-changing requests. Token is set via cookie.',
|
|
1188
|
+
'Exclude API routes that use bearer token auth from CSRF protection.',
|
|
1189
|
+
].join('\n'),
|
|
1190
|
+
cursorRules: [
|
|
1191
|
+
'CSRF protection is via @fastify/csrf-protection. Tokens are cookie-based.',
|
|
1192
|
+
'API endpoints using JWT/API-key auth can skip CSRF. Browser-facing forms need it.',
|
|
1193
|
+
].join('\n'),
|
|
1194
|
+
copilotInstructions: [
|
|
1195
|
+
'CSRF protection uses @fastify/csrf-protection. Applied to browser-facing state-changing routes.',
|
|
1196
|
+
'JWT/API-key protected endpoints can be excluded. Token is delivered via cookie.',
|
|
1197
|
+
].join('\n'),
|
|
1198
|
+
},
|
|
1199
|
+
// ─── API Patterns ──────────────────────────────────────────────────
|
|
1200
|
+
{
|
|
1201
|
+
id: 'pagination',
|
|
1202
|
+
name: 'Pagination',
|
|
1203
|
+
description: 'Cursor and offset pagination utilities',
|
|
1204
|
+
category: 'API Patterns',
|
|
1205
|
+
dependencies: {
|
|
1206
|
+
'@nestjs/swagger': '11.4.2',
|
|
1207
|
+
},
|
|
1208
|
+
devDependencies: {},
|
|
1209
|
+
envVars: [],
|
|
1210
|
+
conflicts: [],
|
|
1211
|
+
requires: [],
|
|
1212
|
+
compatibleWith: 'all',
|
|
1213
|
+
templateDir: 'pagination',
|
|
1214
|
+
claudeMdSection: [
|
|
1215
|
+
'## Pagination',
|
|
1216
|
+
'Use PaginatedQuery for query params (page, limit). PaginatedResponse<T> wraps results with metadata.',
|
|
1217
|
+
'Supports offset-based pagination. Use PaginatedQuery.skip for database offset calculations.',
|
|
1218
|
+
].join('\n'),
|
|
1219
|
+
cursorRules: [
|
|
1220
|
+
'Use PaginatedQuery for pagination query params. Return PaginatedResponse<T> from endpoints.',
|
|
1221
|
+
'Default page size is 20, max 100. Use PaginatedQuery.skip for offset calculations.',
|
|
1222
|
+
].join('\n'),
|
|
1223
|
+
copilotInstructions: [
|
|
1224
|
+
'Pagination uses PaginatedQuery and PaginatedResponse<T>. Offset-based with skip/limit.',
|
|
1225
|
+
'Apply @Query() PaginatedQuery to controller methods. Service returns PaginatedResponse<T> wrapper.',
|
|
1226
|
+
].join('\n'),
|
|
1227
|
+
},
|
|
1228
|
+
{
|
|
1229
|
+
id: 'filtering',
|
|
1230
|
+
name: 'Filtering',
|
|
1231
|
+
description: 'Dynamic query filtering utilities',
|
|
1232
|
+
category: 'API Patterns',
|
|
1233
|
+
dependencies: {
|
|
1234
|
+
'@nestjs/swagger': '11.4.2',
|
|
1235
|
+
},
|
|
1236
|
+
devDependencies: {},
|
|
1237
|
+
envVars: [],
|
|
1238
|
+
conflicts: [],
|
|
1239
|
+
requires: [],
|
|
1240
|
+
compatibleWith: 'all',
|
|
1241
|
+
templateDir: 'filtering',
|
|
1242
|
+
claudeMdSection: [
|
|
1243
|
+
'## Filtering',
|
|
1244
|
+
'Use FilterDto base class for query filters. Supports equals, contains, gt/lt, in operators.',
|
|
1245
|
+
'Apply @Query() with filter DTOs to controller methods for type-safe filtering.',
|
|
1246
|
+
].join('\n'),
|
|
1247
|
+
cursorRules: [
|
|
1248
|
+
'Extend FilterDto for resource-specific filters. Supported operators: eq, contains, gt, lt, in.',
|
|
1249
|
+
'Validate filter values via class-validator. Map filter DTOs to ORM query conditions.',
|
|
1250
|
+
].join('\n'),
|
|
1251
|
+
copilotInstructions: [
|
|
1252
|
+
'Query filtering uses FilterDto pattern. Extend per resource for type-safe filters.',
|
|
1253
|
+
'Map filter DTOs to database queries in the service layer. Validate with class-validator.',
|
|
1254
|
+
].join('\n'),
|
|
1255
|
+
},
|
|
1256
|
+
{
|
|
1257
|
+
id: 'api-versioning',
|
|
1258
|
+
name: 'API Versioning',
|
|
1259
|
+
description: 'URI or header-based API versioning',
|
|
1260
|
+
category: 'API Patterns',
|
|
1261
|
+
dependencies: {},
|
|
1262
|
+
devDependencies: {},
|
|
1263
|
+
envVars: [],
|
|
1264
|
+
conflicts: [],
|
|
1265
|
+
requires: [],
|
|
1266
|
+
compatibleWith: 'all',
|
|
1267
|
+
templateDir: 'api-versioning',
|
|
1268
|
+
claudeMdSection: [
|
|
1269
|
+
'## API Versioning',
|
|
1270
|
+
'URI versioning is enabled: `/v1/resource`, `/v2/resource`. Use @Version() on controllers.',
|
|
1271
|
+
'Default version is set in main.ts. Use VERSION_NEUTRAL for unversioned routes.',
|
|
1272
|
+
].join('\n'),
|
|
1273
|
+
cursorRules: [
|
|
1274
|
+
'Use @Version("1") on controllers or methods. Default version is configured globally.',
|
|
1275
|
+
'Deprecate old versions with @ApiDeprecated() and a sunset date in response headers.',
|
|
1276
|
+
].join('\n'),
|
|
1277
|
+
copilotInstructions: [
|
|
1278
|
+
'API versioning uses URI prefix (/v1/). Apply @Version() decorator to controllers.',
|
|
1279
|
+
'Set default version in main.ts. Use VERSION_NEUTRAL for unversioned endpoints.',
|
|
1280
|
+
].join('\n'),
|
|
1281
|
+
},
|
|
1282
|
+
{
|
|
1283
|
+
id: 'correlation-id',
|
|
1284
|
+
name: 'Correlation ID',
|
|
1285
|
+
description: 'Request correlation ID propagation via AsyncLocalStorage',
|
|
1286
|
+
category: 'API Patterns',
|
|
1287
|
+
dependencies: {},
|
|
1288
|
+
devDependencies: {},
|
|
1289
|
+
envVars: [],
|
|
1290
|
+
conflicts: [],
|
|
1291
|
+
requires: [],
|
|
1292
|
+
compatibleWith: 'all',
|
|
1293
|
+
templateDir: 'correlation-id',
|
|
1294
|
+
claudeMdSection: [
|
|
1295
|
+
'## Correlation ID',
|
|
1296
|
+
'Every request gets a correlation ID (from x-correlation-id header or auto-generated UUID).',
|
|
1297
|
+
'Access via getCorrelationId() from anywhere in the async call chain. Propagate to downstream HTTP calls and log entries.',
|
|
1298
|
+
].join('\n'),
|
|
1299
|
+
cursorRules: [
|
|
1300
|
+
'Correlation ID is set via CorrelationIdMiddleware using AsyncLocalStorage. Access via getCorrelationId().',
|
|
1301
|
+
'Always forward the correlation ID in outgoing HTTP calls and include it in log context.',
|
|
1302
|
+
].join('\n'),
|
|
1303
|
+
copilotInstructions: [
|
|
1304
|
+
'Correlation IDs track requests across services. Auto-generated or from x-correlation-id header.',
|
|
1305
|
+
'Use getCorrelationId() to access from anywhere in the async call chain. Propagate in outgoing HTTP headers and logs.',
|
|
1306
|
+
].join('\n'),
|
|
1307
|
+
},
|
|
1308
|
+
{
|
|
1309
|
+
id: 'http-caching',
|
|
1310
|
+
name: 'HTTP Cache Headers',
|
|
1311
|
+
description: 'RFC 9111 Cache-Control and conditional request headers',
|
|
1312
|
+
category: 'API Patterns',
|
|
1313
|
+
dependencies: {},
|
|
1314
|
+
devDependencies: {},
|
|
1315
|
+
envVars: [],
|
|
1316
|
+
conflicts: [],
|
|
1317
|
+
requires: [],
|
|
1318
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
1319
|
+
templateDir: 'http-caching',
|
|
1320
|
+
claudeMdSection: '## HTTP Caching\nUse @CacheControl() decorator on GET endpoints to set Cache-Control headers. Supports max-age, s-maxage, stale-while-revalidate, no-cache, no-store, private, public directives.',
|
|
1321
|
+
cursorRules: 'Use @CacheControl() decorator for response caching headers. Set appropriate max-age per endpoint. Use no-cache for authenticated endpoints.',
|
|
1322
|
+
copilotInstructions: 'HTTP Cache-Control headers via @CacheControl() decorator. Apply to GET endpoints. Authenticated endpoints should use no-cache or private.',
|
|
1323
|
+
},
|
|
1324
|
+
// ─── Observability ──────────────────────────────────────────────────
|
|
1325
|
+
{
|
|
1326
|
+
id: 'opentelemetry',
|
|
1327
|
+
name: 'OpenTelemetry',
|
|
1328
|
+
description: 'Distributed tracing and metrics with OpenTelemetry SDK',
|
|
1329
|
+
category: 'Observability',
|
|
1330
|
+
dependencies: {
|
|
1331
|
+
'@opentelemetry/sdk-node': '0.57.0',
|
|
1332
|
+
'@opentelemetry/exporter-trace-otlp-http': '0.57.0',
|
|
1333
|
+
'@opentelemetry/instrumentation-http': '0.57.0',
|
|
1334
|
+
'@opentelemetry/instrumentation-fastify': '0.44.0',
|
|
1335
|
+
'@opentelemetry/resources': '1.30.0',
|
|
1336
|
+
'@opentelemetry/semantic-conventions': '1.28.0',
|
|
1337
|
+
},
|
|
1338
|
+
devDependencies: {},
|
|
1339
|
+
envVars: [
|
|
1340
|
+
{
|
|
1341
|
+
key: 'OTEL_EXPORTER_OTLP_ENDPOINT',
|
|
1342
|
+
defaultValue: 'http://localhost:4318',
|
|
1343
|
+
description: 'OpenTelemetry collector endpoint',
|
|
1344
|
+
},
|
|
1345
|
+
{
|
|
1346
|
+
key: 'OTEL_SERVICE_NAME',
|
|
1347
|
+
defaultValue: 'nestjs-app',
|
|
1348
|
+
description: 'Service name for traces',
|
|
1349
|
+
},
|
|
1350
|
+
],
|
|
1351
|
+
conflicts: [],
|
|
1352
|
+
requires: [],
|
|
1353
|
+
compatibleWith: 'all',
|
|
1354
|
+
templateDir: 'opentelemetry',
|
|
1355
|
+
claudeMdSection: [
|
|
1356
|
+
'## OpenTelemetry',
|
|
1357
|
+
'OTel is initialized in `src/instrumentation.ts` (loaded before app bootstrap).',
|
|
1358
|
+
'Auto-instrumentation captures HTTP, database, and external call spans automatically.',
|
|
1359
|
+
].join('\n'),
|
|
1360
|
+
cursorRules: [
|
|
1361
|
+
'OpenTelemetry is initialized in instrumentation.ts via --require flag. Auto-instrumentation is enabled.',
|
|
1362
|
+
'Add custom spans with tracer.startSpan(). Export to Jaeger/OTLP collector.',
|
|
1363
|
+
].join('\n'),
|
|
1364
|
+
copilotInstructions: [
|
|
1365
|
+
'OpenTelemetry handles tracing. Instrumentation file loads before the app via --require.',
|
|
1366
|
+
'Auto-instrumentation covers HTTP/DB. Add custom spans for business-critical operations.',
|
|
1367
|
+
].join('\n'),
|
|
1368
|
+
},
|
|
1369
|
+
{
|
|
1370
|
+
id: 'request-logging',
|
|
1371
|
+
name: 'Request Logging',
|
|
1372
|
+
description: 'HTTP request/response logging middleware',
|
|
1373
|
+
category: 'Observability',
|
|
1374
|
+
dependencies: {},
|
|
1375
|
+
devDependencies: {},
|
|
1376
|
+
envVars: [
|
|
1377
|
+
{
|
|
1378
|
+
key: 'REQUEST_LOG_BODY',
|
|
1379
|
+
defaultValue: 'false',
|
|
1380
|
+
description: 'Log request/response bodies',
|
|
1381
|
+
},
|
|
1382
|
+
],
|
|
1383
|
+
conflicts: [],
|
|
1384
|
+
requires: [],
|
|
1385
|
+
compatibleWith: 'all',
|
|
1386
|
+
templateDir: 'request-logging',
|
|
1387
|
+
claudeMdSection: [
|
|
1388
|
+
'## Request Logging',
|
|
1389
|
+
'All HTTP requests are logged with method, URL, status, and duration.',
|
|
1390
|
+
'Enable body logging with REQUEST_LOG_BODY=true (disable in production for PII safety).',
|
|
1391
|
+
].join('\n'),
|
|
1392
|
+
cursorRules: [
|
|
1393
|
+
'Request logging middleware captures method, URL, status code, and response time.',
|
|
1394
|
+
'Body logging is opt-in. Redact sensitive fields (password, token) before logging.',
|
|
1395
|
+
].join('\n'),
|
|
1396
|
+
copilotInstructions: [
|
|
1397
|
+
'Request/response logging middleware is applied globally. Logs method, URL, status, duration.',
|
|
1398
|
+
'Body logging is off by default. Always redact sensitive fields when enabling.',
|
|
1399
|
+
].join('\n'),
|
|
1400
|
+
},
|
|
1401
|
+
{
|
|
1402
|
+
id: 'distributed-tracing',
|
|
1403
|
+
name: 'Distributed Tracing',
|
|
1404
|
+
description: 'Trace context propagation across services',
|
|
1405
|
+
category: 'Observability',
|
|
1406
|
+
dependencies: {},
|
|
1407
|
+
devDependencies: {},
|
|
1408
|
+
envVars: [],
|
|
1409
|
+
conflicts: [],
|
|
1410
|
+
requires: [],
|
|
1411
|
+
compatibleWith: 'all',
|
|
1412
|
+
templateDir: 'distributed-tracing',
|
|
1413
|
+
claudeMdSection: [
|
|
1414
|
+
'## Distributed Tracing',
|
|
1415
|
+
'W3C Trace Context headers (traceparent, tracestate) are propagated across service calls.',
|
|
1416
|
+
'Middleware extracts incoming trace context; HttpService forwards it to outgoing requests.',
|
|
1417
|
+
].join('\n'),
|
|
1418
|
+
cursorRules: [
|
|
1419
|
+
'Trace context is propagated via W3C traceparent header. Middleware handles extraction.',
|
|
1420
|
+
'All outgoing HTTP calls must forward trace headers. Use the provided HttpService wrapper.',
|
|
1421
|
+
].join('\n'),
|
|
1422
|
+
copilotInstructions: [
|
|
1423
|
+
'Distributed tracing propagates W3C traceparent/tracestate headers across services.',
|
|
1424
|
+
'Middleware extracts context; HttpService wrapper forwards it to downstream calls.',
|
|
1425
|
+
].join('\n'),
|
|
1426
|
+
},
|
|
1427
|
+
// ─── DX ─────────────────────────────────────────────────────────────
|
|
1428
|
+
{
|
|
1429
|
+
id: 'devcontainer',
|
|
1430
|
+
name: 'Dev Container',
|
|
1431
|
+
description: 'VS Code Dev Container configuration',
|
|
1432
|
+
category: 'DX',
|
|
1433
|
+
dependencies: {},
|
|
1434
|
+
devDependencies: {},
|
|
1435
|
+
envVars: [],
|
|
1436
|
+
conflicts: [],
|
|
1437
|
+
requires: [],
|
|
1438
|
+
compatibleWith: 'all',
|
|
1439
|
+
templateDir: 'devcontainer',
|
|
1440
|
+
claudeMdSection: [
|
|
1441
|
+
'## Dev Container',
|
|
1442
|
+
'Open in VS Code with "Reopen in Container" for a fully configured dev environment.',
|
|
1443
|
+
'Docker Compose services (DB, Redis, etc.) start automatically with the container.',
|
|
1444
|
+
].join('\n'),
|
|
1445
|
+
cursorRules: [
|
|
1446
|
+
'Dev Container config is in .devcontainer/. Includes all project dependencies.',
|
|
1447
|
+
'Port forwarding, extensions, and environment are pre-configured.',
|
|
1448
|
+
].join('\n'),
|
|
1449
|
+
copilotInstructions: [
|
|
1450
|
+
'Dev Container is configured in .devcontainer/. Use "Reopen in Container" in VS Code.',
|
|
1451
|
+
'All services and tools are pre-installed. No local setup needed.',
|
|
1452
|
+
].join('\n'),
|
|
1453
|
+
},
|
|
1454
|
+
{
|
|
1455
|
+
id: 'database-seeding',
|
|
1456
|
+
name: 'Database Seeding',
|
|
1457
|
+
description: 'Database seed command for development data',
|
|
1458
|
+
category: 'DX',
|
|
1459
|
+
dependencies: {},
|
|
1460
|
+
devDependencies: {},
|
|
1461
|
+
envVars: [],
|
|
1462
|
+
conflicts: [],
|
|
1463
|
+
requires: [],
|
|
1464
|
+
compatibleWith: 'all',
|
|
1465
|
+
templateDir: 'database-seeding',
|
|
1466
|
+
claudeMdSection: [
|
|
1467
|
+
'## Database Seeding',
|
|
1468
|
+
'Run `pnpm seed` to populate the database with development data.',
|
|
1469
|
+
'Seed files are in `src/database/seeds/`. Seeds are idempotent — safe to run multiple times.',
|
|
1470
|
+
].join('\n'),
|
|
1471
|
+
cursorRules: [
|
|
1472
|
+
'Seeds live in src/database/seeds/. Each seed class implements the Seeder interface.',
|
|
1473
|
+
'Seeds must be idempotent. Use upsert logic to avoid duplicates on re-runs.',
|
|
1474
|
+
].join('\n'),
|
|
1475
|
+
copilotInstructions: [
|
|
1476
|
+
'Database seeding via `pnpm seed`. Seed files in src/database/seeds/ implement Seeder.',
|
|
1477
|
+
'All seeds are idempotent and can be run repeatedly without side effects.',
|
|
1478
|
+
].join('\n'),
|
|
1479
|
+
},
|
|
1480
|
+
{
|
|
1481
|
+
id: 'database-factories',
|
|
1482
|
+
name: 'Database Factories',
|
|
1483
|
+
description: 'Test data factories for database entities',
|
|
1484
|
+
category: 'DX',
|
|
1485
|
+
dependencies: {},
|
|
1486
|
+
devDependencies: {},
|
|
1487
|
+
envVars: [],
|
|
1488
|
+
conflicts: [],
|
|
1489
|
+
requires: [],
|
|
1490
|
+
compatibleWith: 'all',
|
|
1491
|
+
templateDir: 'database-factories',
|
|
1492
|
+
claudeMdSection: [
|
|
1493
|
+
'## Database Factories',
|
|
1494
|
+
'Use factories to create test data: `UserFactory.create({ name: "Test" })`.',
|
|
1495
|
+
'Factories are in `src/database/factories/`. Override any field in the create() call.',
|
|
1496
|
+
].join('\n'),
|
|
1497
|
+
cursorRules: [
|
|
1498
|
+
'Factories are in src/database/factories/. Each entity has a corresponding factory.',
|
|
1499
|
+
'Use Factory.create() with overrides in tests. Factories use realistic default values.',
|
|
1500
|
+
].join('\n'),
|
|
1501
|
+
copilotInstructions: [
|
|
1502
|
+
'Test data factories in src/database/factories/. Use EntityFactory.create() in tests.',
|
|
1503
|
+
'Pass partial overrides to customize. Defaults produce valid, realistic data.',
|
|
1504
|
+
].join('\n'),
|
|
1505
|
+
},
|
|
1506
|
+
{
|
|
1507
|
+
id: 'sdk-generation',
|
|
1508
|
+
name: 'SDK Generation',
|
|
1509
|
+
description: 'Auto-generate client SDKs from OpenAPI spec',
|
|
1510
|
+
category: 'DX',
|
|
1511
|
+
dependencies: {},
|
|
1512
|
+
devDependencies: {
|
|
1513
|
+
'@openapitools/openapi-generator-cli': '2.15.3',
|
|
1514
|
+
},
|
|
1515
|
+
envVars: [],
|
|
1516
|
+
conflicts: [],
|
|
1517
|
+
requires: [],
|
|
1518
|
+
compatibleWith: 'all',
|
|
1519
|
+
templateDir: 'sdk-generation',
|
|
1520
|
+
claudeMdSection: [
|
|
1521
|
+
'## SDK Generation',
|
|
1522
|
+
'Run `pnpm generate:sdk` to generate a TypeScript client SDK from the OpenAPI spec.',
|
|
1523
|
+
'Output is in `generated/sdk/`. Commit the generated SDK or publish as an npm package.',
|
|
1524
|
+
].join('\n'),
|
|
1525
|
+
cursorRules: [
|
|
1526
|
+
'SDK is auto-generated from OpenAPI spec. Do not manually edit files in generated/sdk/.',
|
|
1527
|
+
'Run `pnpm generate:sdk` after changing API endpoints. Commit generated output.',
|
|
1528
|
+
].join('\n'),
|
|
1529
|
+
copilotInstructions: [
|
|
1530
|
+
'Client SDK is generated from OpenAPI via openapi-generator-cli. Run `pnpm generate:sdk`.',
|
|
1531
|
+
'Output in generated/sdk/ is auto-generated — do not edit manually.',
|
|
1532
|
+
].join('\n'),
|
|
1533
|
+
},
|
|
1534
|
+
// ─── Operational ────────────────────────────────────────────────────
|
|
1535
|
+
{
|
|
1536
|
+
id: 'graceful-shutdown',
|
|
1537
|
+
name: 'Graceful Shutdown',
|
|
1538
|
+
description: 'Clean shutdown handling for connections and in-flight requests',
|
|
1539
|
+
category: 'Operational',
|
|
1540
|
+
dependencies: {},
|
|
1541
|
+
devDependencies: {},
|
|
1542
|
+
envVars: [
|
|
1543
|
+
{
|
|
1544
|
+
key: 'SHUTDOWN_TIMEOUT_MS',
|
|
1545
|
+
defaultValue: '10000',
|
|
1546
|
+
description: 'Max wait time for graceful shutdown',
|
|
1547
|
+
},
|
|
1548
|
+
],
|
|
1549
|
+
conflicts: [],
|
|
1550
|
+
requires: [],
|
|
1551
|
+
compatibleWith: 'all',
|
|
1552
|
+
templateDir: 'graceful-shutdown',
|
|
1553
|
+
claudeMdSection: [
|
|
1554
|
+
'## Graceful Shutdown',
|
|
1555
|
+
'SIGTERM/SIGINT trigger graceful shutdown. In-flight requests complete before exit.',
|
|
1556
|
+
'Database connections, queues, and caches are closed cleanly. Timeout is SHUTDOWN_TIMEOUT_MS.',
|
|
1557
|
+
].join('\n'),
|
|
1558
|
+
cursorRules: [
|
|
1559
|
+
'Graceful shutdown is enabled via app.enableShutdownHooks(). Implement OnModuleDestroy for cleanup.',
|
|
1560
|
+
'Close connections in onModuleDestroy(). SHUTDOWN_TIMEOUT_MS sets the maximum wait time.',
|
|
1561
|
+
].join('\n'),
|
|
1562
|
+
copilotInstructions: [
|
|
1563
|
+
'Graceful shutdown hooks handle SIGTERM/SIGINT. Implement OnModuleDestroy for resource cleanup.',
|
|
1564
|
+
'In-flight requests finish before shutdown. Timeout prevents hanging on unresponsive deps.',
|
|
1565
|
+
].join('\n'),
|
|
1566
|
+
},
|
|
1567
|
+
{
|
|
1568
|
+
id: 'circuit-breaker',
|
|
1569
|
+
name: 'Circuit Breaker',
|
|
1570
|
+
description: 'Circuit breaker pattern for external service calls',
|
|
1571
|
+
category: 'Operational',
|
|
1572
|
+
dependencies: {
|
|
1573
|
+
opossum: '9.0.0',
|
|
1574
|
+
},
|
|
1575
|
+
devDependencies: {
|
|
1576
|
+
'@types/opossum': '8.1.7',
|
|
1577
|
+
},
|
|
1578
|
+
envVars: [
|
|
1579
|
+
{
|
|
1580
|
+
key: 'CIRCUIT_BREAKER_TIMEOUT',
|
|
1581
|
+
defaultValue: '3000',
|
|
1582
|
+
description: 'Circuit breaker call timeout in ms',
|
|
1583
|
+
},
|
|
1584
|
+
{
|
|
1585
|
+
key: 'CIRCUIT_BREAKER_THRESHOLD',
|
|
1586
|
+
defaultValue: '50',
|
|
1587
|
+
description: 'Failure percentage to open circuit',
|
|
1588
|
+
},
|
|
1589
|
+
{
|
|
1590
|
+
key: 'CIRCUIT_BREAKER_RESET_TIMEOUT',
|
|
1591
|
+
defaultValue: '30000',
|
|
1592
|
+
description: 'Time before half-open retry in ms',
|
|
1593
|
+
},
|
|
1594
|
+
],
|
|
1595
|
+
conflicts: [],
|
|
1596
|
+
requires: [],
|
|
1597
|
+
compatibleWith: 'all',
|
|
1598
|
+
templateDir: 'circuit-breaker',
|
|
1599
|
+
claudeMdSection: [
|
|
1600
|
+
'## Circuit Breaker',
|
|
1601
|
+
'Wrap external service calls with CircuitBreakerService to prevent cascade failures.',
|
|
1602
|
+
'Circuit opens after CIRCUIT_BREAKER_THRESHOLD% failures. Retries after CIRCUIT_BREAKER_RESET_TIMEOUT.',
|
|
1603
|
+
].join('\n'),
|
|
1604
|
+
cursorRules: [
|
|
1605
|
+
'Use CircuitBreakerService for all external HTTP/API calls. Configure thresholds per dependency.',
|
|
1606
|
+
'Provide fallback functions for graceful degradation when the circuit is open.',
|
|
1607
|
+
].join('\n'),
|
|
1608
|
+
copilotInstructions: [
|
|
1609
|
+
'Circuit breaker via opossum protects external calls. Use CircuitBreakerService wrapper.',
|
|
1610
|
+
'Configure timeout, threshold, and reset per external dependency. Provide fallbacks.',
|
|
1611
|
+
].join('\n'),
|
|
1612
|
+
},
|
|
1613
|
+
{
|
|
1614
|
+
id: 'feature-flags',
|
|
1615
|
+
name: 'Feature Flags',
|
|
1616
|
+
description: 'Config-based feature flag system',
|
|
1617
|
+
category: 'Operational',
|
|
1618
|
+
dependencies: {},
|
|
1619
|
+
devDependencies: {},
|
|
1620
|
+
envVars: [
|
|
1621
|
+
{
|
|
1622
|
+
key: 'FEATURE_FLAGS',
|
|
1623
|
+
defaultValue: '{}',
|
|
1624
|
+
description: 'JSON object of feature flag key-value pairs',
|
|
1625
|
+
},
|
|
1626
|
+
],
|
|
1627
|
+
conflicts: [],
|
|
1628
|
+
requires: [],
|
|
1629
|
+
compatibleWith: 'all',
|
|
1630
|
+
templateDir: 'feature-flags',
|
|
1631
|
+
claudeMdSection: [
|
|
1632
|
+
'## Feature Flags',
|
|
1633
|
+
'Use FeatureFlagService.isEnabled("flag-name") to check flags. Flags are config-based.',
|
|
1634
|
+
'Set flags via FEATURE_FLAGS env var (JSON) or extend to use a remote provider.',
|
|
1635
|
+
].join('\n'),
|
|
1636
|
+
cursorRules: [
|
|
1637
|
+
'Check flags via FeatureFlagService.isEnabled(). Define new flags in the FEATURE_FLAGS config.',
|
|
1638
|
+
'Use @FeatureGuard("flag") on routes to gate entire endpoints behind a feature flag.',
|
|
1639
|
+
].join('\n'),
|
|
1640
|
+
copilotInstructions: [
|
|
1641
|
+
'Feature flags via FeatureFlagService. Check with isEnabled("flag").',
|
|
1642
|
+
'Configure via FEATURE_FLAGS env var (JSON). Use @FeatureGuard() for route-level gating.',
|
|
1643
|
+
].join('\n'),
|
|
1644
|
+
},
|
|
1645
|
+
{
|
|
1646
|
+
id: 'multi-tenancy',
|
|
1647
|
+
name: 'Multi-Tenancy',
|
|
1648
|
+
description: 'Tenant isolation via AsyncLocalStorage and middleware',
|
|
1649
|
+
category: 'Operational',
|
|
1650
|
+
dependencies: {},
|
|
1651
|
+
devDependencies: {},
|
|
1652
|
+
envVars: [
|
|
1653
|
+
{
|
|
1654
|
+
key: 'TENANT_HEADER',
|
|
1655
|
+
defaultValue: 'x-tenant-id',
|
|
1656
|
+
description: 'Header name for tenant identification',
|
|
1657
|
+
},
|
|
1658
|
+
],
|
|
1659
|
+
conflicts: [],
|
|
1660
|
+
requires: [],
|
|
1661
|
+
compatibleWith: 'all',
|
|
1662
|
+
templateDir: 'multi-tenancy',
|
|
1663
|
+
claudeMdSection: [
|
|
1664
|
+
'## Multi-Tenancy',
|
|
1665
|
+
'Tenant ID is extracted from the x-tenant-id header and stored in AsyncLocalStorage.',
|
|
1666
|
+
'Access via TenantService.getTenantId(). All queries are automatically scoped to the tenant.',
|
|
1667
|
+
].join('\n'),
|
|
1668
|
+
cursorRules: [
|
|
1669
|
+
'Tenant context is set via middleware and stored in AsyncLocalStorage. Use TenantService.',
|
|
1670
|
+
'All database queries must be tenant-scoped. Use tenant-aware base repository or interceptor.',
|
|
1671
|
+
].join('\n'),
|
|
1672
|
+
copilotInstructions: [
|
|
1673
|
+
'Multi-tenancy uses AsyncLocalStorage for tenant context. Middleware extracts from header.',
|
|
1674
|
+
'Use TenantService.getTenantId() anywhere. Ensure all queries are tenant-scoped.',
|
|
1675
|
+
].join('\n'),
|
|
1676
|
+
},
|
|
1677
|
+
// ─── Repo Hygiene ───────────────────────────────────────────────────
|
|
1678
|
+
{
|
|
1679
|
+
id: 'changelog',
|
|
1680
|
+
name: 'Changelog',
|
|
1681
|
+
description: 'Auto-generated changelog from conventional commits',
|
|
1682
|
+
category: 'Repo Hygiene',
|
|
1683
|
+
dependencies: {},
|
|
1684
|
+
devDependencies: {
|
|
1685
|
+
'conventional-changelog-cli': '5.0.0',
|
|
1686
|
+
},
|
|
1687
|
+
envVars: [],
|
|
1688
|
+
conflicts: [],
|
|
1689
|
+
requires: [],
|
|
1690
|
+
compatibleWith: 'all',
|
|
1691
|
+
templateDir: 'changelog',
|
|
1692
|
+
claudeMdSection: [
|
|
1693
|
+
'## Changelog',
|
|
1694
|
+
'Run `pnpm changelog` to generate CHANGELOG.md from conventional commits.',
|
|
1695
|
+
'The changelog is auto-generated — do not edit manually.',
|
|
1696
|
+
].join('\n'),
|
|
1697
|
+
cursorRules: [
|
|
1698
|
+
'CHANGELOG.md is auto-generated from conventional commits. Never edit it manually.',
|
|
1699
|
+
'Run `pnpm changelog` before releases. Follows Keep a Changelog format.',
|
|
1700
|
+
].join('\n'),
|
|
1701
|
+
copilotInstructions: [
|
|
1702
|
+
'Changelog is generated from conventional commits via `pnpm changelog`.',
|
|
1703
|
+
'Do not manually edit CHANGELOG.md. Use conventional commit messages for proper entries.',
|
|
1704
|
+
].join('\n'),
|
|
1705
|
+
},
|
|
1706
|
+
{
|
|
1707
|
+
id: 'license',
|
|
1708
|
+
name: 'License',
|
|
1709
|
+
description: 'License file template',
|
|
1710
|
+
category: 'Repo Hygiene',
|
|
1711
|
+
dependencies: {},
|
|
1712
|
+
devDependencies: {},
|
|
1713
|
+
envVars: [],
|
|
1714
|
+
conflicts: [],
|
|
1715
|
+
requires: [],
|
|
1716
|
+
compatibleWith: 'all',
|
|
1717
|
+
templateDir: 'license',
|
|
1718
|
+
claudeMdSection: [
|
|
1719
|
+
'## License',
|
|
1720
|
+
'See LICENSE file in the project root for licensing terms.',
|
|
1721
|
+
].join('\n'),
|
|
1722
|
+
cursorRules: ['License file is in the project root. Update copyright year as needed.'].join('\n'),
|
|
1723
|
+
copilotInstructions: ['Project license is in the LICENSE file at the project root.'].join('\n'),
|
|
1724
|
+
},
|
|
1725
|
+
{
|
|
1726
|
+
id: 'env-per-environment',
|
|
1727
|
+
name: 'Environment Files',
|
|
1728
|
+
description: 'Per-environment .env file templates',
|
|
1729
|
+
category: 'Repo Hygiene',
|
|
1730
|
+
dependencies: {},
|
|
1731
|
+
devDependencies: {},
|
|
1732
|
+
envVars: [],
|
|
1733
|
+
conflicts: [],
|
|
1734
|
+
requires: [],
|
|
1735
|
+
compatibleWith: 'all',
|
|
1736
|
+
templateDir: 'env-per-environment',
|
|
1737
|
+
claudeMdSection: [
|
|
1738
|
+
'## Environment Files',
|
|
1739
|
+
'Environment templates: `.env.development`, `.env.staging`, `.env.production`.',
|
|
1740
|
+
'Copy to `.env` for local use. Never commit `.env` — only `.env.example` and templates.',
|
|
1741
|
+
].join('\n'),
|
|
1742
|
+
cursorRules: [
|
|
1743
|
+
'Use .env.development/.env.staging/.env.production templates. Copy to .env locally.',
|
|
1744
|
+
'Never commit .env files with real secrets. Only .env.example is committed.',
|
|
1745
|
+
].join('\n'),
|
|
1746
|
+
copilotInstructions: [
|
|
1747
|
+
'Per-environment .env templates are provided. Copy the appropriate one to .env locally.',
|
|
1748
|
+
'.env is gitignored. Only .env.example and environment templates are committed.',
|
|
1749
|
+
].join('\n'),
|
|
1750
|
+
},
|
|
1751
|
+
{
|
|
1752
|
+
id: 'dependabot-renovate',
|
|
1753
|
+
name: 'Dependabot / Renovate',
|
|
1754
|
+
description: 'Automated dependency update configuration',
|
|
1755
|
+
category: 'Repo Hygiene',
|
|
1756
|
+
dependencies: {},
|
|
1757
|
+
devDependencies: {},
|
|
1758
|
+
envVars: [],
|
|
1759
|
+
conflicts: [],
|
|
1760
|
+
requires: [],
|
|
1761
|
+
compatibleWith: 'all',
|
|
1762
|
+
templateDir: 'dependabot-renovate',
|
|
1763
|
+
claudeMdSection: [
|
|
1764
|
+
'## Dependabot / Renovate',
|
|
1765
|
+
'Automated dependency update PRs are configured. Review and merge promptly.',
|
|
1766
|
+
'Config is in `.github/dependabot.yml` or `renovate.json`.',
|
|
1767
|
+
].join('\n'),
|
|
1768
|
+
cursorRules: [
|
|
1769
|
+
'Dependency update config is in .github/dependabot.yml or renovate.json.',
|
|
1770
|
+
'Review auto-generated PRs for breaking changes before merging.',
|
|
1771
|
+
].join('\n'),
|
|
1772
|
+
copilotInstructions: [
|
|
1773
|
+
'Dependabot/Renovate is configured for automated dependency updates.',
|
|
1774
|
+
'Review generated PRs carefully, especially for major version bumps.',
|
|
1775
|
+
].join('\n'),
|
|
1776
|
+
},
|
|
1777
|
+
// ─── Docs Site ──────────────────────────────────────────────────────
|
|
1778
|
+
{
|
|
1779
|
+
id: 'docs-site',
|
|
1780
|
+
name: 'Documentation Site',
|
|
1781
|
+
description: 'VitePress-powered documentation site',
|
|
1782
|
+
category: 'Docs Site',
|
|
1783
|
+
dependencies: {},
|
|
1784
|
+
devDependencies: {
|
|
1785
|
+
vitepress: '1.5.0',
|
|
1786
|
+
},
|
|
1787
|
+
envVars: [],
|
|
1788
|
+
conflicts: [],
|
|
1789
|
+
requires: [],
|
|
1790
|
+
compatibleWith: 'all',
|
|
1791
|
+
templateDir: 'docs-site',
|
|
1792
|
+
claudeMdSection: [
|
|
1793
|
+
'## Documentation Site',
|
|
1794
|
+
'Run `pnpm docs:dev` to start the VitePress dev server. Docs are in `docs/`.',
|
|
1795
|
+
'Build for production with `pnpm docs:build`. Output goes to `docs/.vitepress/dist/`.',
|
|
1796
|
+
].join('\n'),
|
|
1797
|
+
cursorRules: [
|
|
1798
|
+
'Documentation lives in docs/ using VitePress. Markdown files map to routes.',
|
|
1799
|
+
'Run `pnpm docs:dev` for local preview. Config is in docs/.vitepress/config.ts.',
|
|
1800
|
+
].join('\n'),
|
|
1801
|
+
copilotInstructions: [
|
|
1802
|
+
'VitePress documentation in docs/. Run `pnpm docs:dev` for development.',
|
|
1803
|
+
'Build with `pnpm docs:build`. Configure navigation in docs/.vitepress/config.ts.',
|
|
1804
|
+
].join('\n'),
|
|
1805
|
+
},
|
|
1806
|
+
// ─── AWS ──────────────────────────────────────────────────────────
|
|
1807
|
+
{
|
|
1808
|
+
id: 'aws-sqs',
|
|
1809
|
+
name: 'AWS SQS',
|
|
1810
|
+
description: 'Amazon Simple Queue Service integration for message queuing',
|
|
1811
|
+
category: 'Cloud — AWS',
|
|
1812
|
+
dependencies: {
|
|
1813
|
+
'@aws-sdk/client-sqs': '3.712.0',
|
|
1814
|
+
},
|
|
1815
|
+
devDependencies: {},
|
|
1816
|
+
envVars: [
|
|
1817
|
+
{ key: 'AWS_REGION', defaultValue: 'eu-west-1', description: 'AWS region' },
|
|
1818
|
+
{ key: 'SQS_QUEUE_URL', defaultValue: '', description: 'SQS queue URL' },
|
|
1819
|
+
],
|
|
1820
|
+
conflicts: [],
|
|
1821
|
+
requires: [],
|
|
1822
|
+
compatibleWith: 'all',
|
|
1823
|
+
templateDir: 'cloud-aws/sqs',
|
|
1824
|
+
claudeMdSection: [
|
|
1825
|
+
'## AWS SQS',
|
|
1826
|
+
'Use SqsService to send and receive messages. Configure queue URL via SQS_QUEUE_URL.',
|
|
1827
|
+
'Use long polling for efficient message retrieval. Handle message visibility timeouts.',
|
|
1828
|
+
].join('\n'),
|
|
1829
|
+
cursorRules: [
|
|
1830
|
+
'Use SqsService for all SQS operations. Never hardcode queue URLs — use ConfigService.',
|
|
1831
|
+
'Handle message deletion after successful processing. Use dead-letter queues for failures.',
|
|
1832
|
+
].join('\n'),
|
|
1833
|
+
copilotInstructions: [
|
|
1834
|
+
'AWS SQS via @aws-sdk/client-sqs. Use SqsService for sending and receiving messages.',
|
|
1835
|
+
'Configure SQS_QUEUE_URL in env. Use long polling and dead-letter queues.',
|
|
1836
|
+
].join('\n'),
|
|
1837
|
+
},
|
|
1838
|
+
{
|
|
1839
|
+
id: 'aws-sns',
|
|
1840
|
+
name: 'AWS SNS',
|
|
1841
|
+
description: 'Amazon Simple Notification Service for pub/sub messaging',
|
|
1842
|
+
category: 'Cloud — AWS',
|
|
1843
|
+
dependencies: {
|
|
1844
|
+
'@aws-sdk/client-sns': '3.712.0',
|
|
1845
|
+
},
|
|
1846
|
+
devDependencies: {},
|
|
1847
|
+
envVars: [
|
|
1848
|
+
{ key: 'AWS_REGION', defaultValue: 'eu-west-1', description: 'AWS region' },
|
|
1849
|
+
{ key: 'SNS_TOPIC_ARN', defaultValue: '', description: 'SNS topic ARN' },
|
|
1850
|
+
],
|
|
1851
|
+
conflicts: [],
|
|
1852
|
+
requires: [],
|
|
1853
|
+
compatibleWith: 'all',
|
|
1854
|
+
templateDir: 'cloud-aws/sns',
|
|
1855
|
+
claudeMdSection: [
|
|
1856
|
+
'## AWS SNS',
|
|
1857
|
+
'Use SnsService to publish messages to topics. Configure topic ARN via SNS_TOPIC_ARN.',
|
|
1858
|
+
'Subscribe SQS queues, Lambda functions, or HTTP endpoints to SNS topics.',
|
|
1859
|
+
].join('\n'),
|
|
1860
|
+
cursorRules: [
|
|
1861
|
+
'Use SnsService for publishing. Never hardcode topic ARNs — use ConfigService.',
|
|
1862
|
+
'Use message attributes for filtering. Fan-out patterns pair SNS with SQS subscriptions.',
|
|
1863
|
+
].join('\n'),
|
|
1864
|
+
copilotInstructions: [
|
|
1865
|
+
'AWS SNS via @aws-sdk/client-sns. Publish with SnsService.',
|
|
1866
|
+
'Topic ARN from env. Use message attributes for subscriber filtering.',
|
|
1867
|
+
].join('\n'),
|
|
1868
|
+
},
|
|
1869
|
+
{
|
|
1870
|
+
id: 'aws-eventbridge',
|
|
1871
|
+
name: 'AWS EventBridge',
|
|
1872
|
+
description: 'Amazon EventBridge for event-driven architectures',
|
|
1873
|
+
category: 'Cloud — AWS',
|
|
1874
|
+
dependencies: {
|
|
1875
|
+
'@aws-sdk/client-eventbridge': '3.712.0',
|
|
1876
|
+
},
|
|
1877
|
+
devDependencies: {},
|
|
1878
|
+
envVars: [
|
|
1879
|
+
{ key: 'AWS_REGION', defaultValue: 'eu-west-1', description: 'AWS region' },
|
|
1880
|
+
{ key: 'EVENTBRIDGE_BUS_NAME', defaultValue: 'default', description: 'EventBridge bus name' },
|
|
1881
|
+
],
|
|
1882
|
+
conflicts: [],
|
|
1883
|
+
requires: [],
|
|
1884
|
+
compatibleWith: 'all',
|
|
1885
|
+
templateDir: 'cloud-aws/eventbridge',
|
|
1886
|
+
claudeMdSection: [
|
|
1887
|
+
'## AWS EventBridge',
|
|
1888
|
+
'Use EventBridgeService to put events on the bus. Configure bus name via EVENTBRIDGE_BUS_NAME.',
|
|
1889
|
+
'Define event patterns and rules in infrastructure-as-code, not application code.',
|
|
1890
|
+
].join('\n'),
|
|
1891
|
+
cursorRules: [
|
|
1892
|
+
'Use EventBridgeService to publish domain events. Define detail-type and source consistently.',
|
|
1893
|
+
'Event rules and targets belong in IaC (Terraform/CDK), not in application code.',
|
|
1894
|
+
].join('\n'),
|
|
1895
|
+
copilotInstructions: [
|
|
1896
|
+
'AWS EventBridge via @aws-sdk/client-eventbridge. Use EventBridgeService for events.',
|
|
1897
|
+
'Set EVENTBRIDGE_BUS_NAME in env. Keep event schemas consistent across services.',
|
|
1898
|
+
].join('\n'),
|
|
1899
|
+
},
|
|
1900
|
+
{
|
|
1901
|
+
id: 'aws-secrets-manager',
|
|
1902
|
+
name: 'AWS Secrets Manager',
|
|
1903
|
+
description: 'Retrieve and cache secrets from AWS Secrets Manager',
|
|
1904
|
+
category: 'Cloud — AWS',
|
|
1905
|
+
dependencies: {
|
|
1906
|
+
'@aws-sdk/client-secrets-manager': '3.712.0',
|
|
1907
|
+
},
|
|
1908
|
+
devDependencies: {},
|
|
1909
|
+
envVars: [{ key: 'AWS_REGION', defaultValue: 'eu-west-1', description: 'AWS region' }],
|
|
1910
|
+
conflicts: [],
|
|
1911
|
+
requires: [],
|
|
1912
|
+
compatibleWith: 'all',
|
|
1913
|
+
templateDir: 'cloud-aws/secrets-manager',
|
|
1914
|
+
claudeMdSection: [
|
|
1915
|
+
'## AWS Secrets Manager',
|
|
1916
|
+
'Use SecretsService to fetch secrets at startup. Secrets are cached to reduce API calls.',
|
|
1917
|
+
'Rotate secrets via AWS console or CLI — the app reads the latest version automatically.',
|
|
1918
|
+
].join('\n'),
|
|
1919
|
+
cursorRules: [
|
|
1920
|
+
'Use SecretsService to load secrets. Cache secrets in memory and refresh on a schedule.',
|
|
1921
|
+
'Never store secret values in env files for production — use Secrets Manager exclusively.',
|
|
1922
|
+
].join('\n'),
|
|
1923
|
+
copilotInstructions: [
|
|
1924
|
+
'AWS Secrets Manager via @aws-sdk/client-secrets-manager. Use SecretsService wrapper.',
|
|
1925
|
+
'Secrets are cached locally. Rotation is handled by AWS — app reads latest version.',
|
|
1926
|
+
].join('\n'),
|
|
1927
|
+
},
|
|
1928
|
+
{
|
|
1929
|
+
id: 'aws-ssm',
|
|
1930
|
+
name: 'AWS SSM Parameter Store',
|
|
1931
|
+
description: 'Retrieve configuration from AWS Systems Manager Parameter Store',
|
|
1932
|
+
category: 'Cloud — AWS',
|
|
1933
|
+
dependencies: {
|
|
1934
|
+
'@aws-sdk/client-ssm': '3.712.0',
|
|
1935
|
+
},
|
|
1936
|
+
devDependencies: {},
|
|
1937
|
+
envVars: [
|
|
1938
|
+
{ key: 'AWS_REGION', defaultValue: 'eu-west-1', description: 'AWS region' },
|
|
1939
|
+
{ key: 'SSM_PREFIX', defaultValue: '/app/prod', description: 'SSM parameter path prefix' },
|
|
1940
|
+
],
|
|
1941
|
+
conflicts: [],
|
|
1942
|
+
requires: [],
|
|
1943
|
+
compatibleWith: 'all',
|
|
1944
|
+
templateDir: 'cloud-aws/ssm',
|
|
1945
|
+
claudeMdSection: [
|
|
1946
|
+
'## AWS SSM Parameter Store',
|
|
1947
|
+
'Use SsmService to load parameters by path prefix at bootstrap.',
|
|
1948
|
+
'Parameters are cached and refreshed periodically. Use SecureString type for sensitive values.',
|
|
1949
|
+
].join('\n'),
|
|
1950
|
+
cursorRules: [
|
|
1951
|
+
'Use SsmService to load configuration. Organize parameters under a path prefix per environment.',
|
|
1952
|
+
'Use SecureString for sensitive values. Cache parameters and refresh on a configurable interval.',
|
|
1953
|
+
].join('\n'),
|
|
1954
|
+
copilotInstructions: [
|
|
1955
|
+
'AWS SSM Parameter Store via @aws-sdk/client-ssm. Use SsmService for config values.',
|
|
1956
|
+
'Set SSM_PREFIX per environment. SecureString for secrets, String for plain config.',
|
|
1957
|
+
].join('\n'),
|
|
1958
|
+
},
|
|
1959
|
+
{
|
|
1960
|
+
id: 'aws-s3',
|
|
1961
|
+
name: 'AWS S3',
|
|
1962
|
+
description: 'Amazon S3 object storage for file uploads and downloads',
|
|
1963
|
+
category: 'Cloud — AWS',
|
|
1964
|
+
dependencies: {
|
|
1965
|
+
'@aws-sdk/client-s3': '3.712.0',
|
|
1966
|
+
'@aws-sdk/s3-request-presigner': '3.712.0',
|
|
1967
|
+
},
|
|
1968
|
+
devDependencies: {},
|
|
1969
|
+
envVars: [
|
|
1970
|
+
{ key: 'AWS_REGION', defaultValue: 'eu-west-1', description: 'AWS region' },
|
|
1971
|
+
{ key: 'S3_BUCKET', defaultValue: 'my-bucket', description: 'S3 bucket name' },
|
|
1972
|
+
],
|
|
1973
|
+
conflicts: [],
|
|
1974
|
+
requires: [],
|
|
1975
|
+
compatibleWith: 'all',
|
|
1976
|
+
templateDir: 'cloud-aws/s3',
|
|
1977
|
+
claudeMdSection: [
|
|
1978
|
+
'## AWS S3',
|
|
1979
|
+
'Use S3Service for uploads, downloads, and presigned URLs.',
|
|
1980
|
+
'Configure bucket name via S3_BUCKET. Use presigned URLs for client-side uploads.',
|
|
1981
|
+
].join('\n'),
|
|
1982
|
+
cursorRules: [
|
|
1983
|
+
'Use S3Service abstraction for all S3 operations. Never expose AWS credentials to clients.',
|
|
1984
|
+
'Generate presigned URLs for direct browser uploads. Set appropriate content-type and size limits.',
|
|
1985
|
+
].join('\n'),
|
|
1986
|
+
copilotInstructions: [
|
|
1987
|
+
'AWS S3 via @aws-sdk/client-s3. Use S3Service for file operations.',
|
|
1988
|
+
'Presigned URLs for client uploads. Bucket name from S3_BUCKET env var.',
|
|
1989
|
+
].join('\n'),
|
|
1990
|
+
},
|
|
1991
|
+
{
|
|
1992
|
+
id: 'aws-cognito',
|
|
1993
|
+
name: 'AWS Cognito',
|
|
1994
|
+
description: 'AWS Cognito user pool authentication and authorization',
|
|
1995
|
+
category: 'Cloud — AWS',
|
|
1996
|
+
dependencies: {
|
|
1997
|
+
'@aws-sdk/client-cognito-identity-provider': '3.712.0',
|
|
1998
|
+
'aws-jwt-verify': '4.0.1',
|
|
1999
|
+
},
|
|
2000
|
+
devDependencies: {},
|
|
2001
|
+
envVars: [
|
|
2002
|
+
{ key: 'AWS_REGION', defaultValue: 'eu-west-1', description: 'AWS region' },
|
|
2003
|
+
{ key: 'COGNITO_USER_POOL_ID', defaultValue: '', description: 'Cognito user pool ID' },
|
|
2004
|
+
{ key: 'COGNITO_CLIENT_ID', defaultValue: '', description: 'Cognito app client ID' },
|
|
2005
|
+
],
|
|
2006
|
+
conflicts: [],
|
|
2007
|
+
requires: [],
|
|
2008
|
+
compatibleWith: 'all',
|
|
2009
|
+
templateDir: 'cloud-aws/cognito',
|
|
2010
|
+
claudeMdSection: [
|
|
2011
|
+
'## AWS Cognito',
|
|
2012
|
+
'Use CognitoAuthGuard to validate Cognito JWT tokens on protected routes.',
|
|
2013
|
+
'Configure user pool ID and client ID via environment variables.',
|
|
2014
|
+
].join('\n'),
|
|
2015
|
+
cursorRules: [
|
|
2016
|
+
'Use CognitoAuthGuard for authentication. Validate JWTs against the Cognito JWKS endpoint.',
|
|
2017
|
+
'Configure COGNITO_USER_POOL_ID and COGNITO_CLIENT_ID from env. Use groups for RBAC.',
|
|
2018
|
+
].join('\n'),
|
|
2019
|
+
copilotInstructions: [
|
|
2020
|
+
'AWS Cognito authenticates users via JWT. Apply CognitoAuthGuard to protected routes.',
|
|
2021
|
+
'User pool and client IDs from env. Token validation uses Cognito JWKS endpoint.',
|
|
2022
|
+
].join('\n'),
|
|
2023
|
+
},
|
|
2024
|
+
{
|
|
2025
|
+
id: 'aws-cloudwatch',
|
|
2026
|
+
name: 'AWS CloudWatch Logs',
|
|
2027
|
+
description: 'Ship application logs to AWS CloudWatch Logs',
|
|
2028
|
+
category: 'Cloud — AWS',
|
|
2029
|
+
dependencies: {
|
|
2030
|
+
'@aws-sdk/client-cloudwatch-logs': '3.712.0',
|
|
2031
|
+
},
|
|
2032
|
+
devDependencies: {},
|
|
2033
|
+
envVars: [
|
|
2034
|
+
{ key: 'AWS_REGION', defaultValue: 'eu-west-1', description: 'AWS region' },
|
|
2035
|
+
{
|
|
2036
|
+
key: 'CLOUDWATCH_LOG_GROUP',
|
|
2037
|
+
defaultValue: '/app/nestjs',
|
|
2038
|
+
description: 'CloudWatch log group name',
|
|
2039
|
+
},
|
|
2040
|
+
],
|
|
2041
|
+
conflicts: [],
|
|
2042
|
+
requires: [],
|
|
2043
|
+
compatibleWith: 'all',
|
|
2044
|
+
templateDir: 'cloud-aws/cloudwatch',
|
|
2045
|
+
claudeMdSection: [
|
|
2046
|
+
'## AWS CloudWatch Logs',
|
|
2047
|
+
'Application logs are shipped to CloudWatch Logs. Configure log group via CLOUDWATCH_LOG_GROUP.',
|
|
2048
|
+
'Use structured JSON logging for CloudWatch Insights queries.',
|
|
2049
|
+
].join('\n'),
|
|
2050
|
+
cursorRules: [
|
|
2051
|
+
'Logs are sent to CloudWatch. Use structured JSON for queryability in CloudWatch Insights.',
|
|
2052
|
+
'Configure CLOUDWATCH_LOG_GROUP from env. Use log streams per instance or container.',
|
|
2053
|
+
].join('\n'),
|
|
2054
|
+
copilotInstructions: [
|
|
2055
|
+
'AWS CloudWatch Logs via @aws-sdk/client-cloudwatch-logs. Structured JSON logs.',
|
|
2056
|
+
'Log group from CLOUDWATCH_LOG_GROUP env. Use Insights for querying.',
|
|
2057
|
+
].join('\n'),
|
|
2058
|
+
},
|
|
2059
|
+
{
|
|
2060
|
+
id: 'aws-rds',
|
|
2061
|
+
name: 'AWS RDS',
|
|
2062
|
+
description: 'AWS RDS connection with IAM authentication support',
|
|
2063
|
+
category: 'Cloud — AWS',
|
|
2064
|
+
dependencies: {
|
|
2065
|
+
'@nestjs/typeorm': '10.0.2',
|
|
2066
|
+
typeorm: '0.3.20',
|
|
2067
|
+
pg: '8.13.1',
|
|
2068
|
+
},
|
|
2069
|
+
devDependencies: {},
|
|
2070
|
+
envVars: [
|
|
2071
|
+
{ key: 'AWS_REGION', defaultValue: 'eu-west-1', description: 'AWS region' },
|
|
2072
|
+
{ key: 'RDS_HOST', defaultValue: '', description: 'RDS instance endpoint' },
|
|
2073
|
+
{ key: 'RDS_PORT', defaultValue: '5432', description: 'RDS port' },
|
|
2074
|
+
{ key: 'RDS_DATABASE', defaultValue: 'app', description: 'RDS database name' },
|
|
2075
|
+
{ key: 'RDS_USERNAME', defaultValue: 'postgres', description: 'RDS username' },
|
|
2076
|
+
{ key: 'RDS_PASSWORD', defaultValue: '', description: 'RDS password' },
|
|
2077
|
+
],
|
|
2078
|
+
conflicts: [],
|
|
2079
|
+
requires: [],
|
|
2080
|
+
compatibleWith: 'all',
|
|
2081
|
+
templateDir: 'cloud-aws/rds',
|
|
2082
|
+
claudeMdSection: [
|
|
2083
|
+
'## AWS RDS',
|
|
2084
|
+
'TypeORM connects to RDS PostgreSQL. Use IAM authentication in production for passwordless access.',
|
|
2085
|
+
'Configure RDS endpoint and credentials via environment variables.',
|
|
2086
|
+
].join('\n'),
|
|
2087
|
+
cursorRules: [
|
|
2088
|
+
'RDS connection uses TypeORM. Use IAM database authentication in production environments.',
|
|
2089
|
+
'Enable SSL for RDS connections. Use RDS Proxy for connection pooling in serverless setups.',
|
|
2090
|
+
].join('\n'),
|
|
2091
|
+
copilotInstructions: [
|
|
2092
|
+
'AWS RDS with TypeORM. Connection details from RDS_HOST, RDS_PORT, RDS_DATABASE env vars.',
|
|
2093
|
+
'Use IAM auth in production. Enable SSL and consider RDS Proxy for Lambda.',
|
|
2094
|
+
].join('\n'),
|
|
2095
|
+
},
|
|
2096
|
+
{
|
|
2097
|
+
id: 'aws-dynamodb',
|
|
2098
|
+
name: 'AWS DynamoDB',
|
|
2099
|
+
description: 'Amazon DynamoDB NoSQL database integration',
|
|
2100
|
+
category: 'Cloud — AWS',
|
|
2101
|
+
dependencies: {
|
|
2102
|
+
'@aws-sdk/client-dynamodb': '3.712.0',
|
|
2103
|
+
'@aws-sdk/lib-dynamodb': '3.712.0',
|
|
2104
|
+
},
|
|
2105
|
+
devDependencies: {},
|
|
2106
|
+
envVars: [
|
|
2107
|
+
{ key: 'AWS_REGION', defaultValue: 'eu-west-1', description: 'AWS region' },
|
|
2108
|
+
{ key: 'DYNAMODB_TABLE_NAME', defaultValue: 'app-table', description: 'DynamoDB table name' },
|
|
2109
|
+
],
|
|
2110
|
+
conflicts: [],
|
|
2111
|
+
requires: [],
|
|
2112
|
+
compatibleWith: 'all',
|
|
2113
|
+
templateDir: 'cloud-aws/dynamodb',
|
|
2114
|
+
claudeMdSection: [
|
|
2115
|
+
'## AWS DynamoDB',
|
|
2116
|
+
'Use DynamoDbService for CRUD operations. Table name is configured via DYNAMODB_TABLE_NAME.',
|
|
2117
|
+
'Use the Document Client (lib-dynamodb) for simplified marshalling of JavaScript objects.',
|
|
2118
|
+
].join('\n'),
|
|
2119
|
+
cursorRules: [
|
|
2120
|
+
'Use DynamoDbService with lib-dynamodb Document Client. Design single-table patterns carefully.',
|
|
2121
|
+
'Use partition and sort keys effectively. Prefer Query over Scan for performance.',
|
|
2122
|
+
].join('\n'),
|
|
2123
|
+
copilotInstructions: [
|
|
2124
|
+
'AWS DynamoDB via @aws-sdk/client-dynamodb and lib-dynamodb. Use DynamoDbService wrapper.',
|
|
2125
|
+
'Table from DYNAMODB_TABLE_NAME env. Use Query over Scan. Design access patterns first.',
|
|
2126
|
+
].join('\n'),
|
|
2127
|
+
},
|
|
2128
|
+
{
|
|
2129
|
+
id: 'aws-elasticache',
|
|
2130
|
+
name: 'AWS ElastiCache',
|
|
2131
|
+
description: 'AWS ElastiCache (Redis) for managed caching',
|
|
2132
|
+
category: 'Cloud — AWS',
|
|
2133
|
+
dependencies: {
|
|
2134
|
+
ioredis: '5.4.2',
|
|
2135
|
+
},
|
|
2136
|
+
devDependencies: {},
|
|
2137
|
+
envVars: [
|
|
2138
|
+
{
|
|
2139
|
+
key: 'ELASTICACHE_ENDPOINT',
|
|
2140
|
+
defaultValue: '',
|
|
2141
|
+
description: 'ElastiCache primary endpoint',
|
|
2142
|
+
},
|
|
2143
|
+
{ key: 'ELASTICACHE_PORT', defaultValue: '6379', description: 'ElastiCache port' },
|
|
2144
|
+
],
|
|
2145
|
+
conflicts: [],
|
|
2146
|
+
requires: [],
|
|
2147
|
+
compatibleWith: 'all',
|
|
2148
|
+
templateDir: 'cloud-aws/elasticache',
|
|
2149
|
+
claudeMdSection: [
|
|
2150
|
+
'## AWS ElastiCache',
|
|
2151
|
+
'ElastiCache Redis is used for caching. Connect via ELASTICACHE_ENDPOINT.',
|
|
2152
|
+
'Enable TLS for in-transit encryption. Use Redis cluster mode for high availability.',
|
|
2153
|
+
].join('\n'),
|
|
2154
|
+
cursorRules: [
|
|
2155
|
+
'Connect to ElastiCache via ioredis. Enable TLS in production.',
|
|
2156
|
+
'Use ELASTICACHE_ENDPOINT from env. Design cache keys with clear namespacing.',
|
|
2157
|
+
].join('\n'),
|
|
2158
|
+
copilotInstructions: [
|
|
2159
|
+
'AWS ElastiCache (Redis) via ioredis. Endpoint from ELASTICACHE_ENDPOINT env.',
|
|
2160
|
+
'Enable TLS for production. Use cluster mode for HA. Namespace cache keys.',
|
|
2161
|
+
].join('\n'),
|
|
2162
|
+
},
|
|
2163
|
+
{
|
|
2164
|
+
id: 'aws-cloudfront',
|
|
2165
|
+
name: 'AWS CloudFront',
|
|
2166
|
+
description: 'AWS CloudFront CDN integration with signed URLs',
|
|
2167
|
+
category: 'Cloud — AWS',
|
|
2168
|
+
dependencies: {
|
|
2169
|
+
'@aws-sdk/client-cloudfront': '3.712.0',
|
|
2170
|
+
'@aws-sdk/cloudfront-signer': '3.723.0',
|
|
2171
|
+
},
|
|
2172
|
+
devDependencies: {},
|
|
2173
|
+
envVars: [
|
|
2174
|
+
{
|
|
2175
|
+
key: 'CLOUDFRONT_KEY_PAIR_ID',
|
|
2176
|
+
defaultValue: '',
|
|
2177
|
+
description: 'CloudFront key pair ID for signed URLs',
|
|
2178
|
+
},
|
|
2179
|
+
{
|
|
2180
|
+
key: 'CLOUDFRONT_PRIVATE_KEY',
|
|
2181
|
+
defaultValue: '',
|
|
2182
|
+
description: 'CloudFront private key for signed URLs',
|
|
2183
|
+
},
|
|
2184
|
+
],
|
|
2185
|
+
conflicts: [],
|
|
2186
|
+
requires: [],
|
|
2187
|
+
compatibleWith: 'all',
|
|
2188
|
+
templateDir: 'cloud-aws/cloudfront',
|
|
2189
|
+
claudeMdSection: [
|
|
2190
|
+
'## AWS CloudFront',
|
|
2191
|
+
'Use CloudFrontService to generate signed URLs and invalidate caches.',
|
|
2192
|
+
'Configure distribution domain and key pair ID for signed URL generation.',
|
|
2193
|
+
].join('\n'),
|
|
2194
|
+
cursorRules: [
|
|
2195
|
+
'Use CloudFrontService for signed URLs and cache invalidation. Never expose signing keys.',
|
|
2196
|
+
'Set CLOUDFRONT_DOMAIN and CLOUDFRONT_KEY_PAIR_ID from env. Use signed URLs for private content.',
|
|
2197
|
+
].join('\n'),
|
|
2198
|
+
copilotInstructions: [
|
|
2199
|
+
'AWS CloudFront via @aws-sdk/client-cloudfront. Use CloudFrontService for signed URLs.',
|
|
2200
|
+
'Distribution config from env. Use cache invalidation sparingly — prefer versioned paths.',
|
|
2201
|
+
].join('\n'),
|
|
2202
|
+
},
|
|
2203
|
+
// ─── GCP ──────────────────────────────────────────────────────────
|
|
2204
|
+
{
|
|
2205
|
+
id: 'gcp-pubsub',
|
|
2206
|
+
name: 'GCP Pub/Sub',
|
|
2207
|
+
description: 'Google Cloud Pub/Sub messaging integration',
|
|
2208
|
+
category: 'Cloud — GCP',
|
|
2209
|
+
dependencies: {
|
|
2210
|
+
'@google-cloud/pubsub': '4.9.0',
|
|
2211
|
+
},
|
|
2212
|
+
devDependencies: {},
|
|
2213
|
+
envVars: [
|
|
2214
|
+
{ key: 'GCP_PROJECT_ID', defaultValue: '', description: 'GCP project ID' },
|
|
2215
|
+
{ key: 'PUBSUB_TOPIC', defaultValue: '', description: 'Pub/Sub topic name' },
|
|
2216
|
+
{ key: 'PUBSUB_SUBSCRIPTION', defaultValue: '', description: 'Pub/Sub subscription name' },
|
|
2217
|
+
],
|
|
2218
|
+
conflicts: [],
|
|
2219
|
+
requires: [],
|
|
2220
|
+
compatibleWith: 'all',
|
|
2221
|
+
templateDir: 'cloud-gcp/pubsub',
|
|
2222
|
+
claudeMdSection: [
|
|
2223
|
+
'## GCP Pub/Sub',
|
|
2224
|
+
'Use PubSubService to publish and subscribe to messages. Configure topic and subscription via env.',
|
|
2225
|
+
'Use ordering keys for ordered delivery. Enable dead-letter topics for failed messages.',
|
|
2226
|
+
].join('\n'),
|
|
2227
|
+
cursorRules: [
|
|
2228
|
+
'Use PubSubService for publish/subscribe. Configure GCP_PROJECT_ID and topic names from env.',
|
|
2229
|
+
'Acknowledge messages after processing. Use dead-letter topics for poison messages.',
|
|
2230
|
+
].join('\n'),
|
|
2231
|
+
copilotInstructions: [
|
|
2232
|
+
'GCP Pub/Sub via @google-cloud/pubsub. Use PubSubService for messaging.',
|
|
2233
|
+
'Set GCP_PROJECT_ID and PUBSUB_TOPIC in env. Ack messages after successful processing.',
|
|
2234
|
+
].join('\n'),
|
|
2235
|
+
},
|
|
2236
|
+
{
|
|
2237
|
+
id: 'gcp-secret-manager',
|
|
2238
|
+
name: 'GCP Secret Manager',
|
|
2239
|
+
description: 'Google Cloud Secret Manager for secret storage',
|
|
2240
|
+
category: 'Cloud — GCP',
|
|
2241
|
+
dependencies: {
|
|
2242
|
+
'@google-cloud/secret-manager': '5.6.0',
|
|
2243
|
+
},
|
|
2244
|
+
devDependencies: {},
|
|
2245
|
+
envVars: [{ key: 'GCP_PROJECT_ID', defaultValue: '', description: 'GCP project ID' }],
|
|
2246
|
+
conflicts: [],
|
|
2247
|
+
requires: [],
|
|
2248
|
+
compatibleWith: 'all',
|
|
2249
|
+
templateDir: 'cloud-gcp/secret-manager',
|
|
2250
|
+
claudeMdSection: [
|
|
2251
|
+
'## GCP Secret Manager',
|
|
2252
|
+
'Use GcpSecretsService to fetch secrets at startup. Secrets are cached to reduce API calls.',
|
|
2253
|
+
'Secret versions are managed in GCP console. The app reads the latest version by default.',
|
|
2254
|
+
].join('\n'),
|
|
2255
|
+
cursorRules: [
|
|
2256
|
+
'Use GcpSecretsService for secrets. Cache values and refresh periodically.',
|
|
2257
|
+
'Never store production secrets in env files — use Secret Manager exclusively.',
|
|
2258
|
+
].join('\n'),
|
|
2259
|
+
copilotInstructions: [
|
|
2260
|
+
'GCP Secret Manager via @google-cloud/secret-manager. Use GcpSecretsService wrapper.',
|
|
2261
|
+
'Set GCP_PROJECT_ID in env. Secrets cached locally with periodic refresh.',
|
|
2262
|
+
].join('\n'),
|
|
2263
|
+
},
|
|
2264
|
+
{
|
|
2265
|
+
id: 'gcp-cloud-storage',
|
|
2266
|
+
name: 'GCP Cloud Storage',
|
|
2267
|
+
description: 'Google Cloud Storage for object storage',
|
|
2268
|
+
category: 'Cloud — GCP',
|
|
2269
|
+
dependencies: {
|
|
2270
|
+
'@google-cloud/storage': '7.14.0',
|
|
2271
|
+
},
|
|
2272
|
+
devDependencies: {},
|
|
2273
|
+
envVars: [
|
|
2274
|
+
{ key: 'GCP_PROJECT_ID', defaultValue: '', description: 'GCP project ID' },
|
|
2275
|
+
{ key: 'GCS_BUCKET', defaultValue: '', description: 'Cloud Storage bucket name' },
|
|
2276
|
+
],
|
|
2277
|
+
conflicts: [],
|
|
2278
|
+
requires: [],
|
|
2279
|
+
compatibleWith: 'all',
|
|
2280
|
+
templateDir: 'cloud-gcp/cloud-storage',
|
|
2281
|
+
claudeMdSection: [
|
|
2282
|
+
'## GCP Cloud Storage',
|
|
2283
|
+
'Use GcsStorageService for file uploads, downloads, and signed URLs.',
|
|
2284
|
+
'Configure bucket name via GCS_BUCKET. Use signed URLs for client-side uploads.',
|
|
2285
|
+
].join('\n'),
|
|
2286
|
+
cursorRules: [
|
|
2287
|
+
'Use GcsStorageService for all Cloud Storage operations. Never expose service account keys to clients.',
|
|
2288
|
+
'Use signed URLs for direct browser uploads. Set appropriate content-type and size limits.',
|
|
2289
|
+
].join('\n'),
|
|
2290
|
+
copilotInstructions: [
|
|
2291
|
+
'GCP Cloud Storage via @google-cloud/storage. Use GcsStorageService for file operations.',
|
|
2292
|
+
'Bucket name from GCS_BUCKET env. Use signed URLs for client uploads.',
|
|
2293
|
+
].join('\n'),
|
|
2294
|
+
},
|
|
2295
|
+
{
|
|
2296
|
+
id: 'gcp-cloud-functions',
|
|
2297
|
+
name: 'GCP Cloud Functions',
|
|
2298
|
+
description: 'Google Cloud Functions integration for serverless workloads',
|
|
2299
|
+
category: 'Cloud — GCP',
|
|
2300
|
+
dependencies: {
|
|
2301
|
+
'@google-cloud/functions-framework': '3.4.5',
|
|
2302
|
+
},
|
|
2303
|
+
devDependencies: {},
|
|
2304
|
+
envVars: [
|
|
2305
|
+
{ key: 'GCP_PROJECT_ID', defaultValue: '', description: 'GCP project ID' },
|
|
2306
|
+
{
|
|
2307
|
+
key: 'FUNCTION_TARGET',
|
|
2308
|
+
defaultValue: 'handler',
|
|
2309
|
+
description: 'Cloud Function entry point',
|
|
2310
|
+
},
|
|
2311
|
+
],
|
|
2312
|
+
conflicts: [],
|
|
2313
|
+
requires: [],
|
|
2314
|
+
compatibleWith: 'all',
|
|
2315
|
+
templateDir: 'cloud-gcp/cloud-functions',
|
|
2316
|
+
claudeMdSection: [
|
|
2317
|
+
'## GCP Cloud Functions',
|
|
2318
|
+
'The NestJS app is wrapped for Cloud Functions via the functions-framework.',
|
|
2319
|
+
'Set FUNCTION_TARGET to the exported handler function name.',
|
|
2320
|
+
].join('\n'),
|
|
2321
|
+
cursorRules: [
|
|
2322
|
+
'Cloud Functions entry point wraps the NestJS app. Keep cold start time minimal.',
|
|
2323
|
+
'Use lazy initialization for heavy dependencies. Set FUNCTION_TARGET in deployment config.',
|
|
2324
|
+
].join('\n'),
|
|
2325
|
+
copilotInstructions: [
|
|
2326
|
+
'GCP Cloud Functions via @google-cloud/functions-framework. NestJS wrapped as function.',
|
|
2327
|
+
'Optimize for cold starts. FUNCTION_TARGET env sets the entry point.',
|
|
2328
|
+
].join('\n'),
|
|
2329
|
+
},
|
|
2330
|
+
{
|
|
2331
|
+
id: 'gcp-firebase-auth',
|
|
2332
|
+
name: 'GCP Firebase Auth',
|
|
2333
|
+
description: 'Firebase Authentication for user identity management',
|
|
2334
|
+
category: 'Cloud — GCP',
|
|
2335
|
+
dependencies: {
|
|
2336
|
+
'firebase-admin': '13.0.2',
|
|
2337
|
+
},
|
|
2338
|
+
devDependencies: {},
|
|
2339
|
+
envVars: [
|
|
2340
|
+
{ key: 'GCP_PROJECT_ID', defaultValue: '', description: 'GCP/Firebase project ID' },
|
|
2341
|
+
{
|
|
2342
|
+
key: 'GOOGLE_APPLICATION_CREDENTIALS',
|
|
2343
|
+
defaultValue: '',
|
|
2344
|
+
description: 'Path to service account key JSON',
|
|
2345
|
+
},
|
|
2346
|
+
],
|
|
2347
|
+
conflicts: [],
|
|
2348
|
+
requires: [],
|
|
2349
|
+
compatibleWith: 'all',
|
|
2350
|
+
templateDir: 'cloud-gcp/firebase-auth',
|
|
2351
|
+
claudeMdSection: [
|
|
2352
|
+
'## GCP Firebase Auth',
|
|
2353
|
+
'Use FirebaseAuthGuard to validate Firebase ID tokens on protected routes.',
|
|
2354
|
+
'Initialize firebase-admin with application default credentials or a service account key.',
|
|
2355
|
+
].join('\n'),
|
|
2356
|
+
cursorRules: [
|
|
2357
|
+
'Use FirebaseAuthGuard for authentication. Validate ID tokens via firebase-admin verifyIdToken.',
|
|
2358
|
+
'Initialize admin SDK once in a module provider. Use application default credentials in GCP.',
|
|
2359
|
+
].join('\n'),
|
|
2360
|
+
copilotInstructions: [
|
|
2361
|
+
'Firebase Auth via firebase-admin. Apply FirebaseAuthGuard to protected routes.',
|
|
2362
|
+
'Token validation uses admin.auth().verifyIdToken(). Set GOOGLE_APPLICATION_CREDENTIALS.',
|
|
2363
|
+
].join('\n'),
|
|
2364
|
+
},
|
|
2365
|
+
{
|
|
2366
|
+
id: 'gcp-cloud-logging',
|
|
2367
|
+
name: 'GCP Cloud Logging',
|
|
2368
|
+
description: 'Google Cloud Logging (Stackdriver) integration',
|
|
2369
|
+
category: 'Cloud — GCP',
|
|
2370
|
+
dependencies: {
|
|
2371
|
+
'@google-cloud/logging': '11.2.0',
|
|
2372
|
+
},
|
|
2373
|
+
devDependencies: {},
|
|
2374
|
+
envVars: [
|
|
2375
|
+
{ key: 'GCP_PROJECT_ID', defaultValue: '', description: 'GCP project ID' },
|
|
2376
|
+
{ key: 'GCP_LOG_NAME', defaultValue: 'nestjs-app', description: 'Cloud Logging log name' },
|
|
2377
|
+
],
|
|
2378
|
+
conflicts: [],
|
|
2379
|
+
requires: [],
|
|
2380
|
+
compatibleWith: 'all',
|
|
2381
|
+
templateDir: 'cloud-gcp/cloud-logging',
|
|
2382
|
+
claudeMdSection: [
|
|
2383
|
+
'## GCP Cloud Logging',
|
|
2384
|
+
'Application logs are shipped to Cloud Logging. Configure log name via GCP_LOG_NAME.',
|
|
2385
|
+
'Use structured JSON for Cloud Logging query compatibility.',
|
|
2386
|
+
].join('\n'),
|
|
2387
|
+
cursorRules: [
|
|
2388
|
+
'Logs are sent to Cloud Logging. Use structured JSON for queryability in Logs Explorer.',
|
|
2389
|
+
'Configure GCP_LOG_NAME from env. Include severity levels compatible with Cloud Logging.',
|
|
2390
|
+
].join('\n'),
|
|
2391
|
+
copilotInstructions: [
|
|
2392
|
+
'GCP Cloud Logging via @google-cloud/logging. Structured JSON logs.',
|
|
2393
|
+
'Log name from GCP_LOG_NAME env. Use severity levels matching Cloud Logging.',
|
|
2394
|
+
].join('\n'),
|
|
2395
|
+
},
|
|
2396
|
+
{
|
|
2397
|
+
id: 'gcp-cloud-sql',
|
|
2398
|
+
name: 'GCP Cloud SQL',
|
|
2399
|
+
description: 'Google Cloud SQL managed database connection',
|
|
2400
|
+
category: 'Cloud — GCP',
|
|
2401
|
+
dependencies: {
|
|
2402
|
+
'@nestjs/typeorm': '10.0.2',
|
|
2403
|
+
typeorm: '0.3.20',
|
|
2404
|
+
pg: '8.13.1',
|
|
2405
|
+
},
|
|
2406
|
+
devDependencies: {},
|
|
2407
|
+
envVars: [
|
|
2408
|
+
{ key: 'GCP_PROJECT_ID', defaultValue: '', description: 'GCP project ID' },
|
|
2409
|
+
{
|
|
2410
|
+
key: 'CLOUD_SQL_CONNECTION_NAME',
|
|
2411
|
+
defaultValue: '',
|
|
2412
|
+
description: 'Cloud SQL instance connection name',
|
|
2413
|
+
},
|
|
2414
|
+
{ key: 'DB_NAME', defaultValue: 'app', description: 'Database name' },
|
|
2415
|
+
{ key: 'DB_USERNAME', defaultValue: 'postgres', description: 'Database username' },
|
|
2416
|
+
{ key: 'DB_PASSWORD', defaultValue: '', description: 'Database password' },
|
|
2417
|
+
],
|
|
2418
|
+
conflicts: [],
|
|
2419
|
+
requires: [],
|
|
2420
|
+
compatibleWith: 'all',
|
|
2421
|
+
templateDir: 'cloud-gcp/cloud-sql',
|
|
2422
|
+
claudeMdSection: [
|
|
2423
|
+
'## GCP Cloud SQL',
|
|
2424
|
+
'TypeORM connects to Cloud SQL PostgreSQL. Use Cloud SQL Auth Proxy for local development.',
|
|
2425
|
+
'Configure instance connection name and credentials via environment variables.',
|
|
2426
|
+
].join('\n'),
|
|
2427
|
+
cursorRules: [
|
|
2428
|
+
'Cloud SQL uses TypeORM. Use Cloud SQL Auth Proxy for secure local connections.',
|
|
2429
|
+
'Enable IAM database authentication in production. Use private IP for VPC access.',
|
|
2430
|
+
].join('\n'),
|
|
2431
|
+
copilotInstructions: [
|
|
2432
|
+
'GCP Cloud SQL with TypeORM. Connection name from CLOUD_SQL_CONNECTION_NAME env.',
|
|
2433
|
+
'Use Cloud SQL Auth Proxy locally. IAM auth and private IP in production.',
|
|
2434
|
+
].join('\n'),
|
|
2435
|
+
},
|
|
2436
|
+
{
|
|
2437
|
+
id: 'gcp-firestore',
|
|
2438
|
+
name: 'GCP Firestore',
|
|
2439
|
+
description: 'Google Cloud Firestore NoSQL document database',
|
|
2440
|
+
category: 'Cloud — GCP',
|
|
2441
|
+
dependencies: {
|
|
2442
|
+
'@google-cloud/firestore': '7.11.0',
|
|
2443
|
+
},
|
|
2444
|
+
devDependencies: {},
|
|
2445
|
+
envVars: [
|
|
2446
|
+
{ key: 'GCP_PROJECT_ID', defaultValue: '', description: 'GCP project ID' },
|
|
2447
|
+
{
|
|
2448
|
+
key: 'FIRESTORE_DATABASE_ID',
|
|
2449
|
+
defaultValue: '(default)',
|
|
2450
|
+
description: 'Firestore database ID',
|
|
2451
|
+
},
|
|
2452
|
+
],
|
|
2453
|
+
conflicts: [],
|
|
2454
|
+
requires: [],
|
|
2455
|
+
compatibleWith: 'all',
|
|
2456
|
+
templateDir: 'cloud-gcp/firestore',
|
|
2457
|
+
claudeMdSection: [
|
|
2458
|
+
'## GCP Firestore',
|
|
2459
|
+
'Use FirestoreService for document CRUD operations. Configure database ID via FIRESTORE_DATABASE_ID.',
|
|
2460
|
+
'Use collection references and document snapshots for type-safe access.',
|
|
2461
|
+
].join('\n'),
|
|
2462
|
+
cursorRules: [
|
|
2463
|
+
'Use FirestoreService wrapper for all Firestore operations. Design collection structures carefully.',
|
|
2464
|
+
'Use batched writes for multiple operations. Prefer queries with indexes over full scans.',
|
|
2465
|
+
].join('\n'),
|
|
2466
|
+
copilotInstructions: [
|
|
2467
|
+
'GCP Firestore via @google-cloud/firestore. Use FirestoreService wrapper.',
|
|
2468
|
+
'Set GCP_PROJECT_ID in env. Use indexed queries and batched writes.',
|
|
2469
|
+
].join('\n'),
|
|
2470
|
+
},
|
|
2471
|
+
{
|
|
2472
|
+
id: 'gcp-memorystore',
|
|
2473
|
+
name: 'GCP Memorystore',
|
|
2474
|
+
description: 'Google Cloud Memorystore (Redis) for managed caching',
|
|
2475
|
+
category: 'Cloud — GCP',
|
|
2476
|
+
dependencies: {
|
|
2477
|
+
ioredis: '5.4.2',
|
|
2478
|
+
},
|
|
2479
|
+
devDependencies: {},
|
|
2480
|
+
envVars: [
|
|
2481
|
+
{ key: 'MEMORYSTORE_HOST', defaultValue: '', description: 'Memorystore Redis host' },
|
|
2482
|
+
{ key: 'MEMORYSTORE_PORT', defaultValue: '6379', description: 'Memorystore Redis port' },
|
|
2483
|
+
],
|
|
2484
|
+
conflicts: [],
|
|
2485
|
+
requires: [],
|
|
2486
|
+
compatibleWith: 'all',
|
|
2487
|
+
templateDir: 'cloud-gcp/memorystore',
|
|
2488
|
+
claudeMdSection: [
|
|
2489
|
+
'## GCP Memorystore',
|
|
2490
|
+
'Memorystore Redis is used for caching. Connect via MEMORYSTORE_HOST.',
|
|
2491
|
+
'Enable AUTH and in-transit encryption for production. Use VPC peering for access.',
|
|
2492
|
+
].join('\n'),
|
|
2493
|
+
cursorRules: [
|
|
2494
|
+
'Connect to Memorystore via ioredis. Enable AUTH and TLS in production.',
|
|
2495
|
+
'Use MEMORYSTORE_HOST from env. Design cache keys with clear namespacing.',
|
|
2496
|
+
].join('\n'),
|
|
2497
|
+
copilotInstructions: [
|
|
2498
|
+
'GCP Memorystore (Redis) via ioredis. Host from MEMORYSTORE_HOST env.',
|
|
2499
|
+
'Enable AUTH and TLS for production. VPC peering required for connectivity.',
|
|
2500
|
+
].join('\n'),
|
|
2501
|
+
},
|
|
2502
|
+
{
|
|
2503
|
+
id: 'gcp-cloud-cdn',
|
|
2504
|
+
name: 'GCP Cloud CDN',
|
|
2505
|
+
description: 'Google Cloud CDN for content delivery',
|
|
2506
|
+
category: 'Cloud — GCP',
|
|
2507
|
+
dependencies: {},
|
|
2508
|
+
devDependencies: {},
|
|
2509
|
+
envVars: [
|
|
2510
|
+
{ key: 'GCP_PROJECT_ID', defaultValue: '', description: 'GCP project ID' },
|
|
2511
|
+
{ key: 'CDN_SIGNING_KEY_NAME', defaultValue: '', description: 'Cloud CDN signing key name' },
|
|
2512
|
+
{ key: 'CDN_SIGNING_KEY', defaultValue: '', description: 'Cloud CDN signing key (base64)' },
|
|
2513
|
+
],
|
|
2514
|
+
conflicts: [],
|
|
2515
|
+
requires: [],
|
|
2516
|
+
compatibleWith: 'all',
|
|
2517
|
+
templateDir: 'cloud-gcp/cloud-cdn',
|
|
2518
|
+
claudeMdSection: [
|
|
2519
|
+
'## GCP Cloud CDN',
|
|
2520
|
+
'Use CdnService to generate signed URLs for private content.',
|
|
2521
|
+
'Configure signing key name and key value via environment variables.',
|
|
2522
|
+
].join('\n'),
|
|
2523
|
+
cursorRules: [
|
|
2524
|
+
'Use CdnService for signed URL generation. Never expose signing keys to clients.',
|
|
2525
|
+
'Set CDN_SIGNING_KEY_NAME and CDN_SIGNING_KEY from env. Use signed URLs for private assets.',
|
|
2526
|
+
].join('\n'),
|
|
2527
|
+
copilotInstructions: [
|
|
2528
|
+
'GCP Cloud CDN signed URLs via CdnService. Signing key config from env.',
|
|
2529
|
+
'CDN is configured at infrastructure level. App generates signed URLs for access control.',
|
|
2530
|
+
].join('\n'),
|
|
2531
|
+
},
|
|
2532
|
+
// ─── Azure ────────────────────────────────────────────────────────
|
|
2533
|
+
{
|
|
2534
|
+
id: 'azure-service-bus',
|
|
2535
|
+
name: 'Azure Service Bus',
|
|
2536
|
+
description: 'Azure Service Bus for enterprise messaging',
|
|
2537
|
+
category: 'Cloud — Azure',
|
|
2538
|
+
dependencies: {
|
|
2539
|
+
'@azure/service-bus': '7.9.5',
|
|
2540
|
+
'@azure/identity': '4.5.0',
|
|
2541
|
+
},
|
|
2542
|
+
devDependencies: {},
|
|
2543
|
+
envVars: [
|
|
2544
|
+
{
|
|
2545
|
+
key: 'AZURE_SERVICE_BUS_CONNECTION_STRING',
|
|
2546
|
+
defaultValue: '',
|
|
2547
|
+
description: 'Service Bus connection string',
|
|
2548
|
+
},
|
|
2549
|
+
{ key: 'AZURE_SERVICEBUS_QUEUE', defaultValue: '', description: 'Service Bus queue name' },
|
|
2550
|
+
],
|
|
2551
|
+
conflicts: [],
|
|
2552
|
+
requires: [],
|
|
2553
|
+
compatibleWith: 'all',
|
|
2554
|
+
templateDir: 'cloud-azure/service-bus',
|
|
2555
|
+
claudeMdSection: [
|
|
2556
|
+
'## Azure Service Bus',
|
|
2557
|
+
'Use ServiceBusService to send and receive messages. Configure connection string via env.',
|
|
2558
|
+
'Use sessions for ordered processing. Dead-letter queues handle poison messages.',
|
|
2559
|
+
].join('\n'),
|
|
2560
|
+
cursorRules: [
|
|
2561
|
+
'Use ServiceBusService for messaging. Connection string from AZURE_SERVICE_BUS_CONNECTION_STRING.',
|
|
2562
|
+
'Complete messages after processing. Use sessions for FIFO. Configure dead-letter queues.',
|
|
2563
|
+
].join('\n'),
|
|
2564
|
+
copilotInstructions: [
|
|
2565
|
+
'Azure Service Bus via @azure/service-bus. Use ServiceBusService wrapper.',
|
|
2566
|
+
'Connection string from env. Complete messages after processing. Use dead-letter for failures.',
|
|
2567
|
+
].join('\n'),
|
|
2568
|
+
},
|
|
2569
|
+
{
|
|
2570
|
+
id: 'azure-key-vault',
|
|
2571
|
+
name: 'Azure Key Vault',
|
|
2572
|
+
description: 'Azure Key Vault for secret and key management',
|
|
2573
|
+
category: 'Cloud — Azure',
|
|
2574
|
+
dependencies: {
|
|
2575
|
+
'@azure/keyvault-secrets': '4.9.0',
|
|
2576
|
+
'@azure/identity': '4.5.0',
|
|
2577
|
+
},
|
|
2578
|
+
devDependencies: {},
|
|
2579
|
+
envVars: [
|
|
2580
|
+
{
|
|
2581
|
+
key: 'AZURE_KEY_VAULT_URL',
|
|
2582
|
+
defaultValue: '',
|
|
2583
|
+
description: 'Key Vault URL (https://<name>.vault.azure.net)',
|
|
2584
|
+
},
|
|
2585
|
+
],
|
|
2586
|
+
conflicts: [],
|
|
2587
|
+
requires: [],
|
|
2588
|
+
compatibleWith: 'all',
|
|
2589
|
+
templateDir: 'cloud-azure/key-vault',
|
|
2590
|
+
claudeMdSection: [
|
|
2591
|
+
'## Azure Key Vault',
|
|
2592
|
+
'Use KeyVaultService to fetch secrets at startup. Secrets are cached to reduce API calls.',
|
|
2593
|
+
'Authenticate via DefaultAzureCredential for managed identity support.',
|
|
2594
|
+
].join('\n'),
|
|
2595
|
+
cursorRules: [
|
|
2596
|
+
'Use KeyVaultService for secrets. Authenticate with DefaultAzureCredential.',
|
|
2597
|
+
'Cache secrets locally. Set AZURE_KEY_VAULT_URL from env. Use managed identities in production.',
|
|
2598
|
+
].join('\n'),
|
|
2599
|
+
copilotInstructions: [
|
|
2600
|
+
'Azure Key Vault via @azure/keyvault-secrets. Use KeyVaultService wrapper.',
|
|
2601
|
+
'AZURE_KEY_VAULT_URL from env. DefaultAzureCredential for authentication.',
|
|
2602
|
+
].join('\n'),
|
|
2603
|
+
},
|
|
2604
|
+
{
|
|
2605
|
+
id: 'azure-blob-storage',
|
|
2606
|
+
name: 'Azure Blob Storage',
|
|
2607
|
+
description: 'Azure Blob Storage for object storage',
|
|
2608
|
+
category: 'Cloud — Azure',
|
|
2609
|
+
dependencies: {
|
|
2610
|
+
'@azure/storage-blob': '12.26.0',
|
|
2611
|
+
'@azure/identity': '4.5.0',
|
|
2612
|
+
},
|
|
2613
|
+
devDependencies: {},
|
|
2614
|
+
envVars: [
|
|
2615
|
+
{
|
|
2616
|
+
key: 'AZURE_STORAGE_ACCOUNT_NAME',
|
|
2617
|
+
defaultValue: '',
|
|
2618
|
+
description: 'Azure Storage account name',
|
|
2619
|
+
},
|
|
2620
|
+
{
|
|
2621
|
+
key: 'AZURE_STORAGE_ACCOUNT_KEY',
|
|
2622
|
+
defaultValue: '',
|
|
2623
|
+
description: 'Azure Storage account key',
|
|
2624
|
+
},
|
|
2625
|
+
],
|
|
2626
|
+
conflicts: [],
|
|
2627
|
+
requires: [],
|
|
2628
|
+
compatibleWith: 'all',
|
|
2629
|
+
templateDir: 'cloud-azure/blob-storage',
|
|
2630
|
+
claudeMdSection: [
|
|
2631
|
+
'## Azure Blob Storage',
|
|
2632
|
+
'Use BlobStorageService for uploads, downloads, and SAS URL generation.',
|
|
2633
|
+
'Configure account name and key via environment variables.',
|
|
2634
|
+
].join('\n'),
|
|
2635
|
+
cursorRules: [
|
|
2636
|
+
'Use BlobStorageService for all blob operations. Generate SAS URLs for client uploads.',
|
|
2637
|
+
'Account name and key from env. Use managed identity (DefaultAzureCredential) in production.',
|
|
2638
|
+
].join('\n'),
|
|
2639
|
+
copilotInstructions: [
|
|
2640
|
+
'Azure Blob Storage via @azure/storage-blob. Use BlobStorageService wrapper.',
|
|
2641
|
+
'Account name and key from env. SAS URLs for client-side uploads. Managed identity in prod.',
|
|
2642
|
+
].join('\n'),
|
|
2643
|
+
},
|
|
2644
|
+
{
|
|
2645
|
+
id: 'azure-functions',
|
|
2646
|
+
name: 'Azure Functions',
|
|
2647
|
+
description: 'Azure Functions integration for serverless workloads',
|
|
2648
|
+
category: 'Cloud — Azure',
|
|
2649
|
+
dependencies: {
|
|
2650
|
+
'@azure/functions': '4.6.0',
|
|
2651
|
+
},
|
|
2652
|
+
devDependencies: {},
|
|
2653
|
+
envVars: [
|
|
2654
|
+
{
|
|
2655
|
+
key: 'AZURE_FUNCTIONS_ENVIRONMENT',
|
|
2656
|
+
defaultValue: 'Development',
|
|
2657
|
+
description: 'Azure Functions environment',
|
|
2658
|
+
},
|
|
2659
|
+
],
|
|
2660
|
+
conflicts: [],
|
|
2661
|
+
requires: [],
|
|
2662
|
+
compatibleWith: 'all',
|
|
2663
|
+
templateDir: 'cloud-azure/functions',
|
|
2664
|
+
claudeMdSection: [
|
|
2665
|
+
'## Azure Functions',
|
|
2666
|
+
'The NestJS app is adapted for Azure Functions via the @azure/functions runtime.',
|
|
2667
|
+
'Configure triggers and bindings in the function definition files.',
|
|
2668
|
+
].join('\n'),
|
|
2669
|
+
cursorRules: [
|
|
2670
|
+
'Azure Functions entry point wraps the NestJS app. Keep cold start time minimal.',
|
|
2671
|
+
'Use lazy initialization for heavy dependencies. Configure bindings declaratively.',
|
|
2672
|
+
].join('\n'),
|
|
2673
|
+
copilotInstructions: [
|
|
2674
|
+
'Azure Functions via @azure/functions. NestJS wrapped as function handler.',
|
|
2675
|
+
'Optimize for cold starts. Use bindings for triggers (HTTP, timer, queue).',
|
|
2676
|
+
].join('\n'),
|
|
2677
|
+
},
|
|
2678
|
+
{
|
|
2679
|
+
id: 'azure-entra-id',
|
|
2680
|
+
name: 'Azure Entra ID',
|
|
2681
|
+
description: 'Azure Entra ID (formerly Azure AD) authentication',
|
|
2682
|
+
category: 'Cloud — Azure',
|
|
2683
|
+
dependencies: {
|
|
2684
|
+
'@azure/msal-node': '2.16.2',
|
|
2685
|
+
'@azure/identity': '4.5.0',
|
|
2686
|
+
jsonwebtoken: '9.0.3',
|
|
2687
|
+
'jwks-rsa': '4.0.1',
|
|
2688
|
+
},
|
|
2689
|
+
devDependencies: {
|
|
2690
|
+
'@types/jsonwebtoken': '9.0.10',
|
|
2691
|
+
},
|
|
2692
|
+
envVars: [
|
|
2693
|
+
{ key: 'AZURE_TENANT_ID', defaultValue: '', description: 'Azure Entra ID tenant ID' },
|
|
2694
|
+
{
|
|
2695
|
+
key: 'AZURE_CLIENT_ID',
|
|
2696
|
+
defaultValue: '',
|
|
2697
|
+
description: 'Azure Entra ID client (application) ID',
|
|
2698
|
+
},
|
|
2699
|
+
{ key: 'AZURE_CLIENT_SECRET', defaultValue: '', description: 'Azure Entra ID client secret' },
|
|
2700
|
+
],
|
|
2701
|
+
conflicts: [],
|
|
2702
|
+
requires: [],
|
|
2703
|
+
compatibleWith: 'all',
|
|
2704
|
+
templateDir: 'cloud-azure/entra-id',
|
|
2705
|
+
claudeMdSection: [
|
|
2706
|
+
'## Azure Entra ID',
|
|
2707
|
+
'Use EntraIdGuard to validate Entra ID JWT tokens on protected routes.',
|
|
2708
|
+
'Configure tenant ID, client ID, and client secret via environment variables.',
|
|
2709
|
+
].join('\n'),
|
|
2710
|
+
cursorRules: [
|
|
2711
|
+
'Use EntraIdGuard for authentication. Validate JWT tokens against the Entra ID JWKS endpoint.',
|
|
2712
|
+
'Configure AZURE_TENANT_ID, AZURE_CLIENT_ID from env. Use app roles for RBAC.',
|
|
2713
|
+
].join('\n'),
|
|
2714
|
+
copilotInstructions: [
|
|
2715
|
+
'Azure Entra ID via @azure/msal-node. Apply EntraIdGuard to protected routes.',
|
|
2716
|
+
'Tenant and client IDs from env. Token validation uses Entra ID JWKS endpoint.',
|
|
2717
|
+
].join('\n'),
|
|
2718
|
+
},
|
|
2719
|
+
{
|
|
2720
|
+
id: 'azure-app-insights',
|
|
2721
|
+
name: 'Azure Application Insights',
|
|
2722
|
+
description: 'Azure Application Insights for telemetry and monitoring',
|
|
2723
|
+
category: 'Cloud — Azure',
|
|
2724
|
+
dependencies: {
|
|
2725
|
+
applicationinsights: '3.4.0',
|
|
2726
|
+
},
|
|
2727
|
+
devDependencies: {},
|
|
2728
|
+
envVars: [
|
|
2729
|
+
{
|
|
2730
|
+
key: 'APPLICATIONINSIGHTS_CONNECTION_STRING',
|
|
2731
|
+
defaultValue: '',
|
|
2732
|
+
description: 'Application Insights connection string',
|
|
2733
|
+
},
|
|
2734
|
+
],
|
|
2735
|
+
conflicts: [],
|
|
2736
|
+
requires: [],
|
|
2737
|
+
compatibleWith: 'all',
|
|
2738
|
+
templateDir: 'cloud-azure/app-insights',
|
|
2739
|
+
claudeMdSection: [
|
|
2740
|
+
'## Azure Application Insights',
|
|
2741
|
+
'Application Insights collects telemetry, traces, and exceptions automatically.',
|
|
2742
|
+
'Configure via APPLICATIONINSIGHTS_CONNECTION_STRING. Custom events via TelemetryClient.',
|
|
2743
|
+
].join('\n'),
|
|
2744
|
+
cursorRules: [
|
|
2745
|
+
'App Insights is initialized at startup. Unhandled exceptions are auto-captured.',
|
|
2746
|
+
'Use TelemetryClient for custom events and metrics. Connection string from env.',
|
|
2747
|
+
].join('\n'),
|
|
2748
|
+
copilotInstructions: [
|
|
2749
|
+
'Azure Application Insights via applicationinsights package. Auto-collects telemetry.',
|
|
2750
|
+
'Connection string from env. Use TelemetryClient for custom events and metrics.',
|
|
2751
|
+
].join('\n'),
|
|
2752
|
+
},
|
|
2753
|
+
{
|
|
2754
|
+
id: 'azure-cosmos-db',
|
|
2755
|
+
name: 'Azure Cosmos DB',
|
|
2756
|
+
description: 'Azure Cosmos DB NoSQL database integration',
|
|
2757
|
+
category: 'Cloud — Azure',
|
|
2758
|
+
dependencies: {
|
|
2759
|
+
'@azure/cosmos': '4.2.0',
|
|
2760
|
+
'@azure/identity': '4.5.0',
|
|
2761
|
+
},
|
|
2762
|
+
devDependencies: {},
|
|
2763
|
+
envVars: [
|
|
2764
|
+
{ key: 'AZURE_COSMOS_ENDPOINT', defaultValue: '', description: 'Cosmos DB account endpoint' },
|
|
2765
|
+
{ key: 'AZURE_COSMOS_KEY', defaultValue: '', description: 'Cosmos DB account key' },
|
|
2766
|
+
{
|
|
2767
|
+
key: 'AZURE_COSMOS_DATABASE',
|
|
2768
|
+
defaultValue: 'app',
|
|
2769
|
+
description: 'Cosmos DB database name',
|
|
2770
|
+
},
|
|
2771
|
+
],
|
|
2772
|
+
conflicts: [],
|
|
2773
|
+
requires: [],
|
|
2774
|
+
compatibleWith: 'all',
|
|
2775
|
+
templateDir: 'cloud-azure/cosmos-db',
|
|
2776
|
+
claudeMdSection: [
|
|
2777
|
+
'## Azure Cosmos DB',
|
|
2778
|
+
'Use CosmosDbService for container and item operations. Configure endpoint and key via env.',
|
|
2779
|
+
'Choose partition keys carefully for optimal performance and cost.',
|
|
2780
|
+
].join('\n'),
|
|
2781
|
+
cursorRules: [
|
|
2782
|
+
'Use CosmosDbService for all Cosmos DB operations. Design partition keys for query patterns.',
|
|
2783
|
+
'Use cross-partition queries sparingly. Configure RU limits per container.',
|
|
2784
|
+
].join('\n'),
|
|
2785
|
+
copilotInstructions: [
|
|
2786
|
+
'Azure Cosmos DB via @azure/cosmos. Use CosmosDbService wrapper.',
|
|
2787
|
+
'Endpoint and key from env. Design partition keys for query access patterns.',
|
|
2788
|
+
].join('\n'),
|
|
2789
|
+
},
|
|
2790
|
+
{
|
|
2791
|
+
id: 'azure-sql-database',
|
|
2792
|
+
name: 'Azure SQL Database',
|
|
2793
|
+
description: 'Azure SQL Database managed connection',
|
|
2794
|
+
category: 'Cloud — Azure',
|
|
2795
|
+
dependencies: {
|
|
2796
|
+
'@nestjs/typeorm': '10.0.2',
|
|
2797
|
+
typeorm: '0.3.20',
|
|
2798
|
+
mssql: '11.0.1',
|
|
2799
|
+
},
|
|
2800
|
+
devDependencies: {},
|
|
2801
|
+
envVars: [
|
|
2802
|
+
{ key: 'AZURE_SQL_HOST', defaultValue: '', description: 'Azure SQL server hostname' },
|
|
2803
|
+
{ key: 'AZURE_SQL_PORT', defaultValue: '1433', description: 'Azure SQL port' },
|
|
2804
|
+
{ key: 'AZURE_SQL_DATABASE', defaultValue: 'app', description: 'Azure SQL database name' },
|
|
2805
|
+
{ key: 'AZURE_SQL_USERNAME', defaultValue: '', description: 'Azure SQL username' },
|
|
2806
|
+
{ key: 'AZURE_SQL_PASSWORD', defaultValue: '', description: 'Azure SQL password' },
|
|
2807
|
+
],
|
|
2808
|
+
conflicts: [],
|
|
2809
|
+
requires: [],
|
|
2810
|
+
compatibleWith: 'all',
|
|
2811
|
+
templateDir: 'cloud-azure/sql-database',
|
|
2812
|
+
claudeMdSection: [
|
|
2813
|
+
'## Azure SQL Database',
|
|
2814
|
+
'TypeORM connects to Azure SQL Database. Configure host and credentials via environment variables.',
|
|
2815
|
+
'Enable encryption and use managed identity authentication in production.',
|
|
2816
|
+
].join('\n'),
|
|
2817
|
+
cursorRules: [
|
|
2818
|
+
'Azure SQL uses TypeORM with mssql driver. Enable encryption for all connections.',
|
|
2819
|
+
'Use Azure AD authentication (managed identity) in production. Connection details from env.',
|
|
2820
|
+
].join('\n'),
|
|
2821
|
+
copilotInstructions: [
|
|
2822
|
+
'Azure SQL Database with TypeORM and mssql driver. Connection from AZURE_SQL_* env vars.',
|
|
2823
|
+
'Enable encryption. Use Azure AD managed identity auth in production.',
|
|
2824
|
+
].join('\n'),
|
|
2825
|
+
},
|
|
2826
|
+
{
|
|
2827
|
+
id: 'azure-cache',
|
|
2828
|
+
name: 'Azure Cache for Redis',
|
|
2829
|
+
description: 'Azure Cache for Redis managed caching service',
|
|
2830
|
+
category: 'Cloud — Azure',
|
|
2831
|
+
dependencies: {
|
|
2832
|
+
ioredis: '5.4.2',
|
|
2833
|
+
},
|
|
2834
|
+
devDependencies: {},
|
|
2835
|
+
envVars: [
|
|
2836
|
+
{ key: 'AZURE_REDIS_HOST', defaultValue: '', description: 'Azure Cache for Redis hostname' },
|
|
2837
|
+
{ key: 'AZURE_REDIS_PORT', defaultValue: '6380', description: 'Azure Cache for Redis port' },
|
|
2838
|
+
{
|
|
2839
|
+
key: 'AZURE_REDIS_PASSWORD',
|
|
2840
|
+
defaultValue: '',
|
|
2841
|
+
description: 'Azure Cache for Redis access key',
|
|
2842
|
+
},
|
|
2843
|
+
],
|
|
2844
|
+
conflicts: [],
|
|
2845
|
+
requires: [],
|
|
2846
|
+
compatibleWith: 'all',
|
|
2847
|
+
templateDir: 'cloud-azure/cache',
|
|
2848
|
+
claudeMdSection: [
|
|
2849
|
+
'## Azure Cache for Redis',
|
|
2850
|
+
'Azure Cache for Redis is used for caching. Connect via AZURE_REDIS_HOST with TLS on port 6380.',
|
|
2851
|
+
'Use access keys or managed identity for authentication.',
|
|
2852
|
+
].join('\n'),
|
|
2853
|
+
cursorRules: [
|
|
2854
|
+
'Connect to Azure Cache via ioredis. Use TLS (port 6380) and access key from env.',
|
|
2855
|
+
'Design cache keys with clear namespacing. Use managed identity in production.',
|
|
2856
|
+
].join('\n'),
|
|
2857
|
+
copilotInstructions: [
|
|
2858
|
+
'Azure Cache for Redis via ioredis. Host from AZURE_REDIS_HOST env, TLS on port 6380.',
|
|
2859
|
+
'Access key from AZURE_REDIS_PASSWORD. Managed identity auth in production.',
|
|
2860
|
+
].join('\n'),
|
|
2861
|
+
},
|
|
2862
|
+
{
|
|
2863
|
+
id: 'azure-front-door',
|
|
2864
|
+
name: 'Azure Front Door',
|
|
2865
|
+
description: 'Azure Front Door CDN and global load balancer',
|
|
2866
|
+
category: 'Cloud — Azure',
|
|
2867
|
+
dependencies: {},
|
|
2868
|
+
devDependencies: {},
|
|
2869
|
+
envVars: [
|
|
2870
|
+
{
|
|
2871
|
+
key: 'AZURE_FRONTDOOR_HOSTNAME',
|
|
2872
|
+
defaultValue: '',
|
|
2873
|
+
description: 'Azure Front Door hostname',
|
|
2874
|
+
},
|
|
2875
|
+
{
|
|
2876
|
+
key: 'AZURE_FRONTDOOR_HEADER',
|
|
2877
|
+
defaultValue: 'X-Azure-FDID',
|
|
2878
|
+
description: 'Front Door ID header name',
|
|
2879
|
+
},
|
|
2880
|
+
{
|
|
2881
|
+
key: 'AZURE_FRONTDOOR_ID',
|
|
2882
|
+
defaultValue: '',
|
|
2883
|
+
description: 'Azure Front Door ID for request validation',
|
|
2884
|
+
},
|
|
2885
|
+
],
|
|
2886
|
+
conflicts: [],
|
|
2887
|
+
requires: [],
|
|
2888
|
+
compatibleWith: 'all',
|
|
2889
|
+
templateDir: 'cloud-azure/front-door',
|
|
2890
|
+
claudeMdSection: [
|
|
2891
|
+
'## Azure Front Door',
|
|
2892
|
+
'Validate that requests come through Front Door by checking the X-Azure-FDID header.',
|
|
2893
|
+
'Configure Front Door hostname and ID via environment variables.',
|
|
2894
|
+
].join('\n'),
|
|
2895
|
+
cursorRules: [
|
|
2896
|
+
'Validate X-Azure-FDID header to ensure traffic comes through Front Door.',
|
|
2897
|
+
'Set AZURE_FRONTDOOR_ID from env. Block direct-to-origin requests in production.',
|
|
2898
|
+
].join('\n'),
|
|
2899
|
+
copilotInstructions: [
|
|
2900
|
+
'Azure Front Door validated via X-Azure-FDID header. Config from env.',
|
|
2901
|
+
'Front Door is configured at infrastructure level. App validates origin of requests.',
|
|
2902
|
+
].join('\n'),
|
|
2903
|
+
},
|
|
2904
|
+
// ─── API Patterns ────────────────────────────────────────────────
|
|
2905
|
+
{
|
|
2906
|
+
id: 'idempotency',
|
|
2907
|
+
name: 'Idempotency Key',
|
|
2908
|
+
description: 'Idempotency-Key header support for safe request retries',
|
|
2909
|
+
category: 'API Patterns',
|
|
2910
|
+
dependencies: {},
|
|
2911
|
+
devDependencies: {},
|
|
2912
|
+
envVars: [],
|
|
2913
|
+
conflicts: [],
|
|
2914
|
+
requires: [],
|
|
2915
|
+
compatibleWith: ['http-api', 'aws-lambda', 'full-stack', 'monorepo'],
|
|
2916
|
+
templateDir: 'idempotency',
|
|
2917
|
+
claudeMdSection: '## Idempotency\nUse @Idempotent() decorator on POST/PUT endpoints. Clients send Idempotency-Key header. Responses are cached and replayed for duplicate keys.',
|
|
2918
|
+
cursorRules: 'Apply @Idempotent() decorator to POST and PUT endpoints that create or modify resources. Requires a cache store (in-memory by default, Redis recommended for production).',
|
|
2919
|
+
copilotInstructions: 'Use @Idempotent() decorator on mutation endpoints. Clients must send Idempotency-Key header for safe retries.',
|
|
2920
|
+
},
|
|
2921
|
+
{
|
|
2922
|
+
id: 'prefer-header',
|
|
2923
|
+
name: 'Prefer Header',
|
|
2924
|
+
description: 'RFC 7240 Prefer header for return=representation and respond-async',
|
|
2925
|
+
category: 'API Patterns',
|
|
2926
|
+
dependencies: {},
|
|
2927
|
+
devDependencies: {},
|
|
2928
|
+
envVars: [],
|
|
2929
|
+
conflicts: [],
|
|
2930
|
+
requires: [],
|
|
2931
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
2932
|
+
templateDir: 'prefer-header',
|
|
2933
|
+
claudeMdSection: '## Prefer Header (RFC 7240)\nThe PreferInterceptor parses the Prefer request header and applies return=minimal (204 No Content), return=representation (full body), and respond-async preferences. Applied preferences are echoed in the Preference-Applied response header.',
|
|
2934
|
+
cursorRules: 'The PreferInterceptor handles Prefer header parsing globally. Handlers receive normal requests; the interceptor adjusts responses based on return=minimal, return=representation, and respond-async preferences.',
|
|
2935
|
+
copilotInstructions: 'PreferInterceptor is registered globally. It supports Prefer: return=minimal (returns 204), return=representation (returns full body), and respond-async. Applied preferences are listed in Preference-Applied header.',
|
|
2936
|
+
},
|
|
2937
|
+
{
|
|
2938
|
+
id: 'content-digest',
|
|
2939
|
+
name: 'Content Digest',
|
|
2940
|
+
description: 'RFC 9530 content integrity verification via digest headers',
|
|
2941
|
+
category: 'Security',
|
|
2942
|
+
dependencies: {},
|
|
2943
|
+
devDependencies: {},
|
|
2944
|
+
envVars: [],
|
|
2945
|
+
conflicts: [],
|
|
2946
|
+
requires: [],
|
|
2947
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
2948
|
+
templateDir: 'content-digest',
|
|
2949
|
+
claudeMdSection: '## Content Digest (RFC 9530)\nContentDigestInterceptor adds sha-256 Content-Digest and Repr-Digest response headers for payload integrity. ContentDigestGuard optionally validates inbound Content-Digest headers on requests.',
|
|
2950
|
+
cursorRules: 'ContentDigestInterceptor hashes JSON response bodies with SHA-256 and sets Content-Digest and Repr-Digest headers. ContentDigestGuard validates the Content-Digest header on incoming requests if present.',
|
|
2951
|
+
copilotInstructions: 'ContentDigestInterceptor is applied globally to add Content-Digest and Repr-Digest headers to responses. ContentDigestGuard validates inbound Content-Digest headers when present. Based on RFC 9530.',
|
|
2952
|
+
},
|
|
2953
|
+
{
|
|
2954
|
+
id: 'dpop',
|
|
2955
|
+
name: 'DPoP (Proof of Possession)',
|
|
2956
|
+
description: 'RFC 9449 Demonstrating Proof of Possession for OAuth tokens',
|
|
2957
|
+
category: 'Auth',
|
|
2958
|
+
dependencies: { jose: '6.0.11' },
|
|
2959
|
+
devDependencies: {},
|
|
2960
|
+
envVars: [],
|
|
2961
|
+
conflicts: [],
|
|
2962
|
+
requires: [],
|
|
2963
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
2964
|
+
templateDir: 'dpop',
|
|
2965
|
+
claudeMdSection: '## DPoP (RFC 9449)\nDPoPGuard validates DPoP proof JWTs on protected endpoints. It checks the proof typ, htm (method), htu (URI), and token age. Apply the guard to routes that require proof-of-possession tokens.',
|
|
2966
|
+
cursorRules: 'DPoPGuard validates DPoP proof JWTs per RFC 9449. It verifies typ=dpop+jwt, htm matches the HTTP method, htu matches the request URI, and the proof is not older than 300 seconds.',
|
|
2967
|
+
copilotInstructions: 'DPoPGuard is used to protect endpoints with DPoP proof-of-possession. Clients must send a DPoP header with a dpop+jwt and use the DPoP authorization scheme. Uses the jose library for JWT validation.',
|
|
2968
|
+
},
|
|
2969
|
+
{
|
|
2970
|
+
id: 'json-patch',
|
|
2971
|
+
name: 'JSON Patch',
|
|
2972
|
+
description: 'RFC 6902 JSON Patch for granular document updates',
|
|
2973
|
+
category: 'API Patterns',
|
|
2974
|
+
dependencies: { 'fast-json-patch': '3.1.1' },
|
|
2975
|
+
devDependencies: {},
|
|
2976
|
+
envVars: [],
|
|
2977
|
+
conflicts: ['json-merge-patch'],
|
|
2978
|
+
requires: [],
|
|
2979
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
2980
|
+
templateDir: 'json-patch',
|
|
2981
|
+
claudeMdSection: '## JSON Patch (RFC 6902)\nUse JsonPatchValidationPipe on PATCH endpoints that accept `application/json-patch+json`. The pipe validates the operation array (add, remove, replace, move, copy, test). Apply patches with fast-json-patch.',
|
|
2982
|
+
cursorRules: 'JsonPatchValidationPipe validates RFC 6902 operation arrays. Use fast-json-patch applyPatch() to apply validated operations to documents. Set Accept-Patch header to application/json-patch+json.',
|
|
2983
|
+
copilotInstructions: 'Use JsonPatchValidationPipe on PATCH endpoints for RFC 6902 support. Pipe validates op, path, value, and from fields. Apply with fast-json-patch. Content-Type is application/json-patch+json.',
|
|
2984
|
+
},
|
|
2985
|
+
{
|
|
2986
|
+
id: 'json-merge-patch',
|
|
2987
|
+
name: 'JSON Merge Patch',
|
|
2988
|
+
description: 'RFC 7396 JSON Merge Patch for simple partial updates',
|
|
2989
|
+
category: 'API Patterns',
|
|
2990
|
+
dependencies: {},
|
|
2991
|
+
devDependencies: {},
|
|
2992
|
+
envVars: [],
|
|
2993
|
+
conflicts: ['json-patch'],
|
|
2994
|
+
requires: [],
|
|
2995
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
2996
|
+
templateDir: 'json-merge-patch',
|
|
2997
|
+
claudeMdSection: '## JSON Merge Patch (RFC 7396)\nUse MergePatchValidationPipe on PATCH endpoints that accept `application/merge-patch+json`. The pipe ensures the body is a plain JSON object. Null values in the patch delete the corresponding key from the target.',
|
|
2998
|
+
cursorRules: 'MergePatchValidationPipe validates RFC 7396 merge patch bodies. The body must be a JSON object (not array or null). Null values mean "delete this key". Nested objects are merged recursively.',
|
|
2999
|
+
copilotInstructions: 'Use MergePatchValidationPipe on PATCH endpoints for RFC 7396 support. Body must be a JSON object. Null values delete keys. Content-Type is application/merge-patch+json. No extra dependencies required.',
|
|
3000
|
+
},
|
|
3001
|
+
// ─── Server-Sent Events ───────────────────────────────────────────
|
|
3002
|
+
{
|
|
3003
|
+
id: 'sse',
|
|
3004
|
+
name: 'Server-Sent Events',
|
|
3005
|
+
description: 'Lightweight real-time server-to-client streaming',
|
|
3006
|
+
category: 'API Patterns',
|
|
3007
|
+
dependencies: {},
|
|
3008
|
+
devDependencies: {},
|
|
3009
|
+
envVars: [],
|
|
3010
|
+
conflicts: [],
|
|
3011
|
+
requires: [],
|
|
3012
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
3013
|
+
templateDir: 'sse',
|
|
3014
|
+
claudeMdSection: [
|
|
3015
|
+
'## Server-Sent Events',
|
|
3016
|
+
'Use @Sse() decorator on controller methods to return an Observable<MessageEvent>.',
|
|
3017
|
+
'SSE is built into NestJS — no extra dependencies required. Use a Subject to push events from services.',
|
|
3018
|
+
].join('\n'),
|
|
3019
|
+
cursorRules: [
|
|
3020
|
+
'Use @Sse() decorator for SSE endpoints. Return Observable<MessageEvent> from rxjs.',
|
|
3021
|
+
'Push events via a Subject. SSE is server-to-client only — use WebSockets for bidirectional.',
|
|
3022
|
+
].join('\n'),
|
|
3023
|
+
copilotInstructions: [
|
|
3024
|
+
'SSE endpoints use the @Sse() decorator and return Observable<MessageEvent>.',
|
|
3025
|
+
'No extra dependencies needed — SSE is built into NestJS. Use rxjs Subject to emit events.',
|
|
3026
|
+
].join('\n'),
|
|
3027
|
+
},
|
|
3028
|
+
// ─── Soft Delete ──────────────────────────────────────────────────
|
|
3029
|
+
{
|
|
3030
|
+
id: 'soft-delete',
|
|
3031
|
+
name: 'Soft Delete',
|
|
3032
|
+
description: 'Mark records as deleted instead of removing them',
|
|
3033
|
+
category: 'Database',
|
|
3034
|
+
dependencies: {
|
|
3035
|
+
'@nestjs/typeorm': '10.0.2',
|
|
3036
|
+
typeorm: '0.3.20',
|
|
3037
|
+
},
|
|
3038
|
+
devDependencies: {},
|
|
3039
|
+
envVars: [],
|
|
3040
|
+
conflicts: [],
|
|
3041
|
+
requires: [],
|
|
3042
|
+
compatibleWith: 'all',
|
|
3043
|
+
templateDir: 'soft-delete',
|
|
3044
|
+
claudeMdSection: [
|
|
3045
|
+
'## Soft Delete',
|
|
3046
|
+
'Extend SoftDeletableEntity for entities that should be soft-deleted.',
|
|
3047
|
+
'Use repository.softRemove() or repository.softDelete() instead of remove()/delete().',
|
|
3048
|
+
'Use @WithDeleted() decorator to include soft-deleted records in queries.',
|
|
3049
|
+
].join('\n'),
|
|
3050
|
+
cursorRules: [
|
|
3051
|
+
'Extend SoftDeletableEntity for soft-deletable entities. Use softRemove()/softDelete() instead of remove()/delete().',
|
|
3052
|
+
'Query soft-deleted records with withDeleted: true or the @WithDeleted() decorator.',
|
|
3053
|
+
].join('\n'),
|
|
3054
|
+
copilotInstructions: [
|
|
3055
|
+
'Soft-deletable entities extend SoftDeletableEntity which adds a deletedAt column.',
|
|
3056
|
+
'Use softRemove()/softDelete() for deletion. Use @WithDeleted() to include deleted records.',
|
|
3057
|
+
].join('\n'),
|
|
3058
|
+
},
|
|
3059
|
+
// ─── Audit Trail ──────────────────────────────────────────────────
|
|
3060
|
+
{
|
|
3061
|
+
id: 'audit-trail',
|
|
3062
|
+
name: 'Audit Trail',
|
|
3063
|
+
description: 'Record entity changes with user, action, and diff',
|
|
3064
|
+
category: 'Database',
|
|
3065
|
+
dependencies: {},
|
|
3066
|
+
devDependencies: {},
|
|
3067
|
+
envVars: [],
|
|
3068
|
+
conflicts: [],
|
|
3069
|
+
requires: [],
|
|
3070
|
+
compatibleWith: 'all',
|
|
3071
|
+
templateDir: 'audit-trail',
|
|
3072
|
+
claudeMdSection: [
|
|
3073
|
+
'## Audit Trail',
|
|
3074
|
+
'Apply AuditInterceptor globally or per-controller to log mutating requests (POST, PUT, PATCH, DELETE).',
|
|
3075
|
+
'Use @Auditable() decorator to mark controllers or handlers for audit logging.',
|
|
3076
|
+
'Audit entries capture userId, action, entityName, entityId, changes, timestamp, and IP.',
|
|
3077
|
+
].join('\n'),
|
|
3078
|
+
cursorRules: [
|
|
3079
|
+
'Use AuditInterceptor to capture mutating request audit entries. Apply globally or per-controller.',
|
|
3080
|
+
'Mark controllers with @Auditable() decorator. Entries include user, action, entity, changes, and IP.',
|
|
3081
|
+
].join('\n'),
|
|
3082
|
+
copilotInstructions: [
|
|
3083
|
+
'AuditInterceptor logs POST/PUT/PATCH/DELETE requests with user, entity, and change information.',
|
|
3084
|
+
'Use @Auditable() to mark auditable controllers. Consider TypeORM subscribers for entity-level auditing.',
|
|
3085
|
+
].join('\n'),
|
|
3086
|
+
},
|
|
3087
|
+
// ─── Request Context (CLS) ───────────────────────────────────────
|
|
3088
|
+
{
|
|
3089
|
+
id: 'request-context',
|
|
3090
|
+
name: 'Request Context (CLS)',
|
|
3091
|
+
description: 'AsyncLocalStorage-based request context via nestjs-cls',
|
|
3092
|
+
category: 'API Patterns',
|
|
3093
|
+
dependencies: {
|
|
3094
|
+
'nestjs-cls': '4.5.0',
|
|
3095
|
+
},
|
|
3096
|
+
devDependencies: {},
|
|
3097
|
+
envVars: [],
|
|
3098
|
+
conflicts: [],
|
|
3099
|
+
requires: [],
|
|
3100
|
+
compatibleWith: 'all',
|
|
3101
|
+
templateDir: 'request-context',
|
|
3102
|
+
claudeMdSection: [
|
|
3103
|
+
'## Request Context (CLS)',
|
|
3104
|
+
'Import RequestContextModule to enable AsyncLocalStorage-based request context.',
|
|
3105
|
+
'Inject ClsService to access correlationId, userId, and ip anywhere in the request lifecycle.',
|
|
3106
|
+
'Context is set up automatically via middleware — no manual setup needed per request.',
|
|
3107
|
+
].join('\n'),
|
|
3108
|
+
cursorRules: [
|
|
3109
|
+
'Use ClsService from nestjs-cls to access request context (correlationId, userId, ip).',
|
|
3110
|
+
'Import RequestContextModule in AppModule. Context is auto-populated via middleware.',
|
|
3111
|
+
].join('\n'),
|
|
3112
|
+
copilotInstructions: [
|
|
3113
|
+
'nestjs-cls provides AsyncLocalStorage-based request context. Inject ClsService to read correlationId, userId, ip.',
|
|
3114
|
+
'RequestContextModule sets up CLS middleware automatically. No manual context threading needed.',
|
|
3115
|
+
].join('\n'),
|
|
3116
|
+
},
|
|
3117
|
+
// ─── i18n ─────────────────────────────────────────────────────────
|
|
3118
|
+
{
|
|
3119
|
+
id: 'i18n',
|
|
3120
|
+
name: 'Internationalization',
|
|
3121
|
+
description: 'Multi-language support with nestjs-i18n',
|
|
3122
|
+
category: 'API Patterns',
|
|
3123
|
+
dependencies: {
|
|
3124
|
+
'nestjs-i18n': '10.8.4',
|
|
3125
|
+
},
|
|
3126
|
+
devDependencies: {},
|
|
3127
|
+
envVars: [],
|
|
3128
|
+
conflicts: [],
|
|
3129
|
+
requires: [],
|
|
3130
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
3131
|
+
templateDir: 'i18n',
|
|
3132
|
+
claudeMdSection: [
|
|
3133
|
+
'## Internationalization (i18n)',
|
|
3134
|
+
'Uses nestjs-i18n for multi-language support. Translation files live in `src/i18n/<lang>/`.',
|
|
3135
|
+
'Language is resolved from the `lang` query parameter or the `Accept-Language` header. Fallback language is `en`.',
|
|
3136
|
+
].join('\n'),
|
|
3137
|
+
cursorRules: 'Use nestjs-i18n I18nService for translations. Translation JSON files live in src/i18n/<lang>/. Fallback language is en. Language is resolved from query param or Accept-Language header.',
|
|
3138
|
+
copilotInstructions: 'nestjs-i18n handles multi-language support. Inject I18nService for translations. Translation files are in src/i18n/<lang>/common.json. Supports query param and Accept-Language header resolution.',
|
|
3139
|
+
},
|
|
3140
|
+
// ─── Config Validation ────────────────────────────────────────────
|
|
3141
|
+
{
|
|
3142
|
+
id: 'config-validation',
|
|
3143
|
+
name: 'Config Schema Validation',
|
|
3144
|
+
description: 'Validate environment variables at startup with typed schemas',
|
|
3145
|
+
category: 'DX',
|
|
3146
|
+
dependencies: {
|
|
3147
|
+
zod: '3.25.67',
|
|
3148
|
+
},
|
|
3149
|
+
devDependencies: {},
|
|
3150
|
+
envVars: [],
|
|
3151
|
+
conflicts: [],
|
|
3152
|
+
requires: [],
|
|
3153
|
+
compatibleWith: 'all',
|
|
3154
|
+
templateDir: 'config-validation',
|
|
3155
|
+
claudeMdSection: [
|
|
3156
|
+
'## Config Schema Validation',
|
|
3157
|
+
'Environment variables are validated at startup using Zod schemas in `src/config/env.validation.ts`.',
|
|
3158
|
+
'Add new env vars to the schema \u2014 the app will fail fast with descriptive errors if validation fails.',
|
|
3159
|
+
].join('\n'),
|
|
3160
|
+
cursorRules: 'Environment variables are validated at startup via Zod in src/config/env.validation.ts. Add new env vars to the schema. The app fails fast with clear errors on invalid config.',
|
|
3161
|
+
copilotInstructions: 'Env vars are validated at startup with Zod schemas in src/config/env.validation.ts. Use the EnvConfig type for typed config access. Add new env vars to the schema to enforce validation.',
|
|
3162
|
+
},
|
|
3163
|
+
// ─── Dead Letter Queue ────────────────────────────────────────────
|
|
3164
|
+
{
|
|
3165
|
+
id: 'dead-letter-queue',
|
|
3166
|
+
name: 'Dead Letter Queue',
|
|
3167
|
+
description: 'Handle permanently failed messages with DLQ routing and replay',
|
|
3168
|
+
category: 'Queue',
|
|
3169
|
+
dependencies: {},
|
|
3170
|
+
devDependencies: {},
|
|
3171
|
+
envVars: [],
|
|
3172
|
+
conflicts: [],
|
|
3173
|
+
requires: [],
|
|
3174
|
+
compatibleWith: ['http-api', 'microservice', 'scheduled-worker', 'monorepo', 'full-stack'],
|
|
3175
|
+
templateDir: 'dead-letter-queue',
|
|
3176
|
+
claudeMdSection: [
|
|
3177
|
+
'## Dead Letter Queue',
|
|
3178
|
+
'Failed messages are routed to a DLQ via `DeadLetterQueueService`. Inspect and replay dead letters through the service API.',
|
|
3179
|
+
'Integrate with BullMQ or RabbitMQ by calling `dlqService.add()` in your error handlers.',
|
|
3180
|
+
].join('\n'),
|
|
3181
|
+
cursorRules: 'DeadLetterQueueService stores permanently failed messages. Call dlqService.add() in queue error handlers. Use getAll()/getByQueue() to inspect and remove() to clear entries.',
|
|
3182
|
+
copilotInstructions: 'DeadLetterQueueService handles permanently failed queue messages. Inject it in queue consumers and call add() on unrecoverable errors. Supports inspection by queue name and removal by id.',
|
|
3183
|
+
},
|
|
3184
|
+
// ─── Webhooks ─────────────────────────────────────────────────────
|
|
3185
|
+
{
|
|
3186
|
+
id: 'webhooks',
|
|
3187
|
+
name: 'Webhook Delivery',
|
|
3188
|
+
description: 'Outbound webhook system with HMAC signing and retry',
|
|
3189
|
+
category: 'API Patterns',
|
|
3190
|
+
dependencies: {},
|
|
3191
|
+
devDependencies: {},
|
|
3192
|
+
envVars: [
|
|
3193
|
+
{
|
|
3194
|
+
key: 'WEBHOOK_SECRET',
|
|
3195
|
+
defaultValue: 'change-me',
|
|
3196
|
+
description: 'HMAC secret for webhook signatures',
|
|
3197
|
+
},
|
|
3198
|
+
],
|
|
3199
|
+
conflicts: [],
|
|
3200
|
+
requires: [],
|
|
3201
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
3202
|
+
templateDir: 'webhooks',
|
|
3203
|
+
claudeMdSection: [
|
|
3204
|
+
'## Webhook Delivery',
|
|
3205
|
+
'Outbound webhooks are sent via `WebhookService`. Payloads are HMAC-signed with SHA-256 using the `WEBHOOK_SECRET` env var.',
|
|
3206
|
+
'Signature is sent in the `X-Webhook-Signature` header. Consumers verify by computing HMAC of the raw body.',
|
|
3207
|
+
].join('\n'),
|
|
3208
|
+
cursorRules: 'WebhookService delivers outbound webhooks with HMAC-SHA256 signatures. Inject it and call deliver(url, payload). Signature is in X-Webhook-Signature header. Set WEBHOOK_SECRET env var.',
|
|
3209
|
+
copilotInstructions: 'WebhookService sends outbound webhooks signed with HMAC-SHA256. Inject ConfigService for the WEBHOOK_SECRET. Call deliver(url, payload) to send. Includes 10s timeout via AbortSignal.',
|
|
3210
|
+
},
|
|
3211
|
+
// ─── Data Masking / PII Redaction ──────────────────────────────────
|
|
3212
|
+
{
|
|
3213
|
+
id: 'data-masking',
|
|
3214
|
+
name: 'Data Masking',
|
|
3215
|
+
description: 'Automatic PII redaction in logs and API responses',
|
|
3216
|
+
category: 'Security',
|
|
3217
|
+
dependencies: {},
|
|
3218
|
+
devDependencies: {},
|
|
3219
|
+
envVars: [],
|
|
3220
|
+
conflicts: [],
|
|
3221
|
+
requires: [],
|
|
3222
|
+
compatibleWith: 'all',
|
|
3223
|
+
templateDir: 'data-masking',
|
|
3224
|
+
claudeMdSection: [
|
|
3225
|
+
'## Data Masking / PII Redaction',
|
|
3226
|
+
'Use @Sensitive() decorator on DTO properties to mask values in API responses (toPlainOnly).',
|
|
3227
|
+
'Use maskEmail(), maskPhone(), maskCreditCard(), maskIban() utils for manual masking in logs.',
|
|
3228
|
+
'Masking is applied automatically by class-transformer when serializing to plain objects.',
|
|
3229
|
+
].join('\n'),
|
|
3230
|
+
cursorRules: [
|
|
3231
|
+
'Apply @Sensitive() decorator to DTO fields containing PII. Masking only applies on serialization (toPlainOnly).',
|
|
3232
|
+
'Use mask utility functions for log redaction. Never log raw PII — always mask before writing to logs.',
|
|
3233
|
+
].join('\n'),
|
|
3234
|
+
copilotInstructions: [
|
|
3235
|
+
'Use @Sensitive() on DTO properties for auto-masking in responses. Uses class-transformer Transform.',
|
|
3236
|
+
'Mask utilities: maskEmail(), maskPhone(), maskCreditCard(), maskIban(). Apply in log statements for PII redaction.',
|
|
3237
|
+
].join('\n'),
|
|
3238
|
+
},
|
|
3239
|
+
// ─── Response Serialization Groups ────────────────────────────────
|
|
3240
|
+
{
|
|
3241
|
+
id: 'serialization-groups',
|
|
3242
|
+
name: 'Response Serialization Groups',
|
|
3243
|
+
description: 'Return different field sets based on role or endpoint',
|
|
3244
|
+
category: 'API Patterns',
|
|
3245
|
+
dependencies: {},
|
|
3246
|
+
devDependencies: {},
|
|
3247
|
+
envVars: [],
|
|
3248
|
+
conflicts: [],
|
|
3249
|
+
requires: [],
|
|
3250
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
3251
|
+
templateDir: 'serialization-groups',
|
|
3252
|
+
claudeMdSection: [
|
|
3253
|
+
'## Response Serialization Groups',
|
|
3254
|
+
'Use Serialize(DtoClass) decorator on controller methods to control which fields are returned.',
|
|
3255
|
+
'Mark DTO properties with @Expose() and optionally { groups: [...] } for role-based field visibility.',
|
|
3256
|
+
'The SerializeInterceptor uses class-transformer plainToInstance with excludeExtraneousValues.',
|
|
3257
|
+
].join('\n'),
|
|
3258
|
+
cursorRules: [
|
|
3259
|
+
'Use Serialize(DtoClass) on controller methods. Mark DTO fields with @Expose() to include them.',
|
|
3260
|
+
'Use groups on @Expose({ groups: ["admin"] }) for role-based serialization. Unlisted fields are excluded.',
|
|
3261
|
+
].join('\n'),
|
|
3262
|
+
copilotInstructions: [
|
|
3263
|
+
'Serialize(DtoClass) decorator applies SerializeInterceptor to transform responses.',
|
|
3264
|
+
'DTO fields need @Expose() to be included. Use @Exclude() or omit @Expose() to hide fields. Groups enable role-based visibility.',
|
|
3265
|
+
].join('\n'),
|
|
3266
|
+
},
|
|
3267
|
+
// ─── Transactional Outbox ─────────────────────────────────────────
|
|
3268
|
+
{
|
|
3269
|
+
id: 'transactional-outbox',
|
|
3270
|
+
name: 'Transactional Outbox',
|
|
3271
|
+
description: 'Guarantee at-least-once event delivery alongside database writes',
|
|
3272
|
+
category: 'Database',
|
|
3273
|
+
dependencies: {
|
|
3274
|
+
'@nestjs/typeorm': '10.0.2',
|
|
3275
|
+
typeorm: '0.3.20',
|
|
3276
|
+
},
|
|
3277
|
+
devDependencies: {},
|
|
3278
|
+
envVars: [],
|
|
3279
|
+
conflicts: [],
|
|
3280
|
+
requires: [],
|
|
3281
|
+
compatibleWith: ['http-api', 'microservice', 'scheduled-worker', 'full-stack', 'monorepo'],
|
|
3282
|
+
templateDir: 'transactional-outbox',
|
|
3283
|
+
claudeMdSection: [
|
|
3284
|
+
'## Transactional Outbox',
|
|
3285
|
+
'Use OutboxService.addMessage() within a transaction to guarantee at-least-once event delivery.',
|
|
3286
|
+
'Events are written to the `outbox` table atomically alongside business data, then published by a polling publisher.',
|
|
3287
|
+
'Mark events as published after successful delivery. Consider CDC (Debezium) for higher throughput.',
|
|
3288
|
+
].join('\n'),
|
|
3289
|
+
cursorRules: [
|
|
3290
|
+
'Use OutboxService.addMessage() inside EntityManager transactions. Never publish events outside a transaction.',
|
|
3291
|
+
'The outbox table stores unpublished events. A polling publisher reads and publishes them, then marks published=true.',
|
|
3292
|
+
].join('\n'),
|
|
3293
|
+
copilotInstructions: [
|
|
3294
|
+
'OutboxService writes events to the outbox table within the same DB transaction as business data.',
|
|
3295
|
+
'A polling publisher picks up unpublished rows and delivers them. For higher throughput, consider CDC with Debezium.',
|
|
3296
|
+
].join('\n'),
|
|
3297
|
+
},
|
|
3298
|
+
// ─── Social OAuth ──────────────────────────────────────────────────
|
|
3299
|
+
{
|
|
3300
|
+
id: 'oauth-google',
|
|
3301
|
+
name: 'Google OAuth',
|
|
3302
|
+
description: 'Google OAuth 2.0 login via Passport',
|
|
3303
|
+
category: 'Auth',
|
|
3304
|
+
dependencies: {
|
|
3305
|
+
'passport-google-oauth20': '2.0.0',
|
|
3306
|
+
'@nestjs/passport': '10.0.3',
|
|
3307
|
+
passport: '0.7.0',
|
|
3308
|
+
},
|
|
3309
|
+
devDependencies: {
|
|
3310
|
+
'@types/passport-google-oauth20': '2.0.16',
|
|
3311
|
+
},
|
|
3312
|
+
envVars: [
|
|
3313
|
+
{
|
|
3314
|
+
key: 'GOOGLE_CLIENT_ID',
|
|
3315
|
+
defaultValue: '',
|
|
3316
|
+
description: 'Google OAuth 2.0 client ID from Google Cloud Console',
|
|
3317
|
+
},
|
|
3318
|
+
{
|
|
3319
|
+
key: 'GOOGLE_CLIENT_SECRET',
|
|
3320
|
+
defaultValue: '',
|
|
3321
|
+
description: 'Google OAuth 2.0 client secret from Google Cloud Console',
|
|
3322
|
+
},
|
|
3323
|
+
{
|
|
3324
|
+
key: 'GOOGLE_CALLBACK_URL',
|
|
3325
|
+
defaultValue: 'http://localhost:3000/auth/google/callback',
|
|
3326
|
+
description: 'OAuth callback URL registered in Google Cloud Console',
|
|
3327
|
+
},
|
|
3328
|
+
],
|
|
3329
|
+
conflicts: [],
|
|
3330
|
+
requires: [],
|
|
3331
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
3332
|
+
templateDir: 'oauth-google',
|
|
3333
|
+
claudeMdSection: [
|
|
3334
|
+
'## Google OAuth',
|
|
3335
|
+
'Google OAuth 2.0 login is handled by GoogleStrategy via passport-google-oauth20.',
|
|
3336
|
+
'Protect routes with @UseGuards(GoogleAuthGuard). The callback route receives the authenticated user profile.',
|
|
3337
|
+
].join('\n'),
|
|
3338
|
+
cursorRules: [
|
|
3339
|
+
'Use @UseGuards(GoogleAuthGuard) to initiate Google login and handle the callback.',
|
|
3340
|
+
'GoogleStrategy validates the OAuth response and maps the profile to a local user object.',
|
|
3341
|
+
].join('\n'),
|
|
3342
|
+
copilotInstructions: [
|
|
3343
|
+
'Google OAuth is integrated via passport-google-oauth20 and @nestjs/passport.',
|
|
3344
|
+
'Use GoogleAuthGuard on login and callback routes. Configure credentials in environment variables.',
|
|
3345
|
+
].join('\n'),
|
|
3346
|
+
},
|
|
3347
|
+
{
|
|
3348
|
+
id: 'oauth-github',
|
|
3349
|
+
name: 'GitHub OAuth',
|
|
3350
|
+
description: 'GitHub OAuth 2.0 login via Passport',
|
|
3351
|
+
category: 'Auth',
|
|
3352
|
+
dependencies: {
|
|
3353
|
+
'passport-github2': '0.1.12',
|
|
3354
|
+
'@nestjs/passport': '10.0.3',
|
|
3355
|
+
passport: '0.7.0',
|
|
3356
|
+
},
|
|
3357
|
+
devDependencies: {
|
|
3358
|
+
'@types/passport-github2': '1.2.9',
|
|
3359
|
+
},
|
|
3360
|
+
envVars: [
|
|
3361
|
+
{
|
|
3362
|
+
key: 'GITHUB_CLIENT_ID',
|
|
3363
|
+
defaultValue: '',
|
|
3364
|
+
description: 'GitHub OAuth App client ID from GitHub Developer Settings',
|
|
3365
|
+
},
|
|
3366
|
+
{
|
|
3367
|
+
key: 'GITHUB_CLIENT_SECRET',
|
|
3368
|
+
defaultValue: '',
|
|
3369
|
+
description: 'GitHub OAuth App client secret from GitHub Developer Settings',
|
|
3370
|
+
},
|
|
3371
|
+
{
|
|
3372
|
+
key: 'GITHUB_CALLBACK_URL',
|
|
3373
|
+
defaultValue: 'http://localhost:3000/auth/github/callback',
|
|
3374
|
+
description: 'OAuth callback URL registered in GitHub Developer Settings',
|
|
3375
|
+
},
|
|
3376
|
+
],
|
|
3377
|
+
conflicts: [],
|
|
3378
|
+
requires: [],
|
|
3379
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
3380
|
+
templateDir: 'oauth-github',
|
|
3381
|
+
claudeMdSection: [
|
|
3382
|
+
'## GitHub OAuth',
|
|
3383
|
+
'GitHub OAuth login is handled by GitHubStrategy via passport-github2.',
|
|
3384
|
+
'Protect routes with @UseGuards(GitHubAuthGuard). The callback route receives the authenticated user profile.',
|
|
3385
|
+
].join('\n'),
|
|
3386
|
+
cursorRules: [
|
|
3387
|
+
'Use @UseGuards(GitHubAuthGuard) to initiate GitHub login and handle the callback.',
|
|
3388
|
+
'GitHubStrategy validates the OAuth response and maps the profile to a local user object.',
|
|
3389
|
+
].join('\n'),
|
|
3390
|
+
copilotInstructions: [
|
|
3391
|
+
'GitHub OAuth is integrated via passport-github2 and @nestjs/passport.',
|
|
3392
|
+
'Use GitHubAuthGuard on login and callback routes. Configure credentials in environment variables.',
|
|
3393
|
+
].join('\n'),
|
|
3394
|
+
},
|
|
3395
|
+
{
|
|
3396
|
+
id: 'oauth-apple',
|
|
3397
|
+
name: 'Apple OAuth',
|
|
3398
|
+
description: 'Sign in with Apple via Passport',
|
|
3399
|
+
category: 'Auth',
|
|
3400
|
+
dependencies: {
|
|
3401
|
+
'passport-apple': '2.0.2',
|
|
3402
|
+
'@nestjs/passport': '10.0.3',
|
|
3403
|
+
passport: '0.7.0',
|
|
3404
|
+
},
|
|
3405
|
+
devDependencies: {},
|
|
3406
|
+
envVars: [
|
|
3407
|
+
{
|
|
3408
|
+
key: 'APPLE_CLIENT_ID',
|
|
3409
|
+
defaultValue: '',
|
|
3410
|
+
description: 'Apple Services ID (e.g. com.example.app)',
|
|
3411
|
+
},
|
|
3412
|
+
{
|
|
3413
|
+
key: 'APPLE_TEAM_ID',
|
|
3414
|
+
defaultValue: '',
|
|
3415
|
+
description: 'Apple Developer Team ID',
|
|
3416
|
+
},
|
|
3417
|
+
{
|
|
3418
|
+
key: 'APPLE_KEY_ID',
|
|
3419
|
+
defaultValue: '',
|
|
3420
|
+
description: 'Apple Sign In private key ID',
|
|
3421
|
+
},
|
|
3422
|
+
{
|
|
3423
|
+
key: 'APPLE_PRIVATE_KEY_PATH',
|
|
3424
|
+
defaultValue: '',
|
|
3425
|
+
description: 'Path to Apple Sign In private key (.p8 file)',
|
|
3426
|
+
},
|
|
3427
|
+
{
|
|
3428
|
+
key: 'APPLE_CALLBACK_URL',
|
|
3429
|
+
defaultValue: 'http://localhost:3000/auth/apple/callback',
|
|
3430
|
+
description: 'OAuth callback URL registered in Apple Developer Portal',
|
|
3431
|
+
},
|
|
3432
|
+
],
|
|
3433
|
+
conflicts: [],
|
|
3434
|
+
requires: [],
|
|
3435
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
3436
|
+
templateDir: 'oauth-apple',
|
|
3437
|
+
claudeMdSection: [
|
|
3438
|
+
'## Apple OAuth',
|
|
3439
|
+
'Sign in with Apple is handled by AppleStrategy via passport-apple.',
|
|
3440
|
+
'Protect routes with @UseGuards(AppleAuthGuard). Apple returns user info only on the first login.',
|
|
3441
|
+
].join('\n'),
|
|
3442
|
+
cursorRules: [
|
|
3443
|
+
'Use @UseGuards(AppleAuthGuard) to initiate Apple login and handle the callback.',
|
|
3444
|
+
'AppleStrategy validates the OAuth response. Note: Apple only sends user name/email on the first authorization.',
|
|
3445
|
+
].join('\n'),
|
|
3446
|
+
copilotInstructions: [
|
|
3447
|
+
'Sign in with Apple is integrated via passport-apple and @nestjs/passport.',
|
|
3448
|
+
'Use AppleAuthGuard on login and callback routes. Apple only returns user details on first authorization.',
|
|
3449
|
+
].join('\n'),
|
|
3450
|
+
},
|
|
3451
|
+
// ─── Docker Compose Dev ──────────────────────────────────────────
|
|
3452
|
+
{
|
|
3453
|
+
id: 'docker-compose-dev',
|
|
3454
|
+
name: 'Docker Compose Dev',
|
|
3455
|
+
description: 'One-command local dev environment with hot reload',
|
|
3456
|
+
category: 'DX',
|
|
3457
|
+
dependencies: {},
|
|
3458
|
+
devDependencies: {},
|
|
3459
|
+
envVars: [],
|
|
3460
|
+
conflicts: [],
|
|
3461
|
+
requires: [],
|
|
3462
|
+
compatibleWith: ['http-api', 'microservice', 'scheduled-worker', 'full-stack', 'monorepo'],
|
|
3463
|
+
templateDir: 'docker-compose-dev',
|
|
3464
|
+
claudeMdSection: [
|
|
3465
|
+
'## Docker Compose Dev',
|
|
3466
|
+
'Start the full local environment with `docker compose -f docker-compose.dev.yml up`.',
|
|
3467
|
+
'Hot reload is enabled via volume mounts. Debug port 9229 is exposed for Node.js inspector.',
|
|
3468
|
+
'Adminer is available at http://localhost:8080 for database management.',
|
|
3469
|
+
].join('\n'),
|
|
3470
|
+
cursorRules: [
|
|
3471
|
+
'Use docker-compose.dev.yml for local development. Run `docker compose -f docker-compose.dev.yml up`.',
|
|
3472
|
+
'Services: app (port 3000 + debug 9229), postgres (5432), redis (6379), adminer (8080).',
|
|
3473
|
+
].join('\n'),
|
|
3474
|
+
copilotInstructions: [
|
|
3475
|
+
'Local dev runs via docker-compose.dev.yml with hot reload and debug support.',
|
|
3476
|
+
'Postgres, Redis, and Adminer are included. Use .env for configuration.',
|
|
3477
|
+
].join('\n'),
|
|
3478
|
+
},
|
|
3479
|
+
// ─── Load Testing (k6) ──────────────────────────────────────────
|
|
3480
|
+
{
|
|
3481
|
+
id: 'load-testing',
|
|
3482
|
+
name: 'Load Testing (k6)',
|
|
3483
|
+
description: 'Performance and load testing with Grafana k6',
|
|
3484
|
+
category: 'Testing',
|
|
3485
|
+
dependencies: {},
|
|
3486
|
+
devDependencies: {},
|
|
3487
|
+
envVars: [],
|
|
3488
|
+
conflicts: [],
|
|
3489
|
+
requires: [],
|
|
3490
|
+
compatibleWith: 'all',
|
|
3491
|
+
templateDir: 'load-testing',
|
|
3492
|
+
claudeMdSection: [
|
|
3493
|
+
'## Load Testing (k6)',
|
|
3494
|
+
'Load tests live in `k6/`. Smoke test: `k6 run k6/smoke.js`. Stress test: `k6 run k6/stress.js`.',
|
|
3495
|
+
'k6 is a standalone binary — install from https://grafana.com/docs/k6/latest/set-up/install-k6/.',
|
|
3496
|
+
'Thresholds are defined in each test script to enforce SLOs.',
|
|
3497
|
+
].join('\n'),
|
|
3498
|
+
cursorRules: [
|
|
3499
|
+
'k6 test scripts are in k6/ directory. Use `k6 run <script>` to execute.',
|
|
3500
|
+
'Define thresholds for p95 latency and error rate in each test script.',
|
|
3501
|
+
].join('\n'),
|
|
3502
|
+
copilotInstructions: [
|
|
3503
|
+
'k6 load tests are in k6/. Run with `k6 run k6/smoke.js` or `k6 run k6/stress.js`.',
|
|
3504
|
+
'k6 is a standalone Go binary, not an npm dependency. Install separately.',
|
|
3505
|
+
].join('\n'),
|
|
3506
|
+
},
|
|
3507
|
+
// ─── Worker Threads ──────────────────────────────────────────────
|
|
3508
|
+
{
|
|
3509
|
+
id: 'worker-threads',
|
|
3510
|
+
name: 'Worker Threads',
|
|
3511
|
+
description: 'Offload CPU-intensive tasks to worker threads',
|
|
3512
|
+
category: 'Operational',
|
|
3513
|
+
dependencies: {},
|
|
3514
|
+
devDependencies: {},
|
|
3515
|
+
envVars: [],
|
|
3516
|
+
conflicts: [],
|
|
3517
|
+
requires: [],
|
|
3518
|
+
compatibleWith: 'all',
|
|
3519
|
+
templateDir: 'worker-threads',
|
|
3520
|
+
claudeMdSection: [
|
|
3521
|
+
'## Worker Threads',
|
|
3522
|
+
'Use `WorkerPool` to offload CPU-intensive work (image processing, PDF generation, crypto) to worker threads.',
|
|
3523
|
+
'Inject `WorkerPool` and call `run<T>(script, data)` — it manages a pool sized to `os.cpus().length - 1`.',
|
|
3524
|
+
'Do not use worker threads for I/O-bound work — use async/await instead.',
|
|
3525
|
+
].join('\n'),
|
|
3526
|
+
cursorRules: [
|
|
3527
|
+
'Use WorkerPool.run() for CPU-intensive tasks. Pool size is auto-configured to (CPU count - 1).',
|
|
3528
|
+
'Worker scripts receive data via workerData and send results via parentPort.postMessage().',
|
|
3529
|
+
].join('\n'),
|
|
3530
|
+
copilotInstructions: [
|
|
3531
|
+
'WorkerPool is an injectable NestJS service for offloading CPU-intensive tasks to worker threads.',
|
|
3532
|
+
'Uses Node.js built-in worker_threads module. Not suitable for I/O-bound work.',
|
|
3533
|
+
].join('\n'),
|
|
3534
|
+
},
|
|
3535
|
+
// ─── File Upload ────────────────────────────────────────────────
|
|
3536
|
+
{
|
|
3537
|
+
id: 'file-upload',
|
|
3538
|
+
name: 'File Upload',
|
|
3539
|
+
description: 'Multipart file upload with validation and streaming',
|
|
3540
|
+
category: 'API Patterns',
|
|
3541
|
+
dependencies: {
|
|
3542
|
+
'@fastify/multipart': '9.0.3',
|
|
3543
|
+
},
|
|
3544
|
+
devDependencies: {},
|
|
3545
|
+
envVars: [
|
|
3546
|
+
{
|
|
3547
|
+
key: 'MAX_FILE_SIZE_MB',
|
|
3548
|
+
defaultValue: '50',
|
|
3549
|
+
description: 'Max upload size in MB',
|
|
3550
|
+
},
|
|
3551
|
+
],
|
|
3552
|
+
conflicts: [],
|
|
3553
|
+
requires: [],
|
|
3554
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
3555
|
+
templateDir: 'file-upload',
|
|
3556
|
+
claudeMdSection: [
|
|
3557
|
+
'## File Upload',
|
|
3558
|
+
'Register @fastify/multipart in `main.ts`. Use `FileUploadInterceptor` on upload routes.',
|
|
3559
|
+
'Validate files with `FileValidationPipe` — configure allowed MIME types and max size.',
|
|
3560
|
+
'Access the uploaded file via `(request as any).uploadedFile` after the interceptor runs.',
|
|
3561
|
+
].join('\n'),
|
|
3562
|
+
cursorRules: [
|
|
3563
|
+
'Use FileUploadInterceptor + FileValidationPipe for multipart uploads. Register @fastify/multipart in main.ts.',
|
|
3564
|
+
'Access uploaded file from request.uploadedFile. Configure MAX_FILE_SIZE_MB in environment.',
|
|
3565
|
+
].join('\n'),
|
|
3566
|
+
copilotInstructions: [
|
|
3567
|
+
'File uploads use @fastify/multipart with a custom interceptor and validation pipe.',
|
|
3568
|
+
'FileUploadInterceptor extracts the file, FileValidationPipe checks MIME type and size.',
|
|
3569
|
+
].join('\n'),
|
|
3570
|
+
},
|
|
3571
|
+
// ─── Two-Factor Authentication (TOTP) ──────────────────────────
|
|
3572
|
+
{
|
|
3573
|
+
id: 'mfa-totp',
|
|
3574
|
+
name: 'Two-Factor Authentication (TOTP)',
|
|
3575
|
+
description: 'TOTP-based 2FA with backup codes',
|
|
3576
|
+
category: 'Auth',
|
|
3577
|
+
dependencies: {
|
|
3578
|
+
otplib: '12.0.1',
|
|
3579
|
+
qrcode: '1.5.4',
|
|
3580
|
+
},
|
|
3581
|
+
devDependencies: {
|
|
3582
|
+
'@types/qrcode': '1.5.5',
|
|
3583
|
+
},
|
|
3584
|
+
envVars: [],
|
|
3585
|
+
conflicts: [],
|
|
3586
|
+
requires: [],
|
|
3587
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
3588
|
+
templateDir: 'mfa-totp',
|
|
3589
|
+
claudeMdSection: [
|
|
3590
|
+
'## Two-Factor Authentication (TOTP)',
|
|
3591
|
+
'Use `TotpService` to generate secrets, QR codes, and verify TOTP tokens.',
|
|
3592
|
+
'Call `generateSecret()` during 2FA setup, `generateQrCode()` to display the QR code, and `verify()` to validate tokens.',
|
|
3593
|
+
'Store backup codes hashed — they are single-use recovery codes.',
|
|
3594
|
+
].join('\n'),
|
|
3595
|
+
cursorRules: [
|
|
3596
|
+
'Use TotpService for all TOTP operations. generateSecret() creates the shared secret, verify() validates tokens.',
|
|
3597
|
+
'Backup codes from generateBackupCodes() are single-use. Hash them before storing in the database.',
|
|
3598
|
+
].join('\n'),
|
|
3599
|
+
copilotInstructions: [
|
|
3600
|
+
'TotpService wraps otplib for TOTP 2FA. Generate secrets, QR codes (via qrcode), and verify tokens.',
|
|
3601
|
+
'Backup codes are plain strings — hash before persisting. They are single-use recovery codes.',
|
|
3602
|
+
].join('\n'),
|
|
3603
|
+
},
|
|
3604
|
+
// ─── AdminJS ──────────────────────────────────────────────────────
|
|
3605
|
+
{
|
|
3606
|
+
id: 'adminjs',
|
|
3607
|
+
name: 'AdminJS',
|
|
3608
|
+
description: 'Auto-generated CRUD admin panel with authentication',
|
|
3609
|
+
category: 'DX',
|
|
3610
|
+
dependencies: {
|
|
3611
|
+
adminjs: '7.8.13',
|
|
3612
|
+
'@adminjs/nestjs': '6.1.0',
|
|
3613
|
+
'@adminjs/express': '6.1.0',
|
|
3614
|
+
express: '5.1.0',
|
|
3615
|
+
'express-session': '1.18.1',
|
|
3616
|
+
'express-formidable': '1.2.0',
|
|
3617
|
+
},
|
|
3618
|
+
devDependencies: {
|
|
3619
|
+
'@types/express-session': '1.18.1',
|
|
3620
|
+
},
|
|
3621
|
+
envVars: [
|
|
3622
|
+
{
|
|
3623
|
+
key: 'ADMIN_EMAIL',
|
|
3624
|
+
defaultValue: 'admin@example.com',
|
|
3625
|
+
description: 'AdminJS login email',
|
|
3626
|
+
},
|
|
3627
|
+
{
|
|
3628
|
+
key: 'ADMIN_PASSWORD',
|
|
3629
|
+
defaultValue: 'changeme',
|
|
3630
|
+
description: 'AdminJS login password',
|
|
3631
|
+
},
|
|
3632
|
+
],
|
|
3633
|
+
conflicts: [],
|
|
3634
|
+
requires: [],
|
|
3635
|
+
compatibleWith: ['http-api', 'full-stack', 'monorepo'],
|
|
3636
|
+
templateDir: 'adminjs',
|
|
3637
|
+
claudeMdSection: '## AdminJS\nAdmin panel available at /admin. Register resources in admin.module.ts. Authentication uses ADMIN_EMAIL/ADMIN_PASSWORD env vars.',
|
|
3638
|
+
cursorRules: 'AdminJS panel at /admin. Register entities as AdminJS resources in AdminModule. Use AdminJS features (actions, components) for customization.',
|
|
3639
|
+
copilotInstructions: 'AdminJS provides an auto-generated admin panel at /admin. Add entity resources in the AdminModule to expose CRUD operations.',
|
|
3640
|
+
},
|
|
3641
|
+
];
|
|
3642
|
+
export function registerAllRecipes(registry) {
|
|
3643
|
+
for (const recipe of recipes) {
|
|
3644
|
+
registry.register(recipe);
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3647
|
+
//# sourceMappingURL=definitions.js.map
|