Add initial implementation strategy documentation
Add comprehensive documentation for energy trading system: - Backend: FastAPI architecture, API routes, services, WebSocket - Frontend: React structure, components, state management - ML: Feature engineering, XGBoost price prediction, RL battery optimization
This commit is contained in:
780
FRONTEND_IMPLEMENTATION.md
Normal file
780
FRONTEND_IMPLEMENTATION.md
Normal file
@@ -0,0 +1,780 @@
|
||||
# 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<string, number>;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface TrainingRequest {
|
||||
model_type: ModelType;
|
||||
horizon?: number;
|
||||
start_date: string;
|
||||
end_date: string;
|
||||
hyperparameters: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface TrainingStatus {
|
||||
id: string;
|
||||
status: BacktestStatus;
|
||||
progress: number;
|
||||
current_epoch?: number;
|
||||
total_epochs?: number;
|
||||
metrics: Record<string, number>;
|
||||
started_at?: string;
|
||||
completed_at?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface PredictionRequest {
|
||||
model_id: string;
|
||||
timestamp: string;
|
||||
features?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
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<string, unknown>;
|
||||
acknowledged: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Client Interface
|
||||
|
||||
### services/api.ts
|
||||
|
||||
#### Dashboard API
|
||||
|
||||
```typescript
|
||||
export const dashboardApi = {
|
||||
getSummary: async (): Promise<DashboardSummary> => { },
|
||||
|
||||
getPrices: async (): Promise<Record<string, PriceData>> => { },
|
||||
|
||||
getPriceHistory: async (
|
||||
region: string,
|
||||
start?: string,
|
||||
end?: string,
|
||||
limit?: number
|
||||
): Promise<{ region: string; data: PriceData[] }> => { },
|
||||
|
||||
getBatteryStates: async (): Promise<BatteryState[]> => { },
|
||||
|
||||
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<BacktestResult> => { },
|
||||
|
||||
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<TrainingStatus> => { },
|
||||
|
||||
getMetrics: async (modelId: string): Promise<{
|
||||
model_id: string;
|
||||
metrics: Record<string, number>;
|
||||
}> => { },
|
||||
|
||||
predict: async (request: PredictionRequest): Promise<PredictionResponse> => { },
|
||||
};
|
||||
```
|
||||
|
||||
#### 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<AppSettings> => { },
|
||||
|
||||
update: async (settings: Partial<AppSettings>): 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<WebSocketEventType, Set<EventHandler>> = new Map();
|
||||
private isConnected = false;
|
||||
|
||||
constructor(url: string = import.meta.env.VITE_WS_URL);
|
||||
|
||||
connect(): void;
|
||||
disconnect(): void;
|
||||
|
||||
subscribe<T = unknown>(
|
||||
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<T = unknown> {
|
||||
type: WebSocketEventType;
|
||||
timestamp: string;
|
||||
data: T;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## State Management (Zustand)
|
||||
|
||||
### store/index.ts
|
||||
|
||||
```typescript
|
||||
interface DashboardState {
|
||||
summary: DashboardSummary | null;
|
||||
prices: Record<string, PriceData>;
|
||||
batteryStates: BatteryState[];
|
||||
arbitrageOpportunities: ArbitrageOpportunity[];
|
||||
alerts: Alert[];
|
||||
|
||||
updateSummary: (summary: DashboardSummary) => void;
|
||||
updatePrices: (prices: Record<string, PriceData>) => void;
|
||||
addAlert: (alert: Alert) => void;
|
||||
// ...
|
||||
}
|
||||
|
||||
interface BacktestState {
|
||||
backtests: Record<string, BacktestStatus>;
|
||||
currentBacktest: string | null;
|
||||
isRunning: boolean;
|
||||
|
||||
updateBacktest: (status: BacktestStatus) => void;
|
||||
setCurrentBacktest: (backtestId: string | null) => void;
|
||||
// ...
|
||||
}
|
||||
|
||||
interface ModelsState {
|
||||
models: ModelInfo[];
|
||||
trainingJobs: Record<string, TrainingStatus>;
|
||||
selectedModel: string | null;
|
||||
|
||||
setModels: (models: ModelInfo[]) => void;
|
||||
updateTrainingJob: (job: TrainingStatus) => void;
|
||||
// ...
|
||||
}
|
||||
|
||||
interface TradingState {
|
||||
strategies: Record<string, StrategyStatus>;
|
||||
positions: TradingPosition[];
|
||||
pnl: number;
|
||||
|
||||
updateStrategy: (strategy: StrategyStatus) => void;
|
||||
updatePositions: (positions: TradingPosition[]) => void;
|
||||
// ...
|
||||
}
|
||||
|
||||
export const useStore = create<AppStore>((set) => ({
|
||||
// ... state and actions
|
||||
}));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Custom Hooks
|
||||
|
||||
### hooks/useWebSocket.ts
|
||||
|
||||
```typescript
|
||||
export function useWebSocket() {
|
||||
const subscribe = <T = unknown>(
|
||||
eventType: WebSocketEventType,
|
||||
handler: (data: T) => void
|
||||
): (() => void) => {
|
||||
return webSocketService.subscribe<T>(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<string | null>(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<string | null>(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
|
||||
Reference in New Issue
Block a user