@h1dr0n/skill-pool 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +296 -0
- package/bin/cli.js +157 -0
- package/package.json +41 -0
- package/skills/api/agents/backend-specialist.md +69 -0
- package/skills/api/agents/database-optimizer.md +176 -0
- package/skills/api/manifest.yaml +20 -0
- package/skills/api/rules/auth-security.md +45 -0
- package/skills/api/skills/api-patterns/SKILL.md +81 -0
- package/skills/api/skills/api-patterns/api-style.md +42 -0
- package/skills/api/skills/api-patterns/auth.md +24 -0
- package/skills/api/skills/api-patterns/documentation.md +26 -0
- package/skills/api/skills/api-patterns/graphql.md +41 -0
- package/skills/api/skills/api-patterns/rate-limiting.md +31 -0
- package/skills/api/skills/api-patterns/response.md +37 -0
- package/skills/api/skills/api-patterns/rest.md +40 -0
- package/skills/api/skills/api-patterns/scripts/api_validator.py +211 -0
- package/skills/api/skills/api-patterns/security-testing.md +122 -0
- package/skills/api/skills/api-patterns/trpc.md +41 -0
- package/skills/api/skills/api-patterns/versioning.md +22 -0
- package/skills/api/skills/database-patterns.md +126 -0
- package/skills/api/skills/deployment-patterns.md +105 -0
- package/skills/api/skills/docker-patterns.md +135 -0
- package/skills/common/agents/code-reviewer.md +78 -0
- package/skills/common/agents/planner.md +80 -0
- package/skills/common/agents/security-reviewer.md +82 -0
- package/skills/common/agents/software-architect.md +81 -0
- package/skills/common/manifest.yaml +25 -0
- package/skills/common/rules/coding-style.md +39 -0
- package/skills/common/rules/git-workflow.md +33 -0
- package/skills/common/rules/security.md +25 -0
- package/skills/common/skills/architecture/SKILL.md +55 -0
- package/skills/common/skills/architecture/context-discovery.md +43 -0
- package/skills/common/skills/architecture/examples.md +94 -0
- package/skills/common/skills/architecture/pattern-selection.md +68 -0
- package/skills/common/skills/architecture/patterns-reference.md +50 -0
- package/skills/common/skills/architecture/trade-off-analysis.md +77 -0
- package/skills/common/skills/brainstorming/SKILL.md +163 -0
- package/skills/common/skills/brainstorming/dynamic-questioning.md +350 -0
- package/skills/common/skills/clean-code.md +99 -0
- package/skills/common/skills/code-review-checklist.md +86 -0
- package/skills/common/skills/plan-writing/SKILL.md +152 -0
- package/skills/common/skills/skill-feedback.md +94 -0
- package/skills/common/skills/tdd-workflow.md +130 -0
- package/skills/common/skills/verification-loop.md +112 -0
- package/skills/cpp/agents/cpp-build-resolver.md +90 -0
- package/skills/cpp/agents/cpp-reviewer.md +72 -0
- package/skills/cpp/manifest.yaml +15 -0
- package/skills/cpp/skills/cpp-coding-standards.md +722 -0
- package/skills/cpp/skills/cpp-testing.md +323 -0
- package/skills/devops/agents/devops-automator.md +376 -0
- package/skills/devops/agents/sre.md +90 -0
- package/skills/devops/manifest.yaml +20 -0
- package/skills/devops/skills/deployment-patterns.md +427 -0
- package/skills/devops/skills/deployment-procedures/SKILL.md +241 -0
- package/skills/devops/skills/docker-patterns.md +364 -0
- package/skills/devops/skills/e2e-testing.md +326 -0
- package/skills/devops/skills/github-ops.md +144 -0
- package/skills/django/manifest.yaml +16 -0
- package/skills/django/skills/django-patterns.md +734 -0
- package/skills/django/skills/django-security.md +593 -0
- package/skills/django/skills/django-tdd.md +729 -0
- package/skills/django/skills/django-verification.md +469 -0
- package/skills/dotnet/agents/csharp-reviewer.md +101 -0
- package/skills/dotnet/manifest.yaml +14 -0
- package/skills/dotnet/skills/csharp-testing.md +321 -0
- package/skills/dotnet/skills/dotnet-patterns.md +321 -0
- package/skills/go/agents/code-reviewer.md +76 -0
- package/skills/go/agents/go-build-resolver.md +94 -0
- package/skills/go/agents/go-reviewer.md +76 -0
- package/skills/go/manifest.yaml +17 -0
- package/skills/go/rules/go-style.md +55 -0
- package/skills/go/skills/golang-patterns.md +674 -0
- package/skills/go/skills/golang-testing.md +720 -0
- package/skills/java/agents/java-build-resolver.md +153 -0
- package/skills/java/agents/java-reviewer.md +92 -0
- package/skills/java/manifest.yaml +18 -0
- package/skills/java/skills/java-coding-standards.md +147 -0
- package/skills/java/skills/jpa-patterns.md +151 -0
- package/skills/java/skills/springboot-patterns.md +314 -0
- package/skills/java/skills/springboot-security.md +272 -0
- package/skills/kotlin/agents/kotlin-build-resolver.md +118 -0
- package/skills/kotlin/agents/kotlin-reviewer.md +159 -0
- package/skills/kotlin/manifest.yaml +17 -0
- package/skills/kotlin/skills/kotlin-coroutines-flows.md +284 -0
- package/skills/kotlin/skills/kotlin-patterns.md +711 -0
- package/skills/kotlin/skills/kotlin-testing.md +824 -0
- package/skills/laravel/manifest.yaml +15 -0
- package/skills/laravel/skills/laravel-patterns.md +409 -0
- package/skills/laravel/skills/laravel-security.md +279 -0
- package/skills/laravel/skills/laravel-tdd.md +277 -0
- package/skills/laravel/skills/laravel-verification.md +173 -0
- package/skills/mobile/agents/dart-build-resolver.md +201 -0
- package/skills/mobile/agents/flutter-reviewer.md +243 -0
- package/skills/mobile/manifest.yaml +19 -0
- package/skills/mobile/skills/android-clean-architecture.md +339 -0
- package/skills/mobile/skills/dart-flutter-patterns.md +563 -0
- package/skills/mobile/skills/swiftui-patterns.md +259 -0
- package/skills/nestjs/manifest.yaml +13 -0
- package/skills/nestjs/skills/nestjs-patterns.md +230 -0
- package/skills/perl/manifest.yaml +13 -0
- package/skills/perl/skills/perl-patterns.md +504 -0
- package/skills/perl/skills/perl-security.md +503 -0
- package/skills/perl/skills/perl-testing.md +475 -0
- package/skills/python/agents/python-reviewer.md +98 -0
- package/skills/python/manifest.yaml +18 -0
- package/skills/python/rules/python-style.md +69 -0
- package/skills/python/skills/python-patterns/SKILL.md +441 -0
- package/skills/python/skills/python-patterns.md +90 -0
- package/skills/python/skills/python-testing.md +81 -0
- package/skills/rust/agents/rust-build-resolver.md +148 -0
- package/skills/rust/agents/rust-reviewer.md +94 -0
- package/skills/rust/manifest.yaml +16 -0
- package/skills/rust/rules/rust-style.md +107 -0
- package/skills/rust/skills/rust-patterns.md +499 -0
- package/skills/rust/skills/rust-testing.md +500 -0
- package/skills/security/agents/accessibility-auditor.md +316 -0
- package/skills/security/agents/security-reviewer.md +108 -0
- package/skills/security/manifest.yaml +19 -0
- package/skills/security/skills/red-team-tactics/SKILL.md +199 -0
- package/skills/security/skills/security-bounty-hunter.md +99 -0
- package/skills/security/skills/security-review.md +495 -0
- package/skills/security/skills/security-scan.md +165 -0
- package/skills/security/skills/vulnerability-scanner/SKILL.md +276 -0
- package/skills/security/skills/vulnerability-scanner/checklists.md +121 -0
- package/skills/security/skills/vulnerability-scanner/scripts/security_scan.py +458 -0
- package/skills/swift/manifest.yaml +16 -0
- package/skills/swift/skills/swift-actor-persistence.md +142 -0
- package/skills/swift/skills/swift-concurrency.md +216 -0
- package/skills/swift/skills/swift-protocol-di-testing.md +190 -0
- package/skills/swift/skills/swiftui-patterns.md +259 -0
- package/skills/unity/agents/game-designer.md +167 -0
- package/skills/unity/agents/unity-architect.md +52 -0
- package/skills/unity/agents/unity-editor-tool-developer.md +310 -0
- package/skills/unity/agents/unity-multiplayer-engineer.md +321 -0
- package/skills/unity/agents/unity-shader-graph-artist.md +269 -0
- package/skills/unity/manifest.yaml +21 -0
- package/skills/unity/rules/csharp-patterns.md +48 -0
- package/skills/unity/rules/unity-specific.md +53 -0
- package/skills/unity/skills/systematic-debugging.md +92 -0
- package/skills/unity/skills/unity-architecture.md +173 -0
- package/skills/unreal/agents/level-designer.md +208 -0
- package/skills/unreal/agents/technical-artist.md +229 -0
- package/skills/unreal/agents/unreal-multiplayer-architect.md +313 -0
- package/skills/unreal/agents/unreal-systems-engineer.md +310 -0
- package/skills/unreal/agents/unreal-technical-artist.md +256 -0
- package/skills/unreal/agents/unreal-world-builder.md +273 -0
- package/skills/unreal/manifest.yaml +21 -0
- package/skills/unreal/skills/unreal-patterns.md +183 -0
- package/skills/web/agents/frontend-specialist.md +71 -0
- package/skills/web/agents/ui-designer.md +383 -0
- package/skills/web/agents/ux-architect.md +469 -0
- package/skills/web/manifest.yaml +22 -0
- package/skills/web/rules/accessibility.md +54 -0
- package/skills/web/rules/css-performance.md +52 -0
- package/skills/web/skills/e2e-testing.md +132 -0
- package/skills/web/skills/frontend-design/SKILL.md +452 -0
- package/skills/web/skills/frontend-design/animation-guide.md +331 -0
- package/skills/web/skills/frontend-design/color-system.md +311 -0
- package/skills/web/skills/frontend-design/decision-trees.md +418 -0
- package/skills/web/skills/frontend-design/motion-graphics.md +306 -0
- package/skills/web/skills/frontend-design/scripts/accessibility_checker.py +183 -0
- package/skills/web/skills/frontend-design/scripts/ux_audit.py +722 -0
- package/skills/web/skills/frontend-design/typography-system.md +345 -0
- package/skills/web/skills/frontend-design/ux-psychology.md +1116 -0
- package/skills/web/skills/frontend-design/visual-effects.md +383 -0
- package/skills/web/skills/react-nextjs.md +135 -0
- package/skills/web/skills/tailwind-patterns/SKILL.md +269 -0
- package/src/adapters/antigravity.js +164 -0
- package/src/adapters/claude.js +188 -0
- package/src/adapters/cursor.js +161 -0
- package/src/adapters/index.js +67 -0
- package/src/adapters/windsurf.js +158 -0
- package/src/commands/add.js +266 -0
- package/src/commands/create.js +127 -0
- package/src/commands/diff.js +78 -0
- package/src/commands/info.js +88 -0
- package/src/commands/init.js +224 -0
- package/src/commands/install.js +90 -0
- package/src/commands/list.js +54 -0
- package/src/commands/remove.js +101 -0
- package/src/commands/targets.js +32 -0
- package/src/commands/update.js +57 -0
- package/src/core/manifest.js +57 -0
- package/src/core/plugins.js +86 -0
- package/src/core/resolver.js +84 -0
- package/src/core/tracker.js +49 -0
- package/src/utils/fs.js +80 -0
- package/src/utils/git.js +52 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: swiftui-patterns
|
|
3
|
+
description: SwiftUI architecture patterns, state management with @Observable, view composition, navigation, performance optimization, and modern iOS/macOS UI best practices.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SwiftUI Patterns
|
|
7
|
+
|
|
8
|
+
Modern SwiftUI patterns for building declarative, performant user interfaces on Apple platforms. Covers the Observation framework, view composition, type-safe navigation, and performance optimization.
|
|
9
|
+
|
|
10
|
+
## When to Activate
|
|
11
|
+
|
|
12
|
+
- Building SwiftUI views and managing state (`@State`, `@Observable`, `@Binding`)
|
|
13
|
+
- Designing navigation flows with `NavigationStack`
|
|
14
|
+
- Structuring view models and data flow
|
|
15
|
+
- Optimizing rendering performance for lists and complex layouts
|
|
16
|
+
- Working with environment values and dependency injection in SwiftUI
|
|
17
|
+
|
|
18
|
+
## State Management
|
|
19
|
+
|
|
20
|
+
### Property Wrapper Selection
|
|
21
|
+
|
|
22
|
+
Choose the simplest wrapper that fits:
|
|
23
|
+
|
|
24
|
+
| Wrapper | Use Case |
|
|
25
|
+
|---------|----------|
|
|
26
|
+
| `@State` | View-local value types (toggles, form fields, sheet presentation) |
|
|
27
|
+
| `@Binding` | Two-way reference to parent's `@State` |
|
|
28
|
+
| `@Observable` class + `@State` | Owned model with multiple properties |
|
|
29
|
+
| `@Observable` class (no wrapper) | Read-only reference passed from parent |
|
|
30
|
+
| `@Bindable` | Two-way binding to an `@Observable` property |
|
|
31
|
+
| `@Environment` | Shared dependencies injected via `.environment()` |
|
|
32
|
+
|
|
33
|
+
### @Observable ViewModel
|
|
34
|
+
|
|
35
|
+
Use `@Observable` (not `ObservableObject`) — it tracks property-level changes so SwiftUI only re-renders views that read the changed property:
|
|
36
|
+
|
|
37
|
+
```swift
|
|
38
|
+
@Observable
|
|
39
|
+
final class ItemListViewModel {
|
|
40
|
+
private(set) var items: [Item] = []
|
|
41
|
+
private(set) var isLoading = false
|
|
42
|
+
var searchText = ""
|
|
43
|
+
|
|
44
|
+
private let repository: any ItemRepository
|
|
45
|
+
|
|
46
|
+
init(repository: any ItemRepository = DefaultItemRepository()) {
|
|
47
|
+
self.repository = repository
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
func load() async {
|
|
51
|
+
isLoading = true
|
|
52
|
+
defer { isLoading = false }
|
|
53
|
+
items = (try? await repository.fetchAll()) ?? []
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### View Consuming the ViewModel
|
|
59
|
+
|
|
60
|
+
```swift
|
|
61
|
+
struct ItemListView: View {
|
|
62
|
+
@State private var viewModel: ItemListViewModel
|
|
63
|
+
|
|
64
|
+
init(viewModel: ItemListViewModel = ItemListViewModel()) {
|
|
65
|
+
_viewModel = State(initialValue: viewModel)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
var body: some View {
|
|
69
|
+
List(viewModel.items) { item in
|
|
70
|
+
ItemRow(item: item)
|
|
71
|
+
}
|
|
72
|
+
.searchable(text: $viewModel.searchText)
|
|
73
|
+
.overlay { if viewModel.isLoading { ProgressView() } }
|
|
74
|
+
.task { await viewModel.load() }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Environment Injection
|
|
80
|
+
|
|
81
|
+
Replace `@EnvironmentObject` with `@Environment`:
|
|
82
|
+
|
|
83
|
+
```swift
|
|
84
|
+
// Inject
|
|
85
|
+
ContentView()
|
|
86
|
+
.environment(authManager)
|
|
87
|
+
|
|
88
|
+
// Consume
|
|
89
|
+
struct ProfileView: View {
|
|
90
|
+
@Environment(AuthManager.self) private var auth
|
|
91
|
+
|
|
92
|
+
var body: some View {
|
|
93
|
+
Text(auth.currentUser?.name ?? "Guest")
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## View Composition
|
|
99
|
+
|
|
100
|
+
### Extract Subviews to Limit Invalidation
|
|
101
|
+
|
|
102
|
+
Break views into small, focused structs. When state changes, only the subview reading that state re-renders:
|
|
103
|
+
|
|
104
|
+
```swift
|
|
105
|
+
struct OrderView: View {
|
|
106
|
+
@State private var viewModel = OrderViewModel()
|
|
107
|
+
|
|
108
|
+
var body: some View {
|
|
109
|
+
VStack {
|
|
110
|
+
OrderHeader(title: viewModel.title)
|
|
111
|
+
OrderItemList(items: viewModel.items)
|
|
112
|
+
OrderTotal(total: viewModel.total)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### ViewModifier for Reusable Styling
|
|
119
|
+
|
|
120
|
+
```swift
|
|
121
|
+
struct CardModifier: ViewModifier {
|
|
122
|
+
func body(content: Content) -> some View {
|
|
123
|
+
content
|
|
124
|
+
.padding()
|
|
125
|
+
.background(.regularMaterial)
|
|
126
|
+
.clipShape(RoundedRectangle(cornerRadius: 12))
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
extension View {
|
|
131
|
+
func cardStyle() -> some View {
|
|
132
|
+
modifier(CardModifier())
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Navigation
|
|
138
|
+
|
|
139
|
+
### Type-Safe NavigationStack
|
|
140
|
+
|
|
141
|
+
Use `NavigationStack` with `NavigationPath` for programmatic, type-safe routing:
|
|
142
|
+
|
|
143
|
+
```swift
|
|
144
|
+
@Observable
|
|
145
|
+
final class Router {
|
|
146
|
+
var path = NavigationPath()
|
|
147
|
+
|
|
148
|
+
func navigate(to destination: Destination) {
|
|
149
|
+
path.append(destination)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
func popToRoot() {
|
|
153
|
+
path = NavigationPath()
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
enum Destination: Hashable {
|
|
158
|
+
case detail(Item.ID)
|
|
159
|
+
case settings
|
|
160
|
+
case profile(User.ID)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
struct RootView: View {
|
|
164
|
+
@State private var router = Router()
|
|
165
|
+
|
|
166
|
+
var body: some View {
|
|
167
|
+
NavigationStack(path: $router.path) {
|
|
168
|
+
HomeView()
|
|
169
|
+
.navigationDestination(for: Destination.self) { dest in
|
|
170
|
+
switch dest {
|
|
171
|
+
case .detail(let id): ItemDetailView(itemID: id)
|
|
172
|
+
case .settings: SettingsView()
|
|
173
|
+
case .profile(let id): ProfileView(userID: id)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
.environment(router)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Performance
|
|
183
|
+
|
|
184
|
+
### Use Lazy Containers for Large Collections
|
|
185
|
+
|
|
186
|
+
`LazyVStack` and `LazyHStack` create views only when visible:
|
|
187
|
+
|
|
188
|
+
```swift
|
|
189
|
+
ScrollView {
|
|
190
|
+
LazyVStack(spacing: 8) {
|
|
191
|
+
ForEach(items) { item in
|
|
192
|
+
ItemRow(item: item)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Stable Identifiers
|
|
199
|
+
|
|
200
|
+
Always use stable, unique IDs in `ForEach` — avoid using array indices:
|
|
201
|
+
|
|
202
|
+
```swift
|
|
203
|
+
// Use Identifiable conformance or explicit id
|
|
204
|
+
ForEach(items, id: \.stableID) { item in
|
|
205
|
+
ItemRow(item: item)
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Avoid Expensive Work in body
|
|
210
|
+
|
|
211
|
+
- Never perform I/O, network calls, or heavy computation inside `body`
|
|
212
|
+
- Use `.task {}` for async work — it cancels automatically when the view disappears
|
|
213
|
+
- Use `.sensoryFeedback()` and `.geometryGroup()` sparingly in scroll views
|
|
214
|
+
- Minimize `.shadow()`, `.blur()`, and `.mask()` in lists — they trigger offscreen rendering
|
|
215
|
+
|
|
216
|
+
### Equatable Conformance
|
|
217
|
+
|
|
218
|
+
For views with expensive bodies, conform to `Equatable` to skip unnecessary re-renders:
|
|
219
|
+
|
|
220
|
+
```swift
|
|
221
|
+
struct ExpensiveChartView: View, Equatable {
|
|
222
|
+
let dataPoints: [DataPoint] // DataPoint must conform to Equatable
|
|
223
|
+
|
|
224
|
+
static func == (lhs: Self, rhs: Self) -> Bool {
|
|
225
|
+
lhs.dataPoints == rhs.dataPoints
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
var body: some View {
|
|
229
|
+
// Complex chart rendering
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Previews
|
|
235
|
+
|
|
236
|
+
Use `#Preview` macro with inline mock data for fast iteration:
|
|
237
|
+
|
|
238
|
+
```swift
|
|
239
|
+
#Preview("Empty state") {
|
|
240
|
+
ItemListView(viewModel: ItemListViewModel(repository: EmptyMockRepository()))
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
#Preview("Loaded") {
|
|
244
|
+
ItemListView(viewModel: ItemListViewModel(repository: PopulatedMockRepository()))
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Anti-Patterns to Avoid
|
|
249
|
+
|
|
250
|
+
- Using `ObservableObject` / `@Published` / `@StateObject` / `@EnvironmentObject` in new code — migrate to `@Observable`
|
|
251
|
+
- Putting async work directly in `body` or `init` — use `.task {}` or explicit load methods
|
|
252
|
+
- Creating view models as `@State` inside child views that don't own the data — pass from parent instead
|
|
253
|
+
- Using `AnyView` type erasure — prefer `@ViewBuilder` or `Group` for conditional views
|
|
254
|
+
- Ignoring `Sendable` requirements when passing data to/from actors
|
|
255
|
+
|
|
256
|
+
## References
|
|
257
|
+
|
|
258
|
+
See skill: `swift-actor-persistence` for actor-based persistence patterns.
|
|
259
|
+
See skill: `swift-protocol-di-testing` for protocol-based DI and testing with Swift Testing.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
name: nestjs
|
|
2
|
+
version: 0.1.0
|
|
3
|
+
description: NestJS architecture patterns for modules, controllers, providers, DTO validation, guards, interceptors, config, and production-grade TypeScript backends.
|
|
4
|
+
depends:
|
|
5
|
+
- common
|
|
6
|
+
tags:
|
|
7
|
+
- nestjs
|
|
8
|
+
- nodejs
|
|
9
|
+
- typescript
|
|
10
|
+
rules: []
|
|
11
|
+
skills:
|
|
12
|
+
- skills/nestjs-patterns.md
|
|
13
|
+
agents: []
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nestjs-patterns
|
|
3
|
+
description: NestJS architecture patterns for modules, controllers, providers, DTO validation, guards, interceptors, config, and production-grade TypeScript backends.
|
|
4
|
+
origin: ECC
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# NestJS Development Patterns
|
|
8
|
+
|
|
9
|
+
Production-grade NestJS patterns for modular TypeScript backends.
|
|
10
|
+
|
|
11
|
+
## When to Activate
|
|
12
|
+
|
|
13
|
+
- Building NestJS APIs or services
|
|
14
|
+
- Structuring modules, controllers, and providers
|
|
15
|
+
- Adding DTO validation, guards, interceptors, or exception filters
|
|
16
|
+
- Configuring environment-aware settings and database integrations
|
|
17
|
+
- Testing NestJS units or HTTP endpoints
|
|
18
|
+
|
|
19
|
+
## Project Structure
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
src/
|
|
23
|
+
├── app.module.ts
|
|
24
|
+
├── main.ts
|
|
25
|
+
├── common/
|
|
26
|
+
│ ├── filters/
|
|
27
|
+
│ ├── guards/
|
|
28
|
+
│ ├── interceptors/
|
|
29
|
+
│ └── pipes/
|
|
30
|
+
├── config/
|
|
31
|
+
│ ├── configuration.ts
|
|
32
|
+
│ └── validation.ts
|
|
33
|
+
├── modules/
|
|
34
|
+
│ ├── auth/
|
|
35
|
+
│ │ ├── auth.controller.ts
|
|
36
|
+
│ │ ├── auth.module.ts
|
|
37
|
+
│ │ ├── auth.service.ts
|
|
38
|
+
│ │ ├── dto/
|
|
39
|
+
│ │ ├── guards/
|
|
40
|
+
│ │ └── strategies/
|
|
41
|
+
│ └── users/
|
|
42
|
+
│ ├── dto/
|
|
43
|
+
│ ├── entities/
|
|
44
|
+
│ ├── users.controller.ts
|
|
45
|
+
│ ├── users.module.ts
|
|
46
|
+
│ └── users.service.ts
|
|
47
|
+
└── prisma/ or database/
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- Keep domain code inside feature modules.
|
|
51
|
+
- Put cross-cutting filters, decorators, guards, and interceptors in `common/`.
|
|
52
|
+
- Keep DTOs close to the module that owns them.
|
|
53
|
+
|
|
54
|
+
## Bootstrap and Global Validation
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
async function bootstrap() {
|
|
58
|
+
const app = await NestFactory.create(AppModule, { bufferLogs: true });
|
|
59
|
+
|
|
60
|
+
app.useGlobalPipes(
|
|
61
|
+
new ValidationPipe({
|
|
62
|
+
whitelist: true,
|
|
63
|
+
forbidNonWhitelisted: true,
|
|
64
|
+
transform: true,
|
|
65
|
+
transformOptions: { enableImplicitConversion: true },
|
|
66
|
+
}),
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));
|
|
70
|
+
app.useGlobalFilters(new HttpExceptionFilter());
|
|
71
|
+
|
|
72
|
+
await app.listen(process.env.PORT ?? 3000);
|
|
73
|
+
}
|
|
74
|
+
bootstrap();
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- Always enable `whitelist` and `forbidNonWhitelisted` on public APIs.
|
|
78
|
+
- Prefer one global validation pipe instead of repeating validation config per route.
|
|
79
|
+
|
|
80
|
+
## Modules, Controllers, and Providers
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
@Module({
|
|
84
|
+
controllers: [UsersController],
|
|
85
|
+
providers: [UsersService],
|
|
86
|
+
exports: [UsersService],
|
|
87
|
+
})
|
|
88
|
+
export class UsersModule {}
|
|
89
|
+
|
|
90
|
+
@Controller('users')
|
|
91
|
+
export class UsersController {
|
|
92
|
+
constructor(private readonly usersService: UsersService) {}
|
|
93
|
+
|
|
94
|
+
@Get(':id')
|
|
95
|
+
getById(@Param('id', ParseUUIDPipe) id: string) {
|
|
96
|
+
return this.usersService.getById(id);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@Post()
|
|
100
|
+
create(@Body() dto: CreateUserDto) {
|
|
101
|
+
return this.usersService.create(dto);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@Injectable()
|
|
106
|
+
export class UsersService {
|
|
107
|
+
constructor(private readonly usersRepo: UsersRepository) {}
|
|
108
|
+
|
|
109
|
+
async create(dto: CreateUserDto) {
|
|
110
|
+
return this.usersRepo.create(dto);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
- Controllers should stay thin: parse HTTP input, call a provider, return response DTOs.
|
|
116
|
+
- Put business logic in injectable services, not controllers.
|
|
117
|
+
- Export only the providers other modules genuinely need.
|
|
118
|
+
|
|
119
|
+
## DTOs and Validation
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
export class CreateUserDto {
|
|
123
|
+
@IsEmail()
|
|
124
|
+
email!: string;
|
|
125
|
+
|
|
126
|
+
@IsString()
|
|
127
|
+
@Length(2, 80)
|
|
128
|
+
name!: string;
|
|
129
|
+
|
|
130
|
+
@IsOptional()
|
|
131
|
+
@IsEnum(UserRole)
|
|
132
|
+
role?: UserRole;
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
- Validate every request DTO with `class-validator`.
|
|
137
|
+
- Use dedicated response DTOs or serializers instead of returning ORM entities directly.
|
|
138
|
+
- Avoid leaking internal fields such as password hashes, tokens, or audit columns.
|
|
139
|
+
|
|
140
|
+
## Auth, Guards, and Request Context
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
144
|
+
@Roles('admin')
|
|
145
|
+
@Get('admin/report')
|
|
146
|
+
getAdminReport(@Req() req: AuthenticatedRequest) {
|
|
147
|
+
return this.reportService.getForUser(req.user.id);
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
- Keep auth strategies and guards module-local unless they are truly shared.
|
|
152
|
+
- Encode coarse access rules in guards, then do resource-specific authorization in services.
|
|
153
|
+
- Prefer explicit request types for authenticated request objects.
|
|
154
|
+
|
|
155
|
+
## Exception Filters and Error Shape
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
@Catch()
|
|
159
|
+
export class HttpExceptionFilter implements ExceptionFilter {
|
|
160
|
+
catch(exception: unknown, host: ArgumentsHost) {
|
|
161
|
+
const response = host.switchToHttp().getResponse<Response>();
|
|
162
|
+
const request = host.switchToHttp().getRequest<Request>();
|
|
163
|
+
|
|
164
|
+
if (exception instanceof HttpException) {
|
|
165
|
+
return response.status(exception.getStatus()).json({
|
|
166
|
+
path: request.url,
|
|
167
|
+
error: exception.getResponse(),
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return response.status(500).json({
|
|
172
|
+
path: request.url,
|
|
173
|
+
error: 'Internal server error',
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
- Keep one consistent error envelope across the API.
|
|
180
|
+
- Throw framework exceptions for expected client errors; log and wrap unexpected failures centrally.
|
|
181
|
+
|
|
182
|
+
## Config and Environment Validation
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
ConfigModule.forRoot({
|
|
186
|
+
isGlobal: true,
|
|
187
|
+
load: [configuration],
|
|
188
|
+
validate: validateEnv,
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
- Validate env at boot, not lazily at first request.
|
|
193
|
+
- Keep config access behind typed helpers or config services.
|
|
194
|
+
- Split dev/staging/prod concerns in config factories instead of branching throughout feature code.
|
|
195
|
+
|
|
196
|
+
## Persistence and Transactions
|
|
197
|
+
|
|
198
|
+
- Keep repository / ORM code behind providers that speak domain language.
|
|
199
|
+
- For Prisma or TypeORM, isolate transactional workflows in services that own the unit of work.
|
|
200
|
+
- Do not let controllers coordinate multi-step writes directly.
|
|
201
|
+
|
|
202
|
+
## Testing
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
describe('UsersController', () => {
|
|
206
|
+
let app: INestApplication;
|
|
207
|
+
|
|
208
|
+
beforeAll(async () => {
|
|
209
|
+
const moduleRef = await Test.createTestingModule({
|
|
210
|
+
imports: [UsersModule],
|
|
211
|
+
}).compile();
|
|
212
|
+
|
|
213
|
+
app = moduleRef.createNestApplication();
|
|
214
|
+
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
|
|
215
|
+
await app.init();
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
- Unit test providers in isolation with mocked dependencies.
|
|
221
|
+
- Add request-level tests for guards, validation pipes, and exception filters.
|
|
222
|
+
- Reuse the same global pipes/filters in tests that you use in production.
|
|
223
|
+
|
|
224
|
+
## Production Defaults
|
|
225
|
+
|
|
226
|
+
- Enable structured logging and request correlation ids.
|
|
227
|
+
- Terminate on invalid env/config instead of booting partially.
|
|
228
|
+
- Prefer async provider initialization for DB/cache clients with explicit health checks.
|
|
229
|
+
- Keep background jobs and event consumers in their own modules, not inside HTTP controllers.
|
|
230
|
+
- Make rate limiting, auth, and audit logging explicit for public endpoints.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
name: perl
|
|
2
|
+
version: 0.1.0
|
|
3
|
+
description: Modern Perl 5.36+ patterns, testing with Test2::V0, and comprehensive security guidelines for building robust Perl applications.
|
|
4
|
+
depends:
|
|
5
|
+
- common
|
|
6
|
+
tags:
|
|
7
|
+
- perl
|
|
8
|
+
rules: []
|
|
9
|
+
skills:
|
|
10
|
+
- skills/perl-patterns.md
|
|
11
|
+
- skills/perl-testing.md
|
|
12
|
+
- skills/perl-security.md
|
|
13
|
+
agents: []
|