@jwdobeutechsolutions/dobeutech-claude-code-custom 1.0.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 (59) hide show
  1. package/CLAUDE.md +174 -0
  2. package/CONTRIBUTING.md +191 -0
  3. package/README.md +345 -0
  4. package/agents/accessibility-auditor.md +315 -0
  5. package/agents/api-designer.md +265 -0
  6. package/agents/architect.md +211 -0
  7. package/agents/build-error-resolver.md +532 -0
  8. package/agents/ci-cd-generator.md +318 -0
  9. package/agents/code-reviewer.md +104 -0
  10. package/agents/database-migrator.md +258 -0
  11. package/agents/deployment-manager.md +296 -0
  12. package/agents/doc-updater.md +452 -0
  13. package/agents/docker-specialist.md +293 -0
  14. package/agents/e2e-runner.md +708 -0
  15. package/agents/fullstack-architect.md +293 -0
  16. package/agents/infrastructure-engineer.md +297 -0
  17. package/agents/integration-tester.md +320 -0
  18. package/agents/performance-tester.md +243 -0
  19. package/agents/planner.md +119 -0
  20. package/agents/refactor-cleaner.md +306 -0
  21. package/agents/security-reviewer.md +545 -0
  22. package/agents/tdd-guide.md +280 -0
  23. package/agents/unit-test-generator.md +290 -0
  24. package/bin/claude-config.js +290 -0
  25. package/commands/api-design.md +55 -0
  26. package/commands/audit-accessibility.md +37 -0
  27. package/commands/audit-performance.md +38 -0
  28. package/commands/audit-security.md +43 -0
  29. package/commands/build-fix.md +29 -0
  30. package/commands/changelog.md +31 -0
  31. package/commands/code-review.md +40 -0
  32. package/commands/deploy.md +51 -0
  33. package/commands/docs-api.md +41 -0
  34. package/commands/e2e.md +363 -0
  35. package/commands/plan.md +113 -0
  36. package/commands/refactor-clean.md +28 -0
  37. package/commands/tdd.md +326 -0
  38. package/commands/test-coverage.md +27 -0
  39. package/commands/update-codemaps.md +17 -0
  40. package/commands/update-docs.md +31 -0
  41. package/hooks/hooks.json +121 -0
  42. package/mcp-configs/mcp-servers.json +163 -0
  43. package/package.json +53 -0
  44. package/rules/agents.md +49 -0
  45. package/rules/coding-style.md +70 -0
  46. package/rules/git-workflow.md +45 -0
  47. package/rules/hooks.md +46 -0
  48. package/rules/patterns.md +55 -0
  49. package/rules/performance.md +47 -0
  50. package/rules/security.md +36 -0
  51. package/rules/testing.md +30 -0
  52. package/scripts/install.js +254 -0
  53. package/skills/backend-patterns.md +582 -0
  54. package/skills/clickhouse-io.md +429 -0
  55. package/skills/coding-standards.md +520 -0
  56. package/skills/frontend-patterns.md +631 -0
  57. package/skills/project-guidelines-example.md +345 -0
  58. package/skills/security-review/SKILL.md +494 -0
  59. package/skills/tdd-workflow/SKILL.md +409 -0
@@ -0,0 +1,582 @@
1
+ ---
2
+ name: backend-patterns
3
+ description: Backend architecture patterns, API design, database optimization, and server-side best practices for Node.js, Express, and Next.js API routes.
4
+ ---
5
+
6
+ # Backend Development Patterns
7
+
8
+ Backend architecture patterns and best practices for scalable server-side applications.
9
+
10
+ ## API Design Patterns
11
+
12
+ ### RESTful API Structure
13
+
14
+ ```typescript
15
+ // ✅ Resource-based URLs
16
+ GET /api/markets # List resources
17
+ GET /api/markets/:id # Get single resource
18
+ POST /api/markets # Create resource
19
+ PUT /api/markets/:id # Replace resource
20
+ PATCH /api/markets/:id # Update resource
21
+ DELETE /api/markets/:id # Delete resource
22
+
23
+ // ✅ Query parameters for filtering, sorting, pagination
24
+ GET /api/markets?status=active&sort=volume&limit=20&offset=0
25
+ ```
26
+
27
+ ### Repository Pattern
28
+
29
+ ```typescript
30
+ // Abstract data access logic
31
+ interface MarketRepository {
32
+ findAll(filters?: MarketFilters): Promise<Market[]>
33
+ findById(id: string): Promise<Market | null>
34
+ create(data: CreateMarketDto): Promise<Market>
35
+ update(id: string, data: UpdateMarketDto): Promise<Market>
36
+ delete(id: string): Promise<void>
37
+ }
38
+
39
+ class SupabaseMarketRepository implements MarketRepository {
40
+ async findAll(filters?: MarketFilters): Promise<Market[]> {
41
+ let query = supabase.from('markets').select('*')
42
+
43
+ if (filters?.status) {
44
+ query = query.eq('status', filters.status)
45
+ }
46
+
47
+ if (filters?.limit) {
48
+ query = query.limit(filters.limit)
49
+ }
50
+
51
+ const { data, error } = await query
52
+
53
+ if (error) throw new Error(error.message)
54
+ return data
55
+ }
56
+
57
+ // Other methods...
58
+ }
59
+ ```
60
+
61
+ ### Service Layer Pattern
62
+
63
+ ```typescript
64
+ // Business logic separated from data access
65
+ class MarketService {
66
+ constructor(private marketRepo: MarketRepository) {}
67
+
68
+ async searchMarkets(query: string, limit: number = 10): Promise<Market[]> {
69
+ // Business logic
70
+ const embedding = await generateEmbedding(query)
71
+ const results = await this.vectorSearch(embedding, limit)
72
+
73
+ // Fetch full data
74
+ const markets = await this.marketRepo.findByIds(results.map(r => r.id))
75
+
76
+ // Sort by similarity
77
+ return markets.sort((a, b) => {
78
+ const scoreA = results.find(r => r.id === a.id)?.score || 0
79
+ const scoreB = results.find(r => r.id === b.id)?.score || 0
80
+ return scoreA - scoreB
81
+ })
82
+ }
83
+
84
+ private async vectorSearch(embedding: number[], limit: number) {
85
+ // Vector search implementation
86
+ }
87
+ }
88
+ ```
89
+
90
+ ### Middleware Pattern
91
+
92
+ ```typescript
93
+ // Request/response processing pipeline
94
+ export function withAuth(handler: NextApiHandler): NextApiHandler {
95
+ return async (req, res) => {
96
+ const token = req.headers.authorization?.replace('Bearer ', '')
97
+
98
+ if (!token) {
99
+ return res.status(401).json({ error: 'Unauthorized' })
100
+ }
101
+
102
+ try {
103
+ const user = await verifyToken(token)
104
+ req.user = user
105
+ return handler(req, res)
106
+ } catch (error) {
107
+ return res.status(401).json({ error: 'Invalid token' })
108
+ }
109
+ }
110
+ }
111
+
112
+ // Usage
113
+ export default withAuth(async (req, res) => {
114
+ // Handler has access to req.user
115
+ })
116
+ ```
117
+
118
+ ## Database Patterns
119
+
120
+ ### Query Optimization
121
+
122
+ ```typescript
123
+ // ✅ GOOD: Select only needed columns
124
+ const { data } = await supabase
125
+ .from('markets')
126
+ .select('id, name, status, volume')
127
+ .eq('status', 'active')
128
+ .order('volume', { ascending: false })
129
+ .limit(10)
130
+
131
+ // ❌ BAD: Select everything
132
+ const { data } = await supabase
133
+ .from('markets')
134
+ .select('*')
135
+ ```
136
+
137
+ ### N+1 Query Prevention
138
+
139
+ ```typescript
140
+ // ❌ BAD: N+1 query problem
141
+ const markets = await getMarkets()
142
+ for (const market of markets) {
143
+ market.creator = await getUser(market.creator_id) // N queries
144
+ }
145
+
146
+ // ✅ GOOD: Batch fetch
147
+ const markets = await getMarkets()
148
+ const creatorIds = markets.map(m => m.creator_id)
149
+ const creators = await getUsers(creatorIds) // 1 query
150
+ const creatorMap = new Map(creators.map(c => [c.id, c]))
151
+
152
+ markets.forEach(market => {
153
+ market.creator = creatorMap.get(market.creator_id)
154
+ })
155
+ ```
156
+
157
+ ### Transaction Pattern
158
+
159
+ ```typescript
160
+ async function createMarketWithPosition(
161
+ marketData: CreateMarketDto,
162
+ positionData: CreatePositionDto
163
+ ) {
164
+ // Use Supabase transaction
165
+ const { data, error } = await supabase.rpc('create_market_with_position', {
166
+ market_data: marketData,
167
+ position_data: positionData
168
+ })
169
+
170
+ if (error) throw new Error('Transaction failed')
171
+ return data
172
+ }
173
+
174
+ // SQL function in Supabase
175
+ CREATE OR REPLACE FUNCTION create_market_with_position(
176
+ market_data jsonb,
177
+ position_data jsonb
178
+ )
179
+ RETURNS jsonb
180
+ LANGUAGE plpgsql
181
+ AS $$
182
+ BEGIN
183
+ -- Start transaction automatically
184
+ INSERT INTO markets VALUES (market_data);
185
+ INSERT INTO positions VALUES (position_data);
186
+ RETURN jsonb_build_object('success', true);
187
+ EXCEPTION
188
+ WHEN OTHERS THEN
189
+ -- Rollback happens automatically
190
+ RETURN jsonb_build_object('success', false, 'error', SQLERRM);
191
+ END;
192
+ $$;
193
+ ```
194
+
195
+ ## Caching Strategies
196
+
197
+ ### Redis Caching Layer
198
+
199
+ ```typescript
200
+ class CachedMarketRepository implements MarketRepository {
201
+ constructor(
202
+ private baseRepo: MarketRepository,
203
+ private redis: RedisClient
204
+ ) {}
205
+
206
+ async findById(id: string): Promise<Market | null> {
207
+ // Check cache first
208
+ const cached = await this.redis.get(`market:${id}`)
209
+
210
+ if (cached) {
211
+ return JSON.parse(cached)
212
+ }
213
+
214
+ // Cache miss - fetch from database
215
+ const market = await this.baseRepo.findById(id)
216
+
217
+ if (market) {
218
+ // Cache for 5 minutes
219
+ await this.redis.setex(`market:${id}`, 300, JSON.stringify(market))
220
+ }
221
+
222
+ return market
223
+ }
224
+
225
+ async invalidateCache(id: string): Promise<void> {
226
+ await this.redis.del(`market:${id}`)
227
+ }
228
+ }
229
+ ```
230
+
231
+ ### Cache-Aside Pattern
232
+
233
+ ```typescript
234
+ async function getMarketWithCache(id: string): Promise<Market> {
235
+ const cacheKey = `market:${id}`
236
+
237
+ // Try cache
238
+ const cached = await redis.get(cacheKey)
239
+ if (cached) return JSON.parse(cached)
240
+
241
+ // Cache miss - fetch from DB
242
+ const market = await db.markets.findUnique({ where: { id } })
243
+
244
+ if (!market) throw new Error('Market not found')
245
+
246
+ // Update cache
247
+ await redis.setex(cacheKey, 300, JSON.stringify(market))
248
+
249
+ return market
250
+ }
251
+ ```
252
+
253
+ ## Error Handling Patterns
254
+
255
+ ### Centralized Error Handler
256
+
257
+ ```typescript
258
+ class ApiError extends Error {
259
+ constructor(
260
+ public statusCode: number,
261
+ public message: string,
262
+ public isOperational = true
263
+ ) {
264
+ super(message)
265
+ Object.setPrototypeOf(this, ApiError.prototype)
266
+ }
267
+ }
268
+
269
+ export function errorHandler(error: unknown, req: Request): Response {
270
+ if (error instanceof ApiError) {
271
+ return NextResponse.json({
272
+ success: false,
273
+ error: error.message
274
+ }, { status: error.statusCode })
275
+ }
276
+
277
+ if (error instanceof z.ZodError) {
278
+ return NextResponse.json({
279
+ success: false,
280
+ error: 'Validation failed',
281
+ details: error.errors
282
+ }, { status: 400 })
283
+ }
284
+
285
+ // Log unexpected errors
286
+ console.error('Unexpected error:', error)
287
+
288
+ return NextResponse.json({
289
+ success: false,
290
+ error: 'Internal server error'
291
+ }, { status: 500 })
292
+ }
293
+
294
+ // Usage
295
+ export async function GET(request: Request) {
296
+ try {
297
+ const data = await fetchData()
298
+ return NextResponse.json({ success: true, data })
299
+ } catch (error) {
300
+ return errorHandler(error, request)
301
+ }
302
+ }
303
+ ```
304
+
305
+ ### Retry with Exponential Backoff
306
+
307
+ ```typescript
308
+ async function fetchWithRetry<T>(
309
+ fn: () => Promise<T>,
310
+ maxRetries = 3
311
+ ): Promise<T> {
312
+ let lastError: Error
313
+
314
+ for (let i = 0; i < maxRetries; i++) {
315
+ try {
316
+ return await fn()
317
+ } catch (error) {
318
+ lastError = error as Error
319
+
320
+ if (i < maxRetries - 1) {
321
+ // Exponential backoff: 1s, 2s, 4s
322
+ const delay = Math.pow(2, i) * 1000
323
+ await new Promise(resolve => setTimeout(resolve, delay))
324
+ }
325
+ }
326
+ }
327
+
328
+ throw lastError!
329
+ }
330
+
331
+ // Usage
332
+ const data = await fetchWithRetry(() => fetchFromAPI())
333
+ ```
334
+
335
+ ## Authentication & Authorization
336
+
337
+ ### JWT Token Validation
338
+
339
+ ```typescript
340
+ import jwt from 'jsonwebtoken'
341
+
342
+ interface JWTPayload {
343
+ userId: string
344
+ email: string
345
+ role: 'admin' | 'user'
346
+ }
347
+
348
+ export function verifyToken(token: string): JWTPayload {
349
+ try {
350
+ const payload = jwt.verify(token, process.env.JWT_SECRET!) as JWTPayload
351
+ return payload
352
+ } catch (error) {
353
+ throw new ApiError(401, 'Invalid token')
354
+ }
355
+ }
356
+
357
+ export async function requireAuth(request: Request) {
358
+ const token = request.headers.get('authorization')?.replace('Bearer ', '')
359
+
360
+ if (!token) {
361
+ throw new ApiError(401, 'Missing authorization token')
362
+ }
363
+
364
+ return verifyToken(token)
365
+ }
366
+
367
+ // Usage in API route
368
+ export async function GET(request: Request) {
369
+ const user = await requireAuth(request)
370
+
371
+ const data = await getDataForUser(user.userId)
372
+
373
+ return NextResponse.json({ success: true, data })
374
+ }
375
+ ```
376
+
377
+ ### Role-Based Access Control
378
+
379
+ ```typescript
380
+ type Permission = 'read' | 'write' | 'delete' | 'admin'
381
+
382
+ interface User {
383
+ id: string
384
+ role: 'admin' | 'moderator' | 'user'
385
+ }
386
+
387
+ const rolePermissions: Record<User['role'], Permission[]> = {
388
+ admin: ['read', 'write', 'delete', 'admin'],
389
+ moderator: ['read', 'write', 'delete'],
390
+ user: ['read', 'write']
391
+ }
392
+
393
+ export function hasPermission(user: User, permission: Permission): boolean {
394
+ return rolePermissions[user.role].includes(permission)
395
+ }
396
+
397
+ export function requirePermission(permission: Permission) {
398
+ return async (request: Request) => {
399
+ const user = await requireAuth(request)
400
+
401
+ if (!hasPermission(user, permission)) {
402
+ throw new ApiError(403, 'Insufficient permissions')
403
+ }
404
+
405
+ return user
406
+ }
407
+ }
408
+
409
+ // Usage
410
+ export const DELETE = requirePermission('delete')(async (request: Request) => {
411
+ // Handler with permission check
412
+ })
413
+ ```
414
+
415
+ ## Rate Limiting
416
+
417
+ ### Simple In-Memory Rate Limiter
418
+
419
+ ```typescript
420
+ class RateLimiter {
421
+ private requests = new Map<string, number[]>()
422
+
423
+ async checkLimit(
424
+ identifier: string,
425
+ maxRequests: number,
426
+ windowMs: number
427
+ ): Promise<boolean> {
428
+ const now = Date.now()
429
+ const requests = this.requests.get(identifier) || []
430
+
431
+ // Remove old requests outside window
432
+ const recentRequests = requests.filter(time => now - time < windowMs)
433
+
434
+ if (recentRequests.length >= maxRequests) {
435
+ return false // Rate limit exceeded
436
+ }
437
+
438
+ // Add current request
439
+ recentRequests.push(now)
440
+ this.requests.set(identifier, recentRequests)
441
+
442
+ return true
443
+ }
444
+ }
445
+
446
+ const limiter = new RateLimiter()
447
+
448
+ export async function GET(request: Request) {
449
+ const ip = request.headers.get('x-forwarded-for') || 'unknown'
450
+
451
+ const allowed = await limiter.checkLimit(ip, 100, 60000) // 100 req/min
452
+
453
+ if (!allowed) {
454
+ return NextResponse.json({
455
+ error: 'Rate limit exceeded'
456
+ }, { status: 429 })
457
+ }
458
+
459
+ // Continue with request
460
+ }
461
+ ```
462
+
463
+ ## Background Jobs & Queues
464
+
465
+ ### Simple Queue Pattern
466
+
467
+ ```typescript
468
+ class JobQueue<T> {
469
+ private queue: T[] = []
470
+ private processing = false
471
+
472
+ async add(job: T): Promise<void> {
473
+ this.queue.push(job)
474
+
475
+ if (!this.processing) {
476
+ this.process()
477
+ }
478
+ }
479
+
480
+ private async process(): Promise<void> {
481
+ this.processing = true
482
+
483
+ while (this.queue.length > 0) {
484
+ const job = this.queue.shift()!
485
+
486
+ try {
487
+ await this.execute(job)
488
+ } catch (error) {
489
+ console.error('Job failed:', error)
490
+ }
491
+ }
492
+
493
+ this.processing = false
494
+ }
495
+
496
+ private async execute(job: T): Promise<void> {
497
+ // Job execution logic
498
+ }
499
+ }
500
+
501
+ // Usage for indexing markets
502
+ interface IndexJob {
503
+ marketId: string
504
+ }
505
+
506
+ const indexQueue = new JobQueue<IndexJob>()
507
+
508
+ export async function POST(request: Request) {
509
+ const { marketId } = await request.json()
510
+
511
+ // Add to queue instead of blocking
512
+ await indexQueue.add({ marketId })
513
+
514
+ return NextResponse.json({ success: true, message: 'Job queued' })
515
+ }
516
+ ```
517
+
518
+ ## Logging & Monitoring
519
+
520
+ ### Structured Logging
521
+
522
+ ```typescript
523
+ interface LogContext {
524
+ userId?: string
525
+ requestId?: string
526
+ method?: string
527
+ path?: string
528
+ [key: string]: unknown
529
+ }
530
+
531
+ class Logger {
532
+ log(level: 'info' | 'warn' | 'error', message: string, context?: LogContext) {
533
+ const entry = {
534
+ timestamp: new Date().toISOString(),
535
+ level,
536
+ message,
537
+ ...context
538
+ }
539
+
540
+ console.log(JSON.stringify(entry))
541
+ }
542
+
543
+ info(message: string, context?: LogContext) {
544
+ this.log('info', message, context)
545
+ }
546
+
547
+ warn(message: string, context?: LogContext) {
548
+ this.log('warn', message, context)
549
+ }
550
+
551
+ error(message: string, error: Error, context?: LogContext) {
552
+ this.log('error', message, {
553
+ ...context,
554
+ error: error.message,
555
+ stack: error.stack
556
+ })
557
+ }
558
+ }
559
+
560
+ const logger = new Logger()
561
+
562
+ // Usage
563
+ export async function GET(request: Request) {
564
+ const requestId = crypto.randomUUID()
565
+
566
+ logger.info('Fetching markets', {
567
+ requestId,
568
+ method: 'GET',
569
+ path: '/api/markets'
570
+ })
571
+
572
+ try {
573
+ const markets = await fetchMarkets()
574
+ return NextResponse.json({ success: true, data: markets })
575
+ } catch (error) {
576
+ logger.error('Failed to fetch markets', error as Error, { requestId })
577
+ return NextResponse.json({ error: 'Internal error' }, { status: 500 })
578
+ }
579
+ }
580
+ ```
581
+
582
+ **Remember**: Backend patterns enable scalable, maintainable server-side applications. Choose patterns that fit your complexity level.