@qazuor/claude-code-config 0.4.0 → 0.6.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/README.md +395 -50
- package/dist/bin.cjs +3207 -165
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +3207 -165
- package/dist/bin.js.map +1 -1
- package/dist/index.cjs +75 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +284 -1
- package/dist/index.d.ts +284 -1
- package/dist/index.js +75 -58
- package/dist/index.js.map +1 -1
- package/package.json +24 -24
- package/templates/CLAUDE.md.template +60 -5
- package/templates/agents/README.md +58 -39
- package/templates/agents/_registry.json +43 -202
- package/templates/agents/engineering/{hono-engineer.md → api-engineer.md} +61 -70
- package/templates/agents/engineering/database-engineer.md +253 -0
- package/templates/agents/engineering/frontend-engineer.md +302 -0
- package/templates/docs/_registry.json +54 -0
- package/templates/docs/standards/code-standards.md +20 -0
- package/templates/docs/standards/design-standards.md +13 -0
- package/templates/docs/standards/documentation-standards.md +13 -0
- package/templates/docs/standards/performance-standards.md +524 -0
- package/templates/docs/standards/security-standards.md +496 -0
- package/templates/docs/standards/testing-standards.md +15 -0
- package/templates/hooks/on-notification.sh +0 -0
- package/templates/scripts/add-changelogs.sh +0 -0
- package/templates/scripts/generate-code-registry.ts +0 -0
- package/templates/scripts/health-check.sh +0 -0
- package/templates/scripts/sync-registry.sh +0 -0
- package/templates/scripts/telemetry-report.ts +0 -0
- package/templates/scripts/validate-docs.sh +0 -0
- package/templates/scripts/validate-registry.sh +0 -0
- package/templates/scripts/validate-structure.sh +0 -0
- package/templates/scripts/worktree-cleanup.sh +0 -0
- package/templates/scripts/worktree-create.sh +0 -0
- package/templates/skills/README.md +99 -90
- package/templates/skills/_registry.json +323 -16
- package/templates/skills/api-frameworks/express-patterns.md +411 -0
- package/templates/skills/api-frameworks/fastify-patterns.md +419 -0
- package/templates/skills/api-frameworks/hono-patterns.md +388 -0
- package/templates/skills/api-frameworks/nestjs-patterns.md +497 -0
- package/templates/skills/database/drizzle-patterns.md +449 -0
- package/templates/skills/database/mongoose-patterns.md +503 -0
- package/templates/skills/database/prisma-patterns.md +487 -0
- package/templates/skills/frontend-frameworks/astro-patterns.md +415 -0
- package/templates/skills/frontend-frameworks/nextjs-patterns.md +470 -0
- package/templates/skills/frontend-frameworks/react-patterns.md +516 -0
- package/templates/skills/frontend-frameworks/tanstack-start-patterns.md +469 -0
- package/templates/skills/patterns/atdd-methodology.md +364 -0
- package/templates/skills/patterns/bdd-methodology.md +281 -0
- package/templates/skills/patterns/clean-architecture.md +444 -0
- package/templates/skills/patterns/hexagonal-architecture.md +567 -0
- package/templates/skills/patterns/vertical-slice-architecture.md +502 -0
- package/templates/agents/engineering/astro-engineer.md +0 -293
- package/templates/agents/engineering/db-drizzle-engineer.md +0 -360
- package/templates/agents/engineering/express-engineer.md +0 -316
- package/templates/agents/engineering/fastify-engineer.md +0 -399
- package/templates/agents/engineering/mongoose-engineer.md +0 -473
- package/templates/agents/engineering/nestjs-engineer.md +0 -429
- package/templates/agents/engineering/nextjs-engineer.md +0 -451
- package/templates/agents/engineering/prisma-engineer.md +0 -432
- package/templates/agents/engineering/react-senior-dev.md +0 -394
- package/templates/agents/engineering/tanstack-start-engineer.md +0 -447
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
# Express.js Framework Patterns
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Express.js is a minimal and flexible Node.js web application framework. This skill provides patterns for implementing APIs with Express.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## App Setup
|
|
10
|
+
|
|
11
|
+
**Pattern**: Security-first with proper middleware order
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import express from 'express';
|
|
15
|
+
import helmet from 'helmet';
|
|
16
|
+
import cors from 'cors';
|
|
17
|
+
import morgan from 'morgan';
|
|
18
|
+
import { errorHandler } from './middleware/error-handler';
|
|
19
|
+
import { routes } from './routes';
|
|
20
|
+
|
|
21
|
+
const app = express();
|
|
22
|
+
|
|
23
|
+
// Security middleware
|
|
24
|
+
app.use(helmet());
|
|
25
|
+
app.use(cors());
|
|
26
|
+
|
|
27
|
+
// Parsing middleware
|
|
28
|
+
app.use(express.json());
|
|
29
|
+
app.use(express.urlencoded({ extended: true }));
|
|
30
|
+
|
|
31
|
+
// Logging
|
|
32
|
+
app.use(morgan('combined'));
|
|
33
|
+
|
|
34
|
+
// Routes
|
|
35
|
+
app.use('/api/v1', routes);
|
|
36
|
+
|
|
37
|
+
// Error handler (must be last)
|
|
38
|
+
app.use(errorHandler);
|
|
39
|
+
|
|
40
|
+
export { app };
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Route Definition
|
|
46
|
+
|
|
47
|
+
### Controller-Based Pattern
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// routes/items.routes.ts
|
|
51
|
+
import { Router } from 'express';
|
|
52
|
+
import { ItemsController } from '../controllers/items.controller';
|
|
53
|
+
import { authenticate } from '../middleware/auth';
|
|
54
|
+
import { validate } from '../middleware/validate';
|
|
55
|
+
import { createItemSchema, updateItemSchema } from '../schemas/items';
|
|
56
|
+
|
|
57
|
+
const router = Router();
|
|
58
|
+
const controller = new ItemsController();
|
|
59
|
+
|
|
60
|
+
router.get('/', controller.getAll);
|
|
61
|
+
router.get('/:id', controller.getById);
|
|
62
|
+
router.post('/', authenticate, validate(createItemSchema), controller.create);
|
|
63
|
+
router.put('/:id', authenticate, validate(updateItemSchema), controller.update);
|
|
64
|
+
router.delete('/:id', authenticate, controller.delete);
|
|
65
|
+
|
|
66
|
+
export { router as itemsRouter };
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Controller Implementation
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// controllers/items.controller.ts
|
|
73
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
74
|
+
import { ItemsService } from '../services/items.service';
|
|
75
|
+
|
|
76
|
+
export class ItemsController {
|
|
77
|
+
private service = new ItemsService();
|
|
78
|
+
|
|
79
|
+
getAll = async (req: Request, res: Response, next: NextFunction) => {
|
|
80
|
+
try {
|
|
81
|
+
const items = await this.service.findAll(req.query);
|
|
82
|
+
res.json({ success: true, data: items });
|
|
83
|
+
} catch (error) {
|
|
84
|
+
next(error);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
getById = async (req: Request, res: Response, next: NextFunction) => {
|
|
89
|
+
try {
|
|
90
|
+
const item = await this.service.findById(req.params.id);
|
|
91
|
+
if (!item) {
|
|
92
|
+
return res.status(404).json({
|
|
93
|
+
success: false,
|
|
94
|
+
error: { message: 'Item not found', code: 'NOT_FOUND' },
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
res.json({ success: true, data: item });
|
|
98
|
+
} catch (error) {
|
|
99
|
+
next(error);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
create = async (req: Request, res: Response, next: NextFunction) => {
|
|
104
|
+
try {
|
|
105
|
+
const item = await this.service.create(req.body);
|
|
106
|
+
res.status(201).json({ success: true, data: item });
|
|
107
|
+
} catch (error) {
|
|
108
|
+
next(error);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
update = async (req: Request, res: Response, next: NextFunction) => {
|
|
113
|
+
try {
|
|
114
|
+
const item = await this.service.update(req.params.id, req.body);
|
|
115
|
+
res.json({ success: true, data: item });
|
|
116
|
+
} catch (error) {
|
|
117
|
+
next(error);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
delete = async (req: Request, res: Response, next: NextFunction) => {
|
|
122
|
+
try {
|
|
123
|
+
await this.service.delete(req.params.id);
|
|
124
|
+
res.status(204).send();
|
|
125
|
+
} catch (error) {
|
|
126
|
+
next(error);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Async Handler Wrapper
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// utils/async-handler.ts
|
|
136
|
+
import type { Request, Response, NextFunction, RequestHandler } from 'express';
|
|
137
|
+
|
|
138
|
+
type AsyncRequestHandler = (
|
|
139
|
+
req: Request,
|
|
140
|
+
res: Response,
|
|
141
|
+
next: NextFunction
|
|
142
|
+
) => Promise<void | Response>;
|
|
143
|
+
|
|
144
|
+
export function asyncHandler(fn: AsyncRequestHandler): RequestHandler {
|
|
145
|
+
return (req, res, next) => {
|
|
146
|
+
Promise.resolve(fn(req, res, next)).catch(next);
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Usage
|
|
151
|
+
router.get('/', asyncHandler(async (req, res) => {
|
|
152
|
+
const items = await service.findAll();
|
|
153
|
+
res.json({ data: items });
|
|
154
|
+
}));
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Middleware Patterns
|
|
160
|
+
|
|
161
|
+
### Authentication Middleware
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
165
|
+
import { AppError } from '../errors/AppError';
|
|
166
|
+
|
|
167
|
+
declare global {
|
|
168
|
+
namespace Express {
|
|
169
|
+
interface Request {
|
|
170
|
+
user?: User;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export async function authenticate(
|
|
176
|
+
req: Request,
|
|
177
|
+
res: Response,
|
|
178
|
+
next: NextFunction
|
|
179
|
+
) {
|
|
180
|
+
try {
|
|
181
|
+
const token = req.headers.authorization?.replace('Bearer ', '');
|
|
182
|
+
|
|
183
|
+
if (!token) {
|
|
184
|
+
throw new AppError('Unauthorized', 401, 'UNAUTHORIZED');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const user = await verifyToken(token);
|
|
188
|
+
if (!user) {
|
|
189
|
+
throw new AppError('Invalid token', 401, 'INVALID_TOKEN');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
req.user = user;
|
|
193
|
+
next();
|
|
194
|
+
} catch (error) {
|
|
195
|
+
next(error);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Validation Middleware
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
204
|
+
import type { z } from 'zod';
|
|
205
|
+
import { AppError } from '../errors/AppError';
|
|
206
|
+
|
|
207
|
+
export function validate(schema: z.ZodSchema) {
|
|
208
|
+
return (req: Request, res: Response, next: NextFunction) => {
|
|
209
|
+
try {
|
|
210
|
+
schema.parse(req.body);
|
|
211
|
+
next();
|
|
212
|
+
} catch (error) {
|
|
213
|
+
if (error instanceof z.ZodError) {
|
|
214
|
+
next(new AppError(
|
|
215
|
+
'Validation failed',
|
|
216
|
+
400,
|
|
217
|
+
'VALIDATION_ERROR',
|
|
218
|
+
error.errors
|
|
219
|
+
));
|
|
220
|
+
} else {
|
|
221
|
+
next(error);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Error Handler Middleware
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
import type { ErrorRequestHandler } from 'express';
|
|
232
|
+
import { AppError } from '../errors/AppError';
|
|
233
|
+
|
|
234
|
+
export const errorHandler: ErrorRequestHandler = (err, req, res, next) => {
|
|
235
|
+
// Already sent response
|
|
236
|
+
if (res.headersSent) {
|
|
237
|
+
return next(err);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Known application error
|
|
241
|
+
if (err instanceof AppError) {
|
|
242
|
+
return res.status(err.statusCode).json({
|
|
243
|
+
success: false,
|
|
244
|
+
error: {
|
|
245
|
+
message: err.message,
|
|
246
|
+
code: err.code,
|
|
247
|
+
details: err.details,
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Unknown error
|
|
253
|
+
console.error('Unhandled error:', err);
|
|
254
|
+
|
|
255
|
+
res.status(500).json({
|
|
256
|
+
success: false,
|
|
257
|
+
error: {
|
|
258
|
+
message: 'Internal server error',
|
|
259
|
+
code: 'INTERNAL_ERROR',
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
};
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Custom Error Class
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
export class AppError extends Error {
|
|
269
|
+
constructor(
|
|
270
|
+
message: string,
|
|
271
|
+
public statusCode: number = 500,
|
|
272
|
+
public code: string = 'INTERNAL_ERROR',
|
|
273
|
+
public details?: unknown
|
|
274
|
+
) {
|
|
275
|
+
super(message);
|
|
276
|
+
this.name = 'AppError';
|
|
277
|
+
Error.captureStackTrace(this, this.constructor);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Rate Limiting
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
import rateLimit from 'express-rate-limit';
|
|
288
|
+
|
|
289
|
+
export const apiLimiter = rateLimit({
|
|
290
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
291
|
+
max: 100, // Limit each IP to 100 requests per window
|
|
292
|
+
message: {
|
|
293
|
+
success: false,
|
|
294
|
+
error: {
|
|
295
|
+
message: 'Too many requests, please try again later',
|
|
296
|
+
code: 'RATE_LIMIT_EXCEEDED',
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
// Apply to all API routes
|
|
302
|
+
app.use('/api/', apiLimiter);
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## Testing with Supertest
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
import request from 'supertest';
|
|
311
|
+
import { app } from '../app';
|
|
312
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
313
|
+
|
|
314
|
+
describe('Item Routes', () => {
|
|
315
|
+
describe('GET /api/v1/items', () => {
|
|
316
|
+
it('should return all items', async () => {
|
|
317
|
+
const response = await request(app)
|
|
318
|
+
.get('/api/v1/items')
|
|
319
|
+
.expect(200);
|
|
320
|
+
|
|
321
|
+
expect(response.body.success).toBe(true);
|
|
322
|
+
expect(Array.isArray(response.body.data)).toBe(true);
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
describe('POST /api/v1/items', () => {
|
|
327
|
+
it('should create item with valid data', async () => {
|
|
328
|
+
const response = await request(app)
|
|
329
|
+
.post('/api/v1/items')
|
|
330
|
+
.set('Authorization', 'Bearer valid-token')
|
|
331
|
+
.send({ title: 'Test Item', description: 'Test' })
|
|
332
|
+
.expect(201);
|
|
333
|
+
|
|
334
|
+
expect(response.body.data).toHaveProperty('id');
|
|
335
|
+
expect(response.body.data.title).toBe('Test Item');
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('should return 400 with invalid data', async () => {
|
|
339
|
+
await request(app)
|
|
340
|
+
.post('/api/v1/items')
|
|
341
|
+
.set('Authorization', 'Bearer valid-token')
|
|
342
|
+
.send({ title: '' })
|
|
343
|
+
.expect(400);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('should return 401 without auth', async () => {
|
|
347
|
+
await request(app)
|
|
348
|
+
.post('/api/v1/items')
|
|
349
|
+
.send({ title: 'Test' })
|
|
350
|
+
.expect(401);
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
describe('GET /api/v1/items/:id', () => {
|
|
355
|
+
it('should return 404 for non-existent item', async () => {
|
|
356
|
+
await request(app)
|
|
357
|
+
.get('/api/v1/items/non-existent-id')
|
|
358
|
+
.expect(404);
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Project Structure
|
|
367
|
+
|
|
368
|
+
```
|
|
369
|
+
{API_PATH}/
|
|
370
|
+
├── routes/
|
|
371
|
+
│ ├── index.ts # Route aggregator
|
|
372
|
+
│ ├── items.routes.ts # Item routes
|
|
373
|
+
│ └── users.routes.ts # User routes
|
|
374
|
+
├── controllers/
|
|
375
|
+
│ ├── items.controller.ts
|
|
376
|
+
│ └── users.controller.ts
|
|
377
|
+
├── services/
|
|
378
|
+
│ ├── items.service.ts
|
|
379
|
+
│ └── users.service.ts
|
|
380
|
+
├── middleware/
|
|
381
|
+
│ ├── auth.ts
|
|
382
|
+
│ ├── validate.ts
|
|
383
|
+
│ └── error-handler.ts
|
|
384
|
+
├── schemas/
|
|
385
|
+
│ └── items.ts # Zod schemas
|
|
386
|
+
├── errors/
|
|
387
|
+
│ └── AppError.ts
|
|
388
|
+
├── types/
|
|
389
|
+
│ └── express.d.ts # Type augmentations
|
|
390
|
+
└── app.ts
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## Best Practices
|
|
396
|
+
|
|
397
|
+
### Good
|
|
398
|
+
|
|
399
|
+
- Use helmet for security headers
|
|
400
|
+
- Use async handler wrapper for cleaner code
|
|
401
|
+
- Use controller-service pattern
|
|
402
|
+
- Centralized error handling
|
|
403
|
+
- Type augmentation for custom properties
|
|
404
|
+
|
|
405
|
+
### Bad
|
|
406
|
+
|
|
407
|
+
- Sync error handlers (Express doesn't catch async errors)
|
|
408
|
+
- Missing validation
|
|
409
|
+
- console.log instead of proper logging
|
|
410
|
+
- Business logic in routes
|
|
411
|
+
- No rate limiting
|