@ngxtm/devkit 3.3.0 → 3.4.1
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/cli/index.js +59 -13
- package/cli/rules.js +248 -0
- package/package.json +2 -1
- package/rules/README.md +141 -0
- package/rules/dart/best-practices/SKILL.md +23 -0
- package/rules/dart/language/SKILL.md +52 -0
- package/rules/dart/tooling/SKILL.md +43 -0
- package/rules/dotnet/aspnet-core/SKILL.md +92 -0
- package/rules/dotnet/aspnet-core/references/REFERENCE.md +335 -0
- package/rules/dotnet/best-practices/SKILL.md +101 -0
- package/rules/dotnet/best-practices/references/REFERENCE.md +256 -0
- package/rules/dotnet/blazor/SKILL.md +146 -0
- package/rules/dotnet/blazor/references/REFERENCE.md +392 -0
- package/rules/dotnet/language/SKILL.md +82 -0
- package/rules/dotnet/language/references/REFERENCE.md +222 -0
- package/rules/dotnet/patterns.rule.md +388 -0
- package/rules/dotnet/razor-pages/SKILL.md +124 -0
- package/rules/dotnet/razor-pages/references/REFERENCE.md +321 -0
- package/rules/dotnet/security/SKILL.md +89 -0
- package/rules/dotnet/security/references/REFERENCE.md +295 -0
- package/rules/dotnet/tooling/SKILL.md +92 -0
- package/rules/dotnet/tooling/references/REFERENCE.md +300 -0
- package/rules/flutter/auto-route-navigation/SKILL.md +43 -0
- package/rules/flutter/auto-route-navigation/references/REFERENCE.md +19 -0
- package/rules/flutter/auto-route-navigation/references/router-config.md +62 -0
- package/rules/flutter/bloc-state-management/SKILL.md +64 -0
- package/rules/flutter/bloc-state-management/references/REFERENCE.md +20 -0
- package/rules/flutter/bloc-state-management/references/auth-bloc-example.md +52 -0
- package/rules/flutter/bloc-state-management/references/equatable-usage.md +56 -0
- package/rules/flutter/bloc-state-management/references/property-based-state.md +68 -0
- package/rules/flutter/bloc.rule.md +76 -0
- package/rules/flutter/cicd/SKILL.md +48 -0
- package/rules/flutter/cicd/references/advanced-workflow.md +66 -0
- package/rules/flutter/cicd/references/fastlane.md +139 -0
- package/rules/flutter/cicd/references/github-actions.md +59 -0
- package/rules/flutter/dependency-injection/SKILL.md +42 -0
- package/rules/flutter/dependency-injection/references/REFERENCE.md +15 -0
- package/rules/flutter/dependency-injection/references/modules.md +37 -0
- package/rules/flutter/error-handling/SKILL.md +32 -0
- package/rules/flutter/error-handling/references/REFERENCE.md +19 -0
- package/rules/flutter/error-handling/references/error-mapping.md +31 -0
- package/rules/flutter/feature-based-clean-architecture/SKILL.md +46 -0
- package/rules/flutter/feature-based-clean-architecture/references/REFERENCE.md +14 -0
- package/rules/flutter/feature-based-clean-architecture/references/folder-structure.md +36 -0
- package/rules/flutter/getx-navigation/SKILL.md +70 -0
- package/rules/flutter/getx-navigation/references/app-pages.md +40 -0
- package/rules/flutter/getx-navigation/references/middleware-example.md +29 -0
- package/rules/flutter/getx-state-management/SKILL.md +76 -0
- package/rules/flutter/getx-state-management/references/binding-example.md +32 -0
- package/rules/flutter/getx-state-management/references/reactive-vs-simple.md +39 -0
- package/rules/flutter/go-router-navigation/SKILL.md +57 -0
- package/rules/flutter/idiomatic-flutter/SKILL.md +20 -0
- package/rules/flutter/layer-based-clean-architecture/SKILL.md +50 -0
- package/rules/flutter/layer-based-clean-architecture/references/REFERENCE.md +60 -0
- package/rules/flutter/layer-based-clean-architecture/references/repository-mapping.md +50 -0
- package/rules/flutter/localization/SKILL.md +50 -0
- package/rules/flutter/localization/references/REFERENCE.md +48 -0
- package/rules/flutter/localization/references/sheet-loader.md +33 -0
- package/rules/flutter/navigator-v1-navigation/SKILL.md +71 -0
- package/rules/flutter/navigator-v1-navigation/references/on-generate-route.md +48 -0
- package/rules/flutter/performance/SKILL.md +24 -0
- package/rules/flutter/retrofit-networking/SKILL.md +51 -0
- package/rules/flutter/retrofit-networking/references/REFERENCE.md +19 -0
- package/rules/flutter/retrofit-networking/references/token-refresh.md +40 -0
- package/rules/flutter/riverpod-state-management/SKILL.md +53 -0
- package/rules/flutter/riverpod-state-management/references/architecture.md +124 -0
- package/rules/flutter/riverpod-state-management/references/best-practices.md +89 -0
- package/rules/flutter/riverpod-state-management/references/testing.md +73 -0
- package/rules/flutter/riverpod.rule.md +78 -0
- package/rules/flutter/security/SKILL.md +33 -0
- package/rules/flutter/security/references/REFERENCE.md +15 -0
- package/rules/flutter/security/references/network-security.md +28 -0
- package/rules/flutter/testing/SKILL.md +44 -0
- package/rules/flutter/testing/references/REFERENCE.md +21 -0
- package/rules/flutter/testing/references/bloc-testing.md +38 -0
- package/rules/flutter/testing/references/integration-testing.md +128 -0
- package/rules/flutter/testing/references/robot-pattern.md +82 -0
- package/rules/flutter/testing/references/unit-testing.md +130 -0
- package/rules/flutter/testing/references/widget-testing.md +120 -0
- package/rules/flutter/widgets/SKILL.md +37 -0
- package/rules/golang/chi-router/SKILL.md +219 -0
- package/rules/golang/chi-router/references/REFERENCE.md +13 -0
- package/rules/golang/chi-router/references/routing-patterns.md +205 -0
- package/rules/golang/cobra-cli/SKILL.md +227 -0
- package/rules/golang/cobra-cli/references/REFERENCE.md +13 -0
- package/rules/golang/cobra-cli/references/command-patterns.md +224 -0
- package/rules/golang/core/SKILL.md +210 -0
- package/rules/golang/core/references/REFERENCE.md +14 -0
- package/rules/golang/core/references/concurrency-patterns.md +114 -0
- package/rules/golang/core/references/error-handling.md +87 -0
- package/rules/golang/echo-framework/SKILL.md +215 -0
- package/rules/golang/echo-framework/references/REFERENCE.md +14 -0
- package/rules/golang/echo-framework/references/middleware-patterns.md +141 -0
- package/rules/golang/echo-framework/references/routing-patterns.md +140 -0
- package/rules/golang/ent-orm/SKILL.md +239 -0
- package/rules/golang/ent-orm/references/REFERENCE.md +13 -0
- package/rules/golang/ent-orm/references/schema-patterns.md +255 -0
- package/rules/golang/fiber-framework/SKILL.md +196 -0
- package/rules/golang/fiber-framework/references/REFERENCE.md +13 -0
- package/rules/golang/fiber-framework/references/routing-patterns.md +191 -0
- package/rules/golang/gin-framework/SKILL.md +205 -0
- package/rules/golang/gin-framework/references/REFERENCE.md +14 -0
- package/rules/golang/gin-framework/references/middleware-patterns.md +119 -0
- package/rules/golang/gorm-orm/SKILL.md +196 -0
- package/rules/golang/gorm-orm/references/REFERENCE.md +14 -0
- package/rules/golang/gorm-orm/references/model-definitions.md +167 -0
- package/rules/golang/gorm-orm/references/query-patterns.md +161 -0
- package/rules/golang/grpc/SKILL.md +231 -0
- package/rules/golang/grpc/references/REFERENCE.md +13 -0
- package/rules/golang/grpc/references/service-patterns.md +276 -0
- package/rules/golang/testify/SKILL.md +239 -0
- package/rules/golang/testify/references/REFERENCE.md +13 -0
- package/rules/golang/testify/references/assert-patterns.md +170 -0
- package/rules/golang/validator/SKILL.md +234 -0
- package/rules/golang/validator/references/REFERENCE.md +13 -0
- package/rules/golang/validator/references/validation-tags.md +211 -0
- package/rules/golang/viper-config/SKILL.md +244 -0
- package/rules/golang/viper-config/references/REFERENCE.md +13 -0
- package/rules/golang/viper-config/references/config-loading.md +181 -0
- package/rules/golang/wire-di/SKILL.md +243 -0
- package/rules/golang/wire-di/references/REFERENCE.md +13 -0
- package/rules/golang/wire-di/references/provider-patterns.md +193 -0
- package/rules/golang/zap-logging/SKILL.md +203 -0
- package/rules/golang/zap-logging/references/REFERENCE.md +13 -0
- package/rules/golang/zap-logging/references/logger-config.md +165 -0
- package/rules/java/build-gradle/SKILL.md +92 -0
- package/rules/java/build-gradle/references/REFERENCE.md +14 -0
- package/rules/java/build-gradle/references/kotlin-dsl.md +118 -0
- package/rules/java/build-gradle/references/task-configuration.md +132 -0
- package/rules/java/build-maven/SKILL.md +86 -0
- package/rules/java/build-maven/references/REFERENCE.md +14 -0
- package/rules/java/build-maven/references/dependency-management.md +111 -0
- package/rules/java/build-maven/references/lifecycle-phases.md +114 -0
- package/rules/java/graalvm-native/SKILL.md +105 -0
- package/rules/java/graalvm-native/references/REFERENCE.md +12 -0
- package/rules/java/java-collections-streams/SKILL.md +148 -0
- package/rules/java/java-collections-streams/references/REFERENCE.md +15 -0
- package/rules/java/java-collections-streams/references/collectors-patterns.md +178 -0
- package/rules/java/java-collections-streams/references/stream-pipelines.md +165 -0
- package/rules/java/java-concurrency/SKILL.md +187 -0
- package/rules/java/java-concurrency/references/REFERENCE.md +17 -0
- package/rules/java/java-concurrency/references/completable-future.md +165 -0
- package/rules/java/java-concurrency/references/executor-patterns.md +176 -0
- package/rules/java/java-concurrency/references/virtual-threads.md +190 -0
- package/rules/java/java-core-language/SKILL.md +121 -0
- package/rules/java/java-core-language/references/REFERENCE.md +15 -0
- package/rules/java/java-core-language/references/jvm-memory-model.md +160 -0
- package/rules/java/java-core-language/references/modern-java-features.md +168 -0
- package/rules/java/java-project-structure/SKILL.md +195 -0
- package/rules/java/java-project-structure/references/REFERENCE.md +15 -0
- package/rules/java/java-project-structure/references/maven-project-layout.md +199 -0
- package/rules/java/java-project-structure/references/module-system.md +159 -0
- package/rules/java/micronaut-core/SKILL.md +99 -0
- package/rules/java/micronaut-core/references/REFERENCE.md +12 -0
- package/rules/java/micronaut-reactive/SKILL.md +68 -0
- package/rules/java/micronaut-reactive/references/REFERENCE.md +12 -0
- package/rules/java/quarkus-core/SKILL.md +85 -0
- package/rules/java/quarkus-core/references/REFERENCE.md +12 -0
- package/rules/java/quarkus-reactive/SKILL.md +67 -0
- package/rules/java/quarkus-reactive/references/REFERENCE.md +12 -0
- package/rules/java/spring-batch/SKILL.md +102 -0
- package/rules/java/spring-batch/references/REFERENCE.md +12 -0
- package/rules/java/spring-boot-architecture/SKILL.md +206 -0
- package/rules/java/spring-boot-architecture/references/REFERENCE.md +15 -0
- package/rules/java/spring-boot-architecture/references/auto-configuration.md +158 -0
- package/rules/java/spring-boot-architecture/references/configuration-properties.md +202 -0
- package/rules/java/spring-boot-web/SKILL.md +217 -0
- package/rules/java/spring-boot-web/references/REFERENCE.md +17 -0
- package/rules/java/spring-cloud/SKILL.md +109 -0
- package/rules/java/spring-cloud/references/REFERENCE.md +13 -0
- package/rules/java/spring-data-jpa/SKILL.md +241 -0
- package/rules/java/spring-data-jpa/references/REFERENCE.md +16 -0
- package/rules/java/spring-security/SKILL.md +161 -0
- package/rules/java/spring-security/references/REFERENCE.md +16 -0
- package/rules/java/spring-security/references/jwt-auth-flow.md +213 -0
- package/rules/java/testing-junit-mockito/SKILL.md +135 -0
- package/rules/java/testing-junit-mockito/references/REFERENCE.md +15 -0
- package/rules/java/testing-junit-mockito/references/junit5-patterns.md +159 -0
- package/rules/java/testing-junit-mockito/references/mockito-patterns.md +148 -0
- package/rules/java/testing-junit-mockito/references/spring-boot-testing.md +152 -0
- package/rules/javascript/best-practices/SKILL.md +64 -0
- package/rules/javascript/best-practices/references/REFERENCE.md +91 -0
- package/rules/javascript/language/SKILL.md +71 -0
- package/rules/javascript/language/references/REFERENCE.md +106 -0
- package/rules/javascript/tooling/SKILL.md +60 -0
- package/rules/javascript/tooling/references/REFERENCE.md +107 -0
- package/rules/metadata.json +54 -0
- package/rules/nestjs/api-standards/SKILL.md +47 -0
- package/rules/nestjs/api-standards/references/pagination-wrapper.md +87 -0
- package/rules/nestjs/architecture/SKILL.md +68 -0
- package/rules/nestjs/architecture/references/dynamic-module.md +53 -0
- package/rules/nestjs/caching/SKILL.md +51 -0
- package/rules/nestjs/caching/references/REFERENCE.md +13 -0
- package/rules/nestjs/caching/references/cache-patterns.md +183 -0
- package/rules/nestjs/configuration/SKILL.md +41 -0
- package/rules/nestjs/configuration/references/REFERENCE.md +13 -0
- package/rules/nestjs/configuration/references/config-patterns.md +184 -0
- package/rules/nestjs/controllers-services/SKILL.md +63 -0
- package/rules/nestjs/controllers-services/references/REFERENCE.md +14 -0
- package/rules/nestjs/controllers-services/references/controller-patterns.md +119 -0
- package/rules/nestjs/controllers-services/references/service-patterns.md +129 -0
- package/rules/nestjs/database/SKILL.md +102 -0
- package/rules/nestjs/database/references/REFERENCE.md +14 -0
- package/rules/nestjs/database/references/typeorm-patterns.md +156 -0
- package/rules/nestjs/deployment/SKILL.md +36 -0
- package/rules/nestjs/deployment/references/REFERENCE.md +13 -0
- package/rules/nestjs/deployment/references/deployment-patterns.md +140 -0
- package/rules/nestjs/documentation/SKILL.md +64 -0
- package/rules/nestjs/documentation/references/REFERENCE.md +13 -0
- package/rules/nestjs/documentation/references/swagger-patterns.md +139 -0
- package/rules/nestjs/error-handling/SKILL.md +55 -0
- package/rules/nestjs/error-handling/references/REFERENCE.md +13 -0
- package/rules/nestjs/error-handling/references/exception-filters.md +152 -0
- package/rules/nestjs/file-uploads/SKILL.md +35 -0
- package/rules/nestjs/file-uploads/references/REFERENCE.md +13 -0
- package/rules/nestjs/file-uploads/references/upload-patterns.md +125 -0
- package/rules/nestjs/observability/SKILL.md +39 -0
- package/rules/nestjs/observability/references/REFERENCE.md +13 -0
- package/rules/nestjs/observability/references/logging-metrics.md +175 -0
- package/rules/nestjs/performance/SKILL.md +60 -0
- package/rules/nestjs/performance/references/REFERENCE.md +13 -0
- package/rules/nestjs/performance/references/performance-patterns.md +107 -0
- package/rules/nestjs/real-time/SKILL.md +45 -0
- package/rules/nestjs/real-time/references/REFERENCE.md +13 -0
- package/rules/nestjs/real-time/references/websocket-patterns.md +121 -0
- package/rules/nestjs/scheduling/SKILL.md +39 -0
- package/rules/nestjs/scheduling/references/REFERENCE.md +13 -0
- package/rules/nestjs/scheduling/references/scheduling-patterns.md +137 -0
- package/rules/nestjs/search/SKILL.md +41 -0
- package/rules/nestjs/search/references/REFERENCE.md +13 -0
- package/rules/nestjs/search/references/search-patterns.md +137 -0
- package/rules/nestjs/security/SKILL.md +87 -0
- package/rules/nestjs/security/references/REFERENCE.md +14 -0
- package/rules/nestjs/security/references/authentication.md +151 -0
- package/rules/nestjs/testing/SKILL.md +40 -0
- package/rules/nestjs/testing/references/REFERENCE.md +14 -0
- package/rules/nestjs/testing/references/unit-testing.md +179 -0
- package/rules/nestjs/transport/SKILL.md +45 -0
- package/rules/nestjs/transport/references/REFERENCE.md +13 -0
- package/rules/nestjs/transport/references/microservices-patterns.md +170 -0
- package/rules/nextjs/app-router/SKILL.md +46 -0
- package/rules/nextjs/app-router/references/REFERENCE.md +14 -0
- package/rules/nextjs/app-router/references/routing-patterns.md +182 -0
- package/rules/nextjs/architecture/SKILL.md +44 -0
- package/rules/nextjs/architecture/references/fsd-structure.md +77 -0
- package/rules/nextjs/authentication/SKILL.md +29 -0
- package/rules/nextjs/authentication/references/auth-implementation.md +73 -0
- package/rules/nextjs/caching/SKILL.md +66 -0
- package/rules/nextjs/caching/references/REFERENCE.md +13 -0
- package/rules/nextjs/caching/references/cache-strategies.md +168 -0
- package/rules/nextjs/data-access-layer/SKILL.md +33 -0
- package/rules/nextjs/data-access-layer/references/patterns.md +66 -0
- package/rules/nextjs/data-fetching/SKILL.md +59 -0
- package/rules/nextjs/data-fetching/references/REFERENCE.md +13 -0
- package/rules/nextjs/data-fetching/references/fetch-patterns.md +160 -0
- package/rules/nextjs/internationalization/SKILL.md +105 -0
- package/rules/nextjs/internationalization/references/REFERENCE.md +13 -0
- package/rules/nextjs/internationalization/references/i18n-patterns.md +180 -0
- package/rules/nextjs/optimization/SKILL.md +64 -0
- package/rules/nextjs/optimization/references/REFERENCE.md +13 -0
- package/rules/nextjs/optimization/references/optimization-patterns.md +190 -0
- package/rules/nextjs/rendering/SKILL.md +91 -0
- package/rules/nextjs/rendering/references/REFERENCE.md +13 -0
- package/rules/nextjs/rendering/references/rendering-modes.md +163 -0
- package/rules/nextjs/server-actions/SKILL.md +46 -0
- package/rules/nextjs/server-actions/references/REFERENCE.md +13 -0
- package/rules/nextjs/server-actions/references/action-patterns.md +188 -0
- package/rules/nextjs/server-components/SKILL.md +52 -0
- package/rules/nextjs/server-components/references/REFERENCE.md +13 -0
- package/rules/nextjs/server-components/references/component-patterns.md +175 -0
- package/rules/nextjs/state-management/SKILL.md +73 -0
- package/rules/nextjs/state-management/references/REFERENCE.md +13 -0
- package/rules/nextjs/state-management/references/state-patterns.md +218 -0
- package/rules/nextjs/styling/SKILL.md +31 -0
- package/rules/nextjs/styling/references/implementation.md +56 -0
- package/rules/react/component-patterns/SKILL.md +66 -0
- package/rules/react/component-patterns/references/REFERENCE.md +126 -0
- package/rules/react/hooks/SKILL.md +60 -0
- package/rules/react/hooks/references/REFERENCE.md +132 -0
- package/rules/react/hooks.rule.md +79 -0
- package/rules/react/performance/SKILL.md +69 -0
- package/rules/react/performance/references/REFERENCE.md +143 -0
- package/rules/react/security/SKILL.md +46 -0
- package/rules/react/security/references/REFERENCE.md +170 -0
- package/rules/react/state-management/SKILL.md +56 -0
- package/rules/react/state-management/references/REFERENCE.md +137 -0
- package/rules/react/testing/SKILL.md +45 -0
- package/rules/react/testing/references/REFERENCE.md +149 -0
- package/rules/react/tooling/SKILL.md +39 -0
- package/rules/react/typescript/SKILL.md +53 -0
- package/rules/rust/actix-web/SKILL.md +160 -0
- package/rules/rust/actix-web/references/REFERENCE.md +13 -0
- package/rules/rust/actix-web/references/handler-patterns.md +198 -0
- package/rules/rust/async-graphql/SKILL.md +228 -0
- package/rules/rust/async-graphql/references/REFERENCE.md +13 -0
- package/rules/rust/async-graphql/references/schema-patterns.md +215 -0
- package/rules/rust/axum/SKILL.md +161 -0
- package/rules/rust/axum/references/REFERENCE.md +14 -0
- package/rules/rust/axum/references/handler-patterns.md +97 -0
- package/rules/rust/bevy/SKILL.md +206 -0
- package/rules/rust/bevy/references/REFERENCE.md +13 -0
- package/rules/rust/bevy/references/ecs-patterns.md +226 -0
- package/rules/rust/clap/SKILL.md +217 -0
- package/rules/rust/clap/references/REFERENCE.md +13 -0
- package/rules/rust/clap/references/derive-patterns.md +205 -0
- package/rules/rust/core/SKILL.md +154 -0
- package/rules/rust/core/references/REFERENCE.md +14 -0
- package/rules/rust/core/references/error-handling.md +92 -0
- package/rules/rust/diesel-orm/SKILL.md +176 -0
- package/rules/rust/diesel-orm/references/REFERENCE.md +13 -0
- package/rules/rust/diesel-orm/references/schema-patterns.md +206 -0
- package/rules/rust/rocket/SKILL.md +182 -0
- package/rules/rust/rocket/references/REFERENCE.md +13 -0
- package/rules/rust/rocket/references/handler-patterns.md +209 -0
- package/rules/rust/sea-orm/SKILL.md +230 -0
- package/rules/rust/sea-orm/references/REFERENCE.md +13 -0
- package/rules/rust/sea-orm/references/entity-patterns.md +221 -0
- package/rules/rust/serde-serialization/SKILL.md +150 -0
- package/rules/rust/serde-serialization/references/REFERENCE.md +13 -0
- package/rules/rust/serde-serialization/references/serialization-patterns.md +199 -0
- package/rules/rust/sqlx-database/SKILL.md +140 -0
- package/rules/rust/sqlx-database/references/REFERENCE.md +13 -0
- package/rules/rust/sqlx-database/references/query-patterns.md +210 -0
- package/rules/rust/tauri/SKILL.md +180 -0
- package/rules/rust/tauri/references/REFERENCE.md +13 -0
- package/rules/rust/tauri/references/command-patterns.md +209 -0
- package/rules/rust/tokio-runtime/SKILL.md +167 -0
- package/rules/rust/tokio-runtime/references/REFERENCE.md +14 -0
- package/rules/rust/tokio-runtime/references/async-patterns.md +137 -0
- package/rules/rust/tokio-runtime/references/synchronization.md +152 -0
- package/rules/rust/tonic/SKILL.md +231 -0
- package/rules/rust/tonic/references/REFERENCE.md +13 -0
- package/rules/rust/tonic/references/service-patterns.md +213 -0
- package/rules/rust/tracing/SKILL.md +214 -0
- package/rules/rust/tracing/references/REFERENCE.md +13 -0
- package/rules/rust/tracing/references/instrumentation.md +187 -0
- package/rules/typescript/best-practices/SKILL.md +108 -0
- package/rules/typescript/best-practices/references/REFERENCE.md +68 -0
- package/rules/typescript/language/SKILL.md +72 -0
- package/rules/typescript/language/references/REFERENCE.md +67 -0
- package/rules/typescript/patterns.rule.md +85 -0
- package/rules/typescript/security/SKILL.md +59 -0
- package/rules/typescript/security/references/REFERENCE.md +113 -0
- package/rules/typescript/tooling/SKILL.md +52 -0
- package/rules/typescript/tooling/references/REFERENCE.md +110 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Dynamic Module Builder Reference
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `ConfigurableModuleBuilder` drastically reduces the boilerplate required to create typed `forRoot` / `register` methods for dynamic modules.
|
|
6
|
+
|
|
7
|
+
## Implementation
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// 1. definition.ts
|
|
11
|
+
import { ConfigurableModuleBuilder } from '@nestjs/common';
|
|
12
|
+
|
|
13
|
+
export interface MyModuleOptions {
|
|
14
|
+
apiKey: string;
|
|
15
|
+
isGlobal?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =
|
|
19
|
+
new ConfigurableModuleBuilder<MyModuleOptions>()
|
|
20
|
+
.setClassMethodName('forRoot') // or 'register'
|
|
21
|
+
.setExtras(
|
|
22
|
+
{
|
|
23
|
+
isGlobal: true,
|
|
24
|
+
},
|
|
25
|
+
(definition, extras) => ({
|
|
26
|
+
...definition,
|
|
27
|
+
global: extras.isGlobal,
|
|
28
|
+
}),
|
|
29
|
+
)
|
|
30
|
+
.build();
|
|
31
|
+
|
|
32
|
+
// 2. my.module.ts
|
|
33
|
+
import { Module } from '@nestjs/common';
|
|
34
|
+
import { ConfigurableModuleClass } from './definition';
|
|
35
|
+
import { MyService } from './my.service';
|
|
36
|
+
|
|
37
|
+
@Module({
|
|
38
|
+
providers: [MyService],
|
|
39
|
+
exports: [MyService],
|
|
40
|
+
})
|
|
41
|
+
export class MyModule extends ConfigurableModuleClass {}
|
|
42
|
+
|
|
43
|
+
// 3. usage (AppModule)
|
|
44
|
+
@Module({
|
|
45
|
+
imports: [
|
|
46
|
+
MyModule.forRoot({
|
|
47
|
+
apiKey: 'secret',
|
|
48
|
+
isGlobal: true,
|
|
49
|
+
}),
|
|
50
|
+
],
|
|
51
|
+
})
|
|
52
|
+
export class AppModule {}
|
|
53
|
+
```
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: NestJS Caching & Redis
|
|
3
|
+
description: Multi-level caching, Invalidation patterns, and Stampede protection.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [nestjs, caching, redis, performance]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**/*.service.ts', '**/*.interceptor.ts']
|
|
8
|
+
keywords: [CacheInterceptor, CacheTTL, Redis, stale-while-revalidate]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Caching & Redis Standards
|
|
12
|
+
|
|
13
|
+
## Caching Strategy
|
|
14
|
+
|
|
15
|
+
- **Layering**: Use **Multi-Level Caching** for high-traffic read endpoints.
|
|
16
|
+
- **L1 (Local)**: In-Memory (Node.js heap). Ultra-fast, no network. Ideal for config/static data. Use `lru-cache`.
|
|
17
|
+
- **L2 (Distributed)**: Redis. Shared across pods.
|
|
18
|
+
- **Pattern**: Implement **Stale-While-Revalidate** where possible to avoid latency spikes during cache misses.
|
|
19
|
+
|
|
20
|
+
## NestJS Implementation
|
|
21
|
+
|
|
22
|
+
- **Library**: Use `cache-manager` with `cache-manager-redis-yet` (Recommended over `cache-manager-redis-store` for better V4 support and stability).
|
|
23
|
+
- **Interceptors**: Use `@UseInterceptors(CacheInterceptor)` for simple GET responses.
|
|
24
|
+
- **Warning**: By default, this uses the URL as the key. Ensure consistent query param ordering or custom key generators.
|
|
25
|
+
- **Decorators**: Standardize custom cache keys.
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
@CacheKey('users_list')
|
|
29
|
+
@CacheTTL(300) // 5 minutes
|
|
30
|
+
findAll() { ... }
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Redis Data Structures (Expert)
|
|
34
|
+
|
|
35
|
+
- Don't just use `GET/SET`.
|
|
36
|
+
- **Hash (`HSET`)**: Storing objects (User profiles). Allows partial updates (`HSET user:1 lastLogin result`) without serialization overhead.
|
|
37
|
+
- **Set (`SADD`)**: Unique collections (e.g., "Online User IDs"). O(1) membership checks.
|
|
38
|
+
- **Sorted Set (`ZADD`)**: Priority queues, Leaderboards, or Rate Limiting windows.
|
|
39
|
+
|
|
40
|
+
## Invalidation Patterns
|
|
41
|
+
|
|
42
|
+
- **Problem**: "There are only two hard things in Computer Science: cache invalidation and naming things."
|
|
43
|
+
- **Tagging**: Since Redis doesn't support wildcards efficiently (`KEYS` is O(N) - bans in PROD), use **Sets** to group keys.
|
|
44
|
+
- _Create_: `SADD post:1:tags cache:post:1`
|
|
45
|
+
- _Invalidate_: Fetch tags from Set, then `DEL` usage keys.
|
|
46
|
+
- **Event-Driven**: Listen to Domain Events (`UserUpdated`) to trigger invalidation asynchronously.
|
|
47
|
+
|
|
48
|
+
## Stampede Protection
|
|
49
|
+
|
|
50
|
+
- **Jitter**: Add random variance to TTLs (e.g., 300s ± 10s) to prevent all keys expiring simultaneously.
|
|
51
|
+
- **Locking**: If a key is missing, **one** process computes it while others wait or return stale. (Complex, often handled by `swr` libraries).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# NestJS Caching References
|
|
2
|
+
|
|
3
|
+
## References
|
|
4
|
+
|
|
5
|
+
- [**Cache Patterns**](cache-patterns.md) - CacheModule, Redis, strategies
|
|
6
|
+
|
|
7
|
+
## Quick Checks
|
|
8
|
+
|
|
9
|
+
- [ ] Use CacheModule for simple caching
|
|
10
|
+
- [ ] Redis for production/distributed
|
|
11
|
+
- [ ] Cache interceptors for routes
|
|
12
|
+
- [ ] TTL configuration per cache
|
|
13
|
+
- [ ] Cache invalidation strategy
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# NestJS Cache Patterns
|
|
2
|
+
|
|
3
|
+
## Basic Setup
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { CacheModule } from '@nestjs/cache-manager';
|
|
7
|
+
|
|
8
|
+
@Module({
|
|
9
|
+
imports: [
|
|
10
|
+
CacheModule.register({
|
|
11
|
+
ttl: 5000, // 5 seconds
|
|
12
|
+
max: 100, // max items
|
|
13
|
+
}),
|
|
14
|
+
],
|
|
15
|
+
})
|
|
16
|
+
export class AppModule {}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Cache Interceptor
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { CacheInterceptor, CacheKey, CacheTTL } from '@nestjs/cache-manager';
|
|
23
|
+
|
|
24
|
+
@Controller('users')
|
|
25
|
+
@UseInterceptors(CacheInterceptor)
|
|
26
|
+
export class UsersController {
|
|
27
|
+
@Get()
|
|
28
|
+
@CacheTTL(30000) // 30 seconds
|
|
29
|
+
findAll() {
|
|
30
|
+
return this.usersService.findAll();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Get(':id')
|
|
34
|
+
@CacheKey('user')
|
|
35
|
+
findOne(@Param('id') id: string) {
|
|
36
|
+
return this.usersService.findOne(id);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Programmatic Caching
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
|
45
|
+
import { Cache } from 'cache-manager';
|
|
46
|
+
|
|
47
|
+
@Injectable()
|
|
48
|
+
export class UsersService {
|
|
49
|
+
constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}
|
|
50
|
+
|
|
51
|
+
async findOne(id: string): Promise<User> {
|
|
52
|
+
// Check cache
|
|
53
|
+
const cached = await this.cacheManager.get<User>(`user:${id}`);
|
|
54
|
+
if (cached) return cached;
|
|
55
|
+
|
|
56
|
+
// Fetch from DB
|
|
57
|
+
const user = await this.usersRepository.findById(id);
|
|
58
|
+
|
|
59
|
+
// Store in cache
|
|
60
|
+
await this.cacheManager.set(`user:${id}`, user, 60000);
|
|
61
|
+
|
|
62
|
+
return user;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async update(id: string, data: UpdateUserDto): Promise<User> {
|
|
66
|
+
const user = await this.usersRepository.update(id, data);
|
|
67
|
+
|
|
68
|
+
// Invalidate cache
|
|
69
|
+
await this.cacheManager.del(`user:${id}`);
|
|
70
|
+
|
|
71
|
+
return user;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async clearAllUsers(): Promise<void> {
|
|
75
|
+
await this.cacheManager.reset();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Redis Store
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { CacheModule } from '@nestjs/cache-manager';
|
|
84
|
+
import * as redisStore from 'cache-manager-redis-store';
|
|
85
|
+
|
|
86
|
+
@Module({
|
|
87
|
+
imports: [
|
|
88
|
+
CacheModule.registerAsync({
|
|
89
|
+
imports: [ConfigModule],
|
|
90
|
+
inject: [ConfigService],
|
|
91
|
+
useFactory: (config: ConfigService) => ({
|
|
92
|
+
store: redisStore,
|
|
93
|
+
host: config.get('REDIS_HOST'),
|
|
94
|
+
port: config.get('REDIS_PORT'),
|
|
95
|
+
ttl: 60,
|
|
96
|
+
}),
|
|
97
|
+
}),
|
|
98
|
+
],
|
|
99
|
+
})
|
|
100
|
+
export class AppModule {}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Custom Cache Key
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
@Injectable()
|
|
107
|
+
export class CustomCacheInterceptor extends CacheInterceptor {
|
|
108
|
+
trackBy(context: ExecutionContext): string | undefined {
|
|
109
|
+
const request = context.switchToHttp().getRequest();
|
|
110
|
+
const { method, url } = request;
|
|
111
|
+
|
|
112
|
+
// Don't cache POST, PUT, DELETE
|
|
113
|
+
if (method !== 'GET') return undefined;
|
|
114
|
+
|
|
115
|
+
// Include user in cache key
|
|
116
|
+
const userId = request.user?.id || 'anonymous';
|
|
117
|
+
return `${userId}:${url}`;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Cache-Aside Pattern
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
@Injectable()
|
|
126
|
+
export class ProductsService {
|
|
127
|
+
constructor(
|
|
128
|
+
@Inject(CACHE_MANAGER) private cache: Cache,
|
|
129
|
+
private productsRepo: ProductsRepository,
|
|
130
|
+
) {}
|
|
131
|
+
|
|
132
|
+
async getProduct(id: string): Promise<Product> {
|
|
133
|
+
const cacheKey = `product:${id}`;
|
|
134
|
+
|
|
135
|
+
// Try cache first
|
|
136
|
+
let product = await this.cache.get<Product>(cacheKey);
|
|
137
|
+
|
|
138
|
+
if (!product) {
|
|
139
|
+
// Cache miss - fetch from DB
|
|
140
|
+
product = await this.productsRepo.findById(id);
|
|
141
|
+
|
|
142
|
+
if (product) {
|
|
143
|
+
// Populate cache
|
|
144
|
+
await this.cache.set(cacheKey, product, 300000); // 5 min
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return product;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Bulk Cache Operations
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
async getProducts(ids: string[]): Promise<Product[]> {
|
|
157
|
+
const products: Product[] = [];
|
|
158
|
+
const missingIds: string[] = [];
|
|
159
|
+
|
|
160
|
+
// Check cache for each
|
|
161
|
+
for (const id of ids) {
|
|
162
|
+
const cached = await this.cache.get<Product>(`product:${id}`);
|
|
163
|
+
if (cached) {
|
|
164
|
+
products.push(cached);
|
|
165
|
+
} else {
|
|
166
|
+
missingIds.push(id);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Fetch missing from DB
|
|
171
|
+
if (missingIds.length > 0) {
|
|
172
|
+
const dbProducts = await this.productsRepo.findByIds(missingIds);
|
|
173
|
+
|
|
174
|
+
// Cache and add to result
|
|
175
|
+
for (const product of dbProducts) {
|
|
176
|
+
await this.cache.set(`product:${product.id}`, product);
|
|
177
|
+
products.push(product);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return products;
|
|
182
|
+
}
|
|
183
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: NestJS Configuration
|
|
3
|
+
description: Environment variables validation and ConfigModule setup.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [nestjs, config, env]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['.env', 'app.module.ts', '**/config.ts']
|
|
8
|
+
keywords: [ConfigModule, Joi, env]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# NestJS Configuration Standards
|
|
12
|
+
|
|
13
|
+
## Setup
|
|
14
|
+
|
|
15
|
+
1. **Library**: Use `@nestjs/config`.
|
|
16
|
+
2. **Initialization**: Import `ConfigModule.forRoot({ isGlobal: true })` in `AppModule`.
|
|
17
|
+
|
|
18
|
+
## Validation
|
|
19
|
+
|
|
20
|
+
- **Mandatory**: Validate environment variables at startup.
|
|
21
|
+
- **Tool**: Use `joi` or a custom validation class.
|
|
22
|
+
- **Effect**: The app **must crash** immediately if a required env var (e.g., `DB_URL`) is missing.
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// app.module.ts
|
|
26
|
+
ConfigModule.forRoot({
|
|
27
|
+
validationSchema: Joi.object({
|
|
28
|
+
NODE_ENV: Joi.string()
|
|
29
|
+
.valid('development', 'production')
|
|
30
|
+
.default('development'),
|
|
31
|
+
PORT: Joi.number().default(3000),
|
|
32
|
+
DATABASE_URL: Joi.string().required(),
|
|
33
|
+
}),
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
- **Injection**: Inject `ConfigService` to access values.
|
|
40
|
+
- **Typing**: Avoid magic strings. Use a type-safe getter helper or a dedicated configuration object/interface.
|
|
41
|
+
- **Secrets**: Never commit `.env` files. Add `.env*` to `.gitignore`.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# NestJS Configuration References
|
|
2
|
+
|
|
3
|
+
## References
|
|
4
|
+
|
|
5
|
+
- [**Config Patterns**](config-patterns.md) - ConfigModule, validation, environments
|
|
6
|
+
|
|
7
|
+
## Quick Checks
|
|
8
|
+
|
|
9
|
+
- [ ] Use ConfigModule for configuration
|
|
10
|
+
- [ ] Validate env vars with Joi/class-validator
|
|
11
|
+
- [ ] Type-safe config with interfaces
|
|
12
|
+
- [ ] Environment-specific configs
|
|
13
|
+
- [ ] Never commit secrets
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# NestJS Configuration Patterns
|
|
2
|
+
|
|
3
|
+
## Basic Setup
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
7
|
+
|
|
8
|
+
@Module({
|
|
9
|
+
imports: [
|
|
10
|
+
ConfigModule.forRoot({
|
|
11
|
+
isGlobal: true,
|
|
12
|
+
envFilePath: ['.env.local', '.env'],
|
|
13
|
+
}),
|
|
14
|
+
],
|
|
15
|
+
})
|
|
16
|
+
export class AppModule {}
|
|
17
|
+
|
|
18
|
+
// Usage
|
|
19
|
+
@Injectable()
|
|
20
|
+
export class AppService {
|
|
21
|
+
constructor(private configService: ConfigService) {}
|
|
22
|
+
|
|
23
|
+
getDatabaseUrl(): string {
|
|
24
|
+
return this.configService.get<string>('DATABASE_URL');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Validation with Joi
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import * as Joi from 'joi';
|
|
33
|
+
|
|
34
|
+
@Module({
|
|
35
|
+
imports: [
|
|
36
|
+
ConfigModule.forRoot({
|
|
37
|
+
validationSchema: Joi.object({
|
|
38
|
+
NODE_ENV: Joi.string()
|
|
39
|
+
.valid('development', 'production', 'test')
|
|
40
|
+
.default('development'),
|
|
41
|
+
PORT: Joi.number().default(3000),
|
|
42
|
+
DATABASE_URL: Joi.string().required(),
|
|
43
|
+
JWT_SECRET: Joi.string().required(),
|
|
44
|
+
JWT_EXPIRATION: Joi.string().default('1h'),
|
|
45
|
+
}),
|
|
46
|
+
validationOptions: {
|
|
47
|
+
abortEarly: true,
|
|
48
|
+
},
|
|
49
|
+
}),
|
|
50
|
+
],
|
|
51
|
+
})
|
|
52
|
+
export class AppModule {}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Configuration Namespaces
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// config/database.config.ts
|
|
59
|
+
import { registerAs } from '@nestjs/config';
|
|
60
|
+
|
|
61
|
+
export default registerAs('database', () => ({
|
|
62
|
+
host: process.env.DB_HOST || 'localhost',
|
|
63
|
+
port: parseInt(process.env.DB_PORT, 10) || 5432,
|
|
64
|
+
name: process.env.DB_NAME,
|
|
65
|
+
user: process.env.DB_USER,
|
|
66
|
+
password: process.env.DB_PASSWORD,
|
|
67
|
+
}));
|
|
68
|
+
|
|
69
|
+
// config/jwt.config.ts
|
|
70
|
+
export default registerAs('jwt', () => ({
|
|
71
|
+
secret: process.env.JWT_SECRET,
|
|
72
|
+
expiresIn: process.env.JWT_EXPIRATION || '1h',
|
|
73
|
+
}));
|
|
74
|
+
|
|
75
|
+
// app.module.ts
|
|
76
|
+
@Module({
|
|
77
|
+
imports: [
|
|
78
|
+
ConfigModule.forRoot({
|
|
79
|
+
load: [databaseConfig, jwtConfig],
|
|
80
|
+
}),
|
|
81
|
+
],
|
|
82
|
+
})
|
|
83
|
+
export class AppModule {}
|
|
84
|
+
|
|
85
|
+
// Usage
|
|
86
|
+
@Injectable()
|
|
87
|
+
export class DatabaseService {
|
|
88
|
+
constructor(private configService: ConfigService) {}
|
|
89
|
+
|
|
90
|
+
getConfig() {
|
|
91
|
+
return {
|
|
92
|
+
host: this.configService.get<string>('database.host'),
|
|
93
|
+
port: this.configService.get<number>('database.port'),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Type-Safe Configuration
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
// config/configuration.ts
|
|
103
|
+
export interface DatabaseConfig {
|
|
104
|
+
host: string;
|
|
105
|
+
port: number;
|
|
106
|
+
name: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface AppConfig {
|
|
110
|
+
database: DatabaseConfig;
|
|
111
|
+
port: number;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export default (): AppConfig => ({
|
|
115
|
+
port: parseInt(process.env.PORT, 10) || 3000,
|
|
116
|
+
database: {
|
|
117
|
+
host: process.env.DB_HOST,
|
|
118
|
+
port: parseInt(process.env.DB_PORT, 10) || 5432,
|
|
119
|
+
name: process.env.DB_NAME,
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Type-safe access
|
|
124
|
+
@Injectable()
|
|
125
|
+
export class AppService {
|
|
126
|
+
constructor(private configService: ConfigService<AppConfig, true>) {}
|
|
127
|
+
|
|
128
|
+
getPort(): number {
|
|
129
|
+
return this.configService.get('port', { infer: true });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
getDbHost(): string {
|
|
133
|
+
return this.configService.get('database.host', { infer: true });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Environment Files
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# .env
|
|
142
|
+
DATABASE_URL=postgres://localhost:5432/myapp
|
|
143
|
+
JWT_SECRET=your-secret-key
|
|
144
|
+
|
|
145
|
+
# .env.development
|
|
146
|
+
DEBUG=true
|
|
147
|
+
LOG_LEVEL=debug
|
|
148
|
+
|
|
149
|
+
# .env.production
|
|
150
|
+
LOG_LEVEL=error
|
|
151
|
+
|
|
152
|
+
# .env.test
|
|
153
|
+
DATABASE_URL=postgres://localhost:5432/myapp_test
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
ConfigModule.forRoot({
|
|
158
|
+
envFilePath: process.env.NODE_ENV === 'test'
|
|
159
|
+
? '.env.test'
|
|
160
|
+
: [`.env.${process.env.NODE_ENV}`, '.env'],
|
|
161
|
+
})
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Async Configuration
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
@Module({
|
|
168
|
+
imports: [
|
|
169
|
+
TypeOrmModule.forRootAsync({
|
|
170
|
+
imports: [ConfigModule],
|
|
171
|
+
inject: [ConfigService],
|
|
172
|
+
useFactory: (config: ConfigService) => ({
|
|
173
|
+
type: 'postgres',
|
|
174
|
+
host: config.get('database.host'),
|
|
175
|
+
port: config.get('database.port'),
|
|
176
|
+
database: config.get('database.name'),
|
|
177
|
+
autoLoadEntities: true,
|
|
178
|
+
synchronize: config.get('NODE_ENV') !== 'production',
|
|
179
|
+
}),
|
|
180
|
+
}),
|
|
181
|
+
],
|
|
182
|
+
})
|
|
183
|
+
export class DatabaseModule {}
|
|
184
|
+
```
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: NestJS Controllers & Services
|
|
3
|
+
description: Controller/Service separation and Custom Decorators.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [nestjs, controller, service]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**/*.controller.ts', '**/*.service.ts']
|
|
8
|
+
keywords: [Controller, Injectable, ExecutionContext, createParamDecorator]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# NestJS Controllers & Services Standards
|
|
12
|
+
|
|
13
|
+
## Controllers
|
|
14
|
+
|
|
15
|
+
- **Role**: Handler only. Delegate **all** logic to Services.
|
|
16
|
+
- **Context**: Use `ExecutionContext` helpers (`switchToHttp()`) for platform-agnostic code.
|
|
17
|
+
- **Custom Decorators**:
|
|
18
|
+
- **Avoid**: `@Request() req` -> `req.user` (Not type-safe).
|
|
19
|
+
- **Pattern**: Create typed decorators like `@CurrentUser()`, `@DeviceIp()`.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
export const CurrentUser = createParamDecorator(
|
|
23
|
+
(data: unknown, ctx: ExecutionContext) =>
|
|
24
|
+
ctx.switchToHttp().getRequest().user,
|
|
25
|
+
);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## DTOs & Validation
|
|
29
|
+
|
|
30
|
+
- **Strictness**:
|
|
31
|
+
- `whitelist: true`: Strip properties without decorators.
|
|
32
|
+
- **Critical**: `forbidNonWhitelisted: true`: Throw error if unknown properties exist.
|
|
33
|
+
- **Transformation**:
|
|
34
|
+
- `transform: true`: Auto-convert primitives (String '1' -> Number 1) and instantiate DTO classes.
|
|
35
|
+
- **Documentation**:
|
|
36
|
+
- **Automation**: Use the `@nestjs/swagger` CLI plugin (`nest-cli.json`) to auto-detect DTO properties without manual `@ApiProperty()` tags.
|
|
37
|
+
|
|
38
|
+
## Interceptors (Response Mapping)
|
|
39
|
+
|
|
40
|
+
- **Standardization**: specific responses should be mapped in **Interceptors**, not Controllers.
|
|
41
|
+
- Use `map()` to wrap success responses (e.g. `{ data: T }`).
|
|
42
|
+
- Refer to **[API Standards](../api-standards/SKILL.md)** for `PageDto` and `ApiResponse`.
|
|
43
|
+
- Use `catchError()` to map low-level errors (DB constraints) to `HttpException` (e.g. `ConflictException`) _before_ they hit the global filter.
|
|
44
|
+
|
|
45
|
+
## Services & Business Logic
|
|
46
|
+
|
|
47
|
+
- **Singleton**: Default.
|
|
48
|
+
- **Stateless**: Do not store request-specific state in class properties unless identifying as `Scope.REQUEST`.
|
|
49
|
+
|
|
50
|
+
## Pipes & Validation
|
|
51
|
+
|
|
52
|
+
- **Global**: Register `ValidationPipe` globally.
|
|
53
|
+
- **Route Params**: Fail fast. Always use `ParseIntPipe`, `ParseUUIDPipe` on all ID parameters.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
@Get(':id')
|
|
57
|
+
findOne(@Param('id', ParseIntPipe) id: number) { ... }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Lifecycle Events
|
|
61
|
+
|
|
62
|
+
- **Init**: Use `OnModuleInit` for connection setup.
|
|
63
|
+
- **Destroy**: Use `OnApplicationShutdown` for cleanup. (Requires `enableShutdownHooks()`).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# NestJS Controllers & Services References
|
|
2
|
+
|
|
3
|
+
## References
|
|
4
|
+
|
|
5
|
+
- [**Controller Patterns**](controller-patterns.md) - Routes, decorators, responses
|
|
6
|
+
- [**Service Patterns**](service-patterns.md) - DI, business logic, providers
|
|
7
|
+
|
|
8
|
+
## Quick Checks
|
|
9
|
+
|
|
10
|
+
- [ ] Use @Controller decorator with route prefix
|
|
11
|
+
- [ ] Inject services via constructor
|
|
12
|
+
- [ ] Use DTOs for request/response
|
|
13
|
+
- [ ] Apply validation pipes
|
|
14
|
+
- [ ] Keep controllers thin, services fat
|