# Frontend Implementation Strategy ## Overview This document outlines the React frontend for the energy trading system UI. The frontend provides real-time monitoring, backtesting tools, ML model insights, and trading controls. **Backend API**: `http://localhost:8000` --- ## Architecture ``` ┌──────────────────────────────────────────────────────────────┐ │ React Application │ ├──────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ Pages Layer │ │ │ │ Dashboard │ Backtest │ Models │ Trading │ Settings │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ Components Layer │ │ │ │ Charts │ Forms │ Alerts │ Tables │ Controls │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ Services Layer │ │ │ │ API Client │ WebSocket │ State Management │ │ │ └──────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────┐ │ FastAPI Backend │ │ REST API + WebSocket │ └──────────────────────────────────────────────────────────────┘ ``` --- ## Project Structure ``` frontend/ ├── public/ │ ├── favicon.ico │ └── index.html │ ├── src/ │ ├── App.tsx # Main app component │ ├── main.tsx # Entry point │ ├── index.css # Global styles │ │ │ ├── components/ │ │ ├── common/ │ │ │ ├── Header.tsx │ │ │ ├── Sidebar.tsx │ │ │ ├── Loading.tsx │ │ │ └── Error.tsx │ │ │ │ │ ├── charts/ │ │ │ ├── PriceChart.tsx │ │ │ ├── BatteryChart.tsx │ │ │ ├── PnLChart.tsx │ │ │ ├── GenerationChart.tsx │ │ │ └── ModelMetricsChart.tsx │ │ │ │ │ ├── alerts/ │ │ │ ├── AlertPanel.tsx │ │ │ └── AlertItem.tsx │ │ │ │ │ ├── tables/ │ │ │ ├── ArbitrageTable.tsx │ │ │ ├── TradeLogTable.tsx │ │ │ └── ModelListTable.tsx │ │ │ │ │ └── forms/ │ │ ├── BacktestForm.tsx │ │ ├── TrainingForm.tsx │ │ └── SettingsForm.tsx │ │ │ ├── pages/ │ │ ├── Dashboard.tsx │ │ ├── Backtest.tsx │ │ ├── Models.tsx │ │ ├── Trading.tsx │ │ └── Settings.tsx │ │ │ ├── hooks/ │ │ ├── useWebSocket.ts │ │ ├── useApi.ts │ │ ├── useBacktest.ts │ │ ├── useModels.ts │ │ └── useTrading.ts │ │ │ ├── services/ │ │ ├── api.ts # REST API client │ │ ├── websocket.ts # WebSocket client │ │ └── types.ts # TypeScript types │ │ │ ├── store/ │ │ ├── index.ts # Zustand store setup │ │ ├── dashboardSlice.ts │ │ ├── backtestSlice.ts │ │ ├── modelsSlice.ts │ │ └── tradingSlice.ts │ │ │ └── lib/ │ ├── utils.ts │ ├── constants.ts │ └── formatters.ts │ ├── tests/ ├── .env.example ├── .env.local ├── package.json ├── tsconfig.json ├── vite.config.ts └── tailwind.config.js ``` --- ## Configuration ### vite.config.ts ```typescript import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import path from 'path'; export default defineConfig({ plugins: [react()], resolve: { alias: { '@': path.resolve(__dirname, './src'), }, }, server: { port: 3000, proxy: { '/api': { target: 'http://localhost:8000', changeOrigin: true, }, '/ws': { target: 'ws://localhost:8000', ws: true, }, }, }, }); ``` ### .env.example ```bash VITE_API_URL=http://localhost:8000 VITE_WS_URL=ws://localhost:8000/ws/real-time ``` --- ## TypeScript Types ### services/types.ts #### Enums ```typescript export enum Region { FR = "FR", BE = "BE", DE = "DE", NL = "NL", UK = "UK", } export enum Strategy { FUNDAMENTAL = "fundamental", TECHNICAL = "technical", ML = "ml", MINING = "mining", } export enum TradeType { BUY = "buy", SELL = "sell", CHARGE = "charge", DISCHARGE = "discharge", } export enum BacktestStatus { PENDING = "pending", RUNNING = "running", COMPLETED = "completed", FAILED = "failed", CANCELLED = "cancelled", } export enum ModelType { PRICE_PREDICTION = "price_prediction", RL_BATTERY = "rl_battery", } ``` #### Key Interfaces ```typescript export interface PriceData { timestamp: string; region: Region; day_ahead_price: number; real_time_price: number; volume_mw: number; } export interface BatteryState { battery_id: string; timestamp: string; capacity_mwh: number; charge_level_mwh: number; charge_level_pct: number; charge_rate_mw: number; discharge_rate_mw: number; efficiency: number; } export interface BacktestConfig { start_date: string; end_date: string; strategies: Strategy[]; use_ml: boolean; battery_min_reserve?: number; battery_max_charge?: number; arbitrage_min_spread?: number; } export interface BacktestMetrics { total_revenue: number; arbitrage_profit: number; battery_revenue: number; mining_profit: number; battery_utilization: number; price_capture_rate: number; win_rate: number; sharpe_ratio: number; max_drawdown: number; total_trades: number; } export interface BacktestStatus { id: string; status: BacktestStatus; progress: number; current_step: string; started_at?: string; completed_at?: string; error?: string; } export interface ModelInfo { id: string; type: ModelType; name: string; horizon?: number; created_at: string; metrics: Record; status: string; } export interface TrainingRequest { model_type: ModelType; horizon?: number; start_date: string; end_date: string; hyperparameters: Record; } export interface TrainingStatus { id: string; status: BacktestStatus; progress: number; current_epoch?: number; total_epochs?: number; metrics: Record; started_at?: string; completed_at?: string; error?: string; } export interface PredictionRequest { model_id: string; timestamp: string; features?: Record; } export interface PredictionResponse { model_id: string; timestamp: string; prediction: number; confidence?: number; features_used: string[]; } export interface StrategyStatus { strategy: Strategy; running: boolean; last_updated?: string; } export interface TradingPosition { region: Region; position_mw: number; battery_charge_pct: number; pnl: number; } export interface Alert { id: string; timestamp: string; type: AlertType; severity: "info" | "warning" | "error"; message: string; data: Record; acknowledged: boolean; } ``` --- ## API Client Interface ### services/api.ts #### Dashboard API ```typescript export const dashboardApi = { getSummary: async (): Promise => { }, getPrices: async (): Promise> => { }, getPriceHistory: async ( region: string, start?: string, end?: string, limit?: number ): Promise<{ region: string; data: PriceData[] }> => { }, getBatteryStates: async (): Promise => { }, getArbitrage: async (minSpread?: number): Promise<{ opportunities: ArbitrageOpportunity[]; count: number; }> => { }, }; ``` #### Backtest API ```typescript export const backtestApi = { start: async (request: BacktestRequest): Promise<{ backtest_id: string; status: BacktestStatus; }> => { }, get: async (backtestId: string): Promise<{ status: BacktestStatus; results?: BacktestResult; }> => { }, getResults: async (backtestId: string): Promise => { }, getTrades: async (backtestId: string, limit?: number): Promise<{ backtest_id: string; trades: Trade[]; total: number; }> => { }, list: async (): Promise<{ backtests: BacktestStatus[]; total: number; }> => { }, delete: async (backtestId: string): Promise<{ message: string }> => { }, }; ``` #### Models API ```typescript export const modelsApi = { list: async (): Promise<{ models: ModelInfo[]; total: number }> => { }, train: async (request: TrainingRequest): Promise<{ training_id: string; status: TrainingStatus; }> => { }, getStatus: async (modelId: string): Promise => { }, getMetrics: async (modelId: string): Promise<{ model_id: string; metrics: Record; }> => { }, predict: async (request: PredictionRequest): Promise => { }, }; ``` #### Trading API ```typescript export const tradingApi = { getStrategies: async (): Promise<{ strategies: StrategyStatus[] }> => { }, toggleStrategy: async (control: { strategy: Strategy; action: "start" | "stop"; }): Promise<{ status: StrategyStatus }> => { }, getPositions: async (): Promise<{ positions: TradingPosition[] }> => { }, }; ``` #### Settings API ```typescript export const settingsApi = { get: async (): Promise => { }, update: async (settings: Partial): Promise<{ message: string; updated_fields: string[]; }> => { }, }; ``` --- ## WebSocket Client Interface ### services/websocket.ts ```typescript class WebSocketService { private ws: WebSocket | null = null; private url: string; private eventHandlers: Map> = new Map(); private isConnected = false; constructor(url: string = import.meta.env.VITE_WS_URL); connect(): void; disconnect(): void; subscribe( eventType: WebSocketEventType, handler: (data: T) => void ): () => void; // Returns unsubscribe function getConnectionStatus(): boolean; private handleMessage(message: WebSocketMessage): void; private attemptReconnect(): void; } export const webSocketService = new WebSocketService(); ``` ### WebSocket Event Types ```typescript export type WebSocketEventType = | "price_update" | "battery_update" | "arbitrage_opportunity" | "trade_executed" | "alert_triggered" | "backtest_progress" | "model_training_progress"; export interface WebSocketMessage { type: WebSocketEventType; timestamp: string; data: T; } ``` --- ## State Management (Zustand) ### store/index.ts ```typescript interface DashboardState { summary: DashboardSummary | null; prices: Record; batteryStates: BatteryState[]; arbitrageOpportunities: ArbitrageOpportunity[]; alerts: Alert[]; updateSummary: (summary: DashboardSummary) => void; updatePrices: (prices: Record) => void; addAlert: (alert: Alert) => void; // ... } interface BacktestState { backtests: Record; currentBacktest: string | null; isRunning: boolean; updateBacktest: (status: BacktestStatus) => void; setCurrentBacktest: (backtestId: string | null) => void; // ... } interface ModelsState { models: ModelInfo[]; trainingJobs: Record; selectedModel: string | null; setModels: (models: ModelInfo[]) => void; updateTrainingJob: (job: TrainingStatus) => void; // ... } interface TradingState { strategies: Record; positions: TradingPosition[]; pnl: number; updateStrategy: (strategy: StrategyStatus) => void; updatePositions: (positions: TradingPosition[]) => void; // ... } export const useStore = create((set) => ({ // ... state and actions })); ``` --- ## Custom Hooks ### hooks/useWebSocket.ts ```typescript export function useWebSocket() { const subscribe = ( eventType: WebSocketEventType, handler: (data: T) => void ): (() => void) => { return webSocketService.subscribe(eventType, handler); }; const isConnected = webSocketService.getConnectionStatus(); return { subscribe, isConnected }; } ``` ### hooks/useApi.ts ```typescript // Dashboard hooks export function useDashboardSummary(); export function usePrices(); export function useBatteryStates(); export function useArbitrageOpportunities(minSpread?: number); // Backtest hooks export function useStartBacktest(); export function useBacktest(backtestId: string); export function useBacktestList(); // Models hooks export function useModels(); export function useTrainModel(); // Trading hooks export function useStrategies(); export function useToggleStrategy(); export function usePositions(); // Settings hooks export function useSettings(); export function useUpdateSettings(); ``` --- ## Pages Interface ### Dashboard.tsx ```typescript export default function Dashboard() { const { subscribe } = useWebSocket(); const { prices, batteryStates, arbitrageOpportunities, alerts } = useStore(); const { data: pricesData } = usePrices(); // Subscribe to real-time updates useEffect(() => { const unsubscribePrice = subscribe('price_update', (data) => { }); const unsubscribeBattery = subscribe('battery_update', (data) => { }); const unsubscribeAlert = subscribe('alert_triggered', (data) => { }); return () => { unsubscribePrice(); unsubscribeBattery(); unsubscribeAlert(); }; }, [subscribe]); // Render stats cards, charts, tables } ``` ### Backtest.tsx ```typescript export default function Backtest() { const [selectedBacktestId, setSelectedBacktestId] = useState(null); const { mutate: startBacktest, isPending } = useStartBacktest(); const { data: backtest } = useBacktest(selectedBacktestId || ''); const { data: backtestList } = useBacktestList(); const handleStartBacktest = (config: any) => { startBacktest({ config, name: config.name }, { onSuccess: (data) => { setSelectedBacktestId(data.backtest_id); }, }); }; // Render form, results, progress } ``` ### Models.tsx ```typescript export default function Models() { const [selectedModel, setSelectedModel] = useState(null); const [showTrainingForm, setShowTrainingForm] = useState(false); const { data: modelsData } = useModels(); const { mutate: trainModel, isPending } = useTrainModel(); const handleTrainModel = (config: any) => { trainModel(config, { onSuccess: () => { setShowTrainingForm(false); }, }); }; // Render model list, training form, model details } ``` ### Trading.tsx ```typescript export default function Trading() { const { data: strategiesData } = useStrategies(); const { data: positionsData } = usePositions(); const { mutate: toggleStrategy } = useToggleStrategy(); const handleToggleStrategy = (strategyName: string, running: boolean) => { toggleStrategy({ strategy: strategyName as any, action: running ? 'stop' : 'start', }); }; // Render strategy status, positions, controls } ``` --- ## Dependencies ### package.json ```json { "name": "energy-trading-ui", "version": "1.0.0", "type": "module", "scripts": { "dev": "vite", "build": "tsc && vite build", "preview": "vite preview", "test": "vitest", "type-check": "tsc --noEmit" }, "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.20.0", "recharts": "^2.10.0", "zustand": "^4.4.0", "@tanstack/react-query": "^5.0.0", "axios": "^1.6.0", "date-fns": "^2.30.0", "lucide-react": "^0.292.0" }, "devDependencies": { "@types/react": "^18.2.37", "@types/react-dom": "^18.2.15", "@vitejs/plugin-react": "^4.2.0", "typescript": "^5.2.2", "vite": "^5.0.0", "vitest": "^1.0.0", "tailwindcss": "^3.3.5" } } ``` --- ## Data Flow ### API Calls ``` Component → useApi Hook → API Client → Axios → Backend ↓ React Query Cache ↓ Automatic Refetch ``` ### WebSocket Updates ``` WebSocket Event → WebSocketService → Event Handler → Store Update → Component Re-render ``` ### State Synchronization ``` API Response → React Query Cache → Component Props → Zustand Store (optional) WebSocket Event → Zustand Store → Component Re-render ``` --- ## Key Integration Points ### Backend API Integration - REST API endpoints are fully typed in `services/types.ts` - API client methods in `services/api.ts` match backend routes - WebSocket events match backend event types ### Error Handling - API errors handled by React Query error states - WebSocket reconnection automatic with exponential backoff - Component-level error boundaries for unhandled errors ### Performance - React Query caching with automatic refetch intervals - WebSocket connection pooling - Component memoization where appropriate - Virtual scrolling for large data tables