@sylix/coworker 2.0.10 → 2.0.12

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.
Files changed (178) hide show
  1. package/dist/commands/slash/config.d.ts.map +1 -1
  2. package/dist/commands/slash/config.js +23 -5
  3. package/dist/commands/slash/config.js.map +1 -1
  4. package/dist/commands/slash/todo.js +1 -1
  5. package/dist/commands/slash/todo.js.map +1 -1
  6. package/dist/core/CoWorkerAgent.d.ts.map +1 -1
  7. package/dist/core/CoWorkerAgent.js +6 -3
  8. package/dist/core/CoWorkerAgent.js.map +1 -1
  9. package/dist/permissions/PermissionInterceptor.js +1 -1
  10. package/dist/permissions/PermissionInterceptor.js.map +1 -1
  11. package/dist/skills/defaults/accessibility/screen-reader-testing.md +545 -0
  12. package/dist/skills/defaults/accessibility/wcag-audit-patterns.md +555 -0
  13. package/dist/skills/defaults/ai-ml/rag.md +276 -0
  14. package/dist/skills/defaults/backend-development/api-design-principles.md +528 -0
  15. package/dist/skills/defaults/backend-development/api-design.md +285 -0
  16. package/dist/skills/defaults/backend-development/architecture-patterns.md +494 -0
  17. package/dist/skills/defaults/backend-development/async-python.md +237 -0
  18. package/dist/skills/defaults/backend-development/auth-implementation-patterns.md +638 -0
  19. package/dist/skills/defaults/backend-development/bazel-build-optimization.md +387 -0
  20. package/dist/skills/defaults/backend-development/billing-automation/SKILL.md +566 -0
  21. package/dist/skills/defaults/backend-development/code-review-excellence.md +538 -0
  22. package/dist/skills/defaults/backend-development/cqrs-implementation.md +554 -0
  23. package/dist/skills/defaults/backend-development/database-design.md +305 -0
  24. package/dist/skills/defaults/backend-development/debugging-strategies.md +536 -0
  25. package/dist/skills/defaults/backend-development/e2e-testing-patterns.md +544 -0
  26. package/dist/skills/defaults/backend-development/error-handling-patterns.md +641 -0
  27. package/dist/skills/defaults/backend-development/fastapi-templates.md +559 -0
  28. package/dist/skills/defaults/backend-development/fastapi.md +309 -0
  29. package/dist/skills/defaults/backend-development/git-advanced-workflows.md +405 -0
  30. package/dist/skills/defaults/backend-development/microservices-patterns.md +595 -0
  31. package/dist/skills/defaults/backend-development/microservices.md +284 -0
  32. package/dist/skills/defaults/backend-development/monorepo-management.md +623 -0
  33. package/dist/skills/defaults/backend-development/nodejs-backend-patterns.md +1048 -0
  34. package/dist/skills/defaults/backend-development/nx-workspace-patterns.md +457 -0
  35. package/dist/skills/defaults/backend-development/paypal-integration/SKILL.md +478 -0
  36. package/dist/skills/defaults/backend-development/pci-compliance/SKILL.md +480 -0
  37. package/dist/skills/defaults/backend-development/python-anti-patterns.md +349 -0
  38. package/dist/skills/defaults/backend-development/python-background-jobs.md +364 -0
  39. package/dist/skills/defaults/backend-development/python-code-style.md +360 -0
  40. package/dist/skills/defaults/backend-development/python-configuration.md +368 -0
  41. package/dist/skills/defaults/backend-development/python-design-patterns.md +296 -0
  42. package/dist/skills/defaults/backend-development/python-error-handling.md +323 -0
  43. package/dist/skills/defaults/backend-development/python-packaging.md +887 -0
  44. package/dist/skills/defaults/backend-development/python-performance-optimization.md +874 -0
  45. package/dist/skills/defaults/backend-development/python-project-structure.md +252 -0
  46. package/dist/skills/defaults/backend-development/python-resilience.md +376 -0
  47. package/dist/skills/defaults/backend-development/python-resource-management.md +421 -0
  48. package/dist/skills/defaults/backend-development/python-type-safety.md +428 -0
  49. package/dist/skills/defaults/backend-development/sql-optimization-patterns.md +509 -0
  50. package/dist/skills/defaults/backend-development/stripe-integration/SKILL.md +522 -0
  51. package/dist/skills/defaults/backend-development/turborepo-caching.md +376 -0
  52. package/dist/skills/defaults/blockchain/defi-protocol-templates.md +430 -0
  53. package/dist/skills/defaults/blockchain/nft-standards.md +364 -0
  54. package/dist/skills/defaults/blockchain/solidity-security.md +514 -0
  55. package/dist/skills/defaults/blockchain/web3-testing.md +360 -0
  56. package/dist/skills/defaults/business/competitive-landscape/SKILL.md +527 -0
  57. package/dist/skills/defaults/business/market-sizing-analysis/SKILL.md +451 -0
  58. package/dist/skills/defaults/business/startup-financial-modeling/SKILL.md +494 -0
  59. package/dist/skills/defaults/business/startup-metrics-framework/SKILL.md +564 -0
  60. package/dist/skills/defaults/business/team-composition-analysis.md +437 -0
  61. package/dist/skills/defaults/compliance/employment-contract-templates/SKILL.md +527 -0
  62. package/dist/skills/defaults/compliance/gdpr-data-handling/SKILL.md +630 -0
  63. package/dist/skills/defaults/data-engineering/airflow-dag-patterns.md +436 -0
  64. package/dist/skills/defaults/data-engineering/airflow.md +519 -0
  65. package/dist/skills/defaults/data-engineering/data-quality.md +583 -0
  66. package/dist/skills/defaults/data-engineering/dbt-transformation-patterns.md +482 -0
  67. package/dist/skills/defaults/data-engineering/dbt.md +556 -0
  68. package/dist/skills/defaults/data-engineering/ml-pipeline-workflow/SKILL.md +247 -0
  69. package/dist/skills/defaults/data-engineering/spark-optimization.md +348 -0
  70. package/dist/skills/defaults/data-engineering/spark.md +411 -0
  71. package/dist/skills/defaults/database/postgresql.md +202 -0
  72. package/dist/skills/defaults/debugging/systematic-debugging.md +249 -0
  73. package/dist/skills/defaults/devops/architecture-decision-records.md +448 -0
  74. package/dist/skills/defaults/devops/changelog-automation.md +580 -0
  75. package/dist/skills/defaults/devops/cicd.md +314 -0
  76. package/dist/skills/defaults/devops/cloud.md +263 -0
  77. package/dist/skills/defaults/devops/code-review-excellence.md +299 -0
  78. package/dist/skills/defaults/devops/cost-optimization.md +295 -0
  79. package/dist/skills/defaults/devops/deployment-pipeline-design.md +356 -0
  80. package/dist/skills/defaults/devops/docker.md +281 -0
  81. package/dist/skills/defaults/devops/git-workflows.md +205 -0
  82. package/dist/skills/defaults/devops/github-actions.md +311 -0
  83. package/dist/skills/defaults/devops/gitlab-ci-patterns.md +266 -0
  84. package/dist/skills/defaults/devops/hybrid-cloud-networking.md +241 -0
  85. package/dist/skills/defaults/devops/istio-traffic-management.md +327 -0
  86. package/dist/skills/defaults/devops/kubernetes.md +339 -0
  87. package/dist/skills/defaults/devops/linkerd-patterns.md +311 -0
  88. package/dist/skills/defaults/devops/multi-cloud-architecture.md +181 -0
  89. package/dist/skills/defaults/devops/observability.md +243 -0
  90. package/dist/skills/defaults/devops/openapi-spec-generation.md +1024 -0
  91. package/dist/skills/defaults/devops/postmortem-writing.md +396 -0
  92. package/dist/skills/defaults/devops/prometheus-configuration.md +265 -0
  93. package/dist/skills/defaults/devops/secrets-management.md +341 -0
  94. package/dist/skills/defaults/devops/service-mesh-observability.md +385 -0
  95. package/dist/skills/defaults/devops/terraform-module-library.md +244 -0
  96. package/dist/skills/defaults/finance/backtesting-frameworks/SKILL.md +663 -0
  97. package/dist/skills/defaults/finance/risk-metrics-calculation/SKILL.md +557 -0
  98. package/dist/skills/defaults/frontend/accessibility-compliance.md +420 -0
  99. package/dist/skills/defaults/frontend/design-system-patterns.md +337 -0
  100. package/dist/skills/defaults/frontend/interaction-design.md +327 -0
  101. package/dist/skills/defaults/frontend/javascript.md +311 -0
  102. package/dist/skills/defaults/frontend/modern-javascript-patterns.md +927 -0
  103. package/dist/skills/defaults/frontend/react-native-design.md +440 -0
  104. package/dist/skills/defaults/frontend/react.md +345 -0
  105. package/dist/skills/defaults/frontend/responsive-design.md +472 -0
  106. package/dist/skills/defaults/frontend/tailwind-design-system.md +337 -0
  107. package/dist/skills/defaults/frontend/typescript-advanced-types.md +724 -0
  108. package/dist/skills/defaults/frontend/typescript.md +334 -0
  109. package/dist/skills/defaults/frontend/visual-design-foundations.md +326 -0
  110. package/dist/skills/defaults/frontend/web-component-design.md +279 -0
  111. package/dist/skills/defaults/game-development/godot-gdscript-patterns.md +188 -0
  112. package/dist/skills/defaults/game-development/unity-ecs-patterns.md +594 -0
  113. package/dist/skills/defaults/kubernetes/gitops-workflow.md +285 -0
  114. package/dist/skills/defaults/kubernetes/gitops.md +280 -0
  115. package/dist/skills/defaults/kubernetes/helm-chart-scaffolding.md +553 -0
  116. package/dist/skills/defaults/kubernetes/helm.md +343 -0
  117. package/dist/skills/defaults/kubernetes/k8s-manifest-generator.md +501 -0
  118. package/dist/skills/defaults/kubernetes/k8s-security-policies.md +342 -0
  119. package/dist/skills/defaults/kubernetes/manifests.md +330 -0
  120. package/dist/skills/defaults/kubernetes/security.md +337 -0
  121. package/dist/skills/defaults/llm-application/embedding-strategies.md +608 -0
  122. package/dist/skills/defaults/llm-application/hybrid-search-implementation.md +570 -0
  123. package/dist/skills/defaults/llm-application/hybrid-search.md +570 -0
  124. package/dist/skills/defaults/llm-application/langchain-architecture.md +666 -0
  125. package/dist/skills/defaults/llm-application/langchain.md +259 -0
  126. package/dist/skills/defaults/llm-application/llm-evaluation.md +695 -0
  127. package/dist/skills/defaults/llm-application/prompt-engineering-patterns.md +449 -0
  128. package/dist/skills/defaults/llm-application/prompt-engineering.md +219 -0
  129. package/dist/skills/defaults/llm-application/rag-implementation.md +434 -0
  130. package/dist/skills/defaults/llm-application/similarity-search-patterns.md +560 -0
  131. package/dist/skills/defaults/llm-application/similarity-search.md +560 -0
  132. package/dist/skills/defaults/llm-application/vector-index-tuning.md +523 -0
  133. package/dist/skills/defaults/mobile/mobile-android-design.md +440 -0
  134. package/dist/skills/defaults/mobile/mobile-ios-design.md +266 -0
  135. package/dist/skills/defaults/monitoring/distributed-tracing.md +436 -0
  136. package/dist/skills/defaults/monitoring/grafana-dashboards.md +370 -0
  137. package/dist/skills/defaults/monitoring/prometheus-configuration.md +379 -0
  138. package/dist/skills/defaults/monitoring/slo-implementation.md +323 -0
  139. package/dist/skills/defaults/refactoring/code-refactoring.md +349 -0
  140. package/dist/skills/defaults/security/anti-reversing-techniques/SKILL.md +559 -0
  141. package/dist/skills/defaults/security/auditor.md +168 -0
  142. package/dist/skills/defaults/security/binary-analysis-patterns/SKILL.md +438 -0
  143. package/dist/skills/defaults/security/memory-forensics/SKILL.md +483 -0
  144. package/dist/skills/defaults/security/mtls-configuration.md +349 -0
  145. package/dist/skills/defaults/security/protocol-reverse-engineering/SKILL.md +520 -0
  146. package/dist/skills/defaults/security/sast-configuration.md +182 -0
  147. package/dist/skills/defaults/security/security.md +313 -0
  148. package/dist/skills/defaults/security/stride-analysis.md +273 -0
  149. package/dist/skills/defaults/security/threat-mitigation-mapping.md +290 -0
  150. package/dist/skills/defaults/systems/bash-defensive-patterns/SKILL.md +539 -0
  151. package/dist/skills/defaults/systems/bats-testing-patterns/SKILL.md +631 -0
  152. package/dist/skills/defaults/systems/go-concurrency-patterns.md +657 -0
  153. package/dist/skills/defaults/systems/memory-safety-patterns.md +605 -0
  154. package/dist/skills/defaults/systems/rust-async-patterns.md +519 -0
  155. package/dist/skills/defaults/systems/shellcheck-configuration/SKILL.md +456 -0
  156. package/dist/skills/defaults/team-collaboration/multi-reviewer-patterns.md +126 -0
  157. package/dist/skills/defaults/team-collaboration/parallel-feature-development.md +151 -0
  158. package/dist/skills/defaults/testing/javascript-testing-patterns.md +1021 -0
  159. package/dist/skills/defaults/testing/python-testing-patterns.md +351 -0
  160. package/dist/skills/defaults/testing/testing.md +332 -0
  161. package/dist/skills/defaults/workflows/context-driven-development.md +384 -0
  162. package/dist/skills/defaults/workflows/track-management.md +592 -0
  163. package/dist/skills/defaults/workflows/workflow-patterns.md +622 -0
  164. package/dist/skills/index.d.ts +11 -0
  165. package/dist/skills/index.d.ts.map +1 -0
  166. package/dist/skills/index.js +129 -0
  167. package/dist/skills/index.js.map +1 -0
  168. package/dist/utils/character.js +6 -9
  169. package/dist/utils/character.js.map +1 -1
  170. package/dist/utils/contextManager.js +3 -7
  171. package/dist/utils/contextManager.js.map +1 -1
  172. package/dist/utils/inputbar.d.ts.map +1 -1
  173. package/dist/utils/inputbar.js +8 -1
  174. package/dist/utils/inputbar.js.map +1 -1
  175. package/dist/utils/output.d.ts.map +1 -1
  176. package/dist/utils/output.js +3 -35
  177. package/dist/utils/output.js.map +1 -1
  178. package/package.json +1 -1
