agentic-team-templates 0.3.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.
Files changed (103) hide show
  1. package/README.md +280 -0
  2. package/bin/cli.js +5 -0
  3. package/package.json +47 -0
  4. package/src/index.js +521 -0
  5. package/templates/_shared/code-quality.md +162 -0
  6. package/templates/_shared/communication.md +114 -0
  7. package/templates/_shared/core-principles.md +62 -0
  8. package/templates/_shared/git-workflow.md +165 -0
  9. package/templates/_shared/security-fundamentals.md +173 -0
  10. package/templates/blockchain/.cursorrules/defi-patterns.md +520 -0
  11. package/templates/blockchain/.cursorrules/gas-optimization.md +339 -0
  12. package/templates/blockchain/.cursorrules/overview.md +130 -0
  13. package/templates/blockchain/.cursorrules/security.md +318 -0
  14. package/templates/blockchain/.cursorrules/smart-contracts.md +364 -0
  15. package/templates/blockchain/.cursorrules/testing.md +415 -0
  16. package/templates/blockchain/.cursorrules/web3-integration.md +538 -0
  17. package/templates/blockchain/CLAUDE.md +389 -0
  18. package/templates/cli-tools/.cursorrules/architecture.md +412 -0
  19. package/templates/cli-tools/.cursorrules/arguments.md +406 -0
  20. package/templates/cli-tools/.cursorrules/distribution.md +546 -0
  21. package/templates/cli-tools/.cursorrules/error-handling.md +455 -0
  22. package/templates/cli-tools/.cursorrules/overview.md +136 -0
  23. package/templates/cli-tools/.cursorrules/testing.md +537 -0
  24. package/templates/cli-tools/.cursorrules/user-experience.md +545 -0
  25. package/templates/cli-tools/CLAUDE.md +356 -0
  26. package/templates/data-engineering/.cursorrules/data-modeling.md +367 -0
  27. package/templates/data-engineering/.cursorrules/data-quality.md +455 -0
  28. package/templates/data-engineering/.cursorrules/overview.md +85 -0
  29. package/templates/data-engineering/.cursorrules/performance.md +339 -0
  30. package/templates/data-engineering/.cursorrules/pipeline-design.md +280 -0
  31. package/templates/data-engineering/.cursorrules/security.md +460 -0
  32. package/templates/data-engineering/.cursorrules/testing.md +452 -0
  33. package/templates/data-engineering/CLAUDE.md +974 -0
  34. package/templates/devops-sre/.cursorrules/capacity-planning.md +653 -0
  35. package/templates/devops-sre/.cursorrules/change-management.md +584 -0
  36. package/templates/devops-sre/.cursorrules/chaos-engineering.md +651 -0
  37. package/templates/devops-sre/.cursorrules/disaster-recovery.md +641 -0
  38. package/templates/devops-sre/.cursorrules/incident-management.md +565 -0
  39. package/templates/devops-sre/.cursorrules/observability.md +714 -0
  40. package/templates/devops-sre/.cursorrules/overview.md +230 -0
  41. package/templates/devops-sre/.cursorrules/postmortems.md +588 -0
  42. package/templates/devops-sre/.cursorrules/runbooks.md +760 -0
  43. package/templates/devops-sre/.cursorrules/slo-sli.md +617 -0
  44. package/templates/devops-sre/.cursorrules/toil-reduction.md +567 -0
  45. package/templates/devops-sre/CLAUDE.md +1007 -0
  46. package/templates/documentation/.cursorrules/adr.md +277 -0
  47. package/templates/documentation/.cursorrules/api-documentation.md +411 -0
  48. package/templates/documentation/.cursorrules/code-comments.md +253 -0
  49. package/templates/documentation/.cursorrules/maintenance.md +260 -0
  50. package/templates/documentation/.cursorrules/overview.md +82 -0
  51. package/templates/documentation/.cursorrules/readme-standards.md +306 -0
  52. package/templates/documentation/CLAUDE.md +120 -0
  53. package/templates/fullstack/.cursorrules/api-contracts.md +331 -0
  54. package/templates/fullstack/.cursorrules/architecture.md +298 -0
  55. package/templates/fullstack/.cursorrules/overview.md +109 -0
  56. package/templates/fullstack/.cursorrules/shared-types.md +348 -0
  57. package/templates/fullstack/.cursorrules/testing.md +386 -0
  58. package/templates/fullstack/CLAUDE.md +349 -0
  59. package/templates/ml-ai/.cursorrules/data-engineering.md +483 -0
  60. package/templates/ml-ai/.cursorrules/deployment.md +601 -0
  61. package/templates/ml-ai/.cursorrules/model-development.md +538 -0
  62. package/templates/ml-ai/.cursorrules/monitoring.md +658 -0
  63. package/templates/ml-ai/.cursorrules/overview.md +131 -0
  64. package/templates/ml-ai/.cursorrules/security.md +637 -0
  65. package/templates/ml-ai/.cursorrules/testing.md +678 -0
  66. package/templates/ml-ai/CLAUDE.md +1136 -0
  67. package/templates/mobile/.cursorrules/navigation.md +246 -0
  68. package/templates/mobile/.cursorrules/offline-first.md +302 -0
  69. package/templates/mobile/.cursorrules/overview.md +71 -0
  70. package/templates/mobile/.cursorrules/performance.md +345 -0
  71. package/templates/mobile/.cursorrules/testing.md +339 -0
  72. package/templates/mobile/CLAUDE.md +233 -0
  73. package/templates/platform-engineering/.cursorrules/ci-cd.md +778 -0
  74. package/templates/platform-engineering/.cursorrules/developer-experience.md +632 -0
  75. package/templates/platform-engineering/.cursorrules/infrastructure-as-code.md +600 -0
  76. package/templates/platform-engineering/.cursorrules/kubernetes.md +710 -0
  77. package/templates/platform-engineering/.cursorrules/observability.md +747 -0
  78. package/templates/platform-engineering/.cursorrules/overview.md +215 -0
  79. package/templates/platform-engineering/.cursorrules/security.md +855 -0
  80. package/templates/platform-engineering/.cursorrules/testing.md +878 -0
  81. package/templates/platform-engineering/CLAUDE.md +850 -0
  82. package/templates/utility-agent/.cursorrules/action-control.md +284 -0
  83. package/templates/utility-agent/.cursorrules/context-management.md +186 -0
  84. package/templates/utility-agent/.cursorrules/hallucination-prevention.md +253 -0
  85. package/templates/utility-agent/.cursorrules/overview.md +78 -0
  86. package/templates/utility-agent/.cursorrules/token-optimization.md +369 -0
  87. package/templates/utility-agent/CLAUDE.md +513 -0
  88. package/templates/web-backend/.cursorrules/api-design.md +255 -0
  89. package/templates/web-backend/.cursorrules/authentication.md +309 -0
  90. package/templates/web-backend/.cursorrules/database-patterns.md +298 -0
  91. package/templates/web-backend/.cursorrules/error-handling.md +366 -0
  92. package/templates/web-backend/.cursorrules/overview.md +69 -0
  93. package/templates/web-backend/.cursorrules/security.md +358 -0
  94. package/templates/web-backend/.cursorrules/testing.md +395 -0
  95. package/templates/web-backend/CLAUDE.md +366 -0
  96. package/templates/web-frontend/.cursorrules/accessibility.md +296 -0
  97. package/templates/web-frontend/.cursorrules/component-patterns.md +204 -0
  98. package/templates/web-frontend/.cursorrules/overview.md +72 -0
  99. package/templates/web-frontend/.cursorrules/performance.md +325 -0
  100. package/templates/web-frontend/.cursorrules/state-management.md +227 -0
  101. package/templates/web-frontend/.cursorrules/styling.md +271 -0
  102. package/templates/web-frontend/.cursorrules/testing.md +311 -0
  103. package/templates/web-frontend/CLAUDE.md +399 -0
