@persistadev/mcp-server 3.3.5 → 3.3.8
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/dist/index.js +73 -0
- package/dist/index.js.map +1 -1
- package/dist/knowledge-base.d.ts +27 -0
- package/dist/knowledge-base.d.ts.map +1 -0
- package/dist/knowledge-base.js +1430 -0
- package/dist/knowledge-base.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,1430 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PERSISTA KNOWLEDGE BASE v2.0
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════
|
|
5
|
+
* A comprehensive collection of development knowledge including:
|
|
6
|
+
* - AI Prompts for every task
|
|
7
|
+
* - Design systems & tokens
|
|
8
|
+
* - Architecture patterns
|
|
9
|
+
* - Checklists for launch, security, a11y, code review
|
|
10
|
+
* - Code patterns & hooks
|
|
11
|
+
* - Boilerplates & templates
|
|
12
|
+
* - Workflows & processes
|
|
13
|
+
* - Best practices for every framework
|
|
14
|
+
* ═══════════════════════════════════════════════════════════════
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.KNOWLEDGE_BASE = void 0;
|
|
18
|
+
exports.KNOWLEDGE_BASE = [
|
|
19
|
+
// ═══════════════════════════════════════════════════════════════
|
|
20
|
+
// 🎯 AI PROMPTS - Elite development prompts
|
|
21
|
+
// ═══════════════════════════════════════════════════════════════
|
|
22
|
+
// React Prompts
|
|
23
|
+
{ domain: 'prompts', topic: 'react', update_type: 'prompt', title: 'Generate React Component', content: `Create a React component called [ComponentName] that:
|
|
24
|
+
- Uses TypeScript with proper type definitions
|
|
25
|
+
- Follows single responsibility principle
|
|
26
|
+
- Includes JSDoc comments for props
|
|
27
|
+
- Uses CSS modules for styling
|
|
28
|
+
- Handles loading, error, and empty states
|
|
29
|
+
- Is accessible (ARIA labels, keyboard nav)
|
|
30
|
+
- Includes basic unit test file
|
|
31
|
+
|
|
32
|
+
Props needed: [describe]
|
|
33
|
+
Functionality: [describe]` },
|
|
34
|
+
{ domain: 'prompts', topic: 'react', update_type: 'prompt', title: 'Refactor React Component', content: `Refactor this React component to:
|
|
35
|
+
1. Extract reusable logic into custom hooks
|
|
36
|
+
2. Memoize expensive computations with useMemo
|
|
37
|
+
3. Optimize re-renders with React.memo
|
|
38
|
+
4. Split into smaller components if over 150 lines
|
|
39
|
+
5. Add proper TypeScript types (no 'any')
|
|
40
|
+
6. Improve accessibility
|
|
41
|
+
7. Add error boundaries if needed
|
|
42
|
+
|
|
43
|
+
Explain each change and why.` },
|
|
44
|
+
{ domain: 'prompts', topic: 'react', update_type: 'prompt', title: 'Debug React Performance', content: `This React app is slow. Help debug:
|
|
45
|
+
1. Identify unnecessary re-renders using React DevTools
|
|
46
|
+
2. Find expensive computations to memoize
|
|
47
|
+
3. Detect prop drilling that needs Context
|
|
48
|
+
4. Spot missing keys in lists
|
|
49
|
+
5. Find components to lazy load
|
|
50
|
+
6. Check for memory leaks in useEffect
|
|
51
|
+
|
|
52
|
+
For each issue: problem, why it's slow, fix with code.` },
|
|
53
|
+
{ domain: 'prompts', topic: 'react', update_type: 'prompt', title: 'Create Custom Hook', content: `Create a custom React hook called [useName] that:
|
|
54
|
+
- Follows the Rules of Hooks
|
|
55
|
+
- Has proper TypeScript types
|
|
56
|
+
- Handles cleanup in useEffect
|
|
57
|
+
- Is reusable across components
|
|
58
|
+
- Includes error handling
|
|
59
|
+
- Has JSDoc documentation
|
|
60
|
+
|
|
61
|
+
Purpose: [describe]
|
|
62
|
+
Inputs: [describe]
|
|
63
|
+
Returns: [describe]` },
|
|
64
|
+
{ domain: 'prompts', topic: 'react', update_type: 'prompt', title: 'Convert Class to Function', content: `Convert this class component to a functional component:
|
|
65
|
+
1. Replace state with useState
|
|
66
|
+
2. Convert lifecycle methods to useEffect
|
|
67
|
+
3. Move instance methods to useCallback
|
|
68
|
+
4. Use useMemo for derived state
|
|
69
|
+
5. Keep same external API
|
|
70
|
+
6. Add TypeScript types
|
|
71
|
+
7. Test behavior is identical` },
|
|
72
|
+
// TypeScript Prompts
|
|
73
|
+
{ domain: 'prompts', topic: 'typescript', update_type: 'prompt', title: 'Type This JavaScript', content: `Convert this JavaScript to TypeScript:
|
|
74
|
+
1. Add types for all variables, params, returns
|
|
75
|
+
2. Create interfaces for complex objects
|
|
76
|
+
3. Use generics where appropriate
|
|
77
|
+
4. Add type guards for runtime checking
|
|
78
|
+
5. Use strict null checks
|
|
79
|
+
6. No 'any' - use 'unknown' if needed
|
|
80
|
+
7. Export types consumers might need` },
|
|
81
|
+
{ domain: 'prompts', topic: 'typescript', update_type: 'prompt', title: 'Create Type-Safe API', content: `Create a type-safe API client:
|
|
82
|
+
1. Full TypeScript types for requests/responses
|
|
83
|
+
2. Type-safe path params and query strings
|
|
84
|
+
3. Proper error types and handling
|
|
85
|
+
4. Generic fetch wrapper with JSON parsing
|
|
86
|
+
5. Request/response interceptors
|
|
87
|
+
6. Retry logic with exponential backoff
|
|
88
|
+
7. Cancel token support` },
|
|
89
|
+
{ domain: 'prompts', topic: 'typescript', update_type: 'prompt', title: 'Fix TypeScript Errors', content: `Fix these TypeScript errors:
|
|
90
|
+
1. Explain what each error means
|
|
91
|
+
2. Show the incorrect code
|
|
92
|
+
3. Show the corrected code
|
|
93
|
+
4. Explain why the fix works
|
|
94
|
+
5. Suggest stricter types if applicable
|
|
95
|
+
6. Check for potential runtime issues the types might miss` },
|
|
96
|
+
{ domain: 'prompts', topic: 'typescript', update_type: 'prompt', title: 'Create Type Utilities', content: `Create TypeScript utility types for:
|
|
97
|
+
1. DeepPartial<T> - all nested props optional
|
|
98
|
+
2. DeepRequired<T> - all nested props required
|
|
99
|
+
3. PickByType<T, U> - pick props of certain type
|
|
100
|
+
4. Mutable<T> - remove readonly
|
|
101
|
+
5. NonNullableProps<T> - remove null/undefined
|
|
102
|
+
6. Include usage examples for each` },
|
|
103
|
+
// Next.js Prompts
|
|
104
|
+
{ domain: 'prompts', topic: 'nextjs', update_type: 'prompt', title: 'Create Next.js Page', content: `Create a Next.js App Router page for [route]:
|
|
105
|
+
1. Server Component by default
|
|
106
|
+
2. Proper metadata export for SEO
|
|
107
|
+
3. Loading state with loading.tsx
|
|
108
|
+
4. Error handling with error.tsx
|
|
109
|
+
5. generateStaticParams if dynamic
|
|
110
|
+
6. Parallel data fetching
|
|
111
|
+
7. Proper TypeScript types
|
|
112
|
+
8. Accessible and responsive` },
|
|
113
|
+
{ domain: 'prompts', topic: 'nextjs', update_type: 'prompt', title: 'Create Server Action', content: `Create a Next.js Server Action:
|
|
114
|
+
1. 'use server' directive at top
|
|
115
|
+
2. Zod validation for all inputs
|
|
116
|
+
3. Proper error handling with try/catch
|
|
117
|
+
4. Revalidate affected paths
|
|
118
|
+
5. Return typed response
|
|
119
|
+
6. Rate limiting consideration
|
|
120
|
+
7. Auth check with getServerSession` },
|
|
121
|
+
{ domain: 'prompts', topic: 'nextjs', update_type: 'prompt', title: 'Optimize Next.js App', content: `Optimize this Next.js app:
|
|
122
|
+
1. Audit with next build --analyze
|
|
123
|
+
2. Identify client vs server components
|
|
124
|
+
3. Add dynamic imports for heavy components
|
|
125
|
+
4. Optimize images with next/image
|
|
126
|
+
5. Implement ISR where appropriate
|
|
127
|
+
6. Add proper caching headers
|
|
128
|
+
7. Check Core Web Vitals` },
|
|
129
|
+
// Database Prompts
|
|
130
|
+
{ domain: 'prompts', topic: 'database', update_type: 'prompt', title: 'Design Database Schema', content: `Design a database schema for [feature]:
|
|
131
|
+
1. Normalized (3NF unless justified)
|
|
132
|
+
2. Proper foreign keys with ON DELETE
|
|
133
|
+
3. Indexes for common queries
|
|
134
|
+
4. Timestamps (created_at, updated_at)
|
|
135
|
+
5. Soft delete if needed (deleted_at)
|
|
136
|
+
6. UUID primary keys
|
|
137
|
+
7. RLS policies for Supabase
|
|
138
|
+
|
|
139
|
+
Output as SQL CREATE statements with comments.` },
|
|
140
|
+
{ domain: 'prompts', topic: 'database', update_type: 'prompt', title: 'Optimize SQL Query', content: `Optimize this SQL query:
|
|
141
|
+
1. Analyze with EXPLAIN ANALYZE
|
|
142
|
+
2. Check for missing indexes
|
|
143
|
+
3. Identify N+1 patterns
|
|
144
|
+
4. Consider denormalization trade-offs
|
|
145
|
+
5. Suggest pagination if large result
|
|
146
|
+
6. Check for proper JOIN types
|
|
147
|
+
7. Show before/after performance` },
|
|
148
|
+
{ domain: 'prompts', topic: 'database', update_type: 'prompt', title: 'Write Supabase RLS', content: `Write Row Level Security policies for [table]:
|
|
149
|
+
1. Enable RLS first
|
|
150
|
+
2. SELECT policy for read access
|
|
151
|
+
3. INSERT policy with auth checks
|
|
152
|
+
4. UPDATE policy scoped to owner
|
|
153
|
+
5. DELETE policy if needed
|
|
154
|
+
6. Consider service role bypass
|
|
155
|
+
7. Test each policy` },
|
|
156
|
+
// Code Review Prompts
|
|
157
|
+
{ domain: 'prompts', topic: 'review', update_type: 'prompt', title: 'Full Code Review', content: `Review this code thoroughly:
|
|
158
|
+
|
|
159
|
+
## Security
|
|
160
|
+
- SQL injection, XSS, CSRF
|
|
161
|
+
- Data exposure, auth issues
|
|
162
|
+
- Secrets in code
|
|
163
|
+
|
|
164
|
+
## Performance
|
|
165
|
+
- N+1 queries, missing indexes
|
|
166
|
+
- Memory leaks, bundle size
|
|
167
|
+
- Unnecessary re-renders
|
|
168
|
+
|
|
169
|
+
## Maintainability
|
|
170
|
+
- Naming conventions
|
|
171
|
+
- Single responsibility
|
|
172
|
+
- DRY violations
|
|
173
|
+
- Code complexity (cyclomatic)
|
|
174
|
+
|
|
175
|
+
## TypeScript
|
|
176
|
+
- No 'any' usage
|
|
177
|
+
- Proper null handling
|
|
178
|
+
- Correct generic usage
|
|
179
|
+
|
|
180
|
+
Provide specific line-by-line feedback with fixes.` },
|
|
181
|
+
{ domain: 'prompts', topic: 'review', update_type: 'prompt', title: 'Security Audit', content: `Security audit this code:
|
|
182
|
+
1. Authentication vulnerabilities
|
|
183
|
+
2. Authorization bypass risks
|
|
184
|
+
3. Input validation gaps
|
|
185
|
+
4. Output encoding issues
|
|
186
|
+
5. Sensitive data exposure
|
|
187
|
+
6. Dependency vulnerabilities
|
|
188
|
+
7. Error message information leaks
|
|
189
|
+
|
|
190
|
+
For each issue: severity, impact, fix.` },
|
|
191
|
+
// Debugging Prompts
|
|
192
|
+
{ domain: 'prompts', topic: 'debugging', update_type: 'prompt', title: 'Debug This Error', content: `Debug this error:
|
|
193
|
+
|
|
194
|
+
Error: [paste error]
|
|
195
|
+
Context: [what you were doing]
|
|
196
|
+
Environment: [dev/prod, versions]
|
|
197
|
+
|
|
198
|
+
1. Explain what this error means
|
|
199
|
+
2. List most common causes (ranked by likelihood)
|
|
200
|
+
3. Debugging steps to find root cause
|
|
201
|
+
4. Give fix with code example
|
|
202
|
+
5. How to prevent this in future` },
|
|
203
|
+
{ domain: 'prompts', topic: 'debugging', update_type: 'prompt', title: 'Debug Memory Leak', content: `This app has a memory leak. Help find it:
|
|
204
|
+
1. How to profile memory in Chrome DevTools
|
|
205
|
+
2. Common React memory leak patterns
|
|
206
|
+
3. Event listener cleanup
|
|
207
|
+
4. Subscription cleanup
|
|
208
|
+
5. Timer cleanup
|
|
209
|
+
6. DOM reference cleanup
|
|
210
|
+
7. Show fix for each pattern` },
|
|
211
|
+
{ domain: 'prompts', topic: 'debugging', update_type: 'prompt', title: 'Debug Slow Page', content: `This page is slow. Diagnose:
|
|
212
|
+
1. Run Lighthouse audit
|
|
213
|
+
2. Check Network tab for slow requests
|
|
214
|
+
3. Look for layout thrashing
|
|
215
|
+
4. Find large JavaScript bundles
|
|
216
|
+
5. Identify render-blocking resources
|
|
217
|
+
6. Check for hydration issues
|
|
218
|
+
7. Prioritize fixes by impact` },
|
|
219
|
+
// Testing Prompts
|
|
220
|
+
{ domain: 'prompts', topic: 'testing', update_type: 'prompt', title: 'Write Unit Tests', content: `Write unit tests for this code:
|
|
221
|
+
1. Test happy path
|
|
222
|
+
2. Test edge cases
|
|
223
|
+
3. Test error handling
|
|
224
|
+
4. Mock external dependencies
|
|
225
|
+
5. Use describe/it structure
|
|
226
|
+
6. Aim for high coverage
|
|
227
|
+
7. Use meaningful test names
|
|
228
|
+
|
|
229
|
+
Framework: Jest + React Testing Library` },
|
|
230
|
+
{ domain: 'prompts', topic: 'testing', update_type: 'prompt', title: 'Write E2E Tests', content: `Write E2E tests for this feature:
|
|
231
|
+
1. User flows to test
|
|
232
|
+
2. Setup/teardown database state
|
|
233
|
+
3. Mock external APIs
|
|
234
|
+
4. Test happy path
|
|
235
|
+
5. Test error states
|
|
236
|
+
6. Test edge cases
|
|
237
|
+
7. Keep tests independent
|
|
238
|
+
|
|
239
|
+
Framework: Playwright` },
|
|
240
|
+
// Architecture Prompts
|
|
241
|
+
{ domain: 'prompts', topic: 'architecture', update_type: 'prompt', title: 'Design System Architecture', content: `Design the architecture for [system]:
|
|
242
|
+
1. Requirements analysis
|
|
243
|
+
2. Component breakdown
|
|
244
|
+
3. Data flow diagram
|
|
245
|
+
4. API design
|
|
246
|
+
5. Database schema
|
|
247
|
+
6. Deployment strategy
|
|
248
|
+
7. Scalability considerations
|
|
249
|
+
8. Security measures
|
|
250
|
+
9. Monitoring plan` },
|
|
251
|
+
{ domain: 'prompts', topic: 'architecture', update_type: 'prompt', title: 'Microservices Design', content: `Design microservices for [domain]:
|
|
252
|
+
1. Service boundaries (DDD approach)
|
|
253
|
+
2. Communication patterns (sync/async)
|
|
254
|
+
3. Data ownership
|
|
255
|
+
4. API contracts
|
|
256
|
+
5. Event-driven patterns
|
|
257
|
+
6. Service discovery
|
|
258
|
+
7. Fault tolerance
|
|
259
|
+
8. Deployment topology` },
|
|
260
|
+
// ═══════════════════════════════════════════════════════════════
|
|
261
|
+
// 🎨 DESIGN SYSTEMS
|
|
262
|
+
// ═══════════════════════════════════════════════════════════════
|
|
263
|
+
{ domain: 'design', topic: 'colors', update_type: 'design_system', title: 'Modern SaaS Light Palette', content: `:root {
|
|
264
|
+
/* Primary */
|
|
265
|
+
--primary-50: #faf5ff;
|
|
266
|
+
--primary-100: #f3e8ff;
|
|
267
|
+
--primary-200: #e9d5ff;
|
|
268
|
+
--primary-500: #a855f7;
|
|
269
|
+
--primary-600: #9333ea;
|
|
270
|
+
--primary-700: #7e22ce;
|
|
271
|
+
|
|
272
|
+
/* Neutrals */
|
|
273
|
+
--gray-50: #f8fafc;
|
|
274
|
+
--gray-100: #f1f5f9;
|
|
275
|
+
--gray-200: #e2e8f0;
|
|
276
|
+
--gray-300: #cbd5e1;
|
|
277
|
+
--gray-400: #94a3b8;
|
|
278
|
+
--gray-500: #64748b;
|
|
279
|
+
--gray-600: #475569;
|
|
280
|
+
--gray-700: #334155;
|
|
281
|
+
--gray-800: #1e293b;
|
|
282
|
+
--gray-900: #0f172a;
|
|
283
|
+
|
|
284
|
+
/* Semantic */
|
|
285
|
+
--success: #10b981;
|
|
286
|
+
--warning: #f59e0b;
|
|
287
|
+
--error: #ef4444;
|
|
288
|
+
--info: #3b82f6;
|
|
289
|
+
}` },
|
|
290
|
+
{ domain: 'design', topic: 'colors', update_type: 'design_system', title: 'Dark Mode Palette', content: `[data-theme="dark"] {
|
|
291
|
+
--bg-primary: #09090b;
|
|
292
|
+
--bg-secondary: #18181b;
|
|
293
|
+
--bg-tertiary: #27272a;
|
|
294
|
+
--bg-elevated: #3f3f46;
|
|
295
|
+
|
|
296
|
+
--text-primary: #fafafa;
|
|
297
|
+
--text-secondary: #a1a1aa;
|
|
298
|
+
--text-muted: #71717a;
|
|
299
|
+
|
|
300
|
+
--border-subtle: #27272a;
|
|
301
|
+
--border-default: #3f3f46;
|
|
302
|
+
--border-strong: #52525b;
|
|
303
|
+
|
|
304
|
+
--accent: #a855f7;
|
|
305
|
+
--accent-hover: #9333ea;
|
|
306
|
+
|
|
307
|
+
/* Adjust semantic colors for dark */
|
|
308
|
+
--success: #34d399;
|
|
309
|
+
--warning: #fbbf24;
|
|
310
|
+
--error: #f87171;
|
|
311
|
+
--info: #60a5fa;
|
|
312
|
+
}` },
|
|
313
|
+
{ domain: 'design', topic: 'typography', update_type: 'design_system', title: 'Typography Scale', content: `:root {
|
|
314
|
+
/* Font Families */
|
|
315
|
+
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
316
|
+
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
|
|
317
|
+
--font-display: 'Cal Sans', 'Inter', sans-serif;
|
|
318
|
+
|
|
319
|
+
/* Size Scale (rem) */
|
|
320
|
+
--text-xs: 0.75rem; /* 12px */
|
|
321
|
+
--text-sm: 0.875rem; /* 14px */
|
|
322
|
+
--text-base: 1rem; /* 16px */
|
|
323
|
+
--text-lg: 1.125rem; /* 18px */
|
|
324
|
+
--text-xl: 1.25rem; /* 20px */
|
|
325
|
+
--text-2xl: 1.5rem; /* 24px */
|
|
326
|
+
--text-3xl: 1.875rem; /* 30px */
|
|
327
|
+
--text-4xl: 2.25rem; /* 36px */
|
|
328
|
+
--text-5xl: 3rem; /* 48px */
|
|
329
|
+
|
|
330
|
+
/* Line Heights */
|
|
331
|
+
--leading-none: 1;
|
|
332
|
+
--leading-tight: 1.25;
|
|
333
|
+
--leading-snug: 1.375;
|
|
334
|
+
--leading-normal: 1.5;
|
|
335
|
+
--leading-relaxed: 1.625;
|
|
336
|
+
|
|
337
|
+
/* Font Weights */
|
|
338
|
+
--font-normal: 400;
|
|
339
|
+
--font-medium: 500;
|
|
340
|
+
--font-semibold: 600;
|
|
341
|
+
--font-bold: 700;
|
|
342
|
+
}` },
|
|
343
|
+
{ domain: 'design', topic: 'spacing', update_type: 'design_system', title: 'Spacing & Layout', content: `:root {
|
|
344
|
+
/* Spacing Scale */
|
|
345
|
+
--space-0: 0;
|
|
346
|
+
--space-1: 0.25rem; /* 4px */
|
|
347
|
+
--space-2: 0.5rem; /* 8px */
|
|
348
|
+
--space-3: 0.75rem; /* 12px */
|
|
349
|
+
--space-4: 1rem; /* 16px */
|
|
350
|
+
--space-5: 1.25rem; /* 20px */
|
|
351
|
+
--space-6: 1.5rem; /* 24px */
|
|
352
|
+
--space-8: 2rem; /* 32px */
|
|
353
|
+
--space-10: 2.5rem; /* 40px */
|
|
354
|
+
--space-12: 3rem; /* 48px */
|
|
355
|
+
--space-16: 4rem; /* 64px */
|
|
356
|
+
--space-20: 5rem; /* 80px */
|
|
357
|
+
|
|
358
|
+
/* Border Radius */
|
|
359
|
+
--radius-sm: 4px;
|
|
360
|
+
--radius-md: 8px;
|
|
361
|
+
--radius-lg: 12px;
|
|
362
|
+
--radius-xl: 16px;
|
|
363
|
+
--radius-2xl: 24px;
|
|
364
|
+
--radius-full: 9999px;
|
|
365
|
+
|
|
366
|
+
/* Shadows */
|
|
367
|
+
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
368
|
+
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
|
369
|
+
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
|
|
370
|
+
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
|
|
371
|
+
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
|
372
|
+
}` },
|
|
373
|
+
{ domain: 'design', topic: 'animations', update_type: 'design_system', title: 'Animation Tokens', content: `:root {
|
|
374
|
+
/* Durations */
|
|
375
|
+
--duration-fast: 150ms;
|
|
376
|
+
--duration-normal: 200ms;
|
|
377
|
+
--duration-slow: 300ms;
|
|
378
|
+
--duration-slower: 500ms;
|
|
379
|
+
|
|
380
|
+
/* Easings */
|
|
381
|
+
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
382
|
+
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
383
|
+
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
|
384
|
+
--ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
|
385
|
+
|
|
386
|
+
/* Common Transitions */
|
|
387
|
+
--transition-colors: color var(--duration-fast) var(--ease-in-out),
|
|
388
|
+
background-color var(--duration-fast) var(--ease-in-out),
|
|
389
|
+
border-color var(--duration-fast) var(--ease-in-out);
|
|
390
|
+
--transition-transform: transform var(--duration-normal) var(--ease-out);
|
|
391
|
+
--transition-opacity: opacity var(--duration-normal) var(--ease-in-out);
|
|
392
|
+
--transition-all: all var(--duration-normal) var(--ease-in-out);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/* Keyframes */
|
|
396
|
+
@keyframes fadeIn {
|
|
397
|
+
from { opacity: 0; }
|
|
398
|
+
to { opacity: 1; }
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
@keyframes slideUp {
|
|
402
|
+
from { opacity: 0; transform: translateY(10px); }
|
|
403
|
+
to { opacity: 1; transform: translateY(0); }
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
@keyframes spin {
|
|
407
|
+
to { transform: rotate(360deg); }
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
@keyframes pulse {
|
|
411
|
+
50% { opacity: 0.5; }
|
|
412
|
+
}` },
|
|
413
|
+
{ domain: 'design', topic: 'components', update_type: 'design_system', title: 'Button Variants', content: `.btn {
|
|
414
|
+
display: inline-flex;
|
|
415
|
+
align-items: center;
|
|
416
|
+
justify-content: center;
|
|
417
|
+
gap: var(--space-2);
|
|
418
|
+
padding: var(--space-2) var(--space-4);
|
|
419
|
+
font-size: var(--text-sm);
|
|
420
|
+
font-weight: var(--font-medium);
|
|
421
|
+
border-radius: var(--radius-md);
|
|
422
|
+
transition: var(--transition-colors);
|
|
423
|
+
cursor: pointer;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.btn-primary {
|
|
427
|
+
background: var(--primary-600);
|
|
428
|
+
color: white;
|
|
429
|
+
border: none;
|
|
430
|
+
}
|
|
431
|
+
.btn-primary:hover { background: var(--primary-700); }
|
|
432
|
+
|
|
433
|
+
.btn-secondary {
|
|
434
|
+
background: transparent;
|
|
435
|
+
color: var(--gray-700);
|
|
436
|
+
border: 1px solid var(--gray-300);
|
|
437
|
+
}
|
|
438
|
+
.btn-secondary:hover { background: var(--gray-50); }
|
|
439
|
+
|
|
440
|
+
.btn-ghost {
|
|
441
|
+
background: transparent;
|
|
442
|
+
color: var(--gray-600);
|
|
443
|
+
border: none;
|
|
444
|
+
}
|
|
445
|
+
.btn-ghost:hover { background: var(--gray-100); }
|
|
446
|
+
|
|
447
|
+
.btn-danger {
|
|
448
|
+
background: var(--error);
|
|
449
|
+
color: white;
|
|
450
|
+
border: none;
|
|
451
|
+
}
|
|
452
|
+
.btn-danger:hover { background: #dc2626; }` },
|
|
453
|
+
// ═══════════════════════════════════════════════════════════════
|
|
454
|
+
// 📁 ARCHITECTURE
|
|
455
|
+
// ═══════════════════════════════════════════════════════════════
|
|
456
|
+
{ domain: 'architecture', topic: 'react', update_type: 'architecture', title: 'React Project Structure', content: `src/
|
|
457
|
+
├── components/
|
|
458
|
+
│ ├── ui/ # Reusable UI (Button, Input, Modal)
|
|
459
|
+
│ ├── features/ # Feature-specific components
|
|
460
|
+
│ ├── layouts/ # Layout components
|
|
461
|
+
│ └── providers/ # Context providers
|
|
462
|
+
├── hooks/ # Custom hooks
|
|
463
|
+
├── lib/
|
|
464
|
+
│ ├── api.ts # API client
|
|
465
|
+
│ ├── utils.ts # Utility functions
|
|
466
|
+
│ └── constants.ts # App constants
|
|
467
|
+
├── stores/ # State management (Zustand/Jotai)
|
|
468
|
+
├── types/ # TypeScript types
|
|
469
|
+
├── styles/ # Global CSS, themes
|
|
470
|
+
└── app/ or pages/ # Routes` },
|
|
471
|
+
{ domain: 'architecture', topic: 'nextjs', update_type: 'architecture', title: 'Next.js App Router Structure', content: `app/
|
|
472
|
+
├── (marketing)/ # Marketing pages (landing, pricing)
|
|
473
|
+
│ ├── page.tsx
|
|
474
|
+
│ └── layout.tsx
|
|
475
|
+
├── (auth)/ # Auth pages (login, register)
|
|
476
|
+
│ ├── login/
|
|
477
|
+
│ ├── register/
|
|
478
|
+
│ └── layout.tsx
|
|
479
|
+
├── (dashboard)/ # Protected dashboard
|
|
480
|
+
│ ├── dashboard/
|
|
481
|
+
│ ├── settings/
|
|
482
|
+
│ └── layout.tsx # With auth check
|
|
483
|
+
├── api/ # API routes
|
|
484
|
+
│ └── [...route]/
|
|
485
|
+
├── globals.css
|
|
486
|
+
├── layout.tsx # Root layout
|
|
487
|
+
└── not-found.tsx
|
|
488
|
+
|
|
489
|
+
Key Conventions:
|
|
490
|
+
(folder) = Route group (no URL impact)
|
|
491
|
+
[folder] = Dynamic route
|
|
492
|
+
@folder = Parallel route
|
|
493
|
+
loading.tsx = Suspense boundary
|
|
494
|
+
error.tsx = Error boundary
|
|
495
|
+
template.tsx = Re-render on nav` },
|
|
496
|
+
{ domain: 'architecture', topic: 'api', update_type: 'architecture', title: 'REST API Design', content: `# Endpoints
|
|
497
|
+
GET /api/users # List (paginated)
|
|
498
|
+
POST /api/users # Create
|
|
499
|
+
GET /api/users/:id # Get one
|
|
500
|
+
PUT /api/users/:id # Replace
|
|
501
|
+
PATCH /api/users/:id # Partial update
|
|
502
|
+
DELETE /api/users/:id # Delete
|
|
503
|
+
|
|
504
|
+
# Query Parameters
|
|
505
|
+
?page=1&limit=20 # Pagination
|
|
506
|
+
?sort=-created_at # Sort (- = desc)
|
|
507
|
+
?filter[status]=active # Filter
|
|
508
|
+
?include=posts,comments # Relations
|
|
509
|
+
?fields=id,name,email # Sparse fields
|
|
510
|
+
|
|
511
|
+
# Response Format
|
|
512
|
+
{
|
|
513
|
+
"data": [...],
|
|
514
|
+
"meta": {
|
|
515
|
+
"total": 100,
|
|
516
|
+
"page": 1,
|
|
517
|
+
"limit": 20,
|
|
518
|
+
"pages": 5
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
# Error Format
|
|
523
|
+
{
|
|
524
|
+
"error": {
|
|
525
|
+
"code": "VALIDATION_ERROR",
|
|
526
|
+
"message": "Invalid input",
|
|
527
|
+
"details": [...]
|
|
528
|
+
}
|
|
529
|
+
}` },
|
|
530
|
+
{ domain: 'architecture', topic: 'monorepo', update_type: 'architecture', title: 'Monorepo Structure (Turborepo)', content: `monorepo/
|
|
531
|
+
├── apps/
|
|
532
|
+
│ ├── web/ # Next.js frontend
|
|
533
|
+
│ ├── api/ # Backend service
|
|
534
|
+
│ ├── admin/ # Admin dashboard
|
|
535
|
+
│ └── docs/ # Documentation
|
|
536
|
+
├── packages/
|
|
537
|
+
│ ├── ui/ # Shared UI components
|
|
538
|
+
│ ├── config/ # Shared configs (ESLint, TS)
|
|
539
|
+
│ ├── database/ # Prisma/Drizzle schema
|
|
540
|
+
│ └── utils/ # Shared utilities
|
|
541
|
+
├── turbo.json # Turborepo config
|
|
542
|
+
├── package.json # Root package.json
|
|
543
|
+
└── pnpm-workspace.yaml # Workspace config
|
|
544
|
+
|
|
545
|
+
Benefits:
|
|
546
|
+
- Shared code between apps
|
|
547
|
+
- Atomic changes across packages
|
|
548
|
+
- Consistent tooling
|
|
549
|
+
- Faster builds with caching` },
|
|
550
|
+
{ domain: 'architecture', topic: 'clean', update_type: 'architecture', title: 'Clean Architecture Layers', content: `# Layer Structure
|
|
551
|
+
|
|
552
|
+
## 1. Domain (innermost)
|
|
553
|
+
- Entities: Core business objects
|
|
554
|
+
- Value Objects: Immutable objects
|
|
555
|
+
- Domain Events: Business events
|
|
556
|
+
- No external dependencies
|
|
557
|
+
|
|
558
|
+
## 2. Application
|
|
559
|
+
- Use Cases: Application-specific logic
|
|
560
|
+
- Interfaces: Ports for adapters
|
|
561
|
+
- DTOs: Data transfer objects
|
|
562
|
+
- Depends only on Domain
|
|
563
|
+
|
|
564
|
+
## 3. Infrastructure (outermost)
|
|
565
|
+
- Repositories: Data access implementation
|
|
566
|
+
- External Services: APIs, email, etc.
|
|
567
|
+
- Framework Code: Express, Next.js
|
|
568
|
+
- Implements Application interfaces
|
|
569
|
+
|
|
570
|
+
## 4. Presentation
|
|
571
|
+
- Controllers: HTTP handlers
|
|
572
|
+
- Views: UI components
|
|
573
|
+
- Presenters: Format data for views
|
|
574
|
+
|
|
575
|
+
# Dependency Rule
|
|
576
|
+
Dependencies point inward only.
|
|
577
|
+
Inner layers don't know about outer layers.` },
|
|
578
|
+
// ═══════════════════════════════════════════════════════════════
|
|
579
|
+
// ✅ CHECKLISTS
|
|
580
|
+
// ═══════════════════════════════════════════════════════════════
|
|
581
|
+
{ domain: 'checklist', topic: 'launch', update_type: 'checklist', title: 'Production Launch Checklist', content: `## Performance
|
|
582
|
+
- [ ] Lighthouse score > 90
|
|
583
|
+
- [ ] Images optimized (WebP, lazy loading)
|
|
584
|
+
- [ ] Bundle size analyzed and optimized
|
|
585
|
+
- [ ] Core Web Vitals passing
|
|
586
|
+
- [ ] CDN configured
|
|
587
|
+
|
|
588
|
+
## SEO
|
|
589
|
+
- [ ] Meta tags on all pages
|
|
590
|
+
- [ ] Open Graph tags for social
|
|
591
|
+
- [ ] Sitemap.xml generated
|
|
592
|
+
- [ ] robots.txt configured
|
|
593
|
+
- [ ] Canonical URLs set
|
|
594
|
+
- [ ] Schema.org markup
|
|
595
|
+
|
|
596
|
+
## Security
|
|
597
|
+
- [ ] HTTPS enforced
|
|
598
|
+
- [ ] Security headers (CSP, HSTS)
|
|
599
|
+
- [ ] Rate limiting enabled
|
|
600
|
+
- [ ] Input validation everywhere
|
|
601
|
+
- [ ] SQL injection prevented
|
|
602
|
+
- [ ] XSS prevented
|
|
603
|
+
|
|
604
|
+
## Monitoring
|
|
605
|
+
- [ ] Error tracking (Sentry)
|
|
606
|
+
- [ ] Analytics (Plausible/GA)
|
|
607
|
+
- [ ] Uptime monitoring
|
|
608
|
+
- [ ] Performance monitoring
|
|
609
|
+
- [ ] Log aggregation
|
|
610
|
+
|
|
611
|
+
## Backups & Recovery
|
|
612
|
+
- [ ] Database backups automated
|
|
613
|
+
- [ ] Backup restore tested
|
|
614
|
+
- [ ] Disaster recovery plan
|
|
615
|
+
|
|
616
|
+
## Legal
|
|
617
|
+
- [ ] Privacy Policy
|
|
618
|
+
- [ ] Terms of Service
|
|
619
|
+
- [ ] Cookie consent (GDPR)
|
|
620
|
+
- [ ] Accessibility statement` },
|
|
621
|
+
{ domain: 'checklist', topic: 'security', update_type: 'checklist', title: 'Security Audit Checklist', content: `## Authentication
|
|
622
|
+
- [ ] Passwords hashed (bcrypt/argon2)
|
|
623
|
+
- [ ] MFA available
|
|
624
|
+
- [ ] Session timeout configured
|
|
625
|
+
- [ ] Account lockout after failed attempts
|
|
626
|
+
- [ ] Password strength requirements
|
|
627
|
+
- [ ] Secure password reset flow
|
|
628
|
+
|
|
629
|
+
## Authorization
|
|
630
|
+
- [ ] Role-based access control
|
|
631
|
+
- [ ] Resource-level permissions
|
|
632
|
+
- [ ] JWT/session validation
|
|
633
|
+
- [ ] API key rotation
|
|
634
|
+
|
|
635
|
+
## Data Protection
|
|
636
|
+
- [ ] Encryption at rest
|
|
637
|
+
- [ ] TLS 1.3 in transit
|
|
638
|
+
- [ ] PII handling compliant
|
|
639
|
+
- [ ] Data retention policy
|
|
640
|
+
- [ ] Audit logs enabled
|
|
641
|
+
|
|
642
|
+
## Input/Output
|
|
643
|
+
- [ ] All input validated
|
|
644
|
+
- [ ] SQL injection prevented
|
|
645
|
+
- [ ] XSS prevented (output encoding)
|
|
646
|
+
- [ ] CSRF tokens implemented
|
|
647
|
+
- [ ] File upload restrictions
|
|
648
|
+
|
|
649
|
+
## Infrastructure
|
|
650
|
+
- [ ] Secrets in env vars/vault
|
|
651
|
+
- [ ] Dependencies updated
|
|
652
|
+
- [ ] Vulnerability scanning (npm audit)
|
|
653
|
+
- [ ] Firewall configured
|
|
654
|
+
- [ ] DDoS protection` },
|
|
655
|
+
{ domain: 'checklist', topic: 'a11y', update_type: 'checklist', title: 'Accessibility (WCAG 2.1)', content: `## Perceivable
|
|
656
|
+
- [ ] All images have alt text
|
|
657
|
+
- [ ] Videos have captions
|
|
658
|
+
- [ ] Audio has transcripts
|
|
659
|
+
- [ ] Color contrast ≥ 4.5:1 (AA)
|
|
660
|
+
- [ ] Text resizable to 200%
|
|
661
|
+
- [ ] Content reflows at 320px
|
|
662
|
+
|
|
663
|
+
## Operable
|
|
664
|
+
- [ ] All functions keyboard accessible
|
|
665
|
+
- [ ] Focus indicators visible
|
|
666
|
+
- [ ] Skip to main content link
|
|
667
|
+
- [ ] Touch targets ≥ 44px
|
|
668
|
+
- [ ] No keyboard traps
|
|
669
|
+
- [ ] Page titles descriptive
|
|
670
|
+
- [ ] Focus order logical
|
|
671
|
+
|
|
672
|
+
## Understandable
|
|
673
|
+
- [ ] Language attribute set
|
|
674
|
+
- [ ] Form labels associated
|
|
675
|
+
- [ ] Error messages descriptive
|
|
676
|
+
- [ ] Required fields indicated
|
|
677
|
+
- [ ] Consistent navigation
|
|
678
|
+
|
|
679
|
+
## Robust
|
|
680
|
+
- [ ] Valid HTML
|
|
681
|
+
- [ ] ARIA used correctly
|
|
682
|
+
- [ ] Screen reader tested (NVDA/VoiceOver)
|
|
683
|
+
- [ ] Automated testing (axe)
|
|
684
|
+
- [ ] Manual testing completed` },
|
|
685
|
+
{ domain: 'checklist', topic: 'code-review', update_type: 'checklist', title: 'Code Review Checklist', content: `## Functionality
|
|
686
|
+
- [ ] Code does what PR description says
|
|
687
|
+
- [ ] Edge cases handled
|
|
688
|
+
- [ ] Error handling appropriate
|
|
689
|
+
- [ ] No broken functionality elsewhere
|
|
690
|
+
|
|
691
|
+
## Code Quality
|
|
692
|
+
- [ ] DRY - no duplication
|
|
693
|
+
- [ ] Single responsibility
|
|
694
|
+
- [ ] Meaningful names
|
|
695
|
+
- [ ] No magic numbers
|
|
696
|
+
- [ ] Comments explain "why", not "what"
|
|
697
|
+
- [ ] No console.log / debugger
|
|
698
|
+
|
|
699
|
+
## TypeScript
|
|
700
|
+
- [ ] No any types
|
|
701
|
+
- [ ] Proper null/undefined handling
|
|
702
|
+
- [ ] Types exported for consumers
|
|
703
|
+
- [ ] Generics used appropriately
|
|
704
|
+
|
|
705
|
+
## Testing
|
|
706
|
+
- [ ] Unit tests for new code
|
|
707
|
+
- [ ] Tests actually test behavior
|
|
708
|
+
- [ ] Edge cases tested
|
|
709
|
+
- [ ] No skipped tests
|
|
710
|
+
|
|
711
|
+
## Security
|
|
712
|
+
- [ ] No secrets in code
|
|
713
|
+
- [ ] User input validated
|
|
714
|
+
- [ ] SQL injection prevented
|
|
715
|
+
- [ ] XSS prevented
|
|
716
|
+
- [ ] Auth checks present
|
|
717
|
+
|
|
718
|
+
## Performance
|
|
719
|
+
- [ ] No N+1 queries
|
|
720
|
+
- [ ] Large lists paginated
|
|
721
|
+
- [ ] Expensive operations memoized
|
|
722
|
+
- [ ] Bundle impact considered` },
|
|
723
|
+
{ domain: 'checklist', topic: 'pr', update_type: 'checklist', title: 'PR Submission Checklist', content: `## Before Opening PR
|
|
724
|
+
- [ ] Code compiles without errors
|
|
725
|
+
- [ ] All tests passing
|
|
726
|
+
- [ ] Linter passes
|
|
727
|
+
- [ ] Self-reviewed changes
|
|
728
|
+
- [ ] Removed debug code/console.logs
|
|
729
|
+
- [ ] Branch up to date with main
|
|
730
|
+
|
|
731
|
+
## PR Description
|
|
732
|
+
- [ ] Clear title (type: description)
|
|
733
|
+
- [ ] Description explains WHAT changed
|
|
734
|
+
- [ ] Description explains WHY
|
|
735
|
+
- [ ] Screenshots/video for UI changes
|
|
736
|
+
- [ ] Breaking changes noted
|
|
737
|
+
- [ ] Migration steps if needed
|
|
738
|
+
|
|
739
|
+
## Testing
|
|
740
|
+
- [ ] Tested locally
|
|
741
|
+
- [ ] Added/updated tests
|
|
742
|
+
- [ ] Tested edge cases
|
|
743
|
+
- [ ] Tested on mobile (if UI)
|
|
744
|
+
|
|
745
|
+
## Documentation
|
|
746
|
+
- [ ] README updated if needed
|
|
747
|
+
- [ ] API docs updated if needed
|
|
748
|
+
- [ ] CHANGELOG updated
|
|
749
|
+
- [ ] Comments added for complex logic
|
|
750
|
+
|
|
751
|
+
## Size
|
|
752
|
+
- [ ] PR is focused (one concern)
|
|
753
|
+
- [ ] < 400 lines (ideal)
|
|
754
|
+
- [ ] Large PRs split if possible` },
|
|
755
|
+
{ domain: 'checklist', topic: 'api', update_type: 'checklist', title: 'API Endpoint Checklist', content: `## Design
|
|
756
|
+
- [ ] RESTful naming conventions
|
|
757
|
+
- [ ] Proper HTTP methods
|
|
758
|
+
- [ ] Consistent response format
|
|
759
|
+
- [ ] Pagination for lists
|
|
760
|
+
- [ ] Versioning strategy
|
|
761
|
+
|
|
762
|
+
## Validation
|
|
763
|
+
- [ ] Request body validated
|
|
764
|
+
- [ ] Query params validated
|
|
765
|
+
- [ ] Path params validated
|
|
766
|
+
- [ ] File uploads restricted
|
|
767
|
+
|
|
768
|
+
## Security
|
|
769
|
+
- [ ] Authentication required
|
|
770
|
+
- [ ] Authorization checked
|
|
771
|
+
- [ ] Rate limiting enabled
|
|
772
|
+
- [ ] Input sanitized
|
|
773
|
+
- [ ] Sensitive data filtered from logs
|
|
774
|
+
|
|
775
|
+
## Error Handling
|
|
776
|
+
- [ ] Proper HTTP status codes
|
|
777
|
+
- [ ] Consistent error format
|
|
778
|
+
- [ ] No stack traces in production
|
|
779
|
+
- [ ] Errors logged server-side
|
|
780
|
+
|
|
781
|
+
## Documentation
|
|
782
|
+
- [ ] OpenAPI/Swagger spec
|
|
783
|
+
- [ ] Request/response examples
|
|
784
|
+
- [ ] Error codes documented
|
|
785
|
+
- [ ] Rate limits documented
|
|
786
|
+
|
|
787
|
+
## Testing
|
|
788
|
+
- [ ] Unit tests for logic
|
|
789
|
+
- [ ] Integration tests for API
|
|
790
|
+
- [ ] Load testing done
|
|
791
|
+
- [ ] Security testing done` },
|
|
792
|
+
// ═══════════════════════════════════════════════════════════════
|
|
793
|
+
// 🔧 CODE PATTERNS
|
|
794
|
+
// ═══════════════════════════════════════════════════════════════
|
|
795
|
+
{ domain: 'patterns', topic: 'react', update_type: 'code_pattern', title: 'useAsync Hook', content: `import { useState, useCallback } from 'react';
|
|
796
|
+
|
|
797
|
+
interface AsyncState<T> {
|
|
798
|
+
data: T | null;
|
|
799
|
+
error: Error | null;
|
|
800
|
+
isLoading: boolean;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
export function useAsync<T>() {
|
|
804
|
+
const [state, setState] = useState<AsyncState<T>>({
|
|
805
|
+
data: null,
|
|
806
|
+
error: null,
|
|
807
|
+
isLoading: false,
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
const execute = useCallback(async (promise: Promise<T>) => {
|
|
811
|
+
setState({ data: null, error: null, isLoading: true });
|
|
812
|
+
try {
|
|
813
|
+
const data = await promise;
|
|
814
|
+
setState({ data, error: null, isLoading: false });
|
|
815
|
+
return data;
|
|
816
|
+
} catch (error) {
|
|
817
|
+
setState({ data: null, error: error as Error, isLoading: false });
|
|
818
|
+
throw error;
|
|
819
|
+
}
|
|
820
|
+
}, []);
|
|
821
|
+
|
|
822
|
+
const reset = useCallback(() => {
|
|
823
|
+
setState({ data: null, error: null, isLoading: false });
|
|
824
|
+
}, []);
|
|
825
|
+
|
|
826
|
+
return { ...state, execute, reset };
|
|
827
|
+
}` },
|
|
828
|
+
{ domain: 'patterns', topic: 'react', update_type: 'code_pattern', title: 'useDebounce Hook', content: `import { useState, useEffect } from 'react';
|
|
829
|
+
|
|
830
|
+
export function useDebounce<T>(value: T, delay: number): T {
|
|
831
|
+
const [debouncedValue, setDebouncedValue] = useState<T>(value);
|
|
832
|
+
|
|
833
|
+
useEffect(() => {
|
|
834
|
+
const timer = setTimeout(() => {
|
|
835
|
+
setDebouncedValue(value);
|
|
836
|
+
}, delay);
|
|
837
|
+
|
|
838
|
+
return () => {
|
|
839
|
+
clearTimeout(timer);
|
|
840
|
+
};
|
|
841
|
+
}, [value, delay]);
|
|
842
|
+
|
|
843
|
+
return debouncedValue;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// Usage
|
|
847
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
848
|
+
const debouncedSearch = useDebounce(searchTerm, 300);
|
|
849
|
+
|
|
850
|
+
useEffect(() => {
|
|
851
|
+
if (debouncedSearch) {
|
|
852
|
+
// Make API call
|
|
853
|
+
}
|
|
854
|
+
}, [debouncedSearch]);` },
|
|
855
|
+
{ domain: 'patterns', topic: 'react', update_type: 'code_pattern', title: 'useLocalStorage Hook', content: `import { useState, useEffect } from 'react';
|
|
856
|
+
|
|
857
|
+
export function useLocalStorage<T>(
|
|
858
|
+
key: string,
|
|
859
|
+
initialValue: T
|
|
860
|
+
): [T, (value: T | ((prev: T) => T)) => void] {
|
|
861
|
+
const [storedValue, setStoredValue] = useState<T>(() => {
|
|
862
|
+
if (typeof window === 'undefined') return initialValue;
|
|
863
|
+
try {
|
|
864
|
+
const item = window.localStorage.getItem(key);
|
|
865
|
+
return item ? JSON.parse(item) : initialValue;
|
|
866
|
+
} catch {
|
|
867
|
+
return initialValue;
|
|
868
|
+
}
|
|
869
|
+
});
|
|
870
|
+
|
|
871
|
+
const setValue = (value: T | ((prev: T) => T)) => {
|
|
872
|
+
try {
|
|
873
|
+
const valueToStore = value instanceof Function
|
|
874
|
+
? value(storedValue)
|
|
875
|
+
: value;
|
|
876
|
+
setStoredValue(valueToStore);
|
|
877
|
+
if (typeof window !== 'undefined') {
|
|
878
|
+
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
879
|
+
}
|
|
880
|
+
} catch (error) {
|
|
881
|
+
console.error('useLocalStorage error:', error);
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
return [storedValue, setValue];
|
|
886
|
+
}` },
|
|
887
|
+
{ domain: 'patterns', topic: 'typescript', update_type: 'code_pattern', title: 'Type-Safe Fetch', content: `type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
888
|
+
|
|
889
|
+
interface RequestConfig {
|
|
890
|
+
headers?: Record<string, string>;
|
|
891
|
+
params?: Record<string, string>;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
async function request<T>(
|
|
895
|
+
method: HttpMethod,
|
|
896
|
+
url: string,
|
|
897
|
+
data?: unknown,
|
|
898
|
+
config?: RequestConfig
|
|
899
|
+
): Promise<T> {
|
|
900
|
+
const headers: Record<string, string> = {
|
|
901
|
+
'Content-Type': 'application/json',
|
|
902
|
+
...config?.headers,
|
|
903
|
+
};
|
|
904
|
+
|
|
905
|
+
const queryString = config?.params
|
|
906
|
+
? '?' + new URLSearchParams(config.params).toString()
|
|
907
|
+
: '';
|
|
908
|
+
|
|
909
|
+
const response = await fetch(url + queryString, {
|
|
910
|
+
method,
|
|
911
|
+
headers,
|
|
912
|
+
body: data ? JSON.stringify(data) : undefined,
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
if (!response.ok) {
|
|
916
|
+
const error = await response.json().catch(() => ({}));
|
|
917
|
+
throw new ApiError(response.status, error.message || response.statusText);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
return response.json();
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
export const api = {
|
|
924
|
+
get: <T>(url: string, config?: RequestConfig) =>
|
|
925
|
+
request<T>('GET', url, undefined, config),
|
|
926
|
+
post: <T>(url: string, data: unknown, config?: RequestConfig) =>
|
|
927
|
+
request<T>('POST', url, data, config),
|
|
928
|
+
put: <T>(url: string, data: unknown, config?: RequestConfig) =>
|
|
929
|
+
request<T>('PUT', url, data, config),
|
|
930
|
+
delete: <T>(url: string, config?: RequestConfig) =>
|
|
931
|
+
request<T>('DELETE', url, undefined, config),
|
|
932
|
+
};` },
|
|
933
|
+
{ domain: 'patterns', topic: 'typescript', update_type: 'code_pattern', title: 'Result Type (No Throws)', content: `type Result<T, E = Error> =
|
|
934
|
+
| { ok: true; value: T }
|
|
935
|
+
| { ok: false; error: E };
|
|
936
|
+
|
|
937
|
+
function Ok<T>(value: T): Result<T, never> {
|
|
938
|
+
return { ok: true, value };
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
function Err<E>(error: E): Result<never, E> {
|
|
942
|
+
return { ok: false, error };
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// Usage
|
|
946
|
+
async function fetchUser(id: string): Promise<Result<User, string>> {
|
|
947
|
+
try {
|
|
948
|
+
const response = await fetch(\`/api/users/\${id}\`);
|
|
949
|
+
if (!response.ok) {
|
|
950
|
+
return Err('User not found');
|
|
951
|
+
}
|
|
952
|
+
const user = await response.json();
|
|
953
|
+
return Ok(user);
|
|
954
|
+
} catch {
|
|
955
|
+
return Err('Network error');
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// Consuming
|
|
960
|
+
const result = await fetchUser('123');
|
|
961
|
+
if (result.ok) {
|
|
962
|
+
console.log(result.value); // User
|
|
963
|
+
} else {
|
|
964
|
+
console.error(result.error); // string
|
|
965
|
+
}` },
|
|
966
|
+
{ domain: 'patterns', topic: 'react', update_type: 'code_pattern', title: 'Compound Component Pattern', content: `import { createContext, useContext, useState, ReactNode } from 'react';
|
|
967
|
+
|
|
968
|
+
// Context
|
|
969
|
+
interface TabsContextValue {
|
|
970
|
+
activeTab: string;
|
|
971
|
+
setActiveTab: (tab: string) => void;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
const TabsContext = createContext<TabsContextValue | null>(null);
|
|
975
|
+
|
|
976
|
+
function useTabsContext() {
|
|
977
|
+
const context = useContext(TabsContext);
|
|
978
|
+
if (!context) throw new Error('Must be used within Tabs');
|
|
979
|
+
return context;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// Root
|
|
983
|
+
interface TabsProps {
|
|
984
|
+
defaultTab: string;
|
|
985
|
+
children: ReactNode;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
function Tabs({ defaultTab, children }: TabsProps) {
|
|
989
|
+
const [activeTab, setActiveTab] = useState(defaultTab);
|
|
990
|
+
return (
|
|
991
|
+
<TabsContext.Provider value={{ activeTab, setActiveTab }}>
|
|
992
|
+
<div className="tabs">{children}</div>
|
|
993
|
+
</TabsContext.Provider>
|
|
994
|
+
);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// Tab Trigger
|
|
998
|
+
function TabTrigger({ value, children }: { value: string; children: ReactNode }) {
|
|
999
|
+
const { activeTab, setActiveTab } = useTabsContext();
|
|
1000
|
+
return (
|
|
1001
|
+
<button
|
|
1002
|
+
className={\`tab \${activeTab === value ? 'active' : ''}\`}
|
|
1003
|
+
onClick={() => setActiveTab(value)}
|
|
1004
|
+
>
|
|
1005
|
+
{children}
|
|
1006
|
+
</button>
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
// Tab Content
|
|
1011
|
+
function TabContent({ value, children }: { value: string; children: ReactNode }) {
|
|
1012
|
+
const { activeTab } = useTabsContext();
|
|
1013
|
+
if (activeTab !== value) return null;
|
|
1014
|
+
return <div className="tab-content">{children}</div>;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// Attach components
|
|
1018
|
+
Tabs.Trigger = TabTrigger;
|
|
1019
|
+
Tabs.Content = TabContent;
|
|
1020
|
+
|
|
1021
|
+
export { Tabs };` },
|
|
1022
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1023
|
+
// 🚀 BOILERPLATES
|
|
1024
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1025
|
+
{ domain: 'boilerplate', topic: 'react', update_type: 'boilerplate', title: 'React Component Template', content: `import { memo, forwardRef, ComponentPropsWithRef } from 'react';
|
|
1026
|
+
import styles from './ComponentName.module.css';
|
|
1027
|
+
|
|
1028
|
+
export interface ComponentNameProps extends ComponentPropsWithRef<'div'> {
|
|
1029
|
+
/** Description of the variant prop */
|
|
1030
|
+
variant?: 'default' | 'primary' | 'secondary';
|
|
1031
|
+
/** Whether the component is loading */
|
|
1032
|
+
isLoading?: boolean;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
/**
|
|
1036
|
+
* ComponentName - Brief description
|
|
1037
|
+
*
|
|
1038
|
+
* @example
|
|
1039
|
+
* <ComponentName variant="primary">Content</ComponentName>
|
|
1040
|
+
*/
|
|
1041
|
+
export const ComponentName = memo(forwardRef<HTMLDivElement, ComponentNameProps>(
|
|
1042
|
+
function ComponentName(
|
|
1043
|
+
{ variant = 'default', isLoading = false, className, children, ...props },
|
|
1044
|
+
ref
|
|
1045
|
+
) {
|
|
1046
|
+
if (isLoading) {
|
|
1047
|
+
return <div className={styles.skeleton} />;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
return (
|
|
1051
|
+
<div
|
|
1052
|
+
ref={ref}
|
|
1053
|
+
className={\`\${styles.root} \${styles[variant]} \${className || ''}\`}
|
|
1054
|
+
{...props}
|
|
1055
|
+
>
|
|
1056
|
+
{children}
|
|
1057
|
+
</div>
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
));` },
|
|
1061
|
+
{ domain: 'boilerplate', topic: 'nextjs', update_type: 'boilerplate', title: 'Next.js API Route Template', content: `import { NextRequest, NextResponse } from 'next/server';
|
|
1062
|
+
import { z } from 'zod';
|
|
1063
|
+
import { getServerSession } from 'next-auth';
|
|
1064
|
+
import { authOptions } from '@/lib/auth';
|
|
1065
|
+
|
|
1066
|
+
const RequestSchema = z.object({
|
|
1067
|
+
name: z.string().min(1).max(100),
|
|
1068
|
+
email: z.string().email(),
|
|
1069
|
+
});
|
|
1070
|
+
|
|
1071
|
+
export async function POST(request: NextRequest) {
|
|
1072
|
+
try {
|
|
1073
|
+
// Auth check
|
|
1074
|
+
const session = await getServerSession(authOptions);
|
|
1075
|
+
if (!session) {
|
|
1076
|
+
return NextResponse.json(
|
|
1077
|
+
{ error: 'Unauthorized' },
|
|
1078
|
+
{ status: 401 }
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
// Validate body
|
|
1083
|
+
const body = await request.json();
|
|
1084
|
+
const data = RequestSchema.parse(body);
|
|
1085
|
+
|
|
1086
|
+
// Business logic
|
|
1087
|
+
const result = await createSomething(data);
|
|
1088
|
+
|
|
1089
|
+
return NextResponse.json(result, { status: 201 });
|
|
1090
|
+
} catch (error) {
|
|
1091
|
+
if (error instanceof z.ZodError) {
|
|
1092
|
+
return NextResponse.json(
|
|
1093
|
+
{ error: 'Validation error', details: error.errors },
|
|
1094
|
+
{ status: 400 }
|
|
1095
|
+
);
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
console.error('API Error:', error);
|
|
1099
|
+
return NextResponse.json(
|
|
1100
|
+
{ error: 'Internal server error' },
|
|
1101
|
+
{ status: 500 }
|
|
1102
|
+
);
|
|
1103
|
+
}
|
|
1104
|
+
}` },
|
|
1105
|
+
{ domain: 'boilerplate', topic: 'nextjs', update_type: 'boilerplate', title: 'Next.js Server Action Template', content: `'use server';
|
|
1106
|
+
|
|
1107
|
+
import { z } from 'zod';
|
|
1108
|
+
import { revalidatePath } from 'next/cache';
|
|
1109
|
+
import { getServerSession } from 'next-auth';
|
|
1110
|
+
import { authOptions } from '@/lib/auth';
|
|
1111
|
+
|
|
1112
|
+
const FormSchema = z.object({
|
|
1113
|
+
title: z.string().min(1, 'Title is required').max(100),
|
|
1114
|
+
content: z.string().min(10, 'Content too short'),
|
|
1115
|
+
});
|
|
1116
|
+
|
|
1117
|
+
export type FormState = {
|
|
1118
|
+
errors?: {
|
|
1119
|
+
title?: string[];
|
|
1120
|
+
content?: string[];
|
|
1121
|
+
};
|
|
1122
|
+
message?: string;
|
|
1123
|
+
success?: boolean;
|
|
1124
|
+
};
|
|
1125
|
+
|
|
1126
|
+
export async function createPost(
|
|
1127
|
+
prevState: FormState,
|
|
1128
|
+
formData: FormData
|
|
1129
|
+
): Promise<FormState> {
|
|
1130
|
+
// Auth
|
|
1131
|
+
const session = await getServerSession(authOptions);
|
|
1132
|
+
if (!session?.user?.id) {
|
|
1133
|
+
return { message: 'Unauthorized', success: false };
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// Validate
|
|
1137
|
+
const validatedFields = FormSchema.safeParse({
|
|
1138
|
+
title: formData.get('title'),
|
|
1139
|
+
content: formData.get('content'),
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
if (!validatedFields.success) {
|
|
1143
|
+
return {
|
|
1144
|
+
errors: validatedFields.error.flatten().fieldErrors,
|
|
1145
|
+
message: 'Invalid fields',
|
|
1146
|
+
success: false,
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
try {
|
|
1151
|
+
// Create
|
|
1152
|
+
await db.post.create({
|
|
1153
|
+
data: {
|
|
1154
|
+
...validatedFields.data,
|
|
1155
|
+
userId: session.user.id,
|
|
1156
|
+
},
|
|
1157
|
+
});
|
|
1158
|
+
|
|
1159
|
+
revalidatePath('/posts');
|
|
1160
|
+
return { message: 'Post created!', success: true };
|
|
1161
|
+
} catch {
|
|
1162
|
+
return { message: 'Database error', success: false };
|
|
1163
|
+
}
|
|
1164
|
+
}` },
|
|
1165
|
+
{ domain: 'boilerplate', topic: 'testing', update_type: 'boilerplate', title: 'Jest Test Template', content: `import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
1166
|
+
import userEvent from '@testing-library/user-event';
|
|
1167
|
+
import { ComponentName } from './ComponentName';
|
|
1168
|
+
|
|
1169
|
+
describe('ComponentName', () => {
|
|
1170
|
+
const defaultProps = {
|
|
1171
|
+
onSubmit: jest.fn(),
|
|
1172
|
+
initialValue: 'test',
|
|
1173
|
+
};
|
|
1174
|
+
|
|
1175
|
+
beforeEach(() => {
|
|
1176
|
+
jest.clearAllMocks();
|
|
1177
|
+
});
|
|
1178
|
+
|
|
1179
|
+
it('renders correctly', () => {
|
|
1180
|
+
render(<ComponentName {...defaultProps} />);
|
|
1181
|
+
expect(screen.getByRole('button')).toBeInTheDocument();
|
|
1182
|
+
});
|
|
1183
|
+
|
|
1184
|
+
it('handles click events', async () => {
|
|
1185
|
+
const user = userEvent.setup();
|
|
1186
|
+
render(<ComponentName {...defaultProps} />);
|
|
1187
|
+
|
|
1188
|
+
await user.click(screen.getByRole('button'));
|
|
1189
|
+
|
|
1190
|
+
expect(defaultProps.onSubmit).toHaveBeenCalledTimes(1);
|
|
1191
|
+
});
|
|
1192
|
+
|
|
1193
|
+
it('shows error state', () => {
|
|
1194
|
+
render(<ComponentName {...defaultProps} error="Something went wrong" />);
|
|
1195
|
+
expect(screen.getByText(/something went wrong/i)).toBeInTheDocument();
|
|
1196
|
+
});
|
|
1197
|
+
|
|
1198
|
+
it('handles async operations', async () => {
|
|
1199
|
+
render(<ComponentName {...defaultProps} />);
|
|
1200
|
+
|
|
1201
|
+
fireEvent.click(screen.getByRole('button'));
|
|
1202
|
+
|
|
1203
|
+
await waitFor(() => {
|
|
1204
|
+
expect(screen.getByText(/success/i)).toBeInTheDocument();
|
|
1205
|
+
});
|
|
1206
|
+
});
|
|
1207
|
+
});` },
|
|
1208
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1209
|
+
// 🔄 WORKFLOWS
|
|
1210
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1211
|
+
{ domain: 'workflow', topic: 'feature', update_type: 'workflow', title: 'Feature Development Flow', content: `1. PLAN
|
|
1212
|
+
- Write user story with acceptance criteria
|
|
1213
|
+
- Break into subtasks
|
|
1214
|
+
- Estimate complexity
|
|
1215
|
+
- Identify dependencies
|
|
1216
|
+
|
|
1217
|
+
2. DESIGN
|
|
1218
|
+
- API contract (if backend)
|
|
1219
|
+
- Component hierarchy (if frontend)
|
|
1220
|
+
- Database changes (if needed)
|
|
1221
|
+
- Get design review
|
|
1222
|
+
|
|
1223
|
+
3. IMPLEMENT
|
|
1224
|
+
- Create feature branch
|
|
1225
|
+
- Write tests first (TDD)
|
|
1226
|
+
- Implement in small commits
|
|
1227
|
+
- Keep PR focused
|
|
1228
|
+
|
|
1229
|
+
4. TEST
|
|
1230
|
+
- Run unit tests
|
|
1231
|
+
- Run integration tests
|
|
1232
|
+
- Manual testing
|
|
1233
|
+
- Cross-browser testing (if UI)
|
|
1234
|
+
|
|
1235
|
+
5. REVIEW
|
|
1236
|
+
- Self-review first
|
|
1237
|
+
- Open PR with description
|
|
1238
|
+
- Address feedback promptly
|
|
1239
|
+
- Get approval
|
|
1240
|
+
|
|
1241
|
+
6. DEPLOY
|
|
1242
|
+
- Merge to main
|
|
1243
|
+
- Verify in staging
|
|
1244
|
+
- Deploy to production
|
|
1245
|
+
- Monitor for errors
|
|
1246
|
+
|
|
1247
|
+
7. DOCUMENT
|
|
1248
|
+
- Update README if needed
|
|
1249
|
+
- Update API docs
|
|
1250
|
+
- Add to changelog` },
|
|
1251
|
+
{ domain: 'workflow', topic: 'debugging', update_type: 'workflow', title: 'Systematic Debugging', content: `1. REPRODUCE
|
|
1252
|
+
- What are the exact steps?
|
|
1253
|
+
- What environment? (browser, OS, versions)
|
|
1254
|
+
- Is it consistent or intermittent?
|
|
1255
|
+
- Can you reproduce locally?
|
|
1256
|
+
|
|
1257
|
+
2. ISOLATE
|
|
1258
|
+
- When did it start working/breaking?
|
|
1259
|
+
- Frontend or backend issue?
|
|
1260
|
+
- Which specific component/function?
|
|
1261
|
+
- Narrow down with binary search
|
|
1262
|
+
|
|
1263
|
+
3. GATHER EVIDENCE
|
|
1264
|
+
- Console errors
|
|
1265
|
+
- Network requests/responses
|
|
1266
|
+
- Server logs
|
|
1267
|
+
- Error tracking (Sentry)
|
|
1268
|
+
- Database state
|
|
1269
|
+
|
|
1270
|
+
4. HYPOTHESIZE
|
|
1271
|
+
- List top 3 likely causes
|
|
1272
|
+
- Rank by probability
|
|
1273
|
+
- Start with simplest explanation
|
|
1274
|
+
|
|
1275
|
+
5. TEST HYPOTHESES
|
|
1276
|
+
- Add logging/breakpoints
|
|
1277
|
+
- Change ONE thing at a time
|
|
1278
|
+
- Verify assumptions
|
|
1279
|
+
- Don't skip steps
|
|
1280
|
+
|
|
1281
|
+
6. FIX
|
|
1282
|
+
- Implement minimal fix
|
|
1283
|
+
- Verify fix works
|
|
1284
|
+
- Check for side effects
|
|
1285
|
+
- Add regression test
|
|
1286
|
+
|
|
1287
|
+
7. PREVENT
|
|
1288
|
+
- Why wasn't this caught earlier?
|
|
1289
|
+
- Add monitoring/alerting?
|
|
1290
|
+
- Improve error handling?
|
|
1291
|
+
- Document for team` },
|
|
1292
|
+
{ domain: 'workflow', topic: 'code-review', update_type: 'workflow', title: 'Effective Code Review', content: `## As Author
|
|
1293
|
+
|
|
1294
|
+
BEFORE SUBMITTING:
|
|
1295
|
+
1. Self-review your changes first
|
|
1296
|
+
2. Run all tests locally
|
|
1297
|
+
3. Check linting passes
|
|
1298
|
+
4. Write clear PR description
|
|
1299
|
+
5. Add screenshots for UI changes
|
|
1300
|
+
6. Keep PR < 400 lines if possible
|
|
1301
|
+
|
|
1302
|
+
DURING REVIEW:
|
|
1303
|
+
1. Respond to all comments
|
|
1304
|
+
2. Don't take feedback personally
|
|
1305
|
+
3. Explain your reasoning
|
|
1306
|
+
4. Make requested changes promptly
|
|
1307
|
+
5. Re-request review when ready
|
|
1308
|
+
|
|
1309
|
+
## As Reviewer
|
|
1310
|
+
|
|
1311
|
+
FIRST PASS (5 min):
|
|
1312
|
+
1. Understand the goal from PR description
|
|
1313
|
+
2. Check PR size is reasonable
|
|
1314
|
+
3. Look at file structure changes
|
|
1315
|
+
4. Identify areas of concern
|
|
1316
|
+
|
|
1317
|
+
DETAILED REVIEW:
|
|
1318
|
+
1. Check logic and edge cases
|
|
1319
|
+
2. Look for security issues
|
|
1320
|
+
3. Check error handling
|
|
1321
|
+
4. Verify tests cover changes
|
|
1322
|
+
5. Check code style consistency
|
|
1323
|
+
|
|
1324
|
+
GIVING FEEDBACK:
|
|
1325
|
+
1. Be specific, not vague
|
|
1326
|
+
2. Explain the "why"
|
|
1327
|
+
3. Suggest alternatives
|
|
1328
|
+
4. Distinguish must-fix vs nice-to-have
|
|
1329
|
+
5. Praise good patterns
|
|
1330
|
+
6. Use conventional comments (nit:, blocking:)` },
|
|
1331
|
+
{ domain: 'workflow', topic: 'incident', update_type: 'workflow', title: 'Incident Response', content: `1. DETECT
|
|
1332
|
+
- Monitoring alert
|
|
1333
|
+
- User report
|
|
1334
|
+
- Automated test failure
|
|
1335
|
+
|
|
1336
|
+
2. TRIAGE (5 min)
|
|
1337
|
+
- Assess severity (P1-P4)
|
|
1338
|
+
- Estimate impact (users affected)
|
|
1339
|
+
- Assign incident commander
|
|
1340
|
+
- Start incident channel
|
|
1341
|
+
|
|
1342
|
+
3. MITIGATE (ASAP)
|
|
1343
|
+
- Can we rollback?
|
|
1344
|
+
- Can we feature flag off?
|
|
1345
|
+
- Can we scale up?
|
|
1346
|
+
- Communicate status to stakeholders
|
|
1347
|
+
|
|
1348
|
+
4. INVESTIGATE
|
|
1349
|
+
- Gather logs and metrics
|
|
1350
|
+
- Identify timeline of events
|
|
1351
|
+
- Find root cause
|
|
1352
|
+
- Document findings
|
|
1353
|
+
|
|
1354
|
+
5. FIX
|
|
1355
|
+
- Implement permanent fix
|
|
1356
|
+
- Test thoroughly
|
|
1357
|
+
- Deploy with monitoring
|
|
1358
|
+
- Verify resolution
|
|
1359
|
+
|
|
1360
|
+
6. COMMUNICATE
|
|
1361
|
+
- Update status page
|
|
1362
|
+
- Notify affected users
|
|
1363
|
+
- Internal update
|
|
1364
|
+
|
|
1365
|
+
7. POST-MORTEM
|
|
1366
|
+
- Blameless analysis
|
|
1367
|
+
- Document timeline
|
|
1368
|
+
- Identify improvements
|
|
1369
|
+
- Create action items
|
|
1370
|
+
- Share learnings` },
|
|
1371
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1372
|
+
// 💡 BEST PRACTICES
|
|
1373
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1374
|
+
// React
|
|
1375
|
+
{ domain: 'react', topic: 'performance', update_type: 'best_practice', title: 'Use React.memo() wisely', content: 'Wrap components with stable props but expensive render logic. Avoid for components with frequently changing props as the comparison overhead isn\'t worth it.', package_name: 'react', min_version: '16.6.0' },
|
|
1376
|
+
{ domain: 'react', topic: 'hooks', update_type: 'best_practice', title: 'useCallback for handlers', content: 'Wrap callbacks passed to memoized child components with useCallback. Without it, a new function reference is created each render, breaking memo.', package_name: 'react', min_version: '16.8.0' },
|
|
1377
|
+
{ domain: 'react', topic: 'lists', update_type: 'best_practice', title: 'Stable keys, never indices', content: 'Keys should be unique IDs from your data, not array indices. Index keys cause bugs with reordering and state preservation.', package_name: 'react', min_version: '16.0.0' },
|
|
1378
|
+
{ domain: 'react', topic: 'state', update_type: 'best_practice', title: 'Colocate state', content: 'Keep state as close to where it\'s used as possible. Only lift state when truly needed. Avoid premature global state.', package_name: 'react', min_version: '16.0.0' },
|
|
1379
|
+
{ domain: 'react', topic: 'effects', update_type: 'best_practice', title: 'Always cleanup useEffect', content: 'Return a cleanup function from useEffect for subscriptions, timers, and event listeners. Prevents memory leaks and stale closures.', package_name: 'react', min_version: '16.8.0' },
|
|
1380
|
+
{ domain: 'react', topic: 'state', update_type: 'best_practice', title: 'Avoid derived state', content: 'Don\'t useState for values derivable from props or other state. Use useMemo or calculate during render instead.', package_name: 'react', min_version: '16.8.0' },
|
|
1381
|
+
{ domain: 'react', topic: 'errors', update_type: 'best_practice', title: 'Use Error Boundaries', content: 'Wrap route-level and critical components in error boundaries. Prevents the entire app from crashing on render errors.', package_name: 'react', min_version: '16.0.0' },
|
|
1382
|
+
{ domain: 'react', topic: 'refs', update_type: 'best_practice', title: 'useRef for non-render values', content: 'Use useRef for values that don\'t need re-render (timers, previous values, DOM refs). Unlike state, changing ref.current won\'t trigger render.', package_name: 'react', min_version: '16.8.0' },
|
|
1383
|
+
// TypeScript
|
|
1384
|
+
{ domain: 'typescript', topic: 'types', update_type: 'best_practice', title: 'type vs interface', content: 'Use type for unions, intersections, and primitives. Use interface for object shapes that might be extended or implemented.', package_name: 'typescript', min_version: '4.0.0' },
|
|
1385
|
+
{ domain: 'typescript', topic: 'safety', update_type: 'best_practice', title: 'unknown over any', content: 'Use unknown instead of any when type is truly unknown. unknown is type-safe - you must narrow it before use.', package_name: 'typescript', min_version: '3.0.0' },
|
|
1386
|
+
{ domain: 'typescript', topic: 'config', update_type: 'best_practice', title: 'Enable strict mode', content: 'Set strict: true in tsconfig.json. This enables strictNullChecks, noImplicitAny, and other safety checks.', package_name: 'typescript', min_version: '2.3.0' },
|
|
1387
|
+
{ domain: 'typescript', topic: 'types', update_type: 'best_practice', title: 'Prefer const assertions', content: 'Use as const for literal types: const routes = { home: "/home" } as const. Prevents widening to string.', package_name: 'typescript', min_version: '3.4.0' },
|
|
1388
|
+
{ domain: 'typescript', topic: 'types', update_type: 'best_practice', title: 'Use satisfies keyword', content: 'satisfies validates type without widening: const config = { a: 1 } satisfies Config keeps literal types while ensuring shape.', package_name: 'typescript', min_version: '4.9.0' },
|
|
1389
|
+
{ domain: 'typescript', topic: 'enums', update_type: 'best_practice', title: 'Avoid enums, use const objects', content: 'const STATUS = { IDLE: "idle" } as const is more predictable than enum at runtime and doesn\'t generate extra code.', package_name: 'typescript', min_version: '3.4.0' },
|
|
1390
|
+
// Next.js
|
|
1391
|
+
{ domain: 'nextjs', topic: 'components', update_type: 'best_practice', title: 'Server Components by default', content: 'In App Router, components are Server Components by default. Only add "use client" when you need hooks, browser APIs, or event handlers.', package_name: 'next', min_version: '13.0.0' },
|
|
1392
|
+
{ domain: 'nextjs', topic: 'data', update_type: 'best_practice', title: 'Fetch in Server Components', content: 'Do data fetching in Server Components, not useEffect. Use async components and fetch() with automatic deduplication.', package_name: 'next', min_version: '13.0.0' },
|
|
1393
|
+
{ domain: 'nextjs', topic: 'data', update_type: 'best_practice', title: 'Parallel data fetching', content: 'Use Promise.all() for independent fetches. Avoid sequential awaits that create waterfalls.', package_name: 'next', min_version: '13.0.0' },
|
|
1394
|
+
{ domain: 'nextjs', topic: 'images', update_type: 'best_practice', title: 'Always use next/image', content: 'Image component provides automatic optimization, lazy loading, responsive sizes, and WebP conversion.', package_name: 'next', min_version: '10.0.0' },
|
|
1395
|
+
{ domain: 'nextjs', topic: 'routing', update_type: 'best_practice', title: 'Use route groups', content: 'Use (folder) syntax for route groups. Organize routes without affecting URL structure.', package_name: 'next', min_version: '13.0.0' },
|
|
1396
|
+
{ domain: 'nextjs', topic: 'caching', update_type: 'best_practice', title: 'Understand caching', content: 'Next.js caches aggressively. Use revalidatePath/revalidateTag for on-demand revalidation. Set { cache: "no-store" } for dynamic data.', package_name: 'next', min_version: '13.0.0' },
|
|
1397
|
+
// Node.js
|
|
1398
|
+
{ domain: 'nodejs', topic: 'async', update_type: 'best_practice', title: 'async/await over callbacks', content: 'Use async/await for cleaner code and better error handling with try/catch. Avoid callback hell.', package_name: 'node', min_version: '8.0.0' },
|
|
1399
|
+
{ domain: 'nodejs', topic: 'config', update_type: 'best_practice', title: 'Validate env vars at startup', content: 'Use zod or joi to validate environment variables when the app starts. Fail fast if required vars are missing.', package_name: 'node', min_version: '12.0.0' },
|
|
1400
|
+
{ domain: 'nodejs', topic: 'errors', update_type: 'best_practice', title: 'Handle uncaught exceptions', content: 'process.on("uncaughtException") should log the error and exit gracefully. Never swallow errors silently.', package_name: 'node', min_version: '1.0.0' },
|
|
1401
|
+
{ domain: 'nodejs', topic: 'production', update_type: 'best_practice', title: 'Graceful shutdown', content: 'Handle SIGTERM/SIGINT to close database connections and finish in-flight requests before exiting.', package_name: 'node', min_version: '1.0.0' },
|
|
1402
|
+
{ domain: 'nodejs', topic: 'streams', update_type: 'best_practice', title: 'Stream large data', content: 'Use streams for large files instead of reading entire files into memory. Prevents memory exhaustion.', package_name: 'node', min_version: '1.0.0' },
|
|
1403
|
+
// CSS
|
|
1404
|
+
{ domain: 'css', topic: 'variables', update_type: 'best_practice', title: 'Use CSS custom properties', content: 'CSS variables (--color-primary) enable theming, reduce repetition, and can be changed at runtime via JavaScript.', package_name: null, min_version: null },
|
|
1405
|
+
{ domain: 'css', topic: 'units', update_type: 'best_practice', title: 'rem for font sizes, px for borders', content: 'rem scales with user preferences for accessibility. px is fine for borders and small fixed elements.', package_name: null, min_version: null },
|
|
1406
|
+
{ domain: 'css', topic: 'layout', update_type: 'best_practice', title: 'Mobile-first media queries', content: 'Write base styles for mobile, use min-width queries to enhance for larger screens. Better performance and simpler code.', package_name: null, min_version: null },
|
|
1407
|
+
{ domain: 'css', topic: 'specificity', update_type: 'best_practice', title: 'Avoid !important', content: '!important breaks the cascade. Fix specificity issues with better selectors or CSS layers instead.', package_name: null, min_version: null },
|
|
1408
|
+
{ domain: 'css', topic: 'performance', update_type: 'best_practice', title: 'Use contain property', content: 'contain: content isolates layout/paint. Great for cards, modals, and independently updating components.', package_name: null, min_version: null },
|
|
1409
|
+
// Git
|
|
1410
|
+
{ domain: 'git', topic: 'commits', update_type: 'best_practice', title: 'Atomic commits', content: 'Each commit should be one logical change. Makes reviews, reverts, and bisecting much easier.', package_name: null, min_version: null },
|
|
1411
|
+
{ domain: 'git', topic: 'commits', update_type: 'best_practice', title: 'Conventional commits', content: 'Use feat:, fix:, docs:, chore:, refactor: prefixes. Enables automatic changelog generation and semantic versioning.', package_name: null, min_version: null },
|
|
1412
|
+
{ domain: 'git', topic: 'branches', update_type: 'best_practice', title: 'Short-lived feature branches', content: 'Feature branches should live hours or days, not weeks. Long-lived branches lead to merge hell.', package_name: null, min_version: null },
|
|
1413
|
+
{ domain: 'git', topic: 'workflow', update_type: 'best_practice', title: 'Rebase feature branches', content: 'Rebase onto main before merging for linear history. Squash WIP commits to keep history clean.', package_name: null, min_version: null },
|
|
1414
|
+
{ domain: 'git', topic: 'safety', update_type: 'best_practice', title: 'Never force push shared branches', content: 'Force pushing rewrites history and breaks collaborators. Only force push personal feature branches.', package_name: null, min_version: null },
|
|
1415
|
+
// Supabase
|
|
1416
|
+
{ domain: 'supabase', topic: 'security', update_type: 'best_practice', title: 'Always enable RLS', content: 'Row Level Security is disabled by default. Enable it on ALL tables. Without RLS, your data is publicly accessible.', package_name: '@supabase/supabase-js', min_version: '2.0.0' },
|
|
1417
|
+
{ domain: 'supabase', topic: 'queries', update_type: 'best_practice', title: 'Select specific columns', content: 'Use .select("id, name") instead of .select("*"). Reduces payload size and improves security.', package_name: '@supabase/supabase-js', min_version: '2.0.0' },
|
|
1418
|
+
{ domain: 'supabase', topic: 'auth', update_type: 'best_practice', title: 'Use auth.uid() in RLS', content: 'Reference auth.uid() in RLS policies to scope data to the current user. Never trust client-side user IDs.', package_name: '@supabase/supabase-js', min_version: '2.0.0' },
|
|
1419
|
+
// Testing
|
|
1420
|
+
{ domain: 'testing', topic: 'unit', update_type: 'best_practice', title: 'Test behavior, not implementation', content: 'Test what the code does, not how it does it. Tests should survive refactoring if behavior stays the same.', package_name: null, min_version: null },
|
|
1421
|
+
{ domain: 'testing', topic: 'mocking', update_type: 'best_practice', title: 'Mock at boundaries', content: 'Mock external services (APIs, databases) not internal modules. Mocking internals makes tests brittle.', package_name: null, min_version: null },
|
|
1422
|
+
{ domain: 'testing', topic: 'naming', update_type: 'best_practice', title: 'Descriptive test names', content: 'Test names should describe expected behavior: "should show error when email is invalid" not "test email"', package_name: null, min_version: null },
|
|
1423
|
+
{ domain: 'testing', topic: 'isolation', update_type: 'best_practice', title: 'Tests should be independent', content: 'Each test should set up its own state and clean up after. Tests should pass in any order.', package_name: null, min_version: null },
|
|
1424
|
+
// Security
|
|
1425
|
+
{ domain: 'security', topic: 'auth', update_type: 'best_practice', title: 'Use established auth libraries', content: 'Don\'t roll your own auth. Use NextAuth.js, Clerk, or Supabase Auth. Auth is hard to get right.', package_name: null, min_version: null },
|
|
1426
|
+
{ domain: 'security', topic: 'secrets', update_type: 'best_practice', title: 'Never commit secrets', content: 'API keys, passwords, and tokens go in .env files (gitignored). Use secret managers in production.', package_name: null, min_version: null },
|
|
1427
|
+
{ domain: 'security', topic: 'input', update_type: 'best_practice', title: 'Validate all input', content: 'Validate on server-side even if validated client-side. Client validation is for UX, server validation is for security.', package_name: null, min_version: null },
|
|
1428
|
+
{ domain: 'security', topic: 'dependencies', update_type: 'best_practice', title: 'Keep dependencies updated', content: 'Run npm audit regularly. Use Dependabot or Renovate for automated updates. Review breaking changes.', package_name: null, min_version: null },
|
|
1429
|
+
];
|
|
1430
|
+
//# sourceMappingURL=knowledge-base.js.map
|