Files
imgPub/doc/architecture-overview.md
2025-11-17 11:39:53 +03:00

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.