mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-28 07:44:56 +00:00
670 lines
17 KiB
Markdown
670 lines
17 KiB
Markdown
# 📊 Component Size Violation Analysis & Refactoring Guide
|
|
|
|
**Document Date:** December 25, 2025
|
|
**Total Violations:** 8 components, 4,146 LOC over limit
|
|
**Target State:** 0 violations, 325 LOC total
|
|
|
|
---
|
|
|
|
## 📈 Complete Violation List
|
|
|
|
### Tier 1: Critical (800+ LOC)
|
|
|
|
| # | Component | Path | Current | Target | Reduction | Priority |
|
|
|---|-----------|------|---------|--------|-----------|----------|
|
|
| 1 | GitHubActionsFetcher | `src/components/` | 887 | 95 | 89% ↓ | 🔴 P0 |
|
|
| 2 | NerdModeIDE | `src/components/` | 733 | 110 | 85% ↓ | 🔴 P0 |
|
|
| 3 | LuaEditor | `src/components/` | 686 | 120 | 82% ↓ | 🔴 P0 |
|
|
|
|
### Tier 2: High (500-700 LOC)
|
|
|
|
| # | Component | Path | Current | Target | Reduction | Priority |
|
|
|---|-----------|------|---------|--------|-----------|----------|
|
|
| 4 | SchemaEditor | `src/components/` | 520 | 100 | 80% ↓ | 🟡 P1 |
|
|
| 5 | ComponentConfigDialog | `src/components/` | 450 | 90 | 80% ↓ | 🟡 P1 |
|
|
| 6 | PropertyInspector | `src/components/` | 380 | 85 | 77% ↓ | 🟡 P1 |
|
|
|
|
### Tier 3: Medium (200-400 LOC)
|
|
|
|
| # | Component | Path | Current | Target | Reduction | Priority |
|
|
|---|-----------|------|---------|--------|-----------|----------|
|
|
| 7 | IRCWebchat | `src/components/` | 290 | 85 | 70% ↓ | 🟢 P2 |
|
|
| 8 | AuditLogViewer | `src/components/` | 210 | 70 | 66% ↓ | 🟢 P2 |
|
|
|
|
**Totals:**
|
|
- **Before:** 4,156 LOC across 8 files
|
|
- **After:** 755 LOC across 40+ smaller files
|
|
- **Expected New Components:** 32+ child components + 8+ hooks
|
|
- **Overall Reduction:** 81.8% ↓
|
|
|
|
---
|
|
|
|
## 🔴 TIER 1 DETAILED ANALYSIS
|
|
|
|
### Component 1: GitHubActionsFetcher.tsx (887 LOC)
|
|
|
|
**Current Architecture:**
|
|
```
|
|
┌─ GitHubActionsFetcher (887 LOC, monolithic)
|
|
├─ useState:
|
|
│ ├─ runs (workflow runs)
|
|
│ ├─ loading
|
|
│ ├─ error
|
|
│ ├─ filters (status, branch)
|
|
│ ├─ sortBy
|
|
│ ├─ autoRefresh
|
|
│ ├─ refreshInterval
|
|
│ └─ selectedRun
|
|
├─ Effects:
|
|
│ ├─ Initial fetch
|
|
│ ├─ Auto-refresh interval
|
|
│ ├─ Local storage sync
|
|
│ └─ Search debounce
|
|
├─ API Calls:
|
|
│ ├─ fetchWorkflowRuns()
|
|
│ ├─ downloadRunLogs()
|
|
│ ├─ retryFailedRun()
|
|
│ └─ analyzeRunLogs()
|
|
└─ Render:
|
|
├─ Filters UI
|
|
├─ Runs table (200+ LOC)
|
|
├─ Run details modal
|
|
├─ Analysis panel
|
|
└─ Download progress
|
|
```
|
|
|
|
**Issues:**
|
|
1. **Mixed responsibilities:** API integration + UI rendering + state management
|
|
2. **Hardcoded logic:** Analysis features, filtering, sorting all in JSX
|
|
3. **No reusability:** Hooks can't be used elsewhere
|
|
4. **Hard to test:** Too many moving parts, complex mocking needed
|
|
5. **Performance:** Re-renders entire tree on any state change
|
|
|
|
**Refactoring Strategy:**
|
|
|
|
```
|
|
BEFORE:
|
|
GitHubActionsFetcher.tsx (887 LOC)
|
|
├─ API integration (200 LOC)
|
|
├─ State management (150 LOC)
|
|
├─ Analysis logic (100 LOC)
|
|
└─ Rendering (437 LOC)
|
|
|
|
AFTER:
|
|
useGitHubFetcher.ts (65 LOC) ← API + polling
|
|
├─ Fetch runs
|
|
├─ Cache + refetch
|
|
└─ Auto-refresh logic
|
|
|
|
useAnalyzeRuns.ts (45 LOC) ← Analysis logic
|
|
├─ Analyze single run
|
|
├─ Analyze logs
|
|
└─ Generate insights
|
|
|
|
WorkflowRunCard.tsx (48 LOC) ← Single run display
|
|
├─ Run info
|
|
├─ Status badge
|
|
└─ Quick actions
|
|
|
|
WorkflowFilterBar.tsx (42 LOC) ← Filters
|
|
├─ Status filter
|
|
├─ Branch filter
|
|
└─ Sort dropdown
|
|
|
|
WorkflowRunsTable.tsx (65 LOC) ← Table view
|
|
├─ Column headers
|
|
├─ Row rendering (uses WorkflowRunCard)
|
|
└─ Pagination
|
|
|
|
WorkflowAnalysisPanel.tsx (52 LOC) ← Analysis UI
|
|
├─ Performance insights
|
|
├─ Job breakdown
|
|
└─ Error summary
|
|
|
|
GitHubActionsFetcher.tsx (85 LOC) ← Container
|
|
├─ Wire hooks
|
|
├─ Compose components
|
|
└─ Handle interactions
|
|
```
|
|
|
|
**Implementation Checklist:**
|
|
|
|
**Step 1: Create useGitHubFetcher Hook** (90 min)
|
|
```typescript
|
|
// src/hooks/useGitHubFetcher.ts
|
|
export interface UseGitHubFetcherOptions {
|
|
autoRefresh?: boolean;
|
|
refreshInterval?: number;
|
|
filters?: WorkflowFilter;
|
|
}
|
|
|
|
export function useGitHubFetcher(options: UseGitHubFetcherOptions) {
|
|
return {
|
|
runs: WorkflowRun[],
|
|
loading: boolean,
|
|
error: Error | null,
|
|
refresh: () => Promise<void>,
|
|
setFilters: (filters: WorkflowFilter) => void,
|
|
setSortBy: (field: string, direction: 'asc' | 'desc') => void,
|
|
}
|
|
}
|
|
```
|
|
|
|
**Responsibilities:**
|
|
- Fetch runs from GitHub API
|
|
- Handle auth and errors
|
|
- Manage auto-refresh interval
|
|
- Cache results with stale-while-revalidate
|
|
- Expose refresh and filter controls
|
|
|
|
**Tests:**
|
|
- Test successful fetch
|
|
- Test auth errors
|
|
- Test network errors
|
|
- Test auto-refresh interval
|
|
- Test filter application
|
|
- Test cache invalidation
|
|
|
|
---
|
|
|
|
**Step 2: Create useAnalyzeRuns Hook** (60 min)
|
|
```typescript
|
|
// src/hooks/useAnalyzeRuns.ts
|
|
export interface AnalysisResult {
|
|
totalRuns: number;
|
|
successRate: number;
|
|
averageDuration: number;
|
|
failureReasons: Map<string, number>;
|
|
slowestJobs: Job[];
|
|
}
|
|
|
|
export function useAnalyzeRuns() {
|
|
return {
|
|
analyze: (runs: WorkflowRun[]) => AnalysisResult,
|
|
analyzeRun: (run: WorkflowRun) => RunAnalysis,
|
|
analyzeLogs: (logs: string) => LogAnalysis,
|
|
}
|
|
}
|
|
```
|
|
|
|
**Tests:**
|
|
- Test success rate calculation
|
|
- Test duration averaging
|
|
- Test failure categorization
|
|
- Test slowest job detection
|
|
|
|
---
|
|
|
|
**Step 3: Create WorkflowRunCard Component** (45 min)
|
|
```typescript
|
|
// src/components/WorkflowRunCard.tsx (48 LOC)
|
|
interface WorkflowRunCardProps {
|
|
run: WorkflowRun;
|
|
onSelect: (run: WorkflowRun) => void;
|
|
onRetry: (run: WorkflowRun) => void;
|
|
onDownloadLogs: (run: WorkflowRun) => void;
|
|
}
|
|
|
|
export function WorkflowRunCard({
|
|
run,
|
|
onSelect,
|
|
onRetry,
|
|
onDownloadLogs,
|
|
}: WorkflowRunCardProps) {
|
|
return (
|
|
<div className="run-card">
|
|
<div className="status-badge" data-status={run.status}>
|
|
{run.status}
|
|
</div>
|
|
<div className="info">
|
|
<h3>{run.name}</h3>
|
|
<p>{run.branch} • {formatDate(run.createdAt)}</p>
|
|
</div>
|
|
<div className="duration">
|
|
{formatDuration(run.duration)}
|
|
</div>
|
|
<div className="actions">
|
|
<button onClick={() => onSelect(run)}>Details</button>
|
|
{run.status === 'failed' && (
|
|
<button onClick={() => onRetry(run)}>Retry</button>
|
|
)}
|
|
<button onClick={() => onDownloadLogs(run)}>Logs</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
**Tests:**
|
|
- Test card rendering with different statuses
|
|
- Test button clicks
|
|
- Test conditional rendering (retry button)
|
|
|
|
---
|
|
|
|
**Step 4-6: Create Other Components** (2 hours each)
|
|
- WorkflowFilterBar: Status/branch filters + sort
|
|
- WorkflowRunsTable: List of WorkflowRunCard components
|
|
- WorkflowAnalysisPanel: Statistics from useAnalyzeRuns
|
|
|
|
---
|
|
|
|
**Step 7: Refactor Container Component** (60 min)
|
|
```typescript
|
|
// src/components/GitHubActionsFetcher.tsx (85 LOC)
|
|
export function GitHubActionsFetcher() {
|
|
const { runs, loading, error, refresh, setFilters, setSortBy } =
|
|
useGitHubFetcher({
|
|
autoRefresh: true,
|
|
refreshInterval: 30000,
|
|
});
|
|
|
|
const { analyze } = useAnalyzeRuns();
|
|
const analysis = useMemo(() => analyze(runs), [runs]);
|
|
|
|
const [selectedRun, setSelectedRun] = useState<WorkflowRun | null>(null);
|
|
|
|
if (loading) return <LoadingSpinner />;
|
|
if (error) return <ErrorBanner error={error} />;
|
|
|
|
return (
|
|
<div className="github-actions">
|
|
<WorkflowFilterBar
|
|
onFilterChange={setFilters}
|
|
onSortChange={setSortBy}
|
|
/>
|
|
<WorkflowRunsTable
|
|
runs={runs}
|
|
onSelectRun={setSelectedRun}
|
|
onRetryRun={handleRetry}
|
|
onDownloadLogs={handleDownloadLogs}
|
|
/>
|
|
{selectedRun && (
|
|
<WorkflowAnalysisPanel run={selectedRun} analysis={analysis} />
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
**Keep API same:** Consumers of GitHubActionsFetcher shouldn't notice any change.
|
|
|
|
---
|
|
|
|
**Step 8: Add Tests** (90 min)
|
|
```typescript
|
|
// src/hooks/useGitHubFetcher.test.ts
|
|
describe('useGitHubFetcher', () => {
|
|
it('should fetch workflow runs on mount', async () => {
|
|
// Test setup with mock API
|
|
// Verify hook returns runs
|
|
});
|
|
|
|
it('should handle authentication errors', async () => {
|
|
// Mock API error
|
|
// Verify error is returned
|
|
});
|
|
|
|
it('should auto-refresh at specified interval', async () => {
|
|
// Mock timer
|
|
// Verify refetch occurs
|
|
});
|
|
|
|
// ... 8+ more tests
|
|
});
|
|
|
|
// src/components/WorkflowRunCard.test.tsx
|
|
describe('WorkflowRunCard', () => {
|
|
it('should render run information', () => {
|
|
// Render component with mock run
|
|
// Verify all fields displayed
|
|
});
|
|
|
|
it('should call onSelect when clicked', () => {
|
|
// Click Details button
|
|
// Verify onSelect called
|
|
});
|
|
|
|
// ... 4+ more tests
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
**Effort Summary:**
|
|
| Task | Effort | Cumulative |
|
|
|------|--------|-----------|
|
|
| useGitHubFetcher hook | 90 min | 90 min |
|
|
| useAnalyzeRuns hook | 60 min | 150 min |
|
|
| WorkflowRunCard | 45 min | 195 min |
|
|
| WorkflowFilterBar | 45 min | 240 min |
|
|
| WorkflowRunsTable | 60 min | 300 min |
|
|
| WorkflowAnalysisPanel | 55 min | 355 min |
|
|
| Container refactor | 60 min | 415 min |
|
|
| Tests | 90 min | 505 min |
|
|
| **Total:** | | **505 min (8.4 hours)** |
|
|
|
|
---
|
|
|
|
### Component 2: NerdModeIDE.tsx (733 LOC)
|
|
|
|
**Current Issues:**
|
|
- File tree navigation + code editor + console + git all combined
|
|
- Complex state: expandedNodes, openFiles, activeTab, editorContent, unsavedChanges
|
|
- Keyboard shortcuts hardcoded
|
|
- Theme/settings not configurable
|
|
|
|
**Refactoring Plan:**
|
|
```
|
|
BEFORE: NerdModeIDE.tsx (733 LOC)
|
|
├─ File tree logic
|
|
├─ Editor state
|
|
├─ Console management
|
|
└─ Git integration
|
|
|
|
AFTER:
|
|
useFileTree.ts (85 LOC) ← Tree operations
|
|
useCodeEditor.ts (68 LOC) ← Editor state
|
|
useConsoleOutput.ts (42 LOC) ← Console management
|
|
useGitStatus.ts (38 LOC) ← Git info
|
|
|
|
FileTreePanel.tsx (72 LOC) ← Tree UI
|
|
EditorPanel.tsx (80 LOC) ← Editor UI
|
|
ConsoleOutput.tsx (55 LOC) ← Console UI
|
|
GitStatusBar.tsx (35 LOC) ← Git UI
|
|
|
|
NerdModeIDE.tsx (110 LOC) ← Container
|
|
```
|
|
|
|
**Key Hooks:**
|
|
|
|
```typescript
|
|
// src/hooks/useFileTree.ts
|
|
interface FileTreeState {
|
|
expandedNodes: Set<string>;
|
|
selectedFile: string | null;
|
|
searchTerm: string;
|
|
}
|
|
|
|
export function useFileTree(projectRoot: string) {
|
|
return {
|
|
tree: FileNode[],
|
|
state: FileTreeState,
|
|
toggleNode: (nodeId: string) => void,
|
|
selectFile: (path: string) => void,
|
|
createFile: (path: string) => Promise<void>,
|
|
deleteFile: (path: string) => Promise<void>,
|
|
renameFile: (oldPath: string, newPath: string) => Promise<void>,
|
|
}
|
|
}
|
|
|
|
// src/hooks/useCodeEditor.ts
|
|
export function useCodeEditor(language: string) {
|
|
return {
|
|
content: string,
|
|
setContent: (content: string) => void,
|
|
openTabs: EditorTab[],
|
|
activeTab: EditorTab | null,
|
|
switchTab: (tabId: string) => void,
|
|
closeTab: (tabId: string) => void,
|
|
hasUnsavedChanges: boolean,
|
|
save: () => Promise<void>,
|
|
}
|
|
}
|
|
```
|
|
|
|
**Effort:** 25 hours (including all components and tests)
|
|
|
|
---
|
|
|
|
### Component 3: LuaEditor.tsx (686 LOC)
|
|
|
|
**Current Issues:**
|
|
- Script editing + preview + console combined
|
|
- Hardcoded syntax highlighting
|
|
- No script library integration
|
|
- Limited error reporting
|
|
|
|
**Refactoring Plan:**
|
|
```
|
|
BEFORE: LuaEditor.tsx (686 LOC)
|
|
├─ Script editing
|
|
├─ Preview/execution
|
|
└─ Console output
|
|
|
|
AFTER:
|
|
useLuaScript.ts (55 LOC) ← Script CRUD
|
|
useLuaPreview.ts (48 LOC) ← Execution
|
|
|
|
ScriptEditor.tsx (65 LOC) ← Edit UI
|
|
ScriptPreview.tsx (48 LOC) ← Preview UI
|
|
|
|
LuaEditor.tsx (120 LOC) ← Container
|
|
```
|
|
|
|
**Key Hooks:**
|
|
|
|
```typescript
|
|
// src/hooks/useLuaScript.ts
|
|
export function useLuaScript(scriptId?: string) {
|
|
return {
|
|
content: string,
|
|
setContent: (content: string) => void,
|
|
save: () => Promise<void>,
|
|
metadata: ScriptMetadata,
|
|
updateMetadata: (metadata: Partial<ScriptMetadata>) => void,
|
|
}
|
|
}
|
|
|
|
// src/hooks/useLuaPreview.ts
|
|
export function useLuaPreview(script: string) {
|
|
return {
|
|
output: string,
|
|
errors: LuaError[],
|
|
run: (context: Record<string, any>) => Promise<void>,
|
|
clear: () => void,
|
|
}
|
|
}
|
|
```
|
|
|
|
**Effort:** 20 hours
|
|
|
|
---
|
|
|
|
## 🟡 TIER 2 ANALYSIS (Medium Components)
|
|
|
|
### Component 4: SchemaEditor.tsx (520 LOC)
|
|
|
|
**Issues:** Form builder + schema display + validation all combined
|
|
|
|
**Refactoring:** Extract form builder to hooks, split into:
|
|
- SchemaForm.tsx (80 LOC)
|
|
- SchemaPreview.tsx (70 LOC)
|
|
- useSchemaBuilder.ts (90 LOC)
|
|
- Container (60 LOC)
|
|
|
|
**Effort:** 10 hours
|
|
|
|
---
|
|
|
|
### Component 5: ComponentConfigDialog.tsx (450 LOC)
|
|
|
|
**Issues:** Too many tabs and config sections
|
|
|
|
**Refactoring:** Each config section as separate tab component
|
|
- TabSelector.tsx (40 LOC)
|
|
- GeneralTab.tsx (60 LOC)
|
|
- StylesTab.tsx (70 LOC)
|
|
- PropsTab.tsx (65 LOC)
|
|
- Container (90 LOC)
|
|
|
|
**Effort:** 8 hours
|
|
|
|
---
|
|
|
|
### Component 6: PropertyInspector.tsx (380 LOC)
|
|
|
|
**Issues:** Different prop types rendered in single component
|
|
|
|
**Refactoring:** Prop type components
|
|
- PropertyInput.tsx (45 LOC)
|
|
- PropertySelect.tsx (40 LOC)
|
|
- PropertyColorPicker.tsx (35 LOC)
|
|
- PropertyToggle.tsx (30 LOC)
|
|
- Container (75 LOC)
|
|
|
|
**Effort:** 7 hours
|
|
|
|
---
|
|
|
|
## 🟢 TIER 3 ANALYSIS (Smaller Components)
|
|
|
|
### Component 7: IRCWebchat.tsx (290 LOC)
|
|
|
|
**Issues:** Chat UI + message rendering + input handling
|
|
|
|
**Refactoring:**
|
|
- MessageList.tsx (65 LOC)
|
|
- ChatInput.tsx (45 LOC)
|
|
- useChatMessages.ts (50 LOC)
|
|
- Container (60 LOC)
|
|
|
|
**Effort:** 4 hours
|
|
|
|
---
|
|
|
|
### Component 8: AuditLogViewer.tsx (210 LOC)
|
|
|
|
**Issues:** Table view + filtering + search
|
|
|
|
**Refactoring:**
|
|
- AuditLogTable.tsx (85 LOC)
|
|
- AuditLogFilter.tsx (50 LOC)
|
|
- Container (50 LOC)
|
|
|
|
**Effort:** 3 hours
|
|
|
|
---
|
|
|
|
## 📊 Summary Table
|
|
|
|
| Component | Current | Target | Components | Hooks | Effort | Start |
|
|
|-----------|---------|--------|------------|-------|--------|-------|
|
|
| GitHubActionsFetcher | 887 | 85 | 6 | 2 | 8.4h | Week 1 |
|
|
| NerdModeIDE | 733 | 110 | 4 | 4 | 25h | Week 1 |
|
|
| LuaEditor | 686 | 120 | 2 | 2 | 20h | Week 2 |
|
|
| SchemaEditor | 520 | 100 | 3 | 1 | 10h | Week 2 |
|
|
| ComponentConfigDialog | 450 | 90 | 5 | 0 | 8h | Week 2 |
|
|
| PropertyInspector | 380 | 85 | 4 | 0 | 7h | Week 3 |
|
|
| IRCWebchat | 290 | 85 | 2 | 1 | 4h | Week 3 |
|
|
| AuditLogViewer | 210 | 70 | 1 | 0 | 3h | Week 3 |
|
|
| **TOTALS** | **4,156** | **755** | **32** | **10** | **85.4h** | |
|
|
|
|
---
|
|
|
|
## ✅ Testing Strategy
|
|
|
|
### Unit Tests (Per Component)
|
|
- Props validation
|
|
- State management
|
|
- Event handlers
|
|
- Edge cases
|
|
|
|
### Hook Tests
|
|
- Initial state
|
|
- State updates
|
|
- Side effects
|
|
- Error handling
|
|
|
|
### Integration Tests
|
|
- Component composition
|
|
- Data flow through hierarchy
|
|
- Performance (re-renders)
|
|
|
|
### E2E Tests
|
|
- Full workflows
|
|
- Multi-component interactions
|
|
- Performance under load
|
|
|
|
---
|
|
|
|
## 🎯 Success Criteria
|
|
|
|
### Per Component
|
|
- [ ] All child components < 150 LOC
|
|
- [ ] All hooks < 100 LOC
|
|
- [ ] Unit test coverage > 90%
|
|
- [ ] No console warnings
|
|
- [ ] Props fully documented with JSDoc
|
|
- [ ] Accessibility compliant (WCAG 2.1 AA)
|
|
- [ ] Performance: no regression in metrics
|
|
|
|
### Overall
|
|
- [ ] 0 violations remaining
|
|
- [ ] 4,156 → 755 LOC reduction
|
|
- [ ] 40+ small components + 10 reusable hooks
|
|
- [ ] All tests passing
|
|
- [ ] All code reviewed
|
|
- [ ] Documentation complete
|
|
|
|
---
|
|
|
|
## 📋 Execution Checklist
|
|
|
|
### Pre-Refactoring (Day 1)
|
|
- [ ] Create feature branch
|
|
- [ ] Set up test environment
|
|
- [ ] Create Storybook stories (optional)
|
|
- [ ] Document current API/props
|
|
|
|
### Refactoring Phase
|
|
- [ ] Create hooks
|
|
- [ ] Create child components
|
|
- [ ] Add unit tests
|
|
- [ ] Refactor container
|
|
- [ ] Update parent imports
|
|
- [ ] Test integration
|
|
|
|
### Post-Refactoring
|
|
- [ ] Code review
|
|
- [ ] E2E tests
|
|
- [ ] Performance testing
|
|
- [ ] Documentation
|
|
- [ ] Merge to main
|
|
|
|
---
|
|
|
|
## 🚀 Recommended Refactoring Order
|
|
|
|
1. **GitHubActionsFetcher** (8.4h) - Simpler, good learning example
|
|
2. **NerdModeIDE** (25h) - Most complex, but infrastructure ready
|
|
3. **LuaEditor** (20h) - Complex but fewer dependencies
|
|
4. **SchemaEditor** (10h) - Medium complexity
|
|
5. **ComponentConfigDialog** (8h) - Straightforward tab separation
|
|
6. **PropertyInspector** (7h) - Similar patterns to PropertyInspector
|
|
7. **IRCWebchat** (4h) - Simple message list pattern
|
|
8. **AuditLogViewer** (3h) - Simple table pattern
|
|
|
|
**Total Timeline:** 8.5 weeks (1 developer, sequential)
|
|
|
|
---
|
|
|
|
## 🎓 Learning Resources
|
|
|
|
### Component Decomposition Patterns
|
|
- [React docs: Composition vs Inheritance](https://react.dev/learn/thinking-in-react)
|
|
- [Atomic Design Methodology](https://bradfrost.com/blog/post/atomic-web-design/)
|
|
|
|
### Hook Development
|
|
- [React Hooks API Reference](https://react.dev/reference/react)
|
|
- [Separating Concerns with Hooks](https://react.dev/learn/separating-concerns-with-effects)
|
|
|
|
### Testing
|
|
- [React Testing Library](https://testing-library.com/docs/react-testing-library/intro)
|
|
- [Jest Documentation](https://jestjs.io/docs/getting-started)
|
|
|
|
---
|
|
|
|
**Generated:** December 25, 2025
|
|
**Next Review:** After Phase 1A completion
|