@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,77 @@
|
|
|
1
|
+
# Feature-Sliced Design (FSD) Structure
|
|
2
|
+
|
|
3
|
+
Adapted for Next.js App Router.
|
|
4
|
+
|
|
5
|
+
## Directory Layout
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
app/ # App Layer (Routing & Layouts)
|
|
9
|
+
(app)/ # Public Pages
|
|
10
|
+
page.tsx
|
|
11
|
+
layout.tsx # Root Provider Setup
|
|
12
|
+
globals.css # Global Styles
|
|
13
|
+
|
|
14
|
+
src/ # Source Content
|
|
15
|
+
widgets/ # Compositional Layers (Header, Footer, Sidebar)
|
|
16
|
+
header/
|
|
17
|
+
ui/
|
|
18
|
+
index.ts
|
|
19
|
+
|
|
20
|
+
features/ # User Interactions (AddToCart, FilterList)
|
|
21
|
+
auth-login/
|
|
22
|
+
ui/ # LoginForm.tsx
|
|
23
|
+
model/ # Server Actions, Zod Schemas
|
|
24
|
+
index.ts
|
|
25
|
+
|
|
26
|
+
entities/ # Business Models (Product, User)
|
|
27
|
+
product/
|
|
28
|
+
ui/ # ProductCard.tsx (Presentation only)
|
|
29
|
+
model/ # types.ts, complex validation
|
|
30
|
+
index.ts
|
|
31
|
+
|
|
32
|
+
shared/ # Reusable, Business-Agnostic
|
|
33
|
+
ui/ # Buttons, Inputs (shadcn)
|
|
34
|
+
lib/ # Utils, Hooks
|
|
35
|
+
api/ # Base fetch wrappers & Simple CRUD
|
|
36
|
+
client.ts
|
|
37
|
+
endpoints/
|
|
38
|
+
orders.ts # Simple API calls (keep out of entities)
|
|
39
|
+
auth/ # Auth Session/Tokens
|
|
40
|
+
index.ts
|
|
41
|
+
config/ # Env vars
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Segments (Inner Structure)
|
|
45
|
+
|
|
46
|
+
Files inside slices (e.g., `features/login/*`) must follow these standard segment names:
|
|
47
|
+
|
|
48
|
+
| Segment | Purpose | Examples |
|
|
49
|
+
| :------------ | :--------------------------- | :----------------------------------------------------- |
|
|
50
|
+
| **`ui/`** | Visual components | `LoginForm.tsx`, `ProductCard.tsx` |
|
|
51
|
+
| **`model/`** | Business logic, state, types | `actions.ts` (Server Actions), `store.ts`, `schema.ts` |
|
|
52
|
+
| **`api/`** | Remote data interactions | `fetchProduct()`, `useProductQuery()` |
|
|
53
|
+
| **`lib/`** | Helper functions | `formatCurrency.ts`, `dateUtils.ts` |
|
|
54
|
+
| **`config/`** | Configuration & constants | `env.ts`, `constants.ts` |
|
|
55
|
+
|
|
56
|
+
**Note**: Do not use generic folder names like `components/`, `hooks/`, or `utils/` inside slices. Use the semantic segments above.
|
|
57
|
+
|
|
58
|
+
## Anti-Patterns ("Excessive Entities")
|
|
59
|
+
|
|
60
|
+
1. **Refactor Later**: Don't start with `entities/`. Put logic in `features/` or `pages/` (slices) first. Extract to `entities/` only when strictly reused.
|
|
61
|
+
2. **Auth is Shared**: User session/tokens often belong in `shared/auth` or `shared/session`, not `entities/user`, because they are app-wide context distinct from the business entity "User".
|
|
62
|
+
3. **CRUD in Shared**: Simple API endpoints (CRUD) without complex domain logic should go in `shared/api/endpoints/`. Don't create an entity just to wrap a fetch call.
|
|
63
|
+
|
|
64
|
+
## Layer Responsibilities
|
|
65
|
+
|
|
66
|
+
1. **App (`app/`)**:
|
|
67
|
+
- **Role**: Entry point. Contains _only_ Next.js routing files (`page.tsx`, `layout.tsx`).
|
|
68
|
+
- **Rule**: Files here should be thin wrappers that import widgets or features.
|
|
69
|
+
2. **Widgets (`src/widgets/`)**:
|
|
70
|
+
- **Role**: Assemble features and entities into self-contained blocks (e.g., `Header`, `ProductList`).
|
|
71
|
+
3. **Features (`src/features/`)**:
|
|
72
|
+
- **Role**: Handle user scenarios (e.g., `AuthByEmail`, `ToggleTheme`). Contains form logic & Server Actions.
|
|
73
|
+
4. **Entities (`src/entities/`)**:
|
|
74
|
+
- **Role**: Business domain concepts. High reuse potential.
|
|
75
|
+
- **Warning**: Avoid "Anemic Domain Models". If it's just data types, put them in `shared/api`.
|
|
76
|
+
5. **Shared (`src/shared/`)**:
|
|
77
|
+
- **Role**: UI Kit (Buttons), Utils, API Clients. No business logic.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Next.js Authentication
|
|
3
|
+
description: Secure token storage (HttpOnly Cookies) and Middleware patterns.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [nextjs, auth, security, cookies]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['middleware.ts', '**/auth.ts', '**/login/page.tsx']
|
|
8
|
+
keywords: [cookie, jwt, session, localstorage, auth]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Authentication & Token Management
|
|
12
|
+
|
|
13
|
+
## **Priority: P0 (CRITICAL)**
|
|
14
|
+
|
|
15
|
+
Use **HttpOnly Cookies** for token storage. **Never** use LocalStorage.
|
|
16
|
+
|
|
17
|
+
## Key Rules
|
|
18
|
+
|
|
19
|
+
1. **Storage**: Use `cookies().set()` with `httpOnly: true`, `secure: true`, `sameSite: 'lax'`.
|
|
20
|
+
- _Reference_: [Auth Implementation](references/auth-implementation.md) (See "Setting Tokens").
|
|
21
|
+
2. **Access**: Read tokens in Server Components via `cookies().get()`.
|
|
22
|
+
- _Reference_: [Auth Implementation](references/auth-implementation.md) (See "Reading Tokens").
|
|
23
|
+
3. **Protection**: Guard routes in `middleware.ts` before rendering.
|
|
24
|
+
- _Reference_: [Auth Implementation](references/auth-implementation.md) (See "Middleware Protection").
|
|
25
|
+
|
|
26
|
+
## Anti-Pattern: LocalStorage
|
|
27
|
+
|
|
28
|
+
- **Security Risk**: Vulnerable to XSS.
|
|
29
|
+
- **Performance Hit**: Incompatible with Server Components (RSC). Forces client hydration and causes layout shift.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Authentication Implementation
|
|
2
|
+
|
|
3
|
+
## 1. Setting Tokens (Server Action)
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
'use server';
|
|
7
|
+
import { cookies } from 'next/headers';
|
|
8
|
+
import { redirect } from 'next/navigation';
|
|
9
|
+
|
|
10
|
+
export async function login(formData: FormData) {
|
|
11
|
+
// 1. Backend Call
|
|
12
|
+
// const result = await api.login(formData);
|
|
13
|
+
// Simulated result:
|
|
14
|
+
const result = { accessToken: 'fake_enc_token' };
|
|
15
|
+
|
|
16
|
+
// 2. Save Token Securely
|
|
17
|
+
(await cookies()).set('session', result.accessToken, {
|
|
18
|
+
httpOnly: true,
|
|
19
|
+
secure: process.env.NODE_ENV === 'production',
|
|
20
|
+
maxAge: 60 * 60 * 24 * 7, // 1 week
|
|
21
|
+
path: '/',
|
|
22
|
+
sameSite: 'lax',
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
redirect('/dashboard');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function logout() {
|
|
29
|
+
(await cookies()).delete('session');
|
|
30
|
+
redirect('/login');
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 2. Reading Tokens (DAL)
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
// lib/auth.ts
|
|
38
|
+
import 'server-only';
|
|
39
|
+
import { cookies } from 'next/headers';
|
|
40
|
+
|
|
41
|
+
export async function getSession() {
|
|
42
|
+
const cookieStore = await cookies();
|
|
43
|
+
const session = cookieStore.get('session')?.value;
|
|
44
|
+
if (!session) return null;
|
|
45
|
+
// return verifyJwt(session);
|
|
46
|
+
return { user: 'simulated' };
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## 3. Middleware Protection
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// middleware.ts
|
|
54
|
+
import { NextResponse } from 'next/server';
|
|
55
|
+
import type { NextRequest } from 'next/server';
|
|
56
|
+
|
|
57
|
+
export function middleware(request: NextRequest) {
|
|
58
|
+
const currentUser = request.cookies.get('session')?.value;
|
|
59
|
+
const isLoginPage = request.nextUrl.pathname.startsWith('/login');
|
|
60
|
+
|
|
61
|
+
if (!currentUser && !isLoginPage) {
|
|
62
|
+
return NextResponse.redirect(new URL('/login', request.url));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (currentUser && isLoginPage) {
|
|
66
|
+
return NextResponse.redirect(new URL('/dashboard', request.url));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const config = {
|
|
71
|
+
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'], // Exclude static files
|
|
72
|
+
};
|
|
73
|
+
```
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Next.js Caching Architecture
|
|
3
|
+
description: The 4 layers of caching (Memoization, Data Cache, Full Route, Router Cache).
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [nextjs, caching, isr, revalidation]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**/page.tsx', '**/layout.tsx', '**/action.ts']
|
|
8
|
+
keywords: [unstable_cache, revalidateTag, Router Cache, Data Cache]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Caching Architecture
|
|
12
|
+
|
|
13
|
+
## **Priority: P1 (HIGH)**
|
|
14
|
+
|
|
15
|
+
Next.js has 4 distinct caching layers. Understanding them prevents stale data bugs.
|
|
16
|
+
|
|
17
|
+
## The 4 Layers
|
|
18
|
+
|
|
19
|
+
| Layer | Where | Duration | Purpose | Control |
|
|
20
|
+
| :------------------------- | :----- | :------------- | :--------------------------------------------------- | :----------------- |
|
|
21
|
+
| **1. Request Memoization** | Server | Per Request | Deduplicate same `fetch()` calls in one render pass. | `AbortController` |
|
|
22
|
+
| **2. Data Cache** | Server | Persistent | Store data across user requests. | `revalidateTag` |
|
|
23
|
+
| **3. Full Route Cache** | Server | Persistent | Store HTML/RSC payload. (Static Rendering). | `revalidatePath` |
|
|
24
|
+
| **4. Router Cache** | Client | Session (< 5m) | Navigating back/forward without server hit. | `router.refresh()` |
|
|
25
|
+
|
|
26
|
+
## 1. Request Memoization
|
|
27
|
+
|
|
28
|
+
- **Behavior**: Calling `getUser(1)` in `layout`, `page`, and `component` only triggers 1 network call.
|
|
29
|
+
- **Key**: Matches URL and Options exactly.
|
|
30
|
+
- **Non-Fetch**: For DB calls/Prisma, use React `cache()` manually.
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { cache } from 'react';
|
|
34
|
+
const getItem = cache(async (id) => db.item.findUnique({ id }));
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 2. Data Cache (The "Server Persistence")
|
|
38
|
+
|
|
39
|
+
- **Default**: `fetch` tracks cache indefinitely (`force-cache`).
|
|
40
|
+
- **Scaling**:
|
|
41
|
+
- **Vercel**: Shared globally via KV/Blob.
|
|
42
|
+
- **Self-Hosted**: Stored in filesystem (Pod ephemeral storage). **Critical**: Must configure a shared `cacheHandler` (Redis) for multi-pod Kubernetes setups, otherwise pods have desynchronized caches.
|
|
43
|
+
- **Granular Control**: Use `unstable_cache` for DB queries caching.
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import { unstable_cache } from 'next/cache';
|
|
47
|
+
const getCachedUser = unstable_cache(
|
|
48
|
+
async (id) => db.user.find(id),
|
|
49
|
+
['users-key'],
|
|
50
|
+
{ tags: ['users'], revalidate: 60 },
|
|
51
|
+
);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 3. Router Cache (The "Client Stale")
|
|
55
|
+
|
|
56
|
+
- **Problem**: User updates a listing, navigates back, and sees old data.
|
|
57
|
+
- **Cause**: Client-side Router Cache holds payload for 30s (dynamic) or 5m (static).
|
|
58
|
+
- **Fix**: Call `router.refresh()` in a Client Component or `revalidatePath()` in a Server Action (which automatically invalidates Router Cache).
|
|
59
|
+
|
|
60
|
+
## Strategies
|
|
61
|
+
|
|
62
|
+
- **Opt-Out (Real-Time)**:
|
|
63
|
+
- Data: `fetch(..., { cache: 'no-store' })`
|
|
64
|
+
- Route: `export const dynamic = 'force-dynamic'`
|
|
65
|
+
- **On-Demand (CMS/Admin)**:
|
|
66
|
+
- Use `revalidateTag('collection')` for surgical updates. Better than `revalidatePath` (which nukes the whole URL).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Next.js Caching References
|
|
2
|
+
|
|
3
|
+
## References
|
|
4
|
+
|
|
5
|
+
- [**Cache Strategies**](cache-strategies.md) - Full Route, Data, Request
|
|
6
|
+
|
|
7
|
+
## Quick Checks
|
|
8
|
+
|
|
9
|
+
- [ ] Understand cache hierarchy
|
|
10
|
+
- [ ] Use revalidation strategies appropriately
|
|
11
|
+
- [ ] Tags for granular cache invalidation
|
|
12
|
+
- [ ] unstable_cache for DB queries
|
|
13
|
+
- [ ] Opt-out with force-dynamic when needed
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Next.js Cache Strategies
|
|
2
|
+
|
|
3
|
+
## Cache Hierarchy
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
1. Request Memoization (React cache)
|
|
7
|
+
- Same request deduped during render
|
|
8
|
+
|
|
9
|
+
2. Data Cache (Next.js)
|
|
10
|
+
- Persisted across requests
|
|
11
|
+
- Controlled by fetch options
|
|
12
|
+
|
|
13
|
+
3. Full Route Cache
|
|
14
|
+
- Static HTML/RSC payload
|
|
15
|
+
- Invalidated by revalidation
|
|
16
|
+
|
|
17
|
+
4. Router Cache (Client)
|
|
18
|
+
- Prefetched routes
|
|
19
|
+
- Session-based
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Data Cache Controls
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
// Default - cached indefinitely
|
|
26
|
+
fetch('https://api.example.com/data');
|
|
27
|
+
|
|
28
|
+
// No caching
|
|
29
|
+
fetch('https://api.example.com/data', { cache: 'no-store' });
|
|
30
|
+
|
|
31
|
+
// Time-based revalidation
|
|
32
|
+
fetch('https://api.example.com/data', {
|
|
33
|
+
next: { revalidate: 3600 } // 1 hour
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Tag-based revalidation
|
|
37
|
+
fetch('https://api.example.com/posts', {
|
|
38
|
+
next: { tags: ['posts'] }
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Revalidate by tag
|
|
42
|
+
import { revalidateTag } from 'next/cache';
|
|
43
|
+
revalidateTag('posts');
|
|
44
|
+
|
|
45
|
+
// Revalidate by path
|
|
46
|
+
import { revalidatePath } from 'next/cache';
|
|
47
|
+
revalidatePath('/blog');
|
|
48
|
+
revalidatePath('/blog', 'layout'); // Include layouts
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Route Segment Config
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
// app/page.tsx
|
|
55
|
+
|
|
56
|
+
// Force dynamic rendering
|
|
57
|
+
export const dynamic = 'force-dynamic';
|
|
58
|
+
|
|
59
|
+
// Force static (error if dynamic features used)
|
|
60
|
+
export const dynamic = 'force-static';
|
|
61
|
+
|
|
62
|
+
// Default - auto detect
|
|
63
|
+
export const dynamic = 'auto';
|
|
64
|
+
|
|
65
|
+
// Time-based revalidation for entire route
|
|
66
|
+
export const revalidate = 3600; // 1 hour
|
|
67
|
+
|
|
68
|
+
// Disable caching
|
|
69
|
+
export const revalidate = 0;
|
|
70
|
+
|
|
71
|
+
// Runtime
|
|
72
|
+
export const runtime = 'nodejs'; // or 'edge'
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Database Query Caching
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
import { unstable_cache } from 'next/cache';
|
|
79
|
+
|
|
80
|
+
const getCachedPosts = unstable_cache(
|
|
81
|
+
async () => {
|
|
82
|
+
return db.post.findMany();
|
|
83
|
+
},
|
|
84
|
+
['posts'], // cache key
|
|
85
|
+
{
|
|
86
|
+
revalidate: 3600,
|
|
87
|
+
tags: ['posts'],
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// Usage
|
|
92
|
+
async function BlogPage() {
|
|
93
|
+
const posts = await getCachedPosts();
|
|
94
|
+
return <PostList posts={posts} />;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Invalidate
|
|
98
|
+
'use server';
|
|
99
|
+
export async function createPost(data: PostData) {
|
|
100
|
+
await db.post.create({ data });
|
|
101
|
+
revalidateTag('posts');
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Request Memoization
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
import { cache } from 'react';
|
|
109
|
+
|
|
110
|
+
// Deduped during single render pass
|
|
111
|
+
export const getUser = cache(async (id: string) => {
|
|
112
|
+
return db.user.findUnique({ where: { id } });
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Both components share same request
|
|
116
|
+
async function UserName({ id }: { id: string }) {
|
|
117
|
+
const user = await getUser(id);
|
|
118
|
+
return <span>{user.name}</span>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function UserAvatar({ id }: { id: string }) {
|
|
122
|
+
const user = await getUser(id);
|
|
123
|
+
return <img src={user.avatar} />;
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Opting Out of Caching
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
// Dynamic functions opt out automatically
|
|
131
|
+
import { cookies, headers } from 'next/headers';
|
|
132
|
+
|
|
133
|
+
async function Page() {
|
|
134
|
+
const cookieStore = await cookies(); // Dynamic
|
|
135
|
+
const headersList = await headers(); // Dynamic
|
|
136
|
+
// Route becomes dynamic
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// searchParams make page dynamic
|
|
140
|
+
async function Page({
|
|
141
|
+
searchParams
|
|
142
|
+
}: {
|
|
143
|
+
searchParams: Promise<{ q: string }>
|
|
144
|
+
}) {
|
|
145
|
+
const { q } = await searchParams; // Dynamic
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Cache Best Practices
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
// ✅ Good - cache expensive operations
|
|
153
|
+
const getExpensiveData = unstable_cache(
|
|
154
|
+
async () => heavyComputation(),
|
|
155
|
+
['expensive-data'],
|
|
156
|
+
{ revalidate: 3600 }
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
// ✅ Good - granular cache invalidation
|
|
160
|
+
fetch('/api/posts', { next: { tags: ['posts'] } });
|
|
161
|
+
fetch(`/api/posts/${id}`, { next: { tags: ['posts', `post-${id}`] } });
|
|
162
|
+
|
|
163
|
+
// After update
|
|
164
|
+
revalidateTag(`post-${id}`); // Only invalidates specific post
|
|
165
|
+
|
|
166
|
+
// ❌ Avoid - overly broad invalidation
|
|
167
|
+
revalidatePath('/'); // Invalidates everything
|
|
168
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Next.js Data Access Layer
|
|
3
|
+
description: Secure, reusable data access patterns with DTOs and Taint checks.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [nextjs, dal, architecture, security]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**/lib/data.ts', '**/services/*.ts', '**/dal/**']
|
|
8
|
+
keywords: [DAL, Data Access Layer, server-only, DTO]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Data Access Layer (DAL)
|
|
12
|
+
|
|
13
|
+
## **Priority: P1 (HIGH)**
|
|
14
|
+
|
|
15
|
+
Centralize all data access (Database & External APIs) to ensure consistent security, authorization, and caching.
|
|
16
|
+
|
|
17
|
+
## Principles
|
|
18
|
+
|
|
19
|
+
1. **Server-Only**: Must include `import 'server-only'` to prevent Client bundling.
|
|
20
|
+
2. **Auth Co-location**: Auth checks (`session.role`) must be **inside** the DAL function.
|
|
21
|
+
3. **DTO Transformation**: Return plain objects (DTOs), never raw ORM instances.
|
|
22
|
+
4. **No Internal Fetch**: Call DAL functions directly. Do not `fetch('localhost/api')`.
|
|
23
|
+
|
|
24
|
+
## Implementation
|
|
25
|
+
|
|
26
|
+
| Approach | When to use | Reference |
|
|
27
|
+
| :-------------------- | :----------------------------------------------- | :---------------------------------- |
|
|
28
|
+
| **API Gateway (BFF)** | Enterprise apps with separated Backend (NestJS). | [Pattern A](references/patterns.md) |
|
|
29
|
+
| **Direct DB** | Fullstack apps or Admin Panels. | [Pattern B](references/patterns.md) |
|
|
30
|
+
|
|
31
|
+
## Limitations
|
|
32
|
+
|
|
33
|
+
- **Client Components**: Cannot import DAL files. Must use Server Actions or Route Handlers as bridges.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Data Access Layer Patterns
|
|
2
|
+
|
|
3
|
+
## Pattern A: API Gateway / BFF (Recommended)
|
|
4
|
+
|
|
5
|
+
Use when Next.js is a generic frontend for a separate backend (NestJS/Go).
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import 'server-only';
|
|
9
|
+
import { cache } from 'react';
|
|
10
|
+
import { getToken } from '@/lib/auth';
|
|
11
|
+
|
|
12
|
+
const API_URL = process.env.API_GATEWAY_URL;
|
|
13
|
+
|
|
14
|
+
export const getProjectDetails = cache(async (id: string) => {
|
|
15
|
+
// 1. Forward Auth Headers
|
|
16
|
+
const token = await getToken();
|
|
17
|
+
|
|
18
|
+
// 2. Upstream Fetch with Next.js Cache tags
|
|
19
|
+
const res = await fetch(`${API_URL}/projects/${id}`, {
|
|
20
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
21
|
+
next: { tags: [`project-${id}`] },
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
if (res.status === 404) return null;
|
|
26
|
+
throw new Error('Upstream API Failed');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const data = await res.json();
|
|
30
|
+
|
|
31
|
+
// 3. UI-Specific DTO Mapping
|
|
32
|
+
return {
|
|
33
|
+
title: data.attributes.title,
|
|
34
|
+
isActive: data.status === 'published',
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Pattern B: Direct Database
|
|
40
|
+
|
|
41
|
+
Use when Next.js owns the data (Fullstack).
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import 'server-only';
|
|
45
|
+
import { cache } from 'react';
|
|
46
|
+
import { verifySession } from '@/lib/auth';
|
|
47
|
+
import { db } from '@/lib/prisma';
|
|
48
|
+
|
|
49
|
+
export const getSafeUserProfile = cache(async (slug: string) => {
|
|
50
|
+
const session = await verifySession();
|
|
51
|
+
|
|
52
|
+
// Auth Co-location
|
|
53
|
+
const canView = session.role === 'admin' || session.slug === slug;
|
|
54
|
+
if (!canView) throw new Error('Unauthorized');
|
|
55
|
+
|
|
56
|
+
const data = await db.user.findUnique({ where: { slug } });
|
|
57
|
+
if (!data) return null;
|
|
58
|
+
|
|
59
|
+
// DTO Transformation
|
|
60
|
+
return {
|
|
61
|
+
id: data.id,
|
|
62
|
+
name: data.name,
|
|
63
|
+
avatar: data.avatarUrl,
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Next.js Data Fetching
|
|
3
|
+
description: Fetch API, Caching, and Revalidation strategies.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [nextjs, data-fetching, caching]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**/*.tsx', '**/service.ts']
|
|
8
|
+
keywords: [fetch, revalidate, no-store, force-cache]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Data Fetching (App Router)
|
|
12
|
+
|
|
13
|
+
## **Priority: P0 (CRITICAL)**
|
|
14
|
+
|
|
15
|
+
Fetch data directly in Server Components using `async/await`.
|
|
16
|
+
|
|
17
|
+
## Fetch API Extensions
|
|
18
|
+
|
|
19
|
+
Next.js extends the native `fetch` API for granular caching control.
|
|
20
|
+
|
|
21
|
+
- **Static (Default)**: `fetch('https://api.com')` -> `cache: 'force-cache'`. Built at build time.
|
|
22
|
+
- **Dynamic**: `fetch('...', { cache: 'no-store' })`. Fetched on every request.
|
|
23
|
+
- **Revalidated (ISR)**: `fetch('...', { next: { revalidate: 60 } })`. Cached for 60s.
|
|
24
|
+
|
|
25
|
+
## Patterns
|
|
26
|
+
|
|
27
|
+
- **Colocation**: Fetch data where it's used. Next.js automatically deduplicates requests for the same URL in the same render pass.
|
|
28
|
+
- **Parallel**: Use `Promise.all()` to prevent waterfalls.
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
const [user, posts] = await Promise.all([getUser(), getPosts()]);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- **Blocking**: To prevent UI blocking, wrap the component in `<Suspense>` and stream the result.
|
|
35
|
+
|
|
36
|
+
## Revalidation
|
|
37
|
+
|
|
38
|
+
- **Path**: `revalidatePath('/blog/[slug]')` - Purges cache for specific route.
|
|
39
|
+
- **Tag**: `revalidateTag('collection')` - Purges all fetches tagged with `next: { tags: ['collection'] }`.
|
|
40
|
+
|
|
41
|
+
## Client-Side Fetching (Live Data)
|
|
42
|
+
|
|
43
|
+
Server Components are the default, but for live/user-specific data that doesn't need SEO:
|
|
44
|
+
|
|
45
|
+
- **SWR / TanStack Query**: PREFERRED over `useEffect`. Handles caching, polling, and deduplication automatically.
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
'use client';
|
|
49
|
+
import useSWR from 'swr';
|
|
50
|
+
|
|
51
|
+
// Good: "Stale-While-Revalidate" - Fast UI, then updates
|
|
52
|
+
const { data } = useSWR('/api/user', fetcher);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
- **Anti-Pattern**: Do not use `useEffect` to fetch data if you can avoid it. It causes "Flash of Loading Content" and waterfalls.
|
|
56
|
+
|
|
57
|
+
## Anti-Patterns
|
|
58
|
+
|
|
59
|
+
- **API Routes**: Don't fetch your own API Routes (`/api/...`) from Server Components. Call the DB/Service function directly.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Next.js Data Fetching References
|
|
2
|
+
|
|
3
|
+
## References
|
|
4
|
+
|
|
5
|
+
- [**Fetch Patterns**](fetch-patterns.md) - Server fetch, caching, revalidation
|
|
6
|
+
|
|
7
|
+
## Quick Checks
|
|
8
|
+
|
|
9
|
+
- [ ] Fetch in Server Components
|
|
10
|
+
- [ ] Use cache() for deduplication
|
|
11
|
+
- [ ] Configure revalidation strategy
|
|
12
|
+
- [ ] Parallel fetching when possible
|
|
13
|
+
- [ ] Handle loading and error states
|