# ๐Ÿ—๏ธ Modular Architecture Guide This guide demonstrates the modular architecture patterns implemented in the video streaming feature and how to apply them to other parts of the project. ## ๐ŸŽฏ Goals - **Separation of Concerns**: Each module has a single responsibility - **Reusability**: Components can be used across different parts of the application - **Maintainability**: Easy to understand, modify, and test individual pieces - **Scalability**: Easy to add new features without affecting existing code ## ๐Ÿ“ Feature-Based Structure ``` src/features/video-streaming/ โ”œโ”€โ”€ components/ # UI Components โ”‚ โ”œโ”€โ”€ VideoPlayer.tsx โ”‚ โ”œโ”€โ”€ VideoCard.tsx โ”‚ โ”œโ”€โ”€ VideoList.tsx โ”‚ โ”œโ”€โ”€ VideoModal.tsx โ”‚ โ”œโ”€โ”€ VideoThumbnail.tsx โ”‚ โ””โ”€โ”€ index.ts โ”œโ”€โ”€ hooks/ # Custom React Hooks โ”‚ โ”œโ”€โ”€ useVideoList.ts โ”‚ โ”œโ”€โ”€ useVideoPlayer.ts โ”‚ โ”œโ”€โ”€ useVideoInfo.ts โ”‚ โ””โ”€โ”€ index.ts โ”œโ”€โ”€ services/ # API & Business Logic โ”‚ โ””โ”€โ”€ videoApi.ts โ”œโ”€โ”€ types/ # TypeScript Definitions โ”‚ โ””โ”€โ”€ index.ts โ”œโ”€โ”€ utils/ # Pure Utility Functions โ”‚ โ””โ”€โ”€ videoUtils.ts โ”œโ”€โ”€ VideoStreamingPage.tsx # Main Feature Page โ””โ”€โ”€ index.ts # Feature Export ``` ## ๐Ÿงฉ Layer Responsibilities ### 1. **Components Layer** (`/components`) - **Purpose**: Pure UI components that handle rendering and user interactions - **Rules**: - No direct API calls - Receive data via props - Emit events via callbacks - Minimal business logic **Example:** ```tsx // โœ… Good: Pure component with clear props export const VideoCard: React.FC = ({ video, onClick, showMetadata = true, }) => { return (
onClick?.(video)}> {/* UI rendering */}
); }; // โŒ Bad: Component with API calls export const VideoCard = () => { const [video, setVideo] = useState(null); useEffect(() => { fetch('/api/videos/123').then(/* ... */); // Don't do this! }, []); }; ``` ### 2. **Hooks Layer** (`/hooks`) - **Purpose**: Manage state, side effects, and provide data to components - **Rules**: - Handle API calls and data fetching - Manage component state - Provide clean interfaces to components **Example:** ```tsx // โœ… Good: Hook handles complexity, provides simple interface export function useVideoList(options = {}) { const [videos, setVideos] = useState([]); const [loading, setLoading] = useState(false); const fetchVideos = useCallback(async () => { setLoading(true); try { const data = await videoApiService.getVideos(); setVideos(data.videos); } finally { setLoading(false); } }, []); return { videos, loading, refetch: fetchVideos }; } ``` ### 3. **Services Layer** (`/services`) - **Purpose**: Handle external dependencies (APIs, storage, etc.) - **Rules**: - Pure functions or classes - No React dependencies - Handle errors gracefully - Provide consistent interfaces **Example:** ```tsx // โœ… Good: Service handles API complexity export class VideoApiService { async getVideos(params = {}) { try { const response = await fetch(this.buildUrl('/videos', params)); return await this.handleResponse(response); } catch (error) { throw new VideoApiError('FETCH_ERROR', error.message); } } } ``` ### 4. **Types Layer** (`/types`) - **Purpose**: Centralized TypeScript definitions - **Rules**: - Define all interfaces and types - Export from index.ts - Keep types close to their usage ### 5. **Utils Layer** (`/utils`) - **Purpose**: Pure utility functions - **Rules**: - No side effects - Easily testable - Single responsibility ## ๐Ÿ”„ Component Composition Patterns ### Small, Focused Components Instead of large monolithic components, create small, focused ones: ```tsx // โœ… Good: Small, focused components {videos.map(video => ( ))} // โŒ Bad: Monolithic component {/* 500+ lines of mixed concerns */} ``` ### Composition over Inheritance ```tsx // โœ… Good: Compose features export const VideoStreamingPage = () => { const { videos, loading } = useVideoList(); const [selectedVideo, setSelectedVideo] = useState(null); return (
); }; ``` ## ๐ŸŽจ Applying to Existing Components ### Example: Breaking Down VisionSystem Component **Current Structure (Monolithic):** ```tsx // โŒ Current: One large component export const VisionSystem = () => { // 900+ lines of mixed concerns return (
{/* System status */} {/* Camera cards */} {/* Storage info */} {/* MQTT status */}
); }; ``` **Proposed Modular Structure:** ``` src/features/vision-system/ โ”œโ”€โ”€ components/ โ”‚ โ”œโ”€โ”€ SystemStatusCard.tsx โ”‚ โ”œโ”€โ”€ CameraCard.tsx โ”‚ โ”œโ”€โ”€ CameraGrid.tsx โ”‚ โ”œโ”€โ”€ StorageOverview.tsx โ”‚ โ”œโ”€โ”€ MqttStatus.tsx โ”‚ โ””โ”€โ”€ index.ts โ”œโ”€โ”€ hooks/ โ”‚ โ”œโ”€โ”€ useSystemStatus.ts โ”‚ โ”œโ”€โ”€ useCameraList.ts โ”‚ โ””โ”€โ”€ index.ts โ”œโ”€โ”€ services/ โ”‚ โ””โ”€โ”€ visionApi.ts โ””โ”€โ”€ VisionSystemPage.tsx ``` **Refactored Usage:** ```tsx // โœ… Better: Composed from smaller parts export const VisionSystemPage = () => { return (
); }; // Now you can reuse components elsewhere: export const DashboardHome = () => { return (
{/* Reused! */}
); }; ``` ## ๐Ÿ“‹ Migration Strategy ### Phase 1: Extract Utilities 1. Move pure functions to `/utils` 2. Move types to `/types` 3. Create service classes for API calls ### Phase 2: Extract Hooks 1. Create custom hooks for data fetching 2. Move state management to hooks 3. Simplify component logic ### Phase 3: Break Down Components 1. Identify distinct UI sections 2. Extract to separate components 3. Use composition in parent components ### Phase 4: Feature Organization 1. Group related components, hooks, and services 2. Create feature-level exports 3. Update imports across the application ## ๐Ÿงช Testing Benefits Modular architecture makes testing much easier: ```tsx // โœ… Easy to test individual pieces describe('VideoCard', () => { it('displays video information', () => { render(); expect(screen.getByText(mockVideo.filename)).toBeInTheDocument(); }); }); describe('useVideoList', () => { it('fetches videos on mount', async () => { const { result } = renderHook(() => useVideoList()); await waitFor(() => { expect(result.current.videos).toHaveLength(3); }); }); }); ``` ## ๐Ÿš€ Benefits Achieved 1. **Reusability**: `VideoCard` can be used in lists, grids, or modals 2. **Maintainability**: Each file has a single, clear purpose 3. **Testability**: Small, focused units are easy to test 4. **Developer Experience**: Clear structure makes onboarding easier 5. **Performance**: Smaller components enable better optimization ## ๐Ÿ“ Best Practices 1. **Start Small**: Begin with one feature and apply patterns gradually 2. **Single Responsibility**: Each file should have one clear purpose 3. **Clear Interfaces**: Use TypeScript to define clear contracts 4. **Consistent Naming**: Follow naming conventions across features 5. **Documentation**: Document complex logic and interfaces This modular approach transforms large, hard-to-maintain components into small, reusable, and testable pieces that can be composed together to create powerful features.