# jparisio/knot architecture

> Architecture diagram of the GitHub repository jparisio/knot, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-29). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/jparisio/knot
- Repository: https://github.com/jparisio/knot

## Overview

Knot is a real-time market dashboard with watchlists, tick charts, paper trading, and Canadian TFSA room tracking. Users follow symbols, add instruments through search, and view live or simulated prices; trades update separate TFSA and Non-Registered accounts, with excess TFSA purchases optionally routed to Non-Registered. The dashboard shares one socket connection, while portfolio state persists in browser localStorage. The README documents the relay’s reconnect and simulation behavior; sampled server excerpts support its subscription and tick dispatch, but do not show every implementation detail.

Main entry points: [`src/app/dashboard/page.tsx`](https://github.com/jparisio/knot/blob/main/src/app/dashboard/page.tsx) (Dashboard), [`socket-server/server.ts`](https://github.com/jparisio/knot/blob/main/socket-server/server.ts) (Socket relay), [`src/hooks/usePortfolio.ts`](https://github.com/jparisio/knot/blob/main/src/hooks/usePortfolio.ts) (Portfolio state), [`src/lib/SocketContext.tsx`](https://github.com/jparisio/knot/blob/main/src/lib/SocketContext.tsx) (Socket context)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_ui["Dashboard UI"]
  node_dashboard["Dashboard<br/>[page.tsx]"]
  node_providers["Client providers"]
  node_watchlist["Watchlist<br/>[page.tsx]"]
  node_marketview["Market view<br/>[page.tsx]"]
  node_chart["Tick chart<br/>[TickChart.tsx]"]
  node_trading["Trading panel<br/>[TradingPanel.tsx]"]
  node_portfolio_view["Portfolio view<br/>[PortfolioView.tsx]"]
end

subgraph group_market["Market data"]
  node_socket_context["Socket context<br/>[SocketContext.tsx]"]
  node_ticks_hook["Tick hook<br/>[useTicks.ts]"]
  node_relay["Socket relay<br/>[server.ts]"]
  node_simulation["Price simulation<br/>[server.ts]"]
  node_finnhub_feed(("Finnhub feed"))
end

subgraph group_portfolio["Portfolio"]
  node_portfolio_hook["Portfolio state<br/>[usePortfolio.ts]"]
  node_portfolio_types["Portfolio model<br/>[portfolio.ts]"]
  node_browser_storage[("Browser storage")]
end

subgraph group_search["Symbol search"]
  node_search_form["Search form<br/>[page.tsx]"]
  node_search_api["Search API<br/>[route.ts]"]
  node_finnhub_search(("Finnhub search"))
end

node_user(("Investor"))

node_user -->|"uses"| node_dashboard
node_providers -->|"provides"| node_socket_context
node_dashboard -->|"renders within"| node_providers
node_dashboard -->|"renders"| node_watchlist
node_dashboard -->|"renders"| node_marketview
node_dashboard -->|"renders"| node_trading
node_dashboard -->|"renders"| node_portfolio_view
node_marketview -->|"reads ticks"| node_ticks_hook
node_watchlist -->|"reads ticks"| node_ticks_hook
node_portfolio_view -->|"reads prices"| node_ticks_hook
node_marketview -->|"passes ticks"| node_chart
node_ticks_hook -->|"subscribes and reads"| node_socket_context
node_socket_context -->|"sends subscriptions"| node_relay
node_relay -->|"dispatches ticks"| node_socket_context
node_finnhub_feed -->|"streams trades"| node_relay
node_relay -.->|"starts fallback"| node_simulation
node_simulation -.->|"emits simulated ticks"| node_relay
node_dashboard -->|"uses state"| node_portfolio_hook
node_trading -->|"executes trades"| node_portfolio_hook
node_portfolio_view -->|"reads and updates"| node_portfolio_hook
node_portfolio_hook -->|"loads and saves"| node_browser_storage
node_portfolio_hook -->|"uses model"| node_portfolio_types
node_search_form -->|"requests matches"| node_search_api
node_search_api -->|"queries"| node_finnhub_search
node_search_api -->|"returns matches"| node_search_form
node_search_form -->|"adds symbol"| node_dashboard

click node_dashboard "https://github.com/jparisio/knot/blob/main/src/app/dashboard/page.tsx"
click node_providers "https://github.com/jparisio/knot/blob/main/src/components/providers/ClientProviders.tsx"
click node_watchlist "https://github.com/jparisio/knot/blob/main/src/app/dashboard/page.tsx"
click node_marketview "https://github.com/jparisio/knot/blob/main/src/app/dashboard/page.tsx"
click node_chart "https://github.com/jparisio/knot/blob/main/src/components/charts/TickChart.tsx"
click node_trading "https://github.com/jparisio/knot/blob/main/src/components/portfolio/TradingPanel.tsx"
click node_portfolio_view "https://github.com/jparisio/knot/blob/main/src/components/portfolio/PortfolioView.tsx"
click node_socket_context "https://github.com/jparisio/knot/blob/main/src/lib/SocketContext.tsx"
click node_ticks_hook "https://github.com/jparisio/knot/blob/main/src/hooks/useTicks.ts"
click node_relay "https://github.com/jparisio/knot/blob/main/socket-server/server.ts"
click node_simulation "https://github.com/jparisio/knot/blob/main/socket-server/server.ts"
click node_portfolio_hook "https://github.com/jparisio/knot/blob/main/src/hooks/usePortfolio.ts"
click node_portfolio_types "https://github.com/jparisio/knot/blob/main/src/types/portfolio.ts"
click node_search_form "https://github.com/jparisio/knot/blob/main/src/app/dashboard/page.tsx"
click node_search_api "https://github.com/jparisio/knot/blob/main/src/app/api/search/route.ts"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_dashboard,node_providers,node_watchlist,node_marketview,node_chart,node_trading,node_portfolio_view toneBlue
class node_socket_context,node_ticks_hook,node_relay,node_simulation,node_finnhub_feed toneAmber
class node_portfolio_hook,node_portfolio_types,node_browser_storage toneMint
class node_search_form,node_search_api,node_finnhub_search toneRose
class node_user toneIndigo
```

## Components

### Dashboard UI

- [Dashboard](https://github.com/jparisio/knot/blob/main/src/app/dashboard/page.tsx): `src/app/dashboard/page.tsx`
- [Client providers](https://github.com/jparisio/knot/blob/main/src/components/providers/ClientProviders.tsx): `src/components/providers/ClientProviders.tsx`
- [Watchlist](https://github.com/jparisio/knot/blob/main/src/app/dashboard/page.tsx): `src/app/dashboard/page.tsx`
- [Market view](https://github.com/jparisio/knot/blob/main/src/app/dashboard/page.tsx): `src/app/dashboard/page.tsx`
- [Tick chart](https://github.com/jparisio/knot/blob/main/src/components/charts/TickChart.tsx): `src/components/charts/TickChart.tsx`
- [Trading panel](https://github.com/jparisio/knot/blob/main/src/components/portfolio/TradingPanel.tsx): `src/components/portfolio/TradingPanel.tsx`
- [Portfolio view](https://github.com/jparisio/knot/blob/main/src/components/portfolio/PortfolioView.tsx): `src/components/portfolio/PortfolioView.tsx`

### Market data

- [Socket context](https://github.com/jparisio/knot/blob/main/src/lib/SocketContext.tsx): `src/lib/SocketContext.tsx`
- [Tick hook](https://github.com/jparisio/knot/blob/main/src/hooks/useTicks.ts): `src/hooks/useTicks.ts`
- [Socket relay](https://github.com/jparisio/knot/blob/main/socket-server/server.ts): `socket-server/server.ts`
- [Price simulation](https://github.com/jparisio/knot/blob/main/socket-server/server.ts): `socket-server/server.ts`
- **Finnhub feed**

### Portfolio

- [Portfolio state](https://github.com/jparisio/knot/blob/main/src/hooks/usePortfolio.ts): `src/hooks/usePortfolio.ts`
- [Portfolio model](https://github.com/jparisio/knot/blob/main/src/types/portfolio.ts): `src/types/portfolio.ts`
- **Browser storage**

### Symbol search

- [Search form](https://github.com/jparisio/knot/blob/main/src/app/dashboard/page.tsx): `src/app/dashboard/page.tsx`
- [Search API](https://github.com/jparisio/knot/blob/main/src/app/api/search/route.ts): `src/app/api/search/route.ts`
- **Finnhub search**

### Other components

- **Investor**

## Connections

- Investor → Dashboard: uses
- Client providers → Socket context: provides
- Dashboard → Client providers: renders within
- Dashboard → Watchlist: renders
- Dashboard → Market view: renders
- Dashboard → Trading panel: renders
- Dashboard → Portfolio view: renders
- Market view → Tick hook: reads ticks
- Watchlist → Tick hook: reads ticks
- Portfolio view → Tick hook: reads prices
- Market view → Tick chart: passes ticks
- Tick hook → Socket context: subscribes and reads
- Socket context → Socket relay: sends subscriptions
- Socket relay → Socket context: dispatches ticks
- Finnhub feed → Socket relay: streams trades
- Socket relay → Price simulation: starts fallback
- Price simulation → Socket relay: emits simulated ticks
- Dashboard → Portfolio state: uses state
- Trading panel → Portfolio state: executes trades
- Portfolio view → Portfolio state: reads and updates
- Portfolio state → Browser storage: loads and saves
- Portfolio state → Portfolio model: uses model
- Search form → Search API: requests matches
- Search API → Finnhub search: queries
- Search API → Search form: returns matches
- Search form → Dashboard: adds symbol
