Files
crypto_trader/docs/architecture/ui_architecture.md

5.3 KiB

UI Architecture

This document describes the user interface architecture and how the frontend integrates with the backend API.

Overview

The UI is built with React and TypeScript, using Material-UI for components. The frontend communicates with the FastAPI backend through REST API endpoints and WebSocket connections for real-time updates.

Architecture

React Frontend → REST API / WebSocket → FastAPI Backend → Python Services → Database

Frontend Structure

frontend/src/
├── pages/           # Page components (Trading, Portfolio, Strategies, etc.)
├── components/      # Reusable UI components
├── api/            # API client functions
├── hooks/          # Custom React hooks
└── types/          # TypeScript type definitions

Page Components

DashboardPage

  • Overview of trading activity
  • Key metrics and charts
  • Quick actions

TradingPage

  • Order placement form
  • Positions table
  • Order history
  • Real-time price updates

PortfolioPage

  • Portfolio summary
  • Holdings table
  • Risk metrics
  • Performance charts

StrategiesPage

  • Strategy list and management
  • Strategy configuration
  • Start/stop controls
  • Performance metrics

BacktestPage

  • Backtest configuration
  • Results display
  • Export functionality

SettingsPage

  • Exchange management
  • Configuration settings
  • API key management

Real-Time Updates

WebSocket Connection

The frontend connects to the backend WebSocket endpoint (/ws/) for real-time updates:

  • Price updates
  • Order status changes
  • Position updates
  • Strategy status changes

Implementation

// Using WebSocket hook
import { useWebSocket } from '@/hooks/useWebSocket';

function TradingPage() {
  const { data, connected } = useWebSocket('/ws/');
  
  // Handle real-time price updates
  useEffect(() => {
    if (data?.type === 'price_update') {
      // Update UI with new price
    }
  }, [data]);
}

API Integration

API Client

All API calls go through the API client which handles:

  • Request/response serialization
  • Error handling
  • Authentication (if added)
// Example API call
import { tradingApi } from '@/api/trading';

const placeOrder = async () => {
  const order = await tradingApi.placeOrder({
    exchangeId: 1,
    symbol: 'BTC/USD',
    side: 'buy',
    type: 'market',
    quantity: 0.1,
    paperTrading: true
  });
};

React Query

The frontend uses React Query for:

  • Data fetching
  • Caching
  • Automatic refetching
  • Optimistic updates
import { useQuery, useMutation } from '@tanstack/react-query';
import { portfolioApi } from '@/api/portfolio';

function PortfolioPage() {
  const { data, isLoading } = useQuery({
    queryKey: ['portfolio'],
    queryFn: () => portfolioApi.getCurrent()
  });
  
  const updateMutation = useMutation({
    mutationFn: portfolioApi.update,
    onSuccess: () => {
      // Invalidate and refetch
      queryClient.invalidateQueries({ queryKey: ['portfolio'] });
    }
  });
}

State Management

Component State

  • Local component state with useState
  • Form state management
  • UI-only state (modals, tabs, etc.)

Server State

  • React Query for server state
  • Automatic caching and synchronization
  • Optimistic updates

Global State

  • Context API for theme, auth (if needed)
  • Minimal global state - prefer server state

Component Patterns

Container/Presentational Pattern

// Container component (handles data fetching)
function TradingPageContainer() {
  const { data } = useQuery({ queryKey: ['orders'], queryFn: fetchOrders });
  return <TradingPage orders={data} />;
}

// Presentational component (pure UI)
function TradingPage({ orders }) {
  return (
    <Box>
      <OrdersTable orders={orders} />
    </Box>
  );
}

Custom Hooks

Extract reusable logic into custom hooks:

function useOrders() {
  const { data, isLoading, error } = useQuery({
    queryKey: ['orders'],
    queryFn: () => tradingApi.getOrders()
  });
  
  const placeOrder = useMutation({
    mutationFn: tradingApi.placeOrder
  });
  
  return { orders: data, isLoading, error, placeOrder };
}

Error Handling

API Errors

try {
  await tradingApi.placeOrder(order);
} catch (error) {
  if (error.response?.status === 400) {
    // Handle validation error
  } else if (error.response?.status === 500) {
    // Handle server error
  }
}

Error Boundaries

Use React Error Boundaries to catch and display errors gracefully:

<ErrorBoundary fallback={<ErrorPage />}>
  <TradingPage />
</ErrorBoundary>

Performance Optimization

Code Splitting

Use React.lazy for code splitting:

const TradingPage = lazy(() => import('@/pages/TradingPage'));

<Suspense fallback={<Loading />}>
  <TradingPage />
</Suspense>

Memoization

Use React.memo, useMemo, and useCallback to prevent unnecessary re-renders:

const MemoizedTable = React.memo(OrdersTable);

const filteredData = useMemo(() => {
  return data.filter(/* ... */);
}, [data, filter]);

Testing

See Testing Guide for frontend testing strategies.

Styling

  • Material-UI components and theming
  • Consistent design system
  • Dark/light theme support
  • Responsive design

Accessibility

  • Semantic HTML
  • ARIA labels where needed
  • Keyboard navigation
  • Screen reader support