aiknowsys 0.0.1

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.
@@ -0,0 +1,662 @@
1
+ ---
2
+ name: code-refactoring
3
+ description: Safe code refactoring guide for gnwebsite project. Use when refactoring components, removing duplication, improving code structure, or simplifying complex functions. Covers test-driven refactoring, incremental changes, extract function/composable patterns, and rollback procedures. Ensures refactoring preserves behavior while improving code quality.
4
+ ---
5
+
6
+ # Code Refactoring Guide
7
+
8
+ Step-by-step guide for safely refactoring code without breaking functionality in the gnwebsite fullstack project.
9
+
10
+ ## When to Use This Skill
11
+
12
+ Use when:
13
+ - User asks "How do I refactor this code?" or "Can I simplify this?"
14
+ - Reducing code duplication (DRY violations)
15
+ - Simplifying complex functions (>50 lines)
16
+ - Extracting reusable logic to composables
17
+ - Improving code structure or naming
18
+ - Addressing technical debt
19
+ - User mentions: "refactor", "clean up", "simplify", "reduce duplication"
20
+
21
+ **Do NOT use for:**
22
+ - Style preferences without measurable benefit
23
+ - Just before deadlines
24
+ - Code without existing tests
25
+ - Changes that alter behavior (that's feature work, not refactoring)
26
+
27
+ ## Decision Tree: Proposal or Direct Refactoring?
28
+
29
+ ```
30
+ Need to refactor?
31
+
32
+ ├─ Breaking changes? (API contracts, schemas, core patterns)
33
+ │ └─ YES → Create OpenSpec proposal
34
+
35
+ ├─ Just reorganizing code? (internal structure, no external impact)
36
+ │ └─ YES → Follow safe refactoring steps
37
+
38
+ └─ Unsure?
39
+ └─ Create proposal (better safe than sorry!)
40
+ ```
41
+
42
+ ## Prerequisites (CRITICAL)
43
+
44
+ **NEVER refactor without tests!**
45
+
46
+ ```bash
47
+ # Check test coverage
48
+ cd frontend && npm run test:run -- --coverage
49
+ cd backend && docker exec backend pytest --cov
50
+
51
+ # If coverage < 80% for code being refactored:
52
+ # 1. STOP
53
+ # 2. Write tests FIRST
54
+ # 3. THEN refactor
55
+ ```
56
+
57
+ **Minimum requirements:**
58
+ - [ ] Unit tests exist for all functions being changed
59
+ - [ ] Integration tests exist for workflows being changed
60
+ - [ ] All tests currently passing ✅
61
+
62
+ ## Phase 1: Preparation
63
+
64
+ ### Step 1: Document Current Behavior
65
+
66
+ Create temporary documentation:
67
+ ```markdown
68
+ # Refactoring: [Component Name]
69
+
70
+ ## Current Behavior
71
+ - Input: X
72
+ - Output: Y
73
+ - Side effects: Z
74
+ - Edge cases: A, B, C
75
+
76
+ ## Existing Tests
77
+ - test_case_1: normal flow
78
+ - test_case_2: error handling
79
+ - test_case_3: edge case
80
+
81
+ ## Success Criteria
82
+ After refactor: all tests pass, same behavior
83
+ ```
84
+
85
+ ### Step 2: Create Safety Backup
86
+
87
+ ```bash
88
+ # Create backup branch
89
+ git checkout -b backup-before-refactor
90
+ git checkout -b refactor-my-feature
91
+ ```
92
+
93
+ ### Step 3: Create Refactoring Checklist
94
+
95
+ ```markdown
96
+ ## Refactoring Checklist
97
+
98
+ ### Before
99
+ - [ ] All existing tests pass
100
+ - [ ] Coverage documented
101
+ - [ ] Behavior documented
102
+ - [ ] Backup branch created
103
+
104
+ ### During
105
+ - [ ] ONE change at a time
106
+ - [ ] Run tests after EACH change
107
+ - [ ] Commit after EACH success
108
+
109
+ ### After
110
+ - [ ] All tests still pass
111
+ - [ ] No console errors
112
+ - [ ] Manual testing complete
113
+ - [ ] Performance unchanged/better
114
+ - [ ] Documentation updated
115
+ ```
116
+
117
+ ## Phase 2: Refactoring Patterns
118
+
119
+ ### Pattern A: Extract Function (Reduce Complexity)
120
+
121
+ **When**: Function >50 lines or multiple responsibilities
122
+
123
+ **Before**:
124
+ ```typescript
125
+ async function processArticle(article: Article) {
126
+ // Validation (10 lines)
127
+ if (!article.title) throw new Error('Title required')
128
+ if (!article.content) throw new Error('Content required')
129
+
130
+ // Image processing (15 lines)
131
+ const images = []
132
+ for (const img of article.images || []) {
133
+ const url = img.image?.fileUrl || img.image?.file_url
134
+ if (url) images.push({ url, caption: img.caption })
135
+ }
136
+
137
+ // Save (20 lines)
138
+ const response = await api.create({ title, content, images })
139
+ return response
140
+ }
141
+ ```
142
+
143
+ **After**:
144
+ ```typescript
145
+ async function processArticle(article: Article) {
146
+ validateArticle(article)
147
+ const images = processImages(article.images)
148
+ return await saveArticle(article, images)
149
+ }
150
+
151
+ function validateArticle(article: Article) {
152
+ if (!article.title) throw new Error('Title required')
153
+ if (!article.content) throw new Error('Content required')
154
+ if (article.title.length > 200) throw new Error('Title too long')
155
+ }
156
+
157
+ function processImages(images?: ArticleImage[]) {
158
+ return (images || [])
159
+ .map(img => ({ url: getImageUrl(img.image), caption: img.caption }))
160
+ .filter(img => img.url && img.url !== '/placeholder-image.png')
161
+ }
162
+
163
+ async function saveArticle(article: Article, images: ProcessedImage[]) {
164
+ return await api.create({
165
+ title: article.title,
166
+ content: article.content,
167
+ images
168
+ })
169
+ }
170
+ ```
171
+
172
+ **Steps**:
173
+ 1. Extract ONE function at a time
174
+ 2. Run tests after each extraction
175
+ 3. Commit each success
176
+ 4. Add tests for new functions:
177
+
178
+ ```typescript
179
+ describe('validateArticle', () => {
180
+ it('should throw on missing title', () => {
181
+ expect(() => validateArticle({ content: 'test' }))
182
+ .toThrow('Title required')
183
+ })
184
+ })
185
+
186
+ describe('processImages', () => {
187
+ it('should extract URLs', () => {
188
+ const imgs = [{ image: { fileUrl: 'test.jpg' }, caption: 'Test' }]
189
+ expect(processImages(imgs)).toEqual([{ url: 'test.jpg', caption: 'Test' }])
190
+ })
191
+
192
+ it('should filter placeholders', () => {
193
+ expect(processImages([{ image: null }])).toEqual([])
194
+ })
195
+ })
196
+ ```
197
+
198
+ ### Pattern B: Extract Composable (Reuse Logic)
199
+
200
+ **When**: Same logic duplicated across 3+ components
201
+
202
+ **Before** (duplicated in BlogView, ArticleView, CategoryView):
203
+ ```vue
204
+ <script setup>
205
+ const items = ref([])
206
+ const loading = ref(false)
207
+ const error = ref('')
208
+
209
+ const loadItems = async () => {
210
+ loading.value = true
211
+ try {
212
+ const response = await blogService.getAll()
213
+ items.value = response.results
214
+ } catch (err) {
215
+ error.value = 'Failed to load'
216
+ } finally {
217
+ loading.value = false
218
+ }
219
+ }
220
+
221
+ onMounted(loadItems)
222
+ </script>
223
+ ```
224
+
225
+ **After**:
226
+ ```typescript
227
+ // composables/useDataLoader.ts
228
+ export function useDataLoader<T>(
229
+ loadFn: () => Promise<{ results: T[] }>
230
+ ) {
231
+ const items = ref<T[]>([])
232
+ const loading = ref(false)
233
+ const error = ref('')
234
+
235
+ const load = async () => {
236
+ loading.value = true
237
+ error.value = ''
238
+ try {
239
+ const response = await loadFn()
240
+ items.value = response.results || []
241
+ } catch (err) {
242
+ error.value = 'Failed to load items'
243
+ console.error(err)
244
+ } finally {
245
+ loading.value = false
246
+ }
247
+ }
248
+
249
+ onMounted(load)
250
+ return { items, loading, error, reload: load }
251
+ }
252
+ ```
253
+
254
+ ```vue
255
+ <!-- All components now -->
256
+ <script setup>
257
+ import { useDataLoader } from '@/composables/useDataLoader'
258
+
259
+ const { items, loading, error, reload } = useDataLoader(() =>
260
+ blogService.getAll()
261
+ )
262
+ </script>
263
+ ```
264
+
265
+ **Steps**:
266
+ 1. Create composable
267
+ 2. Write composable tests
268
+ 3. Migrate ONE component
269
+ 4. Test that component
270
+ 5. Commit
271
+ 6. Repeat for remaining components
272
+
273
+ ### Pattern C: Consolidate Styles
274
+
275
+ **When**: Same CSS in 3+ components
276
+
277
+ **Before** (duplicated in 6 form components):
278
+ ```vue
279
+ <style scoped>
280
+ .form-group { margin-bottom: 1.5rem; }
281
+ .form-control { width: 100%; padding: 0.75rem; }
282
+ .btn-primary { background: #007bff; color: white; }
283
+ </style>
284
+ ```
285
+
286
+ **After**:
287
+ ```css
288
+ /* styles/admin-forms.css */
289
+ .form-group { margin-bottom: 1.5rem; }
290
+ .form-control { width: 100%; padding: 0.75rem; }
291
+ .btn-primary { background: #007bff; color: white; }
292
+ ```
293
+
294
+ ```vue
295
+ <!-- Components keep only unique styles -->
296
+ <style scoped>
297
+ .special-field { /* component-specific */ }
298
+ </style>
299
+ ```
300
+
301
+ **Steps**:
302
+ 1. Extract to shared CSS file
303
+ 2. Import in main.ts/App.vue
304
+ 3. Remove from ONE component
305
+ 4. Visual test
306
+ 5. Commit
307
+ 6. Repeat for remaining
308
+
309
+ ### Pattern D: Replace with Utility
310
+
311
+ **When**: Same calculation in 5+ places
312
+
313
+ **Before** (in 5 files):
314
+ ```typescript
315
+ const imageUrl = img.image?.fileUrl || img.image?.file_url || '/placeholder-image.png'
316
+ ```
317
+
318
+ **After**:
319
+ ```typescript
320
+ // utils/imageData.ts
321
+ export function extractImageUrl(
322
+ imageData: any,
323
+ fallback = '/placeholder-image.png'
324
+ ): string {
325
+ if (!imageData) return fallback
326
+ return imageData.fileUrl || imageData.file_url || fallback
327
+ }
328
+
329
+ // All files:
330
+ const imageUrl = extractImageUrl(img.image)
331
+ ```
332
+
333
+ **Steps**:
334
+ 1. Create utility
335
+ 2. Write comprehensive tests
336
+ 3. Replace in ONE location
337
+ 4. Test
338
+ 5. Commit
339
+ 6. Repeat for each location
340
+
341
+ ## Phase 3: Incremental Execution
342
+
343
+ **CRITICAL WORKFLOW**: One change → Test → Commit
344
+
345
+ ```bash
346
+ # 1. Create working branch
347
+ git checkout -b refactor-my-feature
348
+
349
+ # 2. Make ONE small change
350
+ # ... edit code ...
351
+
352
+ # 3. Run tests
353
+ npm run test:run
354
+
355
+ # 4. If pass, commit
356
+ git add .
357
+ git commit -m "refactor: extract validateArticle function
358
+
359
+ - Moved validation from processArticle
360
+ - All tests passing
361
+ - No behavior changes"
362
+
363
+ # 5. Repeat for next change
364
+ # ... edit code ...
365
+ npm run test:run
366
+ git commit -m "refactor: extract processImages"
367
+
368
+ # Continue until complete
369
+ ```
370
+
371
+ ### Testing After EVERY Change
372
+
373
+ ```bash
374
+ # After each change:
375
+
376
+ # 1. Unit tests
377
+ npm run test:run
378
+
379
+ # 2. Type check
380
+ npm run type-check
381
+
382
+ # 3. Pattern check
383
+ npm run test:patterns
384
+
385
+ # 4. Manual spot check
386
+ npm run dev
387
+ # Test the specific feature
388
+
389
+ # If ANY fail:
390
+ git reset --hard HEAD # Undo
391
+ # OR fix before committing
392
+ ```
393
+
394
+ ## Phase 4: Validation
395
+
396
+ ### Comprehensive Testing Checklist
397
+
398
+ **Automated:**
399
+ - [ ] All unit tests pass
400
+ - [ ] All integration tests pass
401
+ - [ ] Type check passes
402
+ - [ ] Pattern enforcement passes
403
+ - [ ] No new linting errors
404
+
405
+ **Manual:**
406
+ - [ ] Feature works exactly as before
407
+ - [ ] No console errors
408
+ - [ ] No visual regressions
409
+ - [ ] Performance unchanged/better
410
+ - [ ] Works in all browsers
411
+
412
+ **Code Quality:**
413
+ - [ ] More readable
414
+ - [ ] More testable
415
+ - [ ] Less duplication
416
+ - [ ] Lower complexity
417
+ - [ ] Reasonable file sizes
418
+
419
+ ### Performance Verification
420
+
421
+ ```bash
422
+ # Before refactor
423
+ npm run build
424
+ # Note: size, time
425
+
426
+ # After refactor
427
+ npm run build
428
+ # Compare: should be similar or better
429
+ ```
430
+
431
+ ## Phase 5: Documentation
432
+
433
+ ### Update Project Docs
434
+
435
+ If new patterns introduced:
436
+
437
+ **CODEBASE_ESSENTIALS.md**:
438
+ ```markdown
439
+ - **Image URL extraction:** Always use `extractImageUrl()` from `@/utils/imageData`. Prevents silent failures.
440
+ ```
441
+
442
+ **CODEBASE_CHANGELOG.md**:
443
+ ```markdown
444
+ ### Session: Refactor Image URL Handling (Jan 13, 2026)
445
+
446
+ **Goal**: Eliminate duplicated image URL logic
447
+
448
+ **Changes**:
449
+ - Created `extractImageUrl()` utility
450
+ - Replaced 12 instances
451
+ - Added tests (8 unit, 6 integration)
452
+
453
+ **Impact**:
454
+ - Reduced duplication by ~80 lines
455
+ - Improved testability
456
+
457
+ **Validation**:
458
+ - ✅ All 227 tests pass
459
+ - ✅ No behavior changes
460
+ - ✅ Build size unchanged
461
+
462
+ **Commit**: abc123
463
+ ```
464
+
465
+ ## Anti-Patterns (DON'T DO THIS)
466
+
467
+ ### ❌ Big Bang Refactor
468
+
469
+ ```bash
470
+ # WRONG: Change 50 files at once
471
+ git commit -m "refactor: everything"
472
+
473
+ # CORRECT: Incremental commits
474
+ git commit -m "refactor: extract validation"
475
+ # test
476
+ git commit -m "refactor: extract image processing"
477
+ # test
478
+ ```
479
+
480
+ ### ❌ Refactor Without Tests
481
+
482
+ ```typescript
483
+ // WRONG: No tests exist
484
+ function refactoredFunction() {
485
+ // Hope this works! 🤞
486
+ }
487
+
488
+ // CORRECT: Write tests first
489
+ test('refactoredFunction works', () => { ... })
490
+ function refactoredFunction() { ... }
491
+ ```
492
+
493
+ ### ❌ Change Behavior
494
+
495
+ ```typescript
496
+ // WRONG: Added new validation during refactor
497
+ function validateArticle(article: Article) {
498
+ if (!article.title) throw new Error('Title required')
499
+ if (!article.excerpt) throw new Error('Excerpt required') // NEW!
500
+ }
501
+
502
+ // CORRECT: Preserve exact behavior
503
+ function validateArticle(article: Article) {
504
+ if (!article.title) throw new Error('Title required')
505
+ // Same validation as before, just extracted
506
+ }
507
+ ```
508
+
509
+ ### ❌ Premature Optimization
510
+
511
+ ```typescript
512
+ // WRONG: No measured problem, making code complex
513
+ // Replacing simple readable code with "faster" code
514
+
515
+ // CORRECT: Measure first, optimize if needed
516
+ // Keep code simple unless profiling shows issue
517
+ ```
518
+
519
+ ### ❌ Refactor Under Pressure
520
+
521
+ ```
522
+ // WRONG: "Production deploy tomorrow, let me refactor today!"
523
+ // CORRECT: Refactor when you have time to test properly
524
+ ```
525
+
526
+ ## Common Scenarios
527
+
528
+ ### Scenario 1: Component Too Large (>300 lines)
529
+
530
+ **Fix**:
531
+ 1. Extract child components
532
+ 2. Extract composables for logic
533
+ 3. Extract utilities for helpers
534
+ 4. ONE responsibility per file
535
+
536
+ ### Scenario 2: Duplicated Code (3+ places)
537
+
538
+ **Fix**:
539
+ 1. Identify common pattern
540
+ 2. Extract to utility/composable
541
+ 3. Write tests
542
+ 4. Replace one by one
543
+ 5. Delete duplicates
544
+
545
+ ### Scenario 3: Hard to Test
546
+
547
+ **Fix**:
548
+ 1. Identify dependencies
549
+ 2. Extract to parameters
550
+ 3. Make functions pure
551
+ 4. Write tests with mocks
552
+
553
+ ### Scenario 4: Unclear Naming
554
+
555
+ **Fix**:
556
+ 1. Rename ONE identifier
557
+ 2. Use IDE refactor (F2 in VS Code)
558
+ 3. Run tests
559
+ 4. Commit
560
+ 5. Repeat
561
+
562
+ ## Emergency Rollback
563
+
564
+ If refactoring breaks something:
565
+
566
+ ```bash
567
+ # Option 1: Revert last commit
568
+ git revert HEAD
569
+
570
+ # Option 2: Restore from backup
571
+ git checkout backup-before-refactor
572
+ git checkout -b refactor-my-feature-v2
573
+
574
+ # Option 3: Stash and investigate
575
+ git stash
576
+ npm run test:run # Pass now?
577
+ git stash pop # Re-apply and fix
578
+
579
+ # Option 4: Nuclear
580
+ git reset --hard origin/development
581
+ # Start over with smaller changes
582
+ ```
583
+
584
+ ## Success Metrics
585
+
586
+ Refactoring succeeds when:
587
+
588
+ ✅ All tests pass (no behavior changes)
589
+ ✅ Code more readable (clear improvement)
590
+ ✅ Complexity reduced (fewer lines, simpler logic)
591
+ ✅ Duplication removed (DRY)
592
+ ✅ Test coverage maintained/improved
593
+ ✅ Performance unchanged/better
594
+ ✅ No regressions (manual testing confirms)
595
+
596
+ ## Key Commands
597
+
598
+ ```bash
599
+ # Before refactoring
600
+ npm run test:run -- --coverage # Check coverage
601
+ docker exec backend pytest --cov # Backend coverage
602
+ git checkout -b backup-before-refactor # Safety backup
603
+
604
+ # During refactoring (after EACH change)
605
+ npm run test:run # Frontend tests
606
+ npm run type-check # TypeScript
607
+ npm run test:patterns # Pattern enforcement
608
+ docker exec backend pytest -v # Backend tests
609
+ git commit -m "refactor: [change]" # Commit success
610
+
611
+ # After refactoring
612
+ npm run build # Verify build
613
+ npm run dev # Manual test
614
+ git push origin refactor-my-feature # Push when complete
615
+ ```
616
+
617
+ ## Examples
618
+
619
+ ### Example 1: Extract Function
620
+
621
+ ```bash
622
+ # 1. Initial state: 80-line function
623
+ # 2. Extract validation (commit)
624
+ git commit -m "refactor: extract validateArticle"
625
+ # 3. Extract image processing (commit)
626
+ git commit -m "refactor: extract processImages"
627
+ # 4. Simplify main function (commit)
628
+ git commit -m "refactor: simplify processArticle"
629
+ # Result: 3 small focused functions
630
+ ```
631
+
632
+ ### Example 2: Extract Composable
633
+
634
+ ```bash
635
+ # 1. Create useDataLoader composable
636
+ # 2. Write tests for composable
637
+ git commit -m "refactor: add useDataLoader composable"
638
+ # 3. Migrate BlogView (test, commit)
639
+ git commit -m "refactor: BlogView uses useDataLoader"
640
+ # 4. Migrate ArticleView (test, commit)
641
+ git commit -m "refactor: ArticleView uses useDataLoader"
642
+ # 5. Migrate CategoryView (test, commit)
643
+ git commit -m "refactor: CategoryView uses useDataLoader"
644
+ # Result: Eliminated 60 lines of duplication
645
+ ```
646
+
647
+ ## When to Stop
648
+
649
+ Stop refactoring when:
650
+ - Tests start failing frequently (too aggressive)
651
+ - Code is "good enough" (perfect is enemy of done)
652
+ - Deadline approaching (commit what you have)
653
+ - No measurable benefit (diminishing returns)
654
+ - You're just tweaking style (not improving structure)
655
+
656
+ ## Related Resources
657
+
658
+ - [developer-checklist](../developer-checklist/SKILL.md) - Pre-commit validation
659
+ - [feature-implementation](../feature-implementation/SKILL.md) - Adding features
660
+ - [CODEBASE_ESSENTIALS.md](../../../CODEBASE_ESSENTIALS.md) - Current patterns
661
+ - [CODEBASE_CHANGELOG.md](../../../CODEBASE_CHANGELOG.md) - Historical changes
662
+ - [.archive/guides/DRY_REFACTORING_GUIDE.md](../../../.archive/guides/DRY_REFACTORING_GUIDE.md) - Past refactor example