Skip to content

Latest commit

 

History

History
330 lines (241 loc) · 6.97 KB

File metadata and controls

330 lines (241 loc) · 6.97 KB

Architecture – FinBoard (Customizable Finance Dashboard)

Overview

FinBoard is a modular, client-side configurable finance dashboard built with Next.js (App Router). It allows users to dynamically create, configure, persist, and visualize real-time financial data from multiple APIs using customizable widgets.

The architecture emphasizes:

  • Separation of concerns
  • Scalability
  • API-agnostic data handling
  • Resilient real-time updates
  • Persistent, user-driven UI state

High-Level Architecture Diagram

┌──────────────────────────────┐
│          User (UI)           │
└──────────────┬───────────────┘
               │
               ▼
┌──────────────────────────────┐
│        Next.js App Router     │
│  (layout.tsx, page.tsx)      │
└──────────────┬───────────────┘
               │
               ▼
┌────────────────────────────────────────────┐
│             Presentation Layer              │
│  Navbar | Modals | Widgets | Charts | Tables│
└──────────────┬─────────────────────────────┘
               │
               ▼
┌────────────────────────────────────────────┐
│           State Management (Zustand)        │
│  widgetStore | themeStore                  │
└──────────────┬─────────────────────────────┘
               │
               ▼
┌────────────────────────────────────────────┐
│        Data Processing & Caching Layer      │
│  apiCache | dataMapper                     │
└──────────────┬─────────────────────────────┘
               │
               ▼
┌────────────────────────────────────────────┐
│           External Financial APIs           │
│  Finnhub | Custom APIs | Others             │
└────────────────────────────────────────────┘


## Entry Points

### 1. Application Entry

```txt
src/app/layout.tsx

Responsibilities:

  • Global providers (ThemeProvider)
  • Navbar rendering
  • Root HTML/body structure

2. Dashboard Entry

src/app/page.tsx

Responsibilities:

  • Render widget grid
  • Drag & drop layout handling
  • Modal mounting
  • Widget lifecycle orchestration

Core Architectural Layers


1️⃣ State Management Layer (Zustand)

Stores

store/
├── WidgetStore.ts
└── themeStore.ts

widgetStore Responsibilities

  • Widget CRUD (add, remove, update)
  • Widget ordering (drag & drop)
  • Import / Export dashboard configuration
  • Persistent storage via zustand/persist

Design Decision

  • Zustand chosen over Redux for:

    • Minimal boilerplate
    • UI-heavy state
    • Faster iteration

themeStore Responsibilities

  • Global dark/light mode state
  • Persistent theme storage
  • Cross-tab synchronization
  • DOM-safe application via ThemeProvider

2️⃣ UI / Presentation Layer

components/
├── layout/
│   └── Navbar.tsx
│   └── TemplateModal.tsx
├── widget/
│   ├── AddWidget.tsx
│   ├── AddWidgetModal.tsx
│   ├── DataWidget.tsx
│   ├── EmptyDashboard.tsx
│   ├── DraggableWidget.tsx
│   ├── WidgetCard.tsx
│   ├── StockChart.tsx
├── ui/
│   ├── ModernTable.tsx
│   ├── Modal.tsx
│   ├── Button.tsx
│   └── ThemeToggle.tsx
└── ThemeProvider.tsx

Design Principles

  • Pure components
  • No direct API logic in UI
  • Reusable primitives
  • Responsive-first (Tailwind)

3️⃣ Widget Lifecycle (End-to-End Flow)

Widget Creation Flow

Navbar → AddWidgetModal
        → API Test
        → Data Mapper (field discovery)
        → widgetStore.addWidget()
        → Persist to localStorage

Widget Rendering Flow

widgetStore
   ↓
DataWidget
   ├── cachedFetch()
   ├── auto-refresh timer
   ├── dataMapper (path-based mapping)
   ↓
WidgetCard
   ↓
Chart | Table | Card

4️⃣ Data Fetching & Caching Layer

utils/
├── apiCache.ts
└── dataMapper.ts

apiCache.ts Responsibilities

  • In-memory TTL caching
  • Rate limiting per API domain
  • Request deduplication
  • Batch stock fetching
  • Error isolation

Why this matters

  • Prevents API quota exhaustion
  • Improves performance
  • Enables real-time dashboards safely

dataMapper.ts Responsibilities

  • Recursive JSON structure analysis
  • Field path discovery
  • Type inference
  • Path-based value extraction
  • Smart formatting (currency, %, compact numbers)

Key Design

Widgets are API-agnostic — they only care about field paths, not API shape.


5️⃣ Drag & Drop System

Technology

  • @dnd-kit

Flow

DraggableWidget
   ↓
DndContext (page.tsx)
   ↓
onDragEnd(activeId, overId)
   ↓
widgetStore.reorderWidgets()
   ↓
Persisted layout update

6️⃣ Theme System Architecture

ThemeToggle
   ↓
themeStore
   ↓
ThemeProvider
   ↓
<html class="dark | light">

Key Goals

  • No hydration mismatch
  • No flash of unstyled content (FOUC)
  • Cross-tab theme sync

Feature Breakdown

Implemented Features

  • Dynamic widget creation
  • Field-level API mapping
  • Drag & drop layout
  • Auto-refresh per widget
  • API caching & rate limiting
  • Import / Export dashboard
  • Dark / Light theme
  • Responsive layout
  • Error & loading states

Extensible Features (Designed for)

  • WebSocket live data
  • Dashboard templates
  • Widget editing
  • Chart axis configuration
  • Role-based dashboards

Error Handling Strategy

Layer Strategy
API Retry + rate-limit detection
Widget Isolated failure per widget
UI Skeletons + error messages
Import Schema validation

Performance Considerations

  • Widget-level auto-refresh
  • Cached API responses
  • Request deduplication
  • Lazy rendering of charts
  • Minimal global re-renders

Architectural Principles

  • Single source of truth
  • Config-driven UI
  • API-agnostic widgets
  • Fail independently
  • Persist everything