@@ -0,0 +1,298 @@
1
+ # Database Patterns
2
+
3
+ Best practices for working with databases in backend applications.
4
+
5
+ ## General Principles
6
+
7
+ ### 1. Use a Data Access Layer
8
+
9
+ Separate database operations from business logic.
10
+
11
+ ```ts
12
+ // repository/userRepository.ts
13
+ export const userRepository = {
14
+ async findById(id: string): Promise<User | null> {
15
+ return db.user.findUnique({ where: { id } });
16
+ },
17
+
18
+ async create(data: CreateUserInput): Promise<User> {
19
+ return db.user.create({ data });
20
+ },
21
+
22
+ async update(id: string, data: UpdateUserInput): Promise<User> {
23
+ return db.user.update({ where: { id }, data });
24
+ },
25
+ };
26
+
27
+ // services/userService.ts
28
+ export const createUser = async (input: CreateUserInput) => {
29
+ // Business logic here
30
+ const validated = validateUserInput(input);
31
+ return userRepository.create(validated);
32
+ };
33
+ ```
34
+
35
+ ### 2. Use Transactions for Related Operations
36
+
37
+ ```ts
38
+ // Good: Atomic operation
39
+ await db.$transaction(async (tx) => {
40
+ const order = await tx.order.create({ data: orderData });
41
+ await tx.inventory.update({
42
+ where: { productId: order.productId },
43
+ data: { quantity: { decrement: order.quantity } },
44
+ });
45
+ await tx.payment.create({ data: { orderId: order.id, ...paymentData } });
46
+ });
47
+
48
+ // Bad: Non-atomic, can leave inconsistent state
49
+ const order = await db.order.create({ data: orderData });
50
+ await db.inventory.update({ ... }); // What if this fails?
51
+ await db.payment.create({ ... });
52
+ ```
53
+
54
+ ### 3. Handle Connection Errors
55
+
56
+ ```ts
57
+ const connectWithRetry = async (maxRetries = 5) => {
58
+ for (let i = 0; i < maxRetries; i++) {
59
+ try {
60
+ await db.$connect();
61
+ return;
62
+ } catch (error) {
63
+ if (i === maxRetries - 1) throw error;
64
+ await sleep(Math.pow(2, i) * 1000); // Exponential backoff
65
+ }
66
+ }
67
+ };
68
+ ```
69
+
70
+ ## Query Optimization
71
+
72
+ ### Select Only Needed Fields
73
+
74
+ ```ts
75
+ // Good: Select specific fields
76
+ const users = await db.user.findMany({
77
+ select: { id: true, name: true, email: true },
78
+ });
79
+
80
+ // Bad: Select everything when you don't need it
81
+ const users = await db.user.findMany(); // Returns all fields including large blobs
82
+ ```
83
+
84
+ ### Use Pagination
85
+
86
+ ```ts
87
+ // Offset-based (simple, but slow for large offsets)
88
+ const users = await db.user.findMany({
89
+ skip: (page - 1) * limit,
90
+ take: limit,
91
+ orderBy: { createdAt: 'desc' },
92
+ });
93
+
94
+ // Cursor-based (better for large datasets)
95
+ const users = await db.user.findMany({
96
+ take: limit,
97
+ cursor: cursor ? { id: cursor } : undefined,
98
+ orderBy: { id: 'asc' },
99
+ });
100
+ ```
101
+
102
+ ### Avoid N+1 Queries
103
+
104
+ ```ts
105
+ // Bad: N+1 queries
106
+ const posts = await db.post.findMany();
107
+ for (const post of posts) {
108
+ post.author = await db.user.findUnique({ where: { id: post.authorId } });
109
+ }
110
+
111
+ // Good: Single query with include
112
+ const posts = await db.post.findMany({
113
+ include: { author: true },
114
+ });
115
+
116
+ // Good: Batch query
117
+ const posts = await db.post.findMany();
118
+ const authorIds = [...new Set(posts.map(p => p.authorId))];
119
+ const authors = await db.user.findMany({ where: { id: { in: authorIds } } });
120
+ const authorMap = new Map(authors.map(a => [a.id, a]));
121
+ posts.forEach(p => p.author = authorMap.get(p.authorId));
122
+ ```
123
+
124
+ ### Use Indexes
125
+
126
+ ```sql
127
+ -- Create indexes for frequently queried columns
128
+ CREATE INDEX idx_users_email ON users(email);
129
+ CREATE INDEX idx_posts_user_created ON posts(user_id, created_at);
130
+
131
+ -- Composite index for common query patterns
132
+ CREATE INDEX idx_orders_status_date ON orders(status, created_at);
133
+ ```
134
+
135
+ ## Migrations
136
+
137
+ ### Version Control Migrations
138
+
139
+ ```
140
+ migrations/
141
+ ├── 001_create_users_table.sql
142
+ ├── 002_add_email_index.sql
143
+ ├── 003_create_posts_table.sql
144
+ └── 004_add_user_avatar.sql
145
+ ```
146
+
147
+ ### Write Reversible Migrations
148
+
149
+ ```sql
150
+ -- migrations/003_create_posts_table.sql
151
+
152
+ -- Up
153
+ CREATE TABLE posts (
154
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
155
+ title VARCHAR(255) NOT NULL,
156
+ content TEXT,
157
+ user_id UUID REFERENCES users(id),
158
+ created_at TIMESTAMP DEFAULT NOW()
159
+ );
160
+
161
+ -- Down
162
+ DROP TABLE posts;
163
+ ```
164
+
165
+ ### Test Migrations
166
+
167
+ - Test in staging before production
168
+ - Have a rollback plan
169
+ - Consider zero-downtime migrations for large tables
170
+
171
+ ## Connection Pooling
172
+
173
+ ### Configure Pool Size
174
+
175
+ ```ts
176
+ // Match pool size to expected concurrency
177
+ const pool = new Pool({
178
+ host: process.env.DB_HOST,
179
+ max: 20, // Max connections
180
+ idleTimeoutMillis: 30000,
181
+ connectionTimeoutMillis: 2000,
182
+ });
183
+ ```
184
+
185
+ ### Handle Pool Exhaustion
186
+
187
+ ```ts
188
+ // Set appropriate timeouts
189
+ const result = await Promise.race([
190
+ db.query(sql),
191
+ new Promise((_, reject) =>
192
+ setTimeout(() => reject(new Error('Query timeout')), 5000)
193
+ ),
194
+ ]);
195
+ ```
196
+
197
+ ## Data Integrity
198
+
199
+ ### Use Constraints
200
+
201
+ ```sql
202
+ -- Primary keys
203
+ PRIMARY KEY (id)
204
+
205
+ -- Foreign keys with appropriate actions
206
+ FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
207
+
208
+ -- Unique constraints
209
+ UNIQUE (email)
210
+
211
+ -- Check constraints
212
+ CHECK (price >= 0)
213
+ CHECK (status IN ('pending', 'active', 'completed'))
214
+ ```
215
+
216
+ ### Use Appropriate Data Types
217
+
218
+ ```sql
219
+ -- Good: Appropriate types
220
+ id UUID PRIMARY KEY
221
+ email VARCHAR(255) NOT NULL
222
+ price DECIMAL(10, 2)
223
+ created_at TIMESTAMP WITH TIME ZONE
224
+
225
+ -- Bad: Wrong types
226
+ id TEXT
227
+ price FLOAT -- Precision issues
228
+ created_at VARCHAR(50)
229
+ ```
230
+
231
+ ## Soft Deletes (When Needed)
232
+
233
+ ```ts
234
+ // Schema
235
+ model User {
236
+ id String @id
237
+ email String @unique
238
+ deletedAt DateTime?
239
+ }
240
+
241
+ // Query active records
242
+ const activeUsers = await db.user.findMany({
243
+ where: { deletedAt: null },
244
+ });
245
+
246
+ // Soft delete
247
+ await db.user.update({
248
+ where: { id },
249
+ data: { deletedAt: new Date() },
250
+ });
251
+ ```
252
+
253
+ ## Security
254
+
255
+ ### Parameterized Queries
256
+
257
+ ```ts
258
+ // Good: Parameterized
259
+ const user = await db.query(
260
+ 'SELECT * FROM users WHERE id = $1',
261
+ [userId]
262
+ );
263
+
264
+ // Bad: SQL injection vulnerability
265
+ const user = await db.query(
266
+ `SELECT * FROM users WHERE id = '${userId}'`
267
+ );
268
+ ```
269
+
270
+ ### Encrypt Sensitive Data
271
+
272
+ ```ts
273
+ // Encrypt at rest
274
+ const encrypted = encrypt(sensitiveData, encryptionKey);
275
+ await db.user.update({
276
+ where: { id },
277
+ data: { ssn: encrypted },
278
+ });
279
+
280
+ // Decrypt when needed
281
+ const user = await db.user.findUnique({ where: { id } });
282
+ const ssn = decrypt(user.ssn, encryptionKey);
283
+ ```
284
+
285
+ ### Audit Logging
286
+
287
+ ```ts
288
+ // Track changes for sensitive operations
289
+ await db.auditLog.create({
290
+ data: {
291
+ action: 'USER_UPDATE',
292
+ userId: currentUser.id,
293
+ targetId: targetUser.id,
294
+ changes: JSON.stringify(diff(before, after)),
295
+ timestamp: new Date(),
296
+ },
297
+ });
298
+ ```
@@ -0,0 +1,366 @@
1
+ # Error Handling
2
+
3
+ Best practices for handling errors in backend applications.
4
+
5
+ ## Principles
6
+
7
+ ### 1. Fail Fast
8
+ Detect errors early and fail immediately with clear diagnostics.
9
+
10
+ ### 2. Fail Gracefully
11
+ Users should receive helpful messages, not stack traces.
12
+
13
+ ### 3. Log Everything
14
+ Errors need context for debugging. Log appropriately.
15
+
16
+ ### 4. Recover When Possible
17
+ Some errors are transient. Implement retry logic where appropriate.
18
+
19
+ ## Error Types
20
+
21
+ ### Custom Error Classes
22
+
23
+ ```ts
24
+ // Base application error
25
+ class AppError extends Error {
26
+ constructor(
27
+ public statusCode: number,
28
+ public code: string,
29
+ message: string,
30
+ public details?: unknown
31
+ ) {
32
+ super(message);
33
+ this.name = 'AppError';
34
+ }
35
+ }
36
+
37
+ // Specific error types
38
+ class ValidationError extends AppError {
39
+ constructor(message: string, details?: ValidationDetail[]) {
40
+ super(422, 'VALIDATION_ERROR', message, details);
41
+ this.name = 'ValidationError';
42
+ }
43
+ }
44
+
45
+ class NotFoundError extends AppError {
46
+ constructor(resource: string, id: string) {
47
+ super(404, 'NOT_FOUND', `${resource} with id ${id} not found`);
48
+ this.name = 'NotFoundError';
49
+ }
50
+ }
51
+
52
+ class UnauthorizedError extends AppError {
53
+ constructor(message = 'Authentication required') {
54
+ super(401, 'UNAUTHORIZED', message);
55
+ this.name = 'UnauthorizedError';
56
+ }
57
+ }
58
+
59
+ class ForbiddenError extends AppError {
60
+ constructor(message = 'Access denied') {
61
+ super(403, 'FORBIDDEN', message);
62
+ this.name = 'ForbiddenError';
63
+ }
64
+ }
65
+
66
+ class ConflictError extends AppError {
67
+ constructor(message: string) {
68
+ super(409, 'CONFLICT', message);
69
+ this.name = 'ConflictError';
70
+ }
71
+ }
72
+ ```
73
+
74
+ ## Result Types
75
+
76
+ Use Result types for explicit error handling:
77
+
78
+ ```ts
79
+ type Result<T, E = Error> =
80
+ | { ok: true; value: T }
81
+ | { ok: false; error: E };
82
+
83
+ const ok = <T>(value: T): Result<T, never> => ({ ok: true, value });
84
+ const err = <E>(error: E): Result<never, E> => ({ ok: false, error });
85
+
86
+ // Usage
87
+ const findUser = async (id: string): Promise<Result<User, NotFoundError>> => {
88
+ const user = await db.user.findUnique({ where: { id } });
89
+
90
+ if (!user) {
91
+ return err(new NotFoundError('User', id));
92
+ }
93
+
94
+ return ok(user);
95
+ };
96
+
97
+ // Handling
98
+ const result = await findUser(id);
99
+ if (!result.ok) {
100
+ return res.status(result.error.statusCode).json({
101
+ error: { code: result.error.code, message: result.error.message }
102
+ });
103
+ }
104
+ const user = result.value;
105
+ ```
106
+
107
+ ## Global Error Handler
108
+
109
+ ```ts
110
+ // Centralized error handling middleware
111
+ const errorHandler = (err: Error, req: Request, res: Response, next: NextFunction) => {
112
+ // Log error with context
113
+ logger.error({
114
+ error: err.message,
115
+ stack: err.stack,
116
+ requestId: req.id,
117
+ method: req.method,
118
+ path: req.path,
119
+ userId: req.user?.id,
120
+ });
121
+
122
+ // Handle known application errors
123
+ if (err instanceof AppError) {
124
+ return res.status(err.statusCode).json({
125
+ error: {
126
+ code: err.code,
127
+ message: err.message,
128
+ details: err.details,
129
+ },
130
+ });
131
+ }
132
+
133
+ // Handle validation errors (e.g., from Zod)
134
+ if (err.name === 'ZodError') {
135
+ return res.status(422).json({
136
+ error: {
137
+ code: 'VALIDATION_ERROR',
138
+ message: 'Validation failed',
139
+ details: err.errors,
140
+ },
141
+ });
142
+ }
143
+
144
+ // Handle unknown errors (don't leak details)
145
+ res.status(500).json({
146
+ error: {
147
+ code: 'INTERNAL_ERROR',
148
+ message: 'An unexpected error occurred',
149
+ requestId: req.id, // For support reference
150
+ },
151
+ });
152
+ };
153
+
154
+ // Register at end of middleware chain
155
+ app.use(errorHandler);
156
+ ```
157
+
158
+ ## Async Error Handling
159
+
160
+ ### Wrap Async Handlers
161
+
162
+ ```ts
163
+ // Utility to catch async errors
164
+ const asyncHandler = (fn: RequestHandler): RequestHandler => {
165
+ return (req, res, next) => {
166
+ Promise.resolve(fn(req, res, next)).catch(next);
167
+ };
168
+ };
169
+
170
+ // Usage
171
+ app.get('/users/:id', asyncHandler(async (req, res) => {
172
+ const user = await userService.findById(req.params.id);
173
+ res.json({ data: user });
174
+ }));
175
+ ```
176
+
177
+ ### Or Use Try-Catch
178
+
179
+ ```ts
180
+ app.get('/users/:id', async (req, res, next) => {
181
+ try {
182
+ const user = await userService.findById(req.params.id);
183
+ res.json({ data: user });
184
+ } catch (error) {
185
+ next(error);
186
+ }
187
+ });
188
+ ```
189
+
190
+ ## Error Responses
191
+
192
+ ### Consistent Format
193
+
194
+ ```ts
195
+ interface ErrorResponse {
196
+ error: {
197
+ code: string; // Machine-readable code
198
+ message: string; // Human-readable message
199
+ details?: unknown; // Additional context
200
+ requestId?: string; // For support/debugging
201
+ };
202
+ }
203
+
204
+ // Examples
205
+ // 400 Bad Request
206
+ {
207
+ "error": {
208
+ "code": "BAD_REQUEST",
209
+ "message": "Invalid JSON in request body"
210
+ }
211
+ }
212
+
213
+ // 422 Validation Error
214
+ {
215
+ "error": {
216
+ "code": "VALIDATION_ERROR",
217
+ "message": "Validation failed",
218
+ "details": [
219
+ { "field": "email", "message": "Invalid email format" },
220
+ { "field": "age", "message": "Must be a positive number" }
221
+ ]
222
+ }
223
+ }
224
+
225
+ // 500 Internal Error
226
+ {
227
+ "error": {
228
+ "code": "INTERNAL_ERROR",
229
+ "message": "An unexpected error occurred",
230
+ "requestId": "req_abc123"
231
+ }
232
+ }
233
+ ```
234
+
235
+ ## Retry Logic
236
+
237
+ For transient failures:
238
+
239
+ ```ts
240
+ const retry = async <T>(
241
+ fn: () => Promise<T>,
242
+ options: { maxAttempts: number; delay: number; backoff?: number }
243
+ ): Promise<T> => {
244
+ const { maxAttempts, delay, backoff = 2 } = options;
245
+
246
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
247
+ try {
248
+ return await fn();
249
+ } catch (error) {
250
+ if (attempt === maxAttempts) throw error;
251
+
252
+ const waitTime = delay * Math.pow(backoff, attempt - 1);
253
+ await sleep(waitTime);
254
+ }
255
+ }
256
+
257
+ throw new Error('Retry failed'); // Unreachable but TypeScript needs it
258
+ };
259
+
260
+ // Usage
261
+ const result = await retry(
262
+ () => externalApi.call(),
263
+ { maxAttempts: 3, delay: 1000 }
264
+ );
265
+ ```
266
+
267
+ ## Logging Best Practices
268
+
269
+ ### What to Log
270
+
271
+ ```ts
272
+ // Log errors with context
273
+ logger.error({
274
+ message: 'Failed to process payment',
275
+ error: error.message,
276
+ stack: error.stack,
277
+ paymentId: payment.id,
278
+ userId: user.id,
279
+ amount: payment.amount,
280
+ // Never log: card numbers, passwords, tokens
281
+ });
282
+
283
+ // Log important events
284
+ logger.info({
285
+ message: 'Payment processed',
286
+ paymentId: payment.id,
287
+ userId: user.id,
288
+ });
289
+
290
+ // Log warnings for concerning but non-critical issues
291
+ logger.warn({
292
+ message: 'Rate limit approaching',
293
+ userId: user.id,
294
+ remaining: 5,
295
+ });
296
+ ```
297
+
298
+ ### What NOT to Log
299
+
300
+ - Passwords and credentials
301
+ - API keys and tokens
302
+ - Credit card numbers
303
+ - Personal identification numbers
304
+ - Full request/response bodies with sensitive data
305
+
306
+ ## Anti-Patterns
307
+
308
+ ### Swallowing Errors
309
+
310
+ ```ts
311
+ // Bad: Silent failure
312
+ try {
313
+ await riskyOperation();
314
+ } catch (e) {
315
+ // Nothing happens
316
+ }
317
+
318
+ // Good: Handle or rethrow
319
+ try {
320
+ await riskyOperation();
321
+ } catch (e) {
322
+ logger.error('Risky operation failed', e);
323
+ throw new AppError(500, 'OPERATION_FAILED', 'Could not complete operation');
324
+ }
325
+ ```
326
+
327
+ ### Leaking Implementation Details
328
+
329
+ ```ts
330
+ // Bad: Exposes internals
331
+ res.status(500).json({ error: error.stack });
332
+
333
+ // Good: Generic message
334
+ res.status(500).json({
335
+ error: { code: 'INTERNAL_ERROR', message: 'An error occurred' }
336
+ });
337
+ ```
338
+
339
+ ### Catching Too Broadly
340
+
341
+ ```ts
342
+ // Bad: Catches everything including programming errors
343
+ try {
344
+ const data = processInput(input);
345
+ await saveToDb(data);
346
+ sendNotification(data);
347
+ } catch (e) {
348
+ res.status(400).json({ error: 'Bad request' });
349
+ }
350
+
351
+ // Good: Catch specific errors
352
+ try {
353
+ const data = processInput(input);
354
+ await saveToDb(data);
355
+ sendNotification(data);
356
+ } catch (e) {
357
+ if (e instanceof ValidationError) {
358
+ res.status(422).json({ error: e.message });
359
+ } else if (e instanceof DatabaseError) {
360
+ logger.error('Database error', e);
361
+ res.status(500).json({ error: 'Database error' });
362
+ } else {
363
+ throw e; // Let unknown errors bubble up
364
+ }
365
+ }
366
+ ```
@@ -0,0 +1,69 @@
1
+ # Web Backend Development
2
+
3
+ Guidelines for building robust backend APIs and services.
4
+
5
+ ## Scope
6
+
7
+ This ruleset applies to:
8
+ - RESTful APIs
9
+ - GraphQL APIs
10
+ - Microservices
11
+ - Backend-for-frontend (BFF) services
12
+ - Server-side web applications
13
+
14
+ ## Core Technologies
15
+
16
+ Backend development typically involves:
17
+ - Server frameworks (Express, Fastify, Koa, Hono, etc.)
18
+ - Database systems (PostgreSQL, MySQL, MongoDB, Redis, etc.)
19
+ - Authentication/Authorization (JWT, OAuth, sessions)
20
+ - API documentation (OpenAPI/Swagger)
21
+ - Testing frameworks
22
+
23
+ ## Key Principles
24
+
25
+ ### 1. Security First
26
+ Every input is hostile until validated. Defense in depth.
27
+
28
+ ### 2. Reliability
29
+ Handle errors gracefully. Fail fast with clear diagnostics.
30
+
31
+ ### 3. Observability
32
+ Log meaningfully. Track metrics. Enable debugging.
33
+
34
+ ### 4. Scalability
35
+ Design for horizontal scaling. Avoid single points of failure.
36
+
37
+ ## Project Structure
38
+
39
+ ```
40
+ src/
41
+ ├── routes/ # Route handlers/controllers
42
+ ├── services/ # Business logic
43
+ ├── repositories/ # Data access layer
44
+ ├── middleware/ # Request/response middleware
45
+ ├── lib/ # Shared utilities
46
+ ├── types/ # TypeScript definitions
47
+ ├── validation/ # Input validation schemas
48
+ └── config/ # Configuration management
49
+ ```
50
+
51
+ ## API Design Principles
52
+
53
+ - Use consistent naming conventions
54
+ - Return appropriate HTTP status codes
55
+ - Provide meaningful error messages
56
+ - Version your APIs
57
+ - Document endpoints thoroughly
58
+
59
+ ## Definition of Done
60
+
61
+ A backend feature is complete when:
62
+ - [ ] Endpoint works as specified
63
+ - [ ] Input validation implemented
64
+ - [ ] Error handling covers edge cases
65
+ - [ ] Authentication/authorization enforced
66
+ - [ ] Unit and integration tests passing
67
+ - [ ] API documentation updated
68
+ - [ ] No security vulnerabilities
69
+ - [ ] Logging in place for debugging