@@ -0,0 +1,1048 @@
1
+ ---
2
+ name: nodejs-backend-patterns
3
+ description: Build production-ready Node.js backend services with Express/Fastify, implementing middleware patterns, error handling, authentication, database integration, and API design best practices.
4
+ ---
5
+
6
+ # Node.js Backend Patterns
7
+
8
+ Comprehensive guidance for building scalable, maintainable, and production-ready Node.js backend applications with modern frameworks, architectural patterns, and best practices.
9
+
10
+ ## When to Use This Skill
11
+
12
+ - Building REST APIs or GraphQL servers
13
+ - Creating microservices with Node.js
14
+ - Implementing authentication and authorization
15
+ - Designing scalable backend architectures
16
+ - Setting up middleware and error handling
17
+ - Integrating databases (SQL and NoSQL)
18
+ - Building real-time applications with WebSockets
19
+ - Implementing background job processing
20
+
21
+ ## Core Frameworks
22
+
23
+ ### Express.js - Minimalist Framework
24
+
25
+ **Basic Setup:**
26
+
27
+ ```typescript
28
+ import express, { Request, Response, NextFunction } from "express";
29
+ import helmet from "helmet";
30
+ import cors from "cors";
31
+ import compression from "compression";
32
+
33
+ const app = express();
34
+
35
+ // Security middleware
36
+ app.use(helmet());
37
+ app.use(cors({ origin: process.env.ALLOWED_ORIGINS?.split(",") }));
38
+ app.use(compression());
39
+
40
+ // Body parsing
41
+ app.use(express.json({ limit: "10mb" }));
42
+ app.use(express.urlencoded({ extended: true, limit: "10mb" }));
43
+
44
+ // Request logging
45
+ app.use((req: Request, res: Response, next: NextFunction) => {
46
+ console.log(`${req.method} ${req.path}`);
47
+ next();
48
+ });
49
+
50
+ const PORT = process.env.PORT || 3000;
51
+ app.listen(PORT, () => {
52
+ console.log(`Server running on port ${PORT}`);
53
+ });
54
+ ```
55
+
56
+ ### Fastify - High Performance Framework
57
+
58
+ **Basic Setup:**
59
+
60
+ ```typescript
61
+ import Fastify from "fastify";
62
+ import helmet from "@fastify/helmet";
63
+ import cors from "@fastify/cors";
64
+ import compress from "@fastify/compress";
65
+
66
+ const fastify = Fastify({
67
+ logger: {
68
+ level: process.env.LOG_LEVEL || "info",
69
+ transport: {
70
+ target: "pino-pretty",
71
+ options: { colorize: true },
72
+ },
73
+ },
74
+ });
75
+
76
+ // Plugins
77
+ await fastify.register(helmet);
78
+ await fastify.register(cors, { origin: true });
79
+ await fastify.register(compress);
80
+
81
+ // Type-safe routes with schema validation
82
+ fastify.post<{
83
+ Body: { name: string; email: string };
84
+ Reply: { id: string; name: string };
85
+ }>(
86
+ "/users",
87
+ {
88
+ schema: {
89
+ body: {
90
+ type: "object",
91
+ required: ["name", "email"],
92
+ properties: {
93
+ name: { type: "string", minLength: 1 },
94
+ email: { type: "string", format: "email" },
95
+ },
96
+ },
97
+ },
98
+ },
99
+ async (request, reply) => {
100
+ const { name, email } = request.body;
101
+ return { id: "123", name };
102
+ },
103
+ );
104
+
105
+ await fastify.listen({ port: 3000, host: "0.0.0.0" });
106
+ ```
107
+
108
+ ## Architectural Patterns
109
+
110
+ ### Pattern 1: Layered Architecture
111
+
112
+ **Structure:**
113
+
114
+ ```
115
+ src/
116
+ ├── controllers/ # Handle HTTP requests/responses
117
+ ├── services/ # Business logic
118
+ ├── repositories/ # Data access layer
119
+ ├── models/ # Data models
120
+ ├── middleware/ # Express/Fastify middleware
121
+ ├── routes/ # Route definitions
122
+ ├── utils/ # Helper functions
123
+ ├── config/ # Configuration
124
+ └── types/ # TypeScript types
125
+ ```
126
+
127
+ **Controller Layer:**
128
+
129
+ ```typescript
130
+ // controllers/user.controller.ts
131
+ import { Request, Response, NextFunction } from "express";
132
+ import { UserService } from "../services/user.service";
133
+ import { CreateUserDTO, UpdateUserDTO } from "../types/user.types";
134
+
135
+ export class UserController {
136
+ constructor(private userService: UserService) {}
137
+
138
+ async createUser(req: Request, res: Response, next: NextFunction) {
139
+ try {
140
+ const userData: CreateUserDTO = req.body;
141
+ const user = await this.userService.createUser(userData);
142
+ res.status(201).json(user);
143
+ } catch (error) {
144
+ next(error);
145
+ }
146
+ }
147
+
148
+ async getUser(req: Request, res: Response, next: NextFunction) {
149
+ try {
150
+ const { id } = req.params;
151
+ const user = await this.userService.getUserById(id);
152
+ res.json(user);
153
+ } catch (error) {
154
+ next(error);
155
+ }
156
+ }
157
+
158
+ async updateUser(req: Request, res: Response, next: NextFunction) {
159
+ try {
160
+ const { id } = req.params;
161
+ const updates: UpdateUserDTO = req.body;
162
+ const user = await this.userService.updateUser(id, updates);
163
+ res.json(user);
164
+ } catch (error) {
165
+ next(error);
166
+ }
167
+ }
168
+
169
+ async deleteUser(req: Request, res: Response, next: NextFunction) {
170
+ try {
171
+ const { id } = req.params;
172
+ await this.userService.deleteUser(id);
173
+ res.status(204).send();
174
+ } catch (error) {
175
+ next(error);
176
+ }
177
+ }
178
+ }
179
+ ```
180
+
181
+ **Service Layer:**
182
+
183
+ ```typescript
184
+ // services/user.service.ts
185
+ import { UserRepository } from "../repositories/user.repository";
186
+ import { CreateUserDTO, UpdateUserDTO, User } from "../types/user.types";
187
+ import { NotFoundError, ValidationError } from "../utils/errors";
188
+ import bcrypt from "bcrypt";
189
+
190
+ export class UserService {
191
+ constructor(private userRepository: UserRepository) {}
192
+
193
+ async createUser(userData: CreateUserDTO): Promise<User> {
194
+ // Validation
195
+ const existingUser = await this.userRepository.findByEmail(userData.email);
196
+ if (existingUser) {
197
+ throw new ValidationError("Email already exists");
198
+ }
199
+
200
+ // Hash password
201
+ const hashedPassword = await bcrypt.hash(userData.password, 10);
202
+
203
+ // Create user
204
+ const user = await this.userRepository.create({
205
+ ...userData,
206
+ password: hashedPassword,
207
+ });
208
+
209
+ // Remove password from response
210
+ const { password, ...userWithoutPassword } = user;
211
+ return userWithoutPassword as User;
212
+ }
213
+
214
+ async getUserById(id: string): Promise<User> {
215
+ const user = await this.userRepository.findById(id);
216
+ if (!user) {
217
+ throw new NotFoundError("User not found");
218
+ }
219
+ const { password, ...userWithoutPassword } = user;
220
+ return userWithoutPassword as User;
221
+ }
222
+
223
+ async updateUser(id: string, updates: UpdateUserDTO): Promise<User> {
224
+ const user = await this.userRepository.update(id, updates);
225
+ if (!user) {
226
+ throw new NotFoundError("User not found");
227
+ }
228
+ const { password, ...userWithoutPassword } = user;
229
+ return userWithoutPassword as User;
230
+ }
231
+
232
+ async deleteUser(id: string): Promise<void> {
233
+ const deleted = await this.userRepository.delete(id);
234
+ if (!deleted) {
235
+ throw new NotFoundError("User not found");
236
+ }
237
+ }
238
+ }
239
+ ```
240
+
241
+ **Repository Layer:**
242
+
243
+ ```typescript
244
+ // repositories/user.repository.ts
245
+ import { Pool } from "pg";
246
+ import { CreateUserDTO, UpdateUserDTO, UserEntity } from "../types/user.types";
247
+
248
+ export class UserRepository {
249
+ constructor(private db: Pool) {}
250
+
251
+ async create(
252
+ userData: CreateUserDTO & { password: string },
253
+ ): Promise<UserEntity> {
254
+ const query = `
255
+ INSERT INTO users (name, email, password)
256
+ VALUES ($1, $2, $3)
257
+ RETURNING id, name, email, password, created_at, updated_at
258
+ `;
259
+ const { rows } = await this.db.query(query, [
260
+ userData.name,
261
+ userData.email,
262
+ userData.password,
263
+ ]);
264
+ return rows[0];
265
+ }
266
+
267
+ async findById(id: string): Promise<UserEntity | null> {
268
+ const query = "SELECT * FROM users WHERE id = $1";
269
+ const { rows } = await this.db.query(query, [id]);
270
+ return rows[0] || null;
271
+ }
272
+
273
+ async findByEmail(email: string): Promise<UserEntity | null> {
274
+ const query = "SELECT * FROM users WHERE email = $1";
275
+ const { rows } = await this.db.query(query, [email]);
276
+ return rows[0] || null;
277
+ }
278
+
279
+ async update(id: string, updates: UpdateUserDTO): Promise<UserEntity | null> {
280
+ const fields = Object.keys(updates);
281
+ const values = Object.values(updates);
282
+
283
+ const setClause = fields
284
+ .map((field, idx) => `${field} = $${idx + 2}`)
285
+ .join(", ");
286
+
287
+ const query = `
288
+ UPDATE users
289
+ SET ${setClause}, updated_at = CURRENT_TIMESTAMP
290
+ WHERE id = $1
291
+ RETURNING *
292
+ `;
293
+
294
+ const { rows } = await this.db.query(query, [id, ...values]);
295
+ return rows[0] || null;
296
+ }
297
+
298
+ async delete(id: string): Promise<boolean> {
299
+ const query = "DELETE FROM users WHERE id = $1";
300
+ const { rowCount } = await this.db.query(query, [id]);
301
+ return rowCount > 0;
302
+ }
303
+ }
304
+ ```
305
+
306
+ ### Pattern 2: Dependency Injection
307
+
308
+ **DI Container:**
309
+
310
+ ```typescript
311
+ // di-container.ts
312
+ import { Pool } from "pg";
313
+ import { UserRepository } from "./repositories/user.repository";
314
+ import { UserService } from "./services/user.service";
315
+ import { UserController } from "./controllers/user.controller";
316
+ import { AuthService } from "./services/auth.service";
317
+
318
+ class Container {
319
+ private instances = new Map<string, any>();
320
+
321
+ register<T>(key: string, factory: () => T): void {
322
+ this.instances.set(key, factory);
323
+ }
324
+
325
+ resolve<T>(key: string): T {
326
+ const factory = this.instances.get(key);
327
+ if (!factory) {
328
+ throw new Error(`No factory registered for ${key}`);
329
+ }
330
+ return factory();
331
+ }
332
+
333
+ singleton<T>(key: string, factory: () => T): void {
334
+ let instance: T;
335
+ this.instances.set(key, () => {
336
+ if (!instance) {
337
+ instance = factory();
338
+ }
339
+ return instance;
340
+ });
341
+ }
342
+ }
343
+
344
+ export const container = new Container();
345
+
346
+ // Register dependencies
347
+ container.singleton(
348
+ "db",
349
+ () =>
350
+ new Pool({
351
+ host: process.env.DB_HOST,
352
+ port: parseInt(process.env.DB_PORT || "5432"),
353
+ database: process.env.DB_NAME,
354
+ user: process.env.DB_USER,
355
+ password: process.env.DB_PASSWORD,
356
+ max: 20,
357
+ idleTimeoutMillis: 30000,
358
+ connectionTimeoutMillis: 2000,
359
+ }),
360
+ );
361
+
362
+ container.singleton(
363
+ "userRepository",
364
+ () => new UserRepository(container.resolve("db")),
365
+ );
366
+
367
+ container.singleton(
368
+ "userService",
369
+ () => new UserService(container.resolve("userRepository")),
370
+ );
371
+
372
+ container.register(
373
+ "userController",
374
+ () => new UserController(container.resolve("userService")),
375
+ );
376
+
377
+ container.singleton(
378
+ "authService",
379
+ () => new AuthService(container.resolve("userRepository")),
380
+ );
381
+ ```
382
+
383
+ ## Middleware Patterns
384
+
385
+ ### Authentication Middleware
386
+
387
+ ```typescript
388
+ // middleware/auth.middleware.ts
389
+ import { Request, Response, NextFunction } from "express";
390
+ import jwt from "jsonwebtoken";
391
+ import { UnauthorizedError } from "../utils/errors";
392
+
393
+ interface JWTPayload {
394
+ userId: string;
395
+ email: string;
396
+ }
397
+
398
+ declare global {
399
+ namespace Express {
400
+ interface Request {
401
+ user?: JWTPayload;
402
+ }
403
+ }
404
+ }
405
+
406
+ export const authenticate = async (
407
+ req: Request,
408
+ res: Response,
409
+ next: NextFunction,
410
+ ) => {
411
+ try {
412
+ const token = req.headers.authorization?.replace("Bearer ", "");
413
+
414
+ if (!token) {
415
+ throw new UnauthorizedError("No token provided");
416
+ }
417
+
418
+ const payload = jwt.verify(token, process.env.JWT_SECRET!) as JWTPayload;
419
+
420
+ req.user = payload;
421
+ next();
422
+ } catch (error) {
423
+ next(new UnauthorizedError("Invalid token"));
424
+ }
425
+ };
426
+
427
+ export const authorize = (...roles: string[]) => {
428
+ return async (req: Request, res: Response, next: NextFunction) => {
429
+ if (!req.user) {
430
+ return next(new UnauthorizedError("Not authenticated"));
431
+ }
432
+
433
+ // Check if user has required role
434
+ const hasRole = roles.some((role) => req.user?.roles?.includes(role));
435
+
436
+ if (!hasRole) {
437
+ return next(new UnauthorizedError("Insufficient permissions"));
438
+ }
439
+
440
+ next();
441
+ };
442
+ };
443
+ ```
444
+
445
+ ### Validation Middleware
446
+
447
+ ```typescript
448
+ // middleware/validation.middleware.ts
449
+ import { Request, Response, NextFunction } from "express";
450
+ import { AnyZodObject, ZodError } from "zod";
451
+ import { ValidationError } from "../utils/errors";
452
+
453
+ export const validate = (schema: AnyZodObject) => {
454
+ return async (req: Request, res: Response, next: NextFunction) => {
455
+ try {
456
+ await schema.parseAsync({
457
+ body: req.body,
458
+ query: req.query,
459
+ params: req.params,
460
+ });
461
+ next();
462
+ } catch (error) {
463
+ if (error instanceof ZodError) {
464
+ const errors = error.errors.map((err) => ({
465
+ field: err.path.join("."),
466
+ message: err.message,
467
+ }));
468
+ next(new ValidationError("Validation failed", errors));
469
+ } else {
470
+ next(error);
471
+ }
472
+ }
473
+ };
474
+ };
475
+
476
+ // Usage with Zod
477
+ import { z } from "zod";
478
+
479
+ const createUserSchema = z.object({
480
+ body: z.object({
481
+ name: z.string().min(1),
482
+ email: z.string().email(),
483
+ password: z.string().min(8),
484
+ }),
485
+ });
486
+
487
+ router.post("/users", validate(createUserSchema), userController.createUser);
488
+ ```
489
+
490
+ ### Rate Limiting Middleware
491
+
492
+ ```typescript
493
+ // middleware/rate-limit.middleware.ts
494
+ import rateLimit from "express-rate-limit";
495
+ import RedisStore from "rate-limit-redis";
496
+ import Redis from "ioredis";
497
+
498
+ const redis = new Redis({
499
+ host: process.env.REDIS_HOST,
500
+ port: parseInt(process.env.REDIS_PORT || "6379"),
501
+ });
502
+
503
+ export const apiLimiter = rateLimit({
504
+ store: new RedisStore({
505
+ client: redis,
506
+ prefix: "rl:",
507
+ }),
508
+ windowMs: 15 * 60 * 1000, // 15 minutes
509
+ max: 100, // Limit each IP to 100 requests per windowMs
510
+ message: "Too many requests from this IP, please try again later",
511
+ standardHeaders: true,
512
+ legacyHeaders: false,
513
+ });
514
+
515
+ export const authLimiter = rateLimit({
516
+ store: new RedisStore({
517
+ client: redis,
518
+ prefix: "rl:auth:",
519
+ }),
520
+ windowMs: 15 * 60 * 1000,
521
+ max: 5, // Stricter limit for auth endpoints
522
+ skipSuccessfulRequests: true,
523
+ });
524
+ ```
525
+
526
+ ### Request Logging Middleware
527
+
528
+ ```typescript
529
+ // middleware/logger.middleware.ts
530
+ import { Request, Response, NextFunction } from "express";
531
+ import pino from "pino";
532
+
533
+ const logger = pino({
534
+ level: process.env.LOG_LEVEL || "info",
535
+ transport: {
536
+ target: "pino-pretty",
537
+ options: { colorize: true },
538
+ },
539
+ });
540
+
541
+ export const requestLogger = (
542
+ req: Request,
543
+ res: Response,
544
+ next: NextFunction,
545
+ ) => {
546
+ const start = Date.now();
547
+
548
+ // Log response when finished
549
+ res.on("finish", () => {
550
+ const duration = Date.now() - start;
551
+ logger.info({
552
+ method: req.method,
553
+ url: req.url,
554
+ status: res.statusCode,
555
+ duration: `${duration}ms`,
556
+ userAgent: req.headers["user-agent"],
557
+ ip: req.ip,
558
+ });
559
+ });
560
+
561
+ next();
562
+ };
563
+
564
+ export { logger };
565
+ ```
566
+
567
+ ## Error Handling
568
+
569
+ ### Custom Error Classes
570
+
571
+ ```typescript
572
+ // utils/errors.ts
573
+ export class AppError extends Error {
574
+ constructor(
575
+ public message: string,
576
+ public statusCode: number = 500,
577
+ public isOperational: boolean = true,
578
+ ) {
579
+ super(message);
580
+ Object.setPrototypeOf(this, AppError.prototype);
581
+ Error.captureStackTrace(this, this.constructor);
582
+ }
583
+ }
584
+
585
+ export class ValidationError extends AppError {
586
+ constructor(
587
+ public message: string,
588
+ public errors?: any[],
589
+ ) {
590
+ super(message, 400);
591
+ }
592
+ }
593
+
594
+ export class NotFoundError extends AppError {
595
+ constructor(message: string = "Resource not found") {
596
+ super(message, 404);
597
+ }
598
+ }
599
+
600
+ export class UnauthorizedError extends AppError {
601
+ constructor(message: string = "Unauthorized") {
602
+ super(message, 401);
603
+ }
604
+ }
605
+
606
+ export class ForbiddenError extends AppError {
607
+ constructor(message: string = "Forbidden") {
608
+ super(message, 403);
609
+ }
610
+ }
611
+
612
+ export class ConflictError extends AppError {
613
+ constructor(message: string) {
614
+ super(message, 409);
615
+ }
616
+ }
617
+ ```
618
+
619
+ ### Global Error Handler
620
+
621
+ ```typescript
622
+ // middleware/error-handler.ts
623
+ import { Request, Response, NextFunction } from "express";
624
+ import { AppError } from "../utils/errors";
625
+ import { logger } from "./logger.middleware";
626
+
627
+ export const errorHandler = (
628
+ err: Error,
629
+ req: Request,
630
+ res: Response,
631
+ next: NextFunction,
632
+ ) => {
633
+ if (err instanceof AppError) {
634
+ return res.status(err.statusCode).json({
635
+ status: "error",
636
+ message: err.message,
637
+ ...(err instanceof ValidationError && { errors: err.errors }),
638
+ });
639
+ }
640
+
641
+ // Log unexpected errors
642
+ logger.error({
643
+ error: err.message,
644
+ stack: err.stack,
645
+ url: req.url,
646
+ method: req.method,
647
+ });
648
+
649
+ // Don't leak error details in production
650
+ const message =
651
+ process.env.NODE_ENV === "production"
652
+ ? "Internal server error"
653
+ : err.message;
654
+
655
+ res.status(500).json({
656
+ status: "error",
657
+ message,
658
+ });
659
+ };
660
+
661
+ // Async error wrapper
662
+ export const asyncHandler = (
663
+ fn: (req: Request, res: Response, next: NextFunction) => Promise<any>,
664
+ ) => {
665
+ return (req: Request, res: Response, next: NextFunction) => {
666
+ Promise.resolve(fn(req, res, next)).catch(next);
667
+ };
668
+ };
669
+ ```
670
+
671
+ ## Database Patterns
672
+
673
+ ### PostgreSQL with Connection Pool
674
+
675
+ ```typescript
676
+ // config/database.ts
677
+ import { Pool, PoolConfig } from "pg";
678
+
679
+ const poolConfig: PoolConfig = {
680
+ host: process.env.DB_HOST,
681
+ port: parseInt(process.env.DB_PORT || "5432"),
682
+ database: process.env.DB_NAME,
683
+ user: process.env.DB_USER,
684
+ password: process.env.DB_PASSWORD,
685
+ max: 20,
686
+ idleTimeoutMillis: 30000,
687
+ connectionTimeoutMillis: 2000,
688
+ };
689
+
690
+ export const pool = new Pool(poolConfig);
691
+
692
+ // Test connection
693
+ pool.on("connect", () => {
694
+ console.log("Database connected");
695
+ });
696
+
697
+ pool.on("error", (err) => {
698
+ console.error("Unexpected database error", err);
699
+ process.exit(-1);
700
+ });
701
+
702
+ // Graceful shutdown
703
+ export const closeDatabase = async () => {
704
+ await pool.end();
705
+ console.log("Database connection closed");
706
+ };
707
+ ```
708
+
709
+ ### MongoDB with Mongoose
710
+
711
+ ```typescript
712
+ // config/mongoose.ts
713
+ import mongoose from "mongoose";
714
+
715
+ const connectDB = async () => {
716
+ try {
717
+ await mongoose.connect(process.env.MONGODB_URI!, {
718
+ maxPoolSize: 10,
719
+ serverSelectionTimeoutMS: 5000,
720
+ socketTimeoutMS: 45000,
721
+ });
722
+
723
+ console.log("MongoDB connected");
724
+ } catch (error) {
725
+ console.error("MongoDB connection error:", error);
726
+ process.exit(1);
727
+ }
728
+ };
729
+
730
+ mongoose.connection.on("disconnected", () => {
731
+ console.log("MongoDB disconnected");
732
+ });
733
+
734
+ mongoose.connection.on("error", (err) => {
735
+ console.error("MongoDB error:", err);
736
+ });
737
+
738
+ export { connectDB };
739
+
740
+ // Model example
741
+ import { Schema, model, Document } from "mongoose";
742
+
743
+ interface IUser extends Document {
744
+ name: string;
745
+ email: string;
746
+ password: string;
747
+ createdAt: Date;
748
+ updatedAt: Date;
749
+ }
750
+
751
+ const userSchema = new Schema<IUser>(
752
+ {
753
+ name: { type: String, required: true },
754
+ email: { type: String, required: true, unique: true },
755
+ password: { type: String, required: true },
756
+ },
757
+ {
758
+ timestamps: true,
759
+ },
760
+ );
761
+
762
+ // Indexes
763
+ userSchema.index({ email: 1 });
764
+
765
+ export const User = model<IUser>("User", userSchema);
766
+ ```
767
+
768
+ ### Transaction Pattern
769
+
770
+ ```typescript
771
+ // services/order.service.ts
772
+ import { Pool } from "pg";
773
+
774
+ export class OrderService {
775
+ constructor(private db: Pool) {}
776
+
777
+ async createOrder(userId: string, items: any[]) {
778
+ const client = await this.db.connect();
779
+
780
+ try {
781
+ await client.query("BEGIN");
782
+
783
+ // Create order
784
+ const orderResult = await client.query(
785
+ "INSERT INTO orders (user_id, total) VALUES ($1, $2) RETURNING id",
786
+ [userId, calculateTotal(items)],
787
+ );
788
+ const orderId = orderResult.rows[0].id;
789
+
790
+ // Create order items
791
+ for (const item of items) {
792
+ await client.query(
793
+ "INSERT INTO order_items (order_id, product_id, quantity, price) VALUES ($1, $2, $3, $4)",
794
+ [orderId, item.productId, item.quantity, item.price],
795
+ );
796
+
797
+ // Update inventory
798
+ await client.query(
799
+ "UPDATE products SET stock = stock - $1 WHERE id = $2",
800
+ [item.quantity, item.productId],
801
+ );
802
+ }
803
+
804
+ await client.query("COMMIT");
805
+ return orderId;
806
+ } catch (error) {
807
+ await client.query("ROLLBACK");
808
+ throw error;
809
+ } finally {
810
+ client.release();
811
+ }
812
+ }
813
+ }
814
+ ```
815
+
816
+ ## Authentication & Authorization
817
+
818
+ ### JWT Authentication
819
+
820
+ ```typescript
821
+ // services/auth.service.ts
822
+ import jwt from "jsonwebtoken";
823
+ import bcrypt from "bcrypt";
824
+ import { UserRepository } from "../repositories/user.repository";
825
+ import { UnauthorizedError } from "../utils/errors";
826
+
827
+ export class AuthService {
828
+ constructor(private userRepository: UserRepository) {}
829
+
830
+ async login(email: string, password: string) {
831
+ const user = await this.userRepository.findByEmail(email);
832
+
833
+ if (!user) {
834
+ throw new UnauthorizedError("Invalid credentials");
835
+ }
836
+
837
+ const isValid = await bcrypt.compare(password, user.password);
838
+
839
+ if (!isValid) {
840
+ throw new UnauthorizedError("Invalid credentials");
841
+ }
842
+
843
+ const token = this.generateToken({
844
+ userId: user.id,
845
+ email: user.email,
846
+ });
847
+
848
+ const refreshToken = this.generateRefreshToken({
849
+ userId: user.id,
850
+ });
851
+
852
+ return {
853
+ token,
854
+ refreshToken,
855
+ user: {
856
+ id: user.id,
857
+ name: user.name,
858
+ email: user.email,
859
+ },
860
+ };
861
+ }
862
+
863
+ async refreshToken(refreshToken: string) {
864
+ try {
865
+ const payload = jwt.verify(
866
+ refreshToken,
867
+ process.env.REFRESH_TOKEN_SECRET!,
868
+ ) as { userId: string };
869
+
870
+ const user = await this.userRepository.findById(payload.userId);
871
+
872
+ if (!user) {
873
+ throw new UnauthorizedError("User not found");
874
+ }
875
+
876
+ const token = this.generateToken({
877
+ userId: user.id,
878
+ email: user.email,
879
+ });
880
+
881
+ return { token };
882
+ } catch (error) {
883
+ throw new UnauthorizedError("Invalid refresh token");
884
+ }
885
+ }
886
+
887
+ private generateToken(payload: any): string {
888
+ return jwt.sign(payload, process.env.JWT_SECRET!, {
889
+ expiresIn: "15m",
890
+ });
891
+ }
892
+
893
+ private generateRefreshToken(payload: any): string {
894
+ return jwt.sign(payload, process.env.REFRESH_TOKEN_SECRET!, {
895
+ expiresIn: "7d",
896
+ });
897
+ }
898
+ }
899
+ ```
900
+
901
+ ## Caching Strategies
902
+
903
+ ```typescript
904
+ // utils/cache.ts
905
+ import Redis from "ioredis";
906
+
907
+ const redis = new Redis({
908
+ host: process.env.REDIS_HOST,
909
+ port: parseInt(process.env.REDIS_PORT || "6379"),
910
+ retryStrategy: (times) => {
911
+ const delay = Math.min(times * 50, 2000);
912
+ return delay;
913
+ },
914
+ });
915
+
916
+ export class CacheService {
917
+ async get<T>(key: string): Promise<T | null> {
918
+ const data = await redis.get(key);
919
+ return data ? JSON.parse(data) : null;
920
+ }
921
+
922
+ async set(key: string, value: any, ttl?: number): Promise<void> {
923
+ const serialized = JSON.stringify(value);
924
+ if (ttl) {
925
+ await redis.setex(key, ttl, serialized);
926
+ } else {
927
+ await redis.set(key, serialized);
928
+ }
929
+ }
930
+
931
+ async delete(key: string): Promise<void> {
932
+ await redis.del(key);
933
+ }
934
+
935
+ async invalidatePattern(pattern: string): Promise<void> {
936
+ const keys = await redis.keys(pattern);
937
+ if (keys.length > 0) {
938
+ await redis.del(...keys);
939
+ }
940
+ }
941
+ }
942
+
943
+ // Cache decorator
944
+ export function Cacheable(ttl: number = 300) {
945
+ return function (
946
+ target: any,
947
+ propertyKey: string,
948
+ descriptor: PropertyDescriptor,
949
+ ) {
950
+ const originalMethod = descriptor.value;
951
+
952
+ descriptor.value = async function (...args: any[]) {
953
+ const cache = new CacheService();
954
+ const cacheKey = `${propertyKey}:${JSON.stringify(args)}`;
955
+
956
+ const cached = await cache.get(cacheKey);
957
+ if (cached) {
958
+ return cached;
959
+ }
960
+
961
+ const result = await originalMethod.apply(this, args);
962
+ await cache.set(cacheKey, result, ttl);
963
+
964
+ return result;
965
+ };
966
+
967
+ return descriptor;
968
+ };
969
+ }
970
+ ```
971
+
972
+ ## API Response Format
973
+
974
+ ```typescript
975
+ // utils/response.ts
976
+ import { Response } from "express";
977
+
978
+ export class ApiResponse {
979
+ static success<T>(
980
+ res: Response,
981
+ data: T,
982
+ message?: string,
983
+ statusCode = 200,
984
+ ) {
985
+ return res.status(statusCode).json({
986
+ status: "success",
987
+ message,
988
+ data,
989
+ });
990
+ }
991
+
992
+ static error(res: Response, message: string, statusCode = 500, errors?: any) {
993
+ return res.status(statusCode).json({
994
+ status: "error",
995
+ message,
996
+ ...(errors && { errors }),
997
+ });
998
+ }
999
+
1000
+ static paginated<T>(
1001
+ res: Response,
1002
+ data: T[],
1003
+ page: number,
1004
+ limit: number,
1005
+ total: number,
1006
+ ) {
1007
+ return res.json({
1008
+ status: "success",
1009
+ data,
1010
+ pagination: {
1011
+ page,
1012
+ limit,
1013
+ total,
1014
+ pages: Math.ceil(total / limit),
1015
+ },
1016
+ });
1017
+ }
1018
+ }
1019
+ ```
1020
+
1021
+ ## Best Practices
1022
+
1023
+ 1. **Use TypeScript**: Type safety prevents runtime errors
1024
+ 2. **Implement proper error handling**: Use custom error classes
1025
+ 3. **Validate input**: Use libraries like Zod or Joi
1026
+ 4. **Use environment variables**: Never hardcode secrets
1027
+ 5. **Implement logging**: Use structured logging (Pino, Winston)
1028
+ 6. **Add rate limiting**: Prevent abuse
1029
+ 7. **Use HTTPS**: Always in production
1030
+ 8. **Implement CORS properly**: Don't use `*` in production
1031
+ 9. **Use dependency injection**: Easier testing and maintenance
1032
+ 10. **Write tests**: Unit, integration, and E2E tests
1033
+ 11. **Handle graceful shutdown**: Clean up resources
1034
+ 12. **Use connection pooling**: For databases
1035
+ 13. **Implement health checks**: For monitoring
1036
+ 14. **Use compression**: Reduce response size
1037
+ 15. **Monitor performance**: Use APM tools
1038
+
1039
+ ## Testing Patterns
1040
+
1041
+ See `javascript-testing-patterns` skill for comprehensive testing guidance.
1042
+
1043
+ ## Resources
1044
+
1045
+ - **Node.js Best Practices**: https://github.com/goldbergyoni/nodebestpractices
1046
+ - **Express.js Guide**: https://expressjs.com/en/guide/
1047
+ - **Fastify Documentation**: https://www.fastify.io/docs/
1048
+ - **TypeScript Node Starter**: https://github.com/microsoft/TypeScript-Node-Starter