The Question
FE Design

Real-Time Financial Streaming Dashboard

Design a high-performance, responsive real-time financial dashboard capable of displaying thousands of live ticker updates for 50,000+ concurrent viewers. Focus on how the frontend architecture handles high-frequency data ingestion (WebSockets/SSE) without blocking the main thread, the strategy for batching state updates, and the use of virtualization or canvas to maintain 60fps rendering. Address scalability, data normalization, and how to minimize the memory footprint of large, volatile datasets.
React
Web Workers
WebSockets
Zustand
Tailwind CSS
Canvas API
REST
Questions & Insights

Clarifying Questions

Update Frequency: What is the expected tick rate of the financial data (e.g., 100ms, 1s, or tick-by-tick)? Assumption: Sub-second updates (200-500ms) requiring UI throttling to maintain 60fps.
Data Volume: How many active tickers or instruments will a single user track simultaneously? Assumption: Up to 1000 tickers available, with 50-100 visible on screen at once.
Historical Data: Does the dashboard require real-time charting of historical data, or just the "Current Price" view? Assumption: MVP focuses on live price grids with sparklines (mini-charts).
Concurrency Strategy: With 50,000 viewers, are we using a pub/sub model via WebSockets or Server-Sent Events (SSE)? Assumption: WebSockets for bi-directional potential, but SSE is considered for one-way scaling via CDNs.

Crash Strategy

The Core Bottleneck: The main thread will choke if every WebSocket message triggers a React re-render. We must decouple data ingestion from UI rendering.
Progressive Questions:
Ingestion: How do we prevent high-frequency socket messages from blocking user interactions?
Processing: Where do we calculate price deltas and normalize data without taxing the UI thread?
Rendering: How do we update thousands of cells efficiently without re-rendering the entire table?
Scalability: How does the frontend handle 50k concurrent connections from a resource perspective?

Elite Bonus Points

Web Workers: Offloading data normalization and delta calculations to a background thread to keep the Main Thread idle for interactions.
RequestAnimationFrame (rAF) Batching: Instead of updating state on every socket message, buffer updates and flush them once per frame (16.6ms).
Canvas-based Sparklines: Using <canvas> for mini-charts inside table rows to avoid the DOM overhead of hundreds of SVG elements.
Binary Protocols: Implementing Protobuf or MsgPack over WebSockets to reduce bandwidth and parsing overhead compared to JSON.
Design Breakdown

Requirements

Functional Requirements:
Live price grid with real-time updates (Bid/Ask/Last).
Visual indicators for price movement (green/red flashes).
Ticker search and watch-list management.
Interactive sparklines for 24h trends.
Non-Functional Requirements:
Performance: Maintain 60fps even during high market volatility.
Scalability: Support 50k concurrent viewers via efficient connection management and CDN-cached initial state.
Responsiveness: Fluid layout across mobile, tablet, and desktop ultra-wide monitors.
Accessibility: ARIA live regions for screen readers to announce critical price changes (throttled).

Design Summary

Concise Summary: A high-performance SPA utilizing a decoupled "Data Worker" for ingestion and a "Virtualized Grid" for rendering, synchronized via a throttled buffer.
Major Components:
Data Stream Worker: A Web Worker that maintains the WebSocket connection, parses binary data, and calculates deltas.
Throttled State Manager: A centralized store (Zustand or Redux) that batches updates using requestAnimationFrame.
Virtualized Price Grid: A list-virtualization component that renders only the visible tickers.
App Shell: Provides the responsive layout, navigation, and authentication boundaries.
CUJ Walkthrough:
User opens the dashboard -> App Shell fetches initial ticker metadata via REST -> Worker initiates WebSocket connection -> Worker pushes batched updates to UI -> Virtualized Grid renders visible rows -> User filters tickers -> Grid updates view instantly.
Simplicity Audit: This architecture avoids complex micro-frontends or heavy SVG libraries, opting for simple CSS transitions and standard virtualization which are battle-tested and easier to maintain.
Architecture Decision Rationale:
Why this architecture?: Offloading data processing to a Worker ensures the UI remains responsive during "market storms." Virtualization handles large watch-lists without DOM bloat.
Requirement Satisfaction: Meets performance targets (60fps) through batching and minimizes memory leaks through controlled lifecycle management of socket listeners.

System Diagram

Architecture Deep Dive

Presentation Layer

Component Hierarchy: The Outter App Shell handles the top-level navigation and user context. The Dashboard Layout manages the responsive grid/flex areas. The Monitor Page acts as the orchestrator for the Price Grid Container, which utilizes react-window or tanstack-virtual to manage Price Cell Component instances.
Interaction Layer: User interactions (filtering, sorting) are handled by the Price Grid Container. Input validation for search is performed locally. CSS transitions handle the green/red "flash" effects to indicate price direction without JS-driven animations.
Rendering Layer: CSR is preferred for the MVP to handle dynamic streams. Virtualization is mandatory to keep the DOM node count constant regardless of list size. Memoization (React.memo) is applied to rows to prevent unnecessary re-renders when unrelated state changes.
UI Frameworks / Tools: Tailwind CSS for high-performance utility styles; Headless UI for accessible components.

Application Layer

Data Fetching Layer: Initial ticker data (names, symbols) is fetched via REST and cached. The Data Stream Worker manages the WebSocket lifecycle, including automatic reconnection with exponential backoff.
State Management Layer: A push-based model where the Worker sends a "frame" of data every 100-200ms. The Global State Manager (e.g., Zustand) stores only the "Visible Window" data to keep the memory footprint low.
Routing & Navigation: Simple SPA routing. URL stores the current filter/watchlist ID for easy sharing.

Domain Layer

Business Rules: Validation Policy ensures price data is within reasonable bounds (sanity checks) before rendering. Data Converter transforms raw API DTOs into localized Ticker Models.
Entities / Models: Ticker entity includes symbol, price, timestamp, and a calculated 24h change percentage. Models are immutable.
Inter-layer Contracts: The Application Layer interacts with Domain logic via pure functions, ensuring the business logic can be tested in isolation from React.

Infrastructure Layer

API / Network: WebSockets (WS) for real-time data. The system supports Request Deduplication at the socket layer—if multiple components need the same ticker, only one subscription is sent to the server.
Storage: localStorage stores user preferences (e.g., dark mode, saved watchlists). No complex client-side DB (IndexedDB) is needed for the MVP.
Wrap Up

Wrap-up

Evaluation: The design balances extreme performance (50k viewers/high frequency) with developer velocity.
Trade-offs: We trade off "immediate" consistency (updating on every single byte) for "perceptual" consistency (batching updates) to save CPU.
Optimization: For 50k viewers, the infrastructure must use a Load Balancer that supports sticky sessions for WebSockets. On the frontend, we can further optimize by using Uint8Array for data transfer between the Worker and Main thread to avoid JSON parsing overhead.