@ngxtm/devkit 3.4.0 → 3.5.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/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
- package/skills/learn/SKILL.md +476 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: NestJS OpenAPI
|
|
3
|
+
description: Swagger automation and Generic response documentation.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [nestjs, swagger, openapi, docs]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['main.ts', '**/*.dto.ts']
|
|
8
|
+
keywords: [DocumentBuilder, SwaggerModule, ApiProperty, ApiResponse]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# OpenAPI & Documentation
|
|
12
|
+
|
|
13
|
+
## Swagger (OpenAPI)
|
|
14
|
+
|
|
15
|
+
- **Automation**: **ALWAYS** use the Nest CLI Plugin (`@nestjs/swagger/plugin`).
|
|
16
|
+
- **Benefit**: Auto-generates `@ApiProperty` for DTOs and response types. Reduces boilerplate by 50%.
|
|
17
|
+
- **Config**: `nest-cli.json` -> `"plugins": ["@nestjs/swagger"]`.
|
|
18
|
+
- **Versioning**: Maintain separate Swagger docs for `v1`, `v2` if breaking changes occur.
|
|
19
|
+
|
|
20
|
+
## Response Documentation
|
|
21
|
+
|
|
22
|
+
- **Strictness**: Every controller method must have `@ApiResponse({ status: 200, type: UserDto })`.
|
|
23
|
+
- **Generic Wrappers**: Define `ApiPaginatedResponse<T>` decorators to document generic `PageDto<T>` returns properly (Swagger doesn't handle generics well by default).
|
|
24
|
+
- **Technique**: Use `ApiExtraModels` + `getSchemaPath()` in the custom decorator to handle the generic `T` ref.
|
|
25
|
+
|
|
26
|
+
## Advanced Patterns
|
|
27
|
+
|
|
28
|
+
- **Polymorphism**: Use `@ApiExtraModels` and `getSchemaPath` for `oneOf`/`anyOf` union types.
|
|
29
|
+
- **File Uploads**: Document `multipart/form-data` explicitly.
|
|
30
|
+
- **Decorator**: `@ApiConsumes('multipart/form-data')`.
|
|
31
|
+
- **Body**: `@ApiBody({ schema: { type: 'object', properties: { file: { type: 'string', format: 'binary' } } } })`.
|
|
32
|
+
- **Authentication**: Specify granular security schemes per route/controller.
|
|
33
|
+
- **Types**: `@ApiBearerAuth()` or `@ApiSecurity('api-key')` (Must match `DocumentBuilder().addBearerAuth()`).
|
|
34
|
+
- **Enums**: Force named enums for reusable schema references.
|
|
35
|
+
- **Code**: `@ApiProperty({ enum: MyEnum, enumName: 'MyEnum' })`.
|
|
36
|
+
|
|
37
|
+
## Operation Grouping
|
|
38
|
+
|
|
39
|
+
- **Tags**: Mandatory `@ApiTags('domains')` on every Controller to group endpoints logically.
|
|
40
|
+
- **Multiple Docs**: generate separate docs for different audiences (e.g. Public vs Internal).
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
SwaggerModule.createDocument(app, config, { include: [PublicModule] }); // /api/docs
|
|
44
|
+
SwaggerModule.createDocument(app, adminConfig, { include: [AdminModule] }); // /admin/docs
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Self-Documentation
|
|
48
|
+
|
|
49
|
+
- **Compodoc**: Use `@compodoc/compodoc` to generate static documentation of the module graph, services, and dependencies.
|
|
50
|
+
- **Use Case**: New developer onboarding and architectural review.
|
|
51
|
+
|
|
52
|
+
## Advanced OpenAPI
|
|
53
|
+
|
|
54
|
+
- **Polymorphism**: Use `@ApiExtraModels` and `getSchemaPath` for `oneOf`/`anyOf` union types.
|
|
55
|
+
- **Pattern**: Register generic/sub-types in controller, refer via schema `$ref`.
|
|
56
|
+
- **File Uploads**: Document `multipart/form-data` explicitly.
|
|
57
|
+
- **Decorator**: `@ApiConsumes('multipart/form-data')`.
|
|
58
|
+
- **Body**: `@ApiBody({ schema: { type: 'object', properties: { file: { type: 'string', format: 'binary' } } } })`.
|
|
59
|
+
- **Authentication**: Specify granular security schemes per route/controller.
|
|
60
|
+
- **Types**: `@ApiBearerAuth()` or `@ApiSecurity('api-key')`. Match setup in `DocumentBuilder`.
|
|
61
|
+
- **Enums**: Force named enums for reusable schema references.
|
|
62
|
+
- **Code**: `@ApiProperty({ enum: MyEnum, enumName: 'MyEnum' })`.
|
|
63
|
+
- **Grouping**: Segregate public vs. internal docs.
|
|
64
|
+
- **Setup**: `SwaggerModule.createDocument(app, config, { include: [AdminModule] })`.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# NestJS Documentation References
|
|
2
|
+
|
|
3
|
+
## References
|
|
4
|
+
|
|
5
|
+
- [**Swagger Patterns**](swagger-patterns.md) - OpenAPI, decorators, schemas
|
|
6
|
+
|
|
7
|
+
## Quick Checks
|
|
8
|
+
|
|
9
|
+
- [ ] Use @ApiTags for controller grouping
|
|
10
|
+
- [ ] Document all DTOs with @ApiProperty
|
|
11
|
+
- [ ] Add @ApiResponse for all status codes
|
|
12
|
+
- [ ] Include authentication in swagger config
|
|
13
|
+
- [ ] Generate OpenAPI spec for clients
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# NestJS Swagger/OpenAPI Patterns
|
|
2
|
+
|
|
3
|
+
## Setup
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
|
7
|
+
|
|
8
|
+
async function bootstrap() {
|
|
9
|
+
const app = await NestFactory.create(AppModule);
|
|
10
|
+
|
|
11
|
+
const config = new DocumentBuilder()
|
|
12
|
+
.setTitle('API Documentation')
|
|
13
|
+
.setDescription('REST API endpoints')
|
|
14
|
+
.setVersion('1.0')
|
|
15
|
+
.addBearerAuth()
|
|
16
|
+
.addTag('users')
|
|
17
|
+
.addTag('orders')
|
|
18
|
+
.build();
|
|
19
|
+
|
|
20
|
+
const document = SwaggerModule.createDocument(app, config);
|
|
21
|
+
SwaggerModule.setup('api/docs', app, document);
|
|
22
|
+
|
|
23
|
+
await app.listen(3000);
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## DTO Documentation
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
31
|
+
|
|
32
|
+
export class CreateUserDto {
|
|
33
|
+
@ApiProperty({
|
|
34
|
+
description: 'User email address',
|
|
35
|
+
example: 'user@example.com',
|
|
36
|
+
})
|
|
37
|
+
email: string;
|
|
38
|
+
|
|
39
|
+
@ApiProperty({
|
|
40
|
+
description: 'User password',
|
|
41
|
+
minLength: 8,
|
|
42
|
+
})
|
|
43
|
+
password: string;
|
|
44
|
+
|
|
45
|
+
@ApiPropertyOptional({
|
|
46
|
+
description: 'User display name',
|
|
47
|
+
example: 'John Doe',
|
|
48
|
+
})
|
|
49
|
+
name?: string;
|
|
50
|
+
|
|
51
|
+
@ApiProperty({
|
|
52
|
+
enum: ['admin', 'user', 'guest'],
|
|
53
|
+
default: 'user',
|
|
54
|
+
})
|
|
55
|
+
role: string;
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Controller Documentation
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import {
|
|
63
|
+
ApiTags,
|
|
64
|
+
ApiOperation,
|
|
65
|
+
ApiResponse,
|
|
66
|
+
ApiBearerAuth,
|
|
67
|
+
ApiParam,
|
|
68
|
+
ApiQuery,
|
|
69
|
+
} from '@nestjs/swagger';
|
|
70
|
+
|
|
71
|
+
@ApiTags('users')
|
|
72
|
+
@Controller('users')
|
|
73
|
+
export class UsersController {
|
|
74
|
+
@Get()
|
|
75
|
+
@ApiOperation({ summary: 'Get all users' })
|
|
76
|
+
@ApiQuery({ name: 'page', required: false, type: Number })
|
|
77
|
+
@ApiQuery({ name: 'limit', required: false, type: Number })
|
|
78
|
+
@ApiResponse({ status: 200, description: 'List of users', type: [User] })
|
|
79
|
+
findAll(@Query() query: PaginationDto) {
|
|
80
|
+
return this.usersService.findAll(query);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@Get(':id')
|
|
84
|
+
@ApiOperation({ summary: 'Get user by ID' })
|
|
85
|
+
@ApiParam({ name: 'id', description: 'User ID' })
|
|
86
|
+
@ApiResponse({ status: 200, description: 'User found', type: User })
|
|
87
|
+
@ApiResponse({ status: 404, description: 'User not found' })
|
|
88
|
+
findOne(@Param('id') id: string) {
|
|
89
|
+
return this.usersService.findOne(id);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@Post()
|
|
93
|
+
@ApiBearerAuth()
|
|
94
|
+
@ApiOperation({ summary: 'Create new user' })
|
|
95
|
+
@ApiResponse({ status: 201, description: 'User created', type: User })
|
|
96
|
+
@ApiResponse({ status: 400, description: 'Validation error' })
|
|
97
|
+
create(@Body() dto: CreateUserDto) {
|
|
98
|
+
return this.usersService.create(dto);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Response Schema
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import { ApiProperty } from '@nestjs/swagger';
|
|
107
|
+
|
|
108
|
+
export class PaginatedResponse<T> {
|
|
109
|
+
@ApiProperty()
|
|
110
|
+
data: T[];
|
|
111
|
+
|
|
112
|
+
@ApiProperty({ example: 100 })
|
|
113
|
+
total: number;
|
|
114
|
+
|
|
115
|
+
@ApiProperty({ example: 1 })
|
|
116
|
+
page: number;
|
|
117
|
+
|
|
118
|
+
@ApiProperty({ example: 10 })
|
|
119
|
+
limit: number;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Usage in controller
|
|
123
|
+
@ApiResponse({
|
|
124
|
+
status: 200,
|
|
125
|
+
schema: {
|
|
126
|
+
allOf: [
|
|
127
|
+
{ $ref: getSchemaPath(PaginatedResponse) },
|
|
128
|
+
{
|
|
129
|
+
properties: {
|
|
130
|
+
data: {
|
|
131
|
+
type: 'array',
|
|
132
|
+
items: { $ref: getSchemaPath(User) },
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
})
|
|
139
|
+
```
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: NestJS Error Handling
|
|
3
|
+
description: Global Exception Filters and standard error formats.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [nestjs, errors, filters]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**/*.filter.ts', 'main.ts']
|
|
8
|
+
keywords: [ExceptionFilter, Catch, HttpException]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# NestJS Error Handling Standards
|
|
12
|
+
|
|
13
|
+
## Global Exception Filter
|
|
14
|
+
|
|
15
|
+
- **Requirement**: Centralize error formatting.
|
|
16
|
+
- **Platform Agnostic**: Do **not** import `Request`/`Response` from Express/Fastify types directly.
|
|
17
|
+
- **Use**: `HttpAdapterHost` to access the underlying platform response methods.
|
|
18
|
+
- `const { httpAdapter } = this.httpAdapterHost;`
|
|
19
|
+
- **Structure**:
|
|
20
|
+
- Implement strictly typed error responses.
|
|
21
|
+
- Refer to **[API Standards](../api-standards/SKILL.md)** for `ApiErrorResponse`.
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"statusCode": 400,
|
|
26
|
+
"message": "Validation failed",
|
|
27
|
+
"error": "Bad Request",
|
|
28
|
+
"timestamp": "ISO...",
|
|
29
|
+
"path": "/users"
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Error Flow
|
|
34
|
+
|
|
35
|
+
1. **Service**: Throws specific or generic errors (e.g., `EntityNotFoundError`).
|
|
36
|
+
2. **Interceptor**: Maps low-level errors to HTTP Exceptions (e.g., `catchError(err => throw new NotFoundException())`).
|
|
37
|
+
- _Why_: Keeps Exception Filters focused on formatting, not business logic interpretation.
|
|
38
|
+
3. **Global Filter**: Formats the final JSON response.
|
|
39
|
+
|
|
40
|
+
## Built-in Exceptions
|
|
41
|
+
|
|
42
|
+
- **Use**: Throw `NotFoundException`, `ForbiddenException`, `BadRequestException`.
|
|
43
|
+
- **Custom**: Extend `HttpException` only for domain-specific failures that need specific status codes.
|
|
44
|
+
|
|
45
|
+
## Logging
|
|
46
|
+
|
|
47
|
+
- **Context**: Always pass `MyClass.name` to the `Logger` constructor.
|
|
48
|
+
- **Levels**:
|
|
49
|
+
- `error`: 500s (Stack trace required).
|
|
50
|
+
- `warn`: 400s (Client errors).
|
|
51
|
+
|
|
52
|
+
## Security (Information Leakage)
|
|
53
|
+
|
|
54
|
+
- **Production**: **NEVER** expose stack traces in HTTP responses (`process.env.NODE_ENV === 'production'`).
|
|
55
|
+
- **Sanitization**: Ensure `ApiException` payloads do not leak internal file paths or raw variable dumps.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# NestJS Error Handling References
|
|
2
|
+
|
|
3
|
+
## References
|
|
4
|
+
|
|
5
|
+
- [**Exception Filters**](exception-filters.md) - Custom filters, error responses
|
|
6
|
+
|
|
7
|
+
## Quick Checks
|
|
8
|
+
|
|
9
|
+
- [ ] Use built-in HTTP exceptions
|
|
10
|
+
- [ ] Custom exception filters for consistent responses
|
|
11
|
+
- [ ] Log errors appropriately
|
|
12
|
+
- [ ] Don't expose internal errors to clients
|
|
13
|
+
- [ ] Handle validation errors gracefully
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# NestJS Exception Filters
|
|
2
|
+
|
|
3
|
+
## Built-in Exceptions
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import {
|
|
7
|
+
BadRequestException,
|
|
8
|
+
UnauthorizedException,
|
|
9
|
+
ForbiddenException,
|
|
10
|
+
NotFoundException,
|
|
11
|
+
ConflictException,
|
|
12
|
+
InternalServerErrorException,
|
|
13
|
+
} from '@nestjs/common';
|
|
14
|
+
|
|
15
|
+
// Usage
|
|
16
|
+
throw new NotFoundException('User not found');
|
|
17
|
+
throw new BadRequestException('Invalid input');
|
|
18
|
+
throw new UnauthorizedException('Invalid credentials');
|
|
19
|
+
throw new ConflictException('Email already exists');
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Custom Exception
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
export class BusinessException extends HttpException {
|
|
26
|
+
constructor(
|
|
27
|
+
public readonly code: string,
|
|
28
|
+
message: string,
|
|
29
|
+
status: HttpStatus = HttpStatus.BAD_REQUEST,
|
|
30
|
+
) {
|
|
31
|
+
super({ code, message }, status);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Usage
|
|
36
|
+
throw new BusinessException('INSUFFICIENT_FUNDS', 'Not enough balance');
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Global Exception Filter
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
|
|
43
|
+
import { Response } from 'express';
|
|
44
|
+
|
|
45
|
+
@Catch()
|
|
46
|
+
export class AllExceptionsFilter implements ExceptionFilter {
|
|
47
|
+
constructor(private readonly logger: Logger) {}
|
|
48
|
+
|
|
49
|
+
catch(exception: unknown, host: ArgumentsHost) {
|
|
50
|
+
const ctx = host.switchToHttp();
|
|
51
|
+
const response = ctx.getResponse<Response>();
|
|
52
|
+
const request = ctx.getRequest();
|
|
53
|
+
|
|
54
|
+
const status = exception instanceof HttpException
|
|
55
|
+
? exception.getStatus()
|
|
56
|
+
: HttpStatus.INTERNAL_SERVER_ERROR;
|
|
57
|
+
|
|
58
|
+
const message = exception instanceof HttpException
|
|
59
|
+
? exception.getResponse()
|
|
60
|
+
: 'Internal server error';
|
|
61
|
+
|
|
62
|
+
const errorResponse = {
|
|
63
|
+
statusCode: status,
|
|
64
|
+
timestamp: new Date().toISOString(),
|
|
65
|
+
path: request.url,
|
|
66
|
+
message: typeof message === 'string' ? message : (message as any).message,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
this.logger.error(
|
|
70
|
+
`${request.method} ${request.url}`,
|
|
71
|
+
exception instanceof Error ? exception.stack : 'Unknown error',
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
response.status(status).json(errorResponse);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// main.ts
|
|
79
|
+
app.useGlobalFilters(new AllExceptionsFilter(new Logger()));
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Validation Exception Filter
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
@Catch(ValidationError)
|
|
86
|
+
export class ValidationExceptionFilter implements ExceptionFilter {
|
|
87
|
+
catch(exception: ValidationError[], host: ArgumentsHost) {
|
|
88
|
+
const ctx = host.switchToHttp();
|
|
89
|
+
const response = ctx.getResponse<Response>();
|
|
90
|
+
|
|
91
|
+
const errors = exception.map(err => ({
|
|
92
|
+
field: err.property,
|
|
93
|
+
constraints: Object.values(err.constraints || {}),
|
|
94
|
+
}));
|
|
95
|
+
|
|
96
|
+
response.status(HttpStatus.BAD_REQUEST).json({
|
|
97
|
+
statusCode: HttpStatus.BAD_REQUEST,
|
|
98
|
+
message: 'Validation failed',
|
|
99
|
+
errors,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## HTTP Exception Filter
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
@Catch(HttpException)
|
|
109
|
+
export class HttpExceptionFilter implements ExceptionFilter {
|
|
110
|
+
catch(exception: HttpException, host: ArgumentsHost) {
|
|
111
|
+
const ctx = host.switchToHttp();
|
|
112
|
+
const response = ctx.getResponse<Response>();
|
|
113
|
+
const status = exception.getStatus();
|
|
114
|
+
const exceptionResponse = exception.getResponse();
|
|
115
|
+
|
|
116
|
+
response.status(status).json({
|
|
117
|
+
success: false,
|
|
118
|
+
statusCode: status,
|
|
119
|
+
...(typeof exceptionResponse === 'object' ? exceptionResponse : { message: exceptionResponse }),
|
|
120
|
+
timestamp: new Date().toISOString(),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Using Filters
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
// Controller level
|
|
130
|
+
@Controller('users')
|
|
131
|
+
@UseFilters(HttpExceptionFilter)
|
|
132
|
+
export class UsersController {}
|
|
133
|
+
|
|
134
|
+
// Method level
|
|
135
|
+
@Post()
|
|
136
|
+
@UseFilters(ValidationExceptionFilter)
|
|
137
|
+
create(@Body() dto: CreateUserDto) {}
|
|
138
|
+
|
|
139
|
+
// Global (main.ts)
|
|
140
|
+
app.useGlobalFilters(new AllExceptionsFilter());
|
|
141
|
+
|
|
142
|
+
// Global with DI
|
|
143
|
+
@Module({
|
|
144
|
+
providers: [
|
|
145
|
+
{
|
|
146
|
+
provide: APP_FILTER,
|
|
147
|
+
useClass: AllExceptionsFilter,
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
})
|
|
151
|
+
export class AppModule {}
|
|
152
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: NestJS File Uploads
|
|
3
|
+
description: Secure file handling, Validation, and S3 streaming.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [nestjs, upload, multer, s3]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**/*.controller.ts']
|
|
8
|
+
keywords: [FileInterceptor, Multer, S3, UploadedFile]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# File Upload Patterns
|
|
12
|
+
|
|
13
|
+
## Security (Input Validation)
|
|
14
|
+
|
|
15
|
+
- **Magic Bytes**: NEVER trust `content-type` header or file extension.
|
|
16
|
+
- **Tool**: Use `file-type` or `mmmagic` to verify the actual buffer signature.
|
|
17
|
+
- **Limits**: Set strict `limits: { fileSize: 5000000 }` (5MB) in Multer config to prevent DoS.
|
|
18
|
+
|
|
19
|
+
## Streaming (Scalability)
|
|
20
|
+
|
|
21
|
+
- **Memory Warning**: Default Multer `MemoryStorage` crashes servers with large files.
|
|
22
|
+
- **Pattern**: Use **Streaming** for any file > 10MB.
|
|
23
|
+
- **Library**: `multer-s3` (direct upload to bucket) or `busboy` (raw stream processing).
|
|
24
|
+
- **Architecture**:
|
|
25
|
+
1. Client requests Signed URL from API.
|
|
26
|
+
2. Client uploads directly to S3/GCS (Bypassing API server completely).
|
|
27
|
+
3. **Pro Tip**: This is the only way to scale file uploads infinitely.
|
|
28
|
+
|
|
29
|
+
## Processing
|
|
30
|
+
|
|
31
|
+
- **Async**: Don't process images/videos in the HTTP Request.
|
|
32
|
+
- **Flow**:
|
|
33
|
+
1. Upload file.
|
|
34
|
+
2. Push `FileUploadedEvent` to Queue (BullMQ).
|
|
35
|
+
3. Worker downloads, resizes/converts, and re-uploads.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# NestJS File Uploads References
|
|
2
|
+
|
|
3
|
+
## References
|
|
4
|
+
|
|
5
|
+
- [**Upload Patterns**](upload-patterns.md) - Multer, streaming, S3 integration
|
|
6
|
+
|
|
7
|
+
## Quick Checks
|
|
8
|
+
|
|
9
|
+
- [ ] Validate file types and sizes
|
|
10
|
+
- [ ] Use streaming for large files
|
|
11
|
+
- [ ] Configure proper storage destination
|
|
12
|
+
- [ ] Handle multiple file uploads
|
|
13
|
+
- [ ] Implement virus scanning for production
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# NestJS File Upload Patterns
|
|
2
|
+
|
|
3
|
+
## Basic Upload
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import {
|
|
7
|
+
Controller,
|
|
8
|
+
Post,
|
|
9
|
+
UseInterceptors,
|
|
10
|
+
UploadedFile,
|
|
11
|
+
ParseFilePipe,
|
|
12
|
+
MaxFileSizeValidator,
|
|
13
|
+
FileTypeValidator,
|
|
14
|
+
} from '@nestjs/common';
|
|
15
|
+
import { FileInterceptor } from '@nestjs/platform-express';
|
|
16
|
+
import { diskStorage } from 'multer';
|
|
17
|
+
|
|
18
|
+
@Controller('files')
|
|
19
|
+
export class FilesController {
|
|
20
|
+
@Post('upload')
|
|
21
|
+
@UseInterceptors(FileInterceptor('file', {
|
|
22
|
+
storage: diskStorage({
|
|
23
|
+
destination: './uploads',
|
|
24
|
+
filename: (req, file, cb) => {
|
|
25
|
+
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
|
|
26
|
+
cb(null, `${uniqueSuffix}-${file.originalname}`);
|
|
27
|
+
},
|
|
28
|
+
}),
|
|
29
|
+
}))
|
|
30
|
+
uploadFile(
|
|
31
|
+
@UploadedFile(
|
|
32
|
+
new ParseFilePipe({
|
|
33
|
+
validators: [
|
|
34
|
+
new MaxFileSizeValidator({ maxSize: 5 * 1024 * 1024 }), // 5MB
|
|
35
|
+
new FileTypeValidator({ fileType: /image\/(jpeg|png|gif)/ }),
|
|
36
|
+
],
|
|
37
|
+
}),
|
|
38
|
+
)
|
|
39
|
+
file: Express.Multer.File,
|
|
40
|
+
) {
|
|
41
|
+
return { filename: file.filename, size: file.size };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Multiple Files
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { FilesInterceptor, FileFieldsInterceptor } from '@nestjs/platform-express';
|
|
50
|
+
|
|
51
|
+
@Post('multiple')
|
|
52
|
+
@UseInterceptors(FilesInterceptor('files', 10))
|
|
53
|
+
uploadMultiple(@UploadedFiles() files: Express.Multer.File[]) {
|
|
54
|
+
return files.map(f => ({ name: f.filename, size: f.size }));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@Post('fields')
|
|
58
|
+
@UseInterceptors(FileFieldsInterceptor([
|
|
59
|
+
{ name: 'avatar', maxCount: 1 },
|
|
60
|
+
{ name: 'documents', maxCount: 5 },
|
|
61
|
+
]))
|
|
62
|
+
uploadFields(@UploadedFiles() files: {
|
|
63
|
+
avatar?: Express.Multer.File[],
|
|
64
|
+
documents?: Express.Multer.File[],
|
|
65
|
+
}) {
|
|
66
|
+
return { avatar: files.avatar?.[0], documents: files.documents };
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## S3 Upload
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
|
|
74
|
+
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
75
|
+
|
|
76
|
+
@Injectable()
|
|
77
|
+
export class S3Service {
|
|
78
|
+
private s3: S3Client;
|
|
79
|
+
|
|
80
|
+
constructor(private config: ConfigService) {
|
|
81
|
+
this.s3 = new S3Client({
|
|
82
|
+
region: config.get('AWS_REGION'),
|
|
83
|
+
credentials: {
|
|
84
|
+
accessKeyId: config.get('AWS_ACCESS_KEY'),
|
|
85
|
+
secretAccessKey: config.get('AWS_SECRET_KEY'),
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async upload(file: Express.Multer.File, key: string): Promise<string> {
|
|
91
|
+
await this.s3.send(new PutObjectCommand({
|
|
92
|
+
Bucket: this.config.get('S3_BUCKET'),
|
|
93
|
+
Key: key,
|
|
94
|
+
Body: file.buffer,
|
|
95
|
+
ContentType: file.mimetype,
|
|
96
|
+
}));
|
|
97
|
+
|
|
98
|
+
return `https://${this.config.get('S3_BUCKET')}.s3.amazonaws.com/${key}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async getPresignedUrl(key: string): Promise<string> {
|
|
102
|
+
const command = new PutObjectCommand({
|
|
103
|
+
Bucket: this.config.get('S3_BUCKET'),
|
|
104
|
+
Key: key,
|
|
105
|
+
});
|
|
106
|
+
return getSignedUrl(this.s3, command, { expiresIn: 3600 });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Streaming Large Files
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { StreamableFile } from '@nestjs/common';
|
|
115
|
+
import { createReadStream } from 'fs';
|
|
116
|
+
|
|
117
|
+
@Get('download/:filename')
|
|
118
|
+
downloadFile(@Param('filename') filename: string): StreamableFile {
|
|
119
|
+
const file = createReadStream(`./uploads/${filename}`);
|
|
120
|
+
return new StreamableFile(file, {
|
|
121
|
+
type: 'application/octet-stream',
|
|
122
|
+
disposition: `attachment; filename="${filename}"`,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: NestJS Observability
|
|
3
|
+
description: Structured logging (Pino) and Prometheus metrics.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [nestjs, logging, monitoring, pino]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['main.ts', '**/*.module.ts']
|
|
8
|
+
keywords: [nestjs-pino, Prometheus, Logger, reqId]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Observability Standards
|
|
12
|
+
|
|
13
|
+
## Structured Logging
|
|
14
|
+
|
|
15
|
+
- **Standard**: Use `nestjs-pino` for high-performance JSON logging.
|
|
16
|
+
- **Why**: Node's built-in `console.log` is blocking and unstructured.
|
|
17
|
+
- **Configuration**:
|
|
18
|
+
- **Redaction**: Mandatory masking of sensitive fields (`password`, `token`, `email`).
|
|
19
|
+
- **Context**: Always inject `Logger` and set the context (`LoginService`).
|
|
20
|
+
|
|
21
|
+
## Tracing (Correlation)
|
|
22
|
+
|
|
23
|
+
- **Request ID**: Every log line **must** include a `reqId` (Request ID).
|
|
24
|
+
- `nestjs-pino` handles this automatically using `AsyncLocalStorage`.
|
|
25
|
+
- **Propagation**: Pass `x-request-id` to downstream microservices/database queries key to trace flows.
|
|
26
|
+
|
|
27
|
+
## Metrics
|
|
28
|
+
|
|
29
|
+
- **Exposure**: Use `@willsoto/nestjs-prometheus` to expose `/metrics` for Prometheus scraping.
|
|
30
|
+
- **Key Metrics**:
|
|
31
|
+
1. `http_request_duration_seconds` (Histogram)
|
|
32
|
+
2. `db_query_duration_seconds` (Histogram)
|
|
33
|
+
3. `memory_usage_bytes` (Gauge)
|
|
34
|
+
|
|
35
|
+
## Health Checks
|
|
36
|
+
|
|
37
|
+
- **Terminus**: Implement explicit logic for "Liveness" (I'm alive) vs "Readiness" (I can take traffic).
|
|
38
|
+
- **DB Check**: `TypeOrmHealthIndicator` / `PrismaHealthIndicator`.
|
|
39
|
+
- **Memory Check**: Fail if Heap > 300MB (prevent crash loops).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# NestJS Observability References
|
|
2
|
+
|
|
3
|
+
## References
|
|
4
|
+
|
|
5
|
+
- [**Logging & Metrics**](logging-metrics.md) - Logger, Prometheus, tracing
|
|
6
|
+
|
|
7
|
+
## Quick Checks
|
|
8
|
+
|
|
9
|
+
- [ ] Structured logging with context
|
|
10
|
+
- [ ] Request correlation IDs
|
|
11
|
+
- [ ] Prometheus metrics for monitoring
|
|
12
|
+
- [ ] Health checks for readiness
|
|
13
|
+
- [ ] Distributed tracing for microservices
|