Skip to Content
Frontend Dashboard

Frontend Dashboard

Overview

The frontend is a sophisticated Next.js 14 application designed to provide a fluid, responsive, and data-rich interface to the trading platform. It is engineered to handle high-frequency, real-time data streams without compromising user experience.

Architecture Overview

The frontend uses a dual-state architecture that explicitly separates two types of state:

  1. Live/Client State (Zustand): Data that changes frequently and is pushed from the server via WebSockets
  2. Server/Cache State (TanStack Query): Data that is fetched via request-response (e.g., historical data)

Core Components

Real-Time Data Layer (modules/core/)

  • WebSocket Client (services/ws.ts): A singleton, SSR-safe client that establishes and maintains a persistent connection to the backend’s WebSocket stream. It includes robust logic for exponential backoff and reconnection attempts.

  • Event Router (services/eventRouter.ts): The central hub for all incoming WebSocket messages. Upon receiving an event, it performs a three-step process:

    1. Validation: Uses type guards to ensure the event payload matches a known EventEnvelope
    2. Deduplication: Uses an EventDeduper to discard duplicate events
    3. Staging & Routing: Routes the validated event to the appropriate domain store
  • Frame Clock (shared/lib/frameClock.ts): A simple, fixed-cadence timer (defaulting to 250ms). The EventRouter subscribes to its “tick,” and on each tick, it flushes the staged event buffers to the Zustand stores in a single, batched update.

  • useRealtime Hook (hooks/useRealtime.ts): A React hook that initializes the EventRouter when a component mounts and cleans it up when it unmounts.

State Management

Zustand for Live/Volatile State

Data that changes frequently and is pushed from the server via WebSockets is managed in a set of modular Zustand stores:

  • Market Store (modules/trading/stores/marketStore.ts): Maintains a ring buffer of recent price ticks for each asset, as well as a list of recent trades
  • Portfolio Store (modules/trading/stores/portfolioStore.ts): Holds a snapshot of the user’s current portfolio, including total value and positions
  • Intents & Strategies Stores (modules/strategy/stores/): Track the state of user-submitted intents and the status of their trading strategies

TanStack Query for Server/Cached State

Data that is fetched via request-response is managed by TanStack Query:

  • Query Provider (shared/query/provider.tsx): The root provider that sets up the query client
  • Query Keys (shared/query/keys.ts): A centralized definition of query keys for type safety and consistency

The Synergy: The two libraries work in perfect harmony. Real-time WebSocket events can be used to invalidate TanStack Query’s cache, ensuring the UI always displays fresh data.

UI and Component Architecture

  • Dashboard Composition (components/trading/trading-dashboard.tsx): The main dashboard is a composite view built from smaller, independent modules. It uses a responsive DashboardGrid to arrange these modules.

  • Modular Panels (modules/dashboard/components/*-module.tsx): Each distinct piece of functionality is encapsulated in its own module component. These components are responsible for fetching their own data and rendering the appropriate UI.

  • Theming (shared/styles/theme.css.ts): The application uses Vanilla Extract for a zero-runtime CSS-in-TS styling solution. It defines a vars contract and implements multiple themes.

Real-Time Data Pipeline

The journey of a real-time update is a carefully orchestrated pipeline designed for resilience and performance.

How It Works

  1. WsClient: This singleton class manages the WebSocket connection. It’s SSR-safe and includes robust exponential backoff logic.

  2. EventRouter: This is the brain of the real-time layer. It subscribes to all messages from the WsClient and processes them through validation, deduplication, and staging.

  3. FrameClock: This is a simple but critical utility. It’s a global timer that “ticks” every 250 milliseconds.

  4. Flush to Store: On each tick of the FrameClock, the EventRouter takes all the events that have accumulated in its staging buffer and commits them to the appropriate Zustand stores in a single, batched action.

This batching mechanism is the key to a smooth UI. Instead of triggering 100 separate React re-renders for 100 price ticks, it triggers just one render every 250ms with the latest state.

Server-Side Rendering (SSR) and Client Hydration

To avoid showing the user an empty page with loading spinners, we use Next.js’s Server-Side Rendering capabilities.

Code Reference: app/dashboard/page.tsx and modules/dashboard/components/DashboardBootstrap.tsx

The Flow:

  1. When the user navigates to /dashboard, the request hits the Next.js server first
  2. The server-side component executes and makes a fast, server-to-server call to fetch an initial snapshot of data
  3. This initial data is passed as props to the DashboardBootstrap component
  4. The server renders the complete HTML for the dashboard with this initial data already populated
  5. On the client, the JavaScript loads and the DashboardBootstrap component runs its useEffect hook, which:
    • “Hydrates” the client-side Zustand stores with the initial data
    • Calls the useRealtime() hook, which kicks off the real-time data pipeline

From this point on, the client has taken over. The initial server-rendered view seamlessly transitions to a live, WebSocket-powered dashboard.

Styling and Theming

We use Vanilla Extract for a type-safe, zero-runtime CSS-in-TS solution.

  • Theme Contract (shared/styles/theme.css.ts): We define a vars contract that lists all our design tokens (colors, spacing, etc.)

  • Theme Provider (app/providers/theme/VanillaThemeProvider.tsx): A React context provider that allows the user to switch between themes

  • Tailwind CSS Bridge (shared/styles/base.css.ts): To enable the use of a shared component library that relies on Tailwind’s utility classes, we create a global stylesheet that maps our Vanilla Extract theme variables to CSS custom properties

Component Examples

Dashboard Module

// modules/dashboard/components/portfolio-module.tsx import { usePortfolioStore } from '@/modules/trading/stores/portfolioStore' export function PortfolioModule() { const { portfolio, isLoading } = usePortfolioStore() if (isLoading) return <div>Loading portfolio...</div> return ( <div className="portfolio-module"> <h3>Portfolio</h3> <div className="total-value"> ${portfolio.totalValue.toLocaleString()} </div> {/* Portfolio details */} </div> ) }

Real-Time Hook Usage

// components/trading/trading-dashboard.tsx import { useRealtime } from '@/modules/core/hooks/useRealtime' export function TradingDashboard() { // Initialize real-time data flow useRealtime() return ( <div className="trading-dashboard"> <PortfolioModule /> <MarketModule /> <IntentsModule /> </div> ) }

Performance Optimizations

Event Batching

The frame clock batching system ensures that high-frequency updates (like market ticks) don’t overwhelm the UI. Multiple updates are coalesced into single React render cycles.

Selective Re-rendering

Zustand’s selector-based subscription model ensures components only re-render when the specific slice of state they care about actually changes.

Request Deduplication

TanStack Query automatically deduplicates identical requests, preventing unnecessary API calls when multiple components need the same data.

Error Handling and Resilience

WebSocket Reconnection

The WebSocket client includes exponential backoff logic for automatic reconnection attempts. If the connection drops, it will attempt to reconnect with increasing delays.

Event Validation

All incoming WebSocket events are validated against TypeScript types before processing. Malformed events are silently dropped to prevent crashes.

Graceful Degradation

If real-time data is unavailable, the UI gracefully falls back to showing cached or static data while indicating the connection status.

Development Tools

React DevTools

Use React DevTools to inspect component hierarchies and state changes in real-time.

Zustand DevTools

Zustand includes built-in DevTools for inspecting store state and actions during development.

Network Tab

Monitor WebSocket connections and real-time event flow in the browser’s Network tab.

Testing

Component Testing

# Run component tests npm run test:components # Run with coverage npm run test:components:coverage

Integration Testing

# Run integration tests npm run test:integration

E2E Testing

# Run end-to-end tests npm run test:e2e

Next Steps

  • Backend Engineers: Return to Backend Engine to understand how the real-time events are generated
  • UI/UX Developers: Explore the component library and styling system
  • Full-Stack Developers: Continue to Development Guide to learn how to build complete features
  • DevOps Engineers: Check Integration & Operations for deployment and monitoring information
Last updated on