14 KiB
14 KiB
Architecture Overview & Design Patterns
System Architecture
High-Level Architecture
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Browser │ │ Backend │ │ External │
│ (Frontend) │ │ Services │ │ Services │
│ │ │ │ │ │
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
│ │ React App │◄┼────┼──│ Express API │◄┼────┼──│ GLM-4.6 API │ │
│ │ (Vite) │ │ │ │ (EPUB Gen) │ │ │ │ (Translation)│ │
│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
│ │ │ │ │ │
│ ┌─────────────┐ │ │ │ │ ┌─────────────┐ │
│ │ Supabase │◄┼────────────────────┼────┼──│ Supabase │ │
│ │ Auth │ │ │ │ │ Database │ │
│ └─────────────┘ │ │ │ └─────────────┘ │
│ │ │ │ │
│ ┌─────────────┐ │ │ │ │
│ │ Tesseract │ │ │ │ │
│ │ OCR Engine │ │ │ │ │
│ └─────────────┘ │ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
Component Architecture
Frontend Layer Architecture
┌─────────────────────────────────────────────────────────────┐
│ Presentation Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ Header │ │ Stepper │ │ Main Content │ │
│ │ Component │ │ Component │ │ (Router Outlet) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────┐
│ Application Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ Router │ │ State │ │ Utility │ │
│ │ Management │ │ Management │ │ Services │ │
│ │(React Router)│ │ (Zustand) │ │ (API, Auth, Utils) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────┐
│ Data Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ Browser │ │ Local │ │ External │ │
│ │ Storage │ │ Storage │ │ APIs │ │
│ │ (Blobs, URLs)│ │ (localStorage)│ │ (Supabase, Backend) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Design Patterns
1. State Management Pattern (Zustand)
// Centralized Store Pattern
const useAppStore = create((set, get) => ({
// State
uploadedImages: [],
cropConfig: {},
ocrText: '',
// Actions
setUploadedImages: (images) => set({ uploadedImages: images }),
resetFromStep: (step) => set((state) => {
// Clean, atomic state updates
const newState = {};
// Reset logic based on step
return newState;
}),
}));
// Usage in components
const uploadedImages = useAppStore(state => state.uploadedImages);
const setUploadedImages = useAppStore(state => state.setUploadedImages);
2. Component Composition Pattern
// Wizard Step Composition
const WizardStep = ({ children, title, onNext, onPrev }) => {
return (
<Box>
<Typography variant="h6">{title}</Typography>
{children}
<StepActions onNext={onNext} onPrev={onPrev} />
</Box>
);
};
// Specific step implementation
const UploadStep = () => {
return (
<WizardStep title="Upload Images">
<DropzoneUpload />
<ImagePreview />
</WizardStep>
);
};
3. Service Layer Pattern
// API Service Abstraction
export const epubService = {
generate: async (text, metadata) => {
const response = await fetch(`${API_BASE_URL}/generate-epub`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text, meta: metadata }),
});
return response.json();
},
};
// Authentication Service
export const authService = {
login: async (credentials) => {
// Authentication logic
},
logout: async () => {
// Logout logic
},
};
4. Observer Pattern (Authentication)
// Supabase Auth Observer
useEffect(() => {
const { data: subscription } = supabaseClient.auth.onAuthStateChange(
(event, session) => {
if (event === 'SIGNED_IN') {
// Handle sign in
exchangeGoogleSession(session);
} else if (event === 'SIGNED_OUT') {
// Handle sign out
clearAuthSession();
}
}
);
return () => subscription.subscription.unsubscribe();
}, []);
5. Strategy Pattern (OCR Processing)
// OCR Language Strategy
const ocrLanguageStrategy = {
primary: 'tur',
fallback: 'eng',
detect: async (imageData) => {
try {
const result = await worker.recognize(imageData, 'tur');
return result.data.text;
} catch (error) {
// Fallback to English
return await worker.recognize(imageData, 'eng');
}
},
};
Data Flow Architecture
Unidirectional Data Flow
User Action → Component Event → State Update → Re-render → New UI
Example:
1. User uploads files
2. Dropzone component triggers onDrop
3. useAppStore.setUploadedImages() called
4. State updated in Zustand store
5. Components subscribed to state re-render
6. New UI shows uploaded images
Async Data Handling
// Async Action Pattern
const handleOcrProcessing = async () => {
try {
setTranslationStatus('processing');
setTranslationProgress(0);
const processedText = await processOcrImages(
croppedImages,
(progress) => setTranslationProgress(progress)
);
setOcrText(processedText);
setTranslationStatus('completed');
} catch (error) {
setTranslationError(error.message);
setTranslationStatus('error');
}
};
Component Architecture
Hierarchy Structure
App (Root Component)
├── Header (Authentication & Navigation)
├── Stepper (Wizard Progress)
├── Main Content (Router Outlet)
│ ├── UploadStep
│ ├── CropStep
│ ├── BulkCropStep
│ ├── OcrStep
│ ├── TranslationStep
│ ├── EpubStep
│ ├── DownloadStep
│ └── Auth Pages
└── Error Handling (Snackbar)
Smart vs Dumb Components
// Smart Component (Stateful)
const OcrStep = () => {
const { croppedImages, ocrText, setOcrText } = useAppStore();
const [isProcessing, setIsProcessing] = useState(false);
const handleOcrStart = async () => {
setIsProcessing(true);
// OCR processing logic
setOcrText(resultText);
setIsProcessing(false);
};
return (
<OcrProcessing
images={croppedImages}
onStart={handleOcrStart}
isProcessing={isProcessing}
result={ocrText}
/>
);
};
// Dumb Component (Presentational)
const OcrProcessing = ({ images, onStart, isProcessing, result }) => {
return (
<Box>
<Button onClick={onStart} disabled={isProcessing}>
Start OCR
</Button>
{isProcessing && <ProgressIndicator />}
{result && <TextResult text={result} />}
</Box>
);
};
Security Architecture
Authentication Flow
User Login Attempt
↓
Supabase Auth Service
↓
JWT Token Generation
↓
Token Storage (localStorage)
↓
Authenticated API Requests
↓
Token Validation & Refresh
Data Security Measures
// Secure API Requests
const secureApiCall = async (endpoint, data) => {
const token = useAppStore.getState().authToken;
return await fetch(endpoint, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
};
// Data Sanitization
const sanitizeInput = (input) => {
return input
.trim()
.replace(/[<>]/g, '') // Remove potential HTML
.substring(0, MAX_LENGTH); // Length limit
};
Performance Architecture
Lazy Loading Pattern
// Code Splitting
const UploadStep = lazy(() => import('./components/UploadStep'));
const CropStep = lazy(() => import('./components/CropStep'));
// Asset Lazy Loading
const loadTesseractAssets = async () => {
const worker = await createWorker('tur', 1, {
workerPath: '/tesseract/worker.min.js',
corePath: '/tesseract/tesseract-core-simd-lstm.wasm.js',
langPath: '/tesseract/',
});
return worker;
};
Memory Management Pattern
// Resource Cleanup
useEffect(() => {
return () => {
// Cleanup on unmount
if (generatedEpub?.url) {
URL.revokeObjectURL(generatedEpub.url);
}
};
}, []);
// Batch Processing Control
const processImagesInBatches = async (images, batchSize = 5) => {
for (let i = 0; i < images.length; i += batchSize) {
const batch = images.slice(i, i + batchSize);
await processBatch(batch);
// Allow UI to breathe
await new Promise(resolve => setTimeout(resolve, 100));
}
};
Error Handling Architecture
Error Boundary Pattern
const ErrorBoundary = ({ children }) => {
const [hasError, setHasError] = useState(false);
const [error, setError] = useState(null);
const handleError = (error, errorInfo) => {
setHasError(true);
setError(error);
// Log error to service
logError(error, errorInfo);
};
if (hasError) {
return <ErrorFallback error={error} />;
}
return (
<ErrorBoundary onError={handleError}>
{children}
</ErrorBoundary>
);
};
Global Error Handling
// Global Error Store
const useErrorStore = create((set) => ({
error: null,
setError: (message) => set({ error: message }),
clearError: () => set({ error: null }),
}));
// Error Display Component
const ErrorDisplay = () => {
const error = useAppStore(state => state.error);
const clearError = useAppStore(state => state.clearError);
return (
<Snackbar open={!!error} autoHideDuration={6000} onClose={clearError}>
<Alert severity="error" onClose={clearError}>
{error}
</Alert>
</Snackbar>
);
};
Testing Architecture
Component Testing Strategy
Unit Tests:
├── Utility functions (fileUtils, ocrUtils)
├── Service layer functions
└── Custom hooks
Integration Tests:
├── Component interactions
├── State management flow
└── API service integration
E2E Tests:
├── Complete user workflows
├── Authentication flows
└── File processing pipelines
Deployment Architecture
Build Process
Development:
├── Vite dev server
├── Hot module replacement
├── Source maps
└── Fast refresh
Production:
├── Code optimization
├── Asset bundling
├── Tree shaking
└── Compression
Container Strategy
# Multi-stage Docker build
FROM node:18-alpine AS builder
# Build stage
FROM nginx:alpine AS production
# Production stage with static files
This architecture provides a robust, scalable foundation for the imgPub application with clear separation of concerns, maintainable code structure, and optimized performance characteristics.