@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,631 @@
1
+ ---
2
+ name: frontend-patterns
3
+ description: Frontend development patterns for React, Next.js, state management, performance optimization, and UI best practices.
4
+ ---
5
+
6
+ # Frontend Development Patterns
7
+
8
+ Modern frontend patterns for React, Next.js, and performant user interfaces.
9
+
10
+ ## Component Patterns
11
+
12
+ ### Composition Over Inheritance
13
+
14
+ ```typescript
15
+ // ✅ GOOD: Component composition
16
+ interface CardProps {
17
+ children: React.ReactNode
18
+ variant?: 'default' | 'outlined'
19
+ }
20
+
21
+ export function Card({ children, variant = 'default' }: CardProps) {
22
+ return <div className={`card card-${variant}`}>{children}</div>
23
+ }
24
+
25
+ export function CardHeader({ children }: { children: React.ReactNode }) {
26
+ return <div className="card-header">{children}</div>
27
+ }
28
+
29
+ export function CardBody({ children }: { children: React.ReactNode }) {
30
+ return <div className="card-body">{children}</div>
31
+ }
32
+
33
+ // Usage
34
+ <Card>
35
+ <CardHeader>Title</CardHeader>
36
+ <CardBody>Content</CardBody>
37
+ </Card>
38
+ ```
39
+
40
+ ### Compound Components
41
+
42
+ ```typescript
43
+ interface TabsContextValue {
44
+ activeTab: string
45
+ setActiveTab: (tab: string) => void
46
+ }
47
+
48
+ const TabsContext = createContext<TabsContextValue | undefined>(undefined)
49
+
50
+ export function Tabs({ children, defaultTab }: {
51
+ children: React.ReactNode
52
+ defaultTab: string
53
+ }) {
54
+ const [activeTab, setActiveTab] = useState(defaultTab)
55
+
56
+ return (
57
+ <TabsContext.Provider value={{ activeTab, setActiveTab }}>
58
+ {children}
59
+ </TabsContext.Provider>
60
+ )
61
+ }
62
+
63
+ export function TabList({ children }: { children: React.ReactNode }) {
64
+ return <div className="tab-list">{children}</div>
65
+ }
66
+
67
+ export function Tab({ id, children }: { id: string, children: React.ReactNode }) {
68
+ const context = useContext(TabsContext)
69
+ if (!context) throw new Error('Tab must be used within Tabs')
70
+
71
+ return (
72
+ <button
73
+ className={context.activeTab === id ? 'active' : ''}
74
+ onClick={() => context.setActiveTab(id)}
75
+ >
76
+ {children}
77
+ </button>
78
+ )
79
+ }
80
+
81
+ // Usage
82
+ <Tabs defaultTab="overview">
83
+ <TabList>
84
+ <Tab id="overview">Overview</Tab>
85
+ <Tab id="details">Details</Tab>
86
+ </TabList>
87
+ </Tabs>
88
+ ```
89
+
90
+ ### Render Props Pattern
91
+
92
+ ```typescript
93
+ interface DataLoaderProps<T> {
94
+ url: string
95
+ children: (data: T | null, loading: boolean, error: Error | null) => React.ReactNode
96
+ }
97
+
98
+ export function DataLoader<T>({ url, children }: DataLoaderProps<T>) {
99
+ const [data, setData] = useState<T | null>(null)
100
+ const [loading, setLoading] = useState(true)
101
+ const [error, setError] = useState<Error | null>(null)
102
+
103
+ useEffect(() => {
104
+ fetch(url)
105
+ .then(res => res.json())
106
+ .then(setData)
107
+ .catch(setError)
108
+ .finally(() => setLoading(false))
109
+ }, [url])
110
+
111
+ return <>{children(data, loading, error)}</>
112
+ }
113
+
114
+ // Usage
115
+ <DataLoader<Market[]> url="/api/markets">
116
+ {(markets, loading, error) => {
117
+ if (loading) return <Spinner />
118
+ if (error) return <Error error={error} />
119
+ return <MarketList markets={markets!} />
120
+ }}
121
+ </DataLoader>
122
+ ```
123
+
124
+ ## Custom Hooks Patterns
125
+
126
+ ### State Management Hook
127
+
128
+ ```typescript
129
+ export function useToggle(initialValue = false): [boolean, () => void] {
130
+ const [value, setValue] = useState(initialValue)
131
+
132
+ const toggle = useCallback(() => {
133
+ setValue(v => !v)
134
+ }, [])
135
+
136
+ return [value, toggle]
137
+ }
138
+
139
+ // Usage
140
+ const [isOpen, toggleOpen] = useToggle()
141
+ ```
142
+
143
+ ### Async Data Fetching Hook
144
+
145
+ ```typescript
146
+ interface UseQueryOptions<T> {
147
+ onSuccess?: (data: T) => void
148
+ onError?: (error: Error) => void
149
+ enabled?: boolean
150
+ }
151
+
152
+ export function useQuery<T>(
153
+ key: string,
154
+ fetcher: () => Promise<T>,
155
+ options?: UseQueryOptions<T>
156
+ ) {
157
+ const [data, setData] = useState<T | null>(null)
158
+ const [error, setError] = useState<Error | null>(null)
159
+ const [loading, setLoading] = useState(false)
160
+
161
+ const refetch = useCallback(async () => {
162
+ setLoading(true)
163
+ setError(null)
164
+
165
+ try {
166
+ const result = await fetcher()
167
+ setData(result)
168
+ options?.onSuccess?.(result)
169
+ } catch (err) {
170
+ const error = err as Error
171
+ setError(error)
172
+ options?.onError?.(error)
173
+ } finally {
174
+ setLoading(false)
175
+ }
176
+ }, [fetcher, options])
177
+
178
+ useEffect(() => {
179
+ if (options?.enabled !== false) {
180
+ refetch()
181
+ }
182
+ }, [key, refetch, options?.enabled])
183
+
184
+ return { data, error, loading, refetch }
185
+ }
186
+
187
+ // Usage
188
+ const { data: markets, loading, error, refetch } = useQuery(
189
+ 'markets',
190
+ () => fetch('/api/markets').then(r => r.json()),
191
+ {
192
+ onSuccess: data => console.log('Fetched', data.length, 'markets'),
193
+ onError: err => console.error('Failed:', err)
194
+ }
195
+ )
196
+ ```
197
+
198
+ ### Debounce Hook
199
+
200
+ ```typescript
201
+ export function useDebounce<T>(value: T, delay: number): T {
202
+ const [debouncedValue, setDebouncedValue] = useState<T>(value)
203
+
204
+ useEffect(() => {
205
+ const handler = setTimeout(() => {
206
+ setDebouncedValue(value)
207
+ }, delay)
208
+
209
+ return () => clearTimeout(handler)
210
+ }, [value, delay])
211
+
212
+ return debouncedValue
213
+ }
214
+
215
+ // Usage
216
+ const [searchQuery, setSearchQuery] = useState('')
217
+ const debouncedQuery = useDebounce(searchQuery, 500)
218
+
219
+ useEffect(() => {
220
+ if (debouncedQuery) {
221
+ performSearch(debouncedQuery)
222
+ }
223
+ }, [debouncedQuery])
224
+ ```
225
+
226
+ ## State Management Patterns
227
+
228
+ ### Context + Reducer Pattern
229
+
230
+ ```typescript
231
+ interface State {
232
+ markets: Market[]
233
+ selectedMarket: Market | null
234
+ loading: boolean
235
+ }
236
+
237
+ type Action =
238
+ | { type: 'SET_MARKETS'; payload: Market[] }
239
+ | { type: 'SELECT_MARKET'; payload: Market }
240
+ | { type: 'SET_LOADING'; payload: boolean }
241
+
242
+ function reducer(state: State, action: Action): State {
243
+ switch (action.type) {
244
+ case 'SET_MARKETS':
245
+ return { ...state, markets: action.payload }
246
+ case 'SELECT_MARKET':
247
+ return { ...state, selectedMarket: action.payload }
248
+ case 'SET_LOADING':
249
+ return { ...state, loading: action.payload }
250
+ default:
251
+ return state
252
+ }
253
+ }
254
+
255
+ const MarketContext = createContext<{
256
+ state: State
257
+ dispatch: Dispatch<Action>
258
+ } | undefined>(undefined)
259
+
260
+ export function MarketProvider({ children }: { children: React.ReactNode }) {
261
+ const [state, dispatch] = useReducer(reducer, {
262
+ markets: [],
263
+ selectedMarket: null,
264
+ loading: false
265
+ })
266
+
267
+ return (
268
+ <MarketContext.Provider value={{ state, dispatch }}>
269
+ {children}
270
+ </MarketContext.Provider>
271
+ )
272
+ }
273
+
274
+ export function useMarkets() {
275
+ const context = useContext(MarketContext)
276
+ if (!context) throw new Error('useMarkets must be used within MarketProvider')
277
+ return context
278
+ }
279
+ ```
280
+
281
+ ## Performance Optimization
282
+
283
+ ### Memoization
284
+
285
+ ```typescript
286
+ // ✅ useMemo for expensive computations
287
+ const sortedMarkets = useMemo(() => {
288
+ return markets.sort((a, b) => b.volume - a.volume)
289
+ }, [markets])
290
+
291
+ // ✅ useCallback for functions passed to children
292
+ const handleSearch = useCallback((query: string) => {
293
+ setSearchQuery(query)
294
+ }, [])
295
+
296
+ // ✅ React.memo for pure components
297
+ export const MarketCard = React.memo<MarketCardProps>(({ market }) => {
298
+ return (
299
+ <div className="market-card">
300
+ <h3>{market.name}</h3>
301
+ <p>{market.description}</p>
302
+ </div>
303
+ )
304
+ })
305
+ ```
306
+
307
+ ### Code Splitting & Lazy Loading
308
+
309
+ ```typescript
310
+ import { lazy, Suspense } from 'react'
311
+
312
+ // ✅ Lazy load heavy components
313
+ const HeavyChart = lazy(() => import('./HeavyChart'))
314
+ const ThreeJsBackground = lazy(() => import('./ThreeJsBackground'))
315
+
316
+ export function Dashboard() {
317
+ return (
318
+ <div>
319
+ <Suspense fallback={<ChartSkeleton />}>
320
+ <HeavyChart data={data} />
321
+ </Suspense>
322
+
323
+ <Suspense fallback={null}>
324
+ <ThreeJsBackground />
325
+ </Suspense>
326
+ </div>
327
+ )
328
+ }
329
+ ```
330
+
331
+ ### Virtualization for Long Lists
332
+
333
+ ```typescript
334
+ import { useVirtualizer } from '@tanstack/react-virtual'
335
+
336
+ export function VirtualMarketList({ markets }: { markets: Market[] }) {
337
+ const parentRef = useRef<HTMLDivElement>(null)
338
+
339
+ const virtualizer = useVirtualizer({
340
+ count: markets.length,
341
+ getScrollElement: () => parentRef.current,
342
+ estimateSize: () => 100, // Estimated row height
343
+ overscan: 5 // Extra items to render
344
+ })
345
+
346
+ return (
347
+ <div ref={parentRef} style={{ height: '600px', overflow: 'auto' }}>
348
+ <div
349
+ style={{
350
+ height: `${virtualizer.getTotalSize()}px`,
351
+ position: 'relative'
352
+ }}
353
+ >
354
+ {virtualizer.getVirtualItems().map(virtualRow => (
355
+ <div
356
+ key={virtualRow.index}
357
+ style={{
358
+ position: 'absolute',
359
+ top: 0,
360
+ left: 0,
361
+ width: '100%',
362
+ height: `${virtualRow.size}px`,
363
+ transform: `translateY(${virtualRow.start}px)`
364
+ }}
365
+ >
366
+ <MarketCard market={markets[virtualRow.index]} />
367
+ </div>
368
+ ))}
369
+ </div>
370
+ </div>
371
+ )
372
+ }
373
+ ```
374
+
375
+ ## Form Handling Patterns
376
+
377
+ ### Controlled Form with Validation
378
+
379
+ ```typescript
380
+ interface FormData {
381
+ name: string
382
+ description: string
383
+ endDate: string
384
+ }
385
+
386
+ interface FormErrors {
387
+ name?: string
388
+ description?: string
389
+ endDate?: string
390
+ }
391
+
392
+ export function CreateMarketForm() {
393
+ const [formData, setFormData] = useState<FormData>({
394
+ name: '',
395
+ description: '',
396
+ endDate: ''
397
+ })
398
+
399
+ const [errors, setErrors] = useState<FormErrors>({})
400
+
401
+ const validate = (): boolean => {
402
+ const newErrors: FormErrors = {}
403
+
404
+ if (!formData.name.trim()) {
405
+ newErrors.name = 'Name is required'
406
+ } else if (formData.name.length > 200) {
407
+ newErrors.name = 'Name must be under 200 characters'
408
+ }
409
+
410
+ if (!formData.description.trim()) {
411
+ newErrors.description = 'Description is required'
412
+ }
413
+
414
+ if (!formData.endDate) {
415
+ newErrors.endDate = 'End date is required'
416
+ }
417
+
418
+ setErrors(newErrors)
419
+ return Object.keys(newErrors).length === 0
420
+ }
421
+
422
+ const handleSubmit = async (e: React.FormEvent) => {
423
+ e.preventDefault()
424
+
425
+ if (!validate()) return
426
+
427
+ try {
428
+ await createMarket(formData)
429
+ // Success handling
430
+ } catch (error) {
431
+ // Error handling
432
+ }
433
+ }
434
+
435
+ return (
436
+ <form onSubmit={handleSubmit}>
437
+ <input
438
+ value={formData.name}
439
+ onChange={e => setFormData(prev => ({ ...prev, name: e.target.value }))}
440
+ placeholder="Market name"
441
+ />
442
+ {errors.name && <span className="error">{errors.name}</span>}
443
+
444
+ {/* Other fields */}
445
+
446
+ <button type="submit">Create Market</button>
447
+ </form>
448
+ )
449
+ }
450
+ ```
451
+
452
+ ## Error Boundary Pattern
453
+
454
+ ```typescript
455
+ interface ErrorBoundaryState {
456
+ hasError: boolean
457
+ error: Error | null
458
+ }
459
+
460
+ export class ErrorBoundary extends React.Component<
461
+ { children: React.ReactNode },
462
+ ErrorBoundaryState
463
+ > {
464
+ state: ErrorBoundaryState = {
465
+ hasError: false,
466
+ error: null
467
+ }
468
+
469
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState {
470
+ return { hasError: true, error }
471
+ }
472
+
473
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
474
+ console.error('Error boundary caught:', error, errorInfo)
475
+ }
476
+
477
+ render() {
478
+ if (this.state.hasError) {
479
+ return (
480
+ <div className="error-fallback">
481
+ <h2>Something went wrong</h2>
482
+ <p>{this.state.error?.message}</p>
483
+ <button onClick={() => this.setState({ hasError: false })}>
484
+ Try again
485
+ </button>
486
+ </div>
487
+ )
488
+ }
489
+
490
+ return this.props.children
491
+ }
492
+ }
493
+
494
+ // Usage
495
+ <ErrorBoundary>
496
+ <App />
497
+ </ErrorBoundary>
498
+ ```
499
+
500
+ ## Animation Patterns
501
+
502
+ ### Framer Motion Animations
503
+
504
+ ```typescript
505
+ import { motion, AnimatePresence } from 'framer-motion'
506
+
507
+ // ✅ List animations
508
+ export function AnimatedMarketList({ markets }: { markets: Market[] }) {
509
+ return (
510
+ <AnimatePresence>
511
+ {markets.map(market => (
512
+ <motion.div
513
+ key={market.id}
514
+ initial={{ opacity: 0, y: 20 }}
515
+ animate={{ opacity: 1, y: 0 }}
516
+ exit={{ opacity: 0, y: -20 }}
517
+ transition={{ duration: 0.3 }}
518
+ >
519
+ <MarketCard market={market} />
520
+ </motion.div>
521
+ ))}
522
+ </AnimatePresence>
523
+ )
524
+ }
525
+
526
+ // ✅ Modal animations
527
+ export function Modal({ isOpen, onClose, children }: ModalProps) {
528
+ return (
529
+ <AnimatePresence>
530
+ {isOpen && (
531
+ <>
532
+ <motion.div
533
+ className="modal-overlay"
534
+ initial={{ opacity: 0 }}
535
+ animate={{ opacity: 1 }}
536
+ exit={{ opacity: 0 }}
537
+ onClick={onClose}
538
+ />
539
+ <motion.div
540
+ className="modal-content"
541
+ initial={{ opacity: 0, scale: 0.9, y: 20 }}
542
+ animate={{ opacity: 1, scale: 1, y: 0 }}
543
+ exit={{ opacity: 0, scale: 0.9, y: 20 }}
544
+ >
545
+ {children}
546
+ </motion.div>
547
+ </>
548
+ )}
549
+ </AnimatePresence>
550
+ )
551
+ }
552
+ ```
553
+
554
+ ## Accessibility Patterns
555
+
556
+ ### Keyboard Navigation
557
+
558
+ ```typescript
559
+ export function Dropdown({ options, onSelect }: DropdownProps) {
560
+ const [isOpen, setIsOpen] = useState(false)
561
+ const [activeIndex, setActiveIndex] = useState(0)
562
+
563
+ const handleKeyDown = (e: React.KeyboardEvent) => {
564
+ switch (e.key) {
565
+ case 'ArrowDown':
566
+ e.preventDefault()
567
+ setActiveIndex(i => Math.min(i + 1, options.length - 1))
568
+ break
569
+ case 'ArrowUp':
570
+ e.preventDefault()
571
+ setActiveIndex(i => Math.max(i - 1, 0))
572
+ break
573
+ case 'Enter':
574
+ e.preventDefault()
575
+ onSelect(options[activeIndex])
576
+ setIsOpen(false)
577
+ break
578
+ case 'Escape':
579
+ setIsOpen(false)
580
+ break
581
+ }
582
+ }
583
+
584
+ return (
585
+ <div
586
+ role="combobox"
587
+ aria-expanded={isOpen}
588
+ aria-haspopup="listbox"
589
+ onKeyDown={handleKeyDown}
590
+ >
591
+ {/* Dropdown implementation */}
592
+ </div>
593
+ )
594
+ }
595
+ ```
596
+
597
+ ### Focus Management
598
+
599
+ ```typescript
600
+ export function Modal({ isOpen, onClose, children }: ModalProps) {
601
+ const modalRef = useRef<HTMLDivElement>(null)
602
+ const previousFocusRef = useRef<HTMLElement | null>(null)
603
+
604
+ useEffect(() => {
605
+ if (isOpen) {
606
+ // Save currently focused element
607
+ previousFocusRef.current = document.activeElement as HTMLElement
608
+
609
+ // Focus modal
610
+ modalRef.current?.focus()
611
+ } else {
612
+ // Restore focus when closing
613
+ previousFocusRef.current?.focus()
614
+ }
615
+ }, [isOpen])
616
+
617
+ return isOpen ? (
618
+ <div
619
+ ref={modalRef}
620
+ role="dialog"
621
+ aria-modal="true"
622
+ tabIndex={-1}
623
+ onKeyDown={e => e.key === 'Escape' && onClose()}
624
+ >
625
+ {children}
626
+ </div>
627
+ ) : null
628
+ }
629
+ ```
630
+
631
+ **Remember**: Modern frontend patterns enable maintainable, performant user interfaces. Choose patterns that fit your project complexity.