Liquidity.io

Frontend Architecture

Exchange frontend data flow, state model, and component contract

The frontend is a thin consumer of 6 canonical API endpoints. No business logic in the frontend. No per-asset-type fetchers. One data flow, one state model, one way to do everything.

Data Flow

Boot -> /v1/navigation -> render rails + categories
  |
Select category -> /v1/assets?marketRail=...&category=... -> render asset list
  |
Select asset -> /v1/assets/{id}     -> detail panel
             -> /v1/assets/{id}/quote -> price ticker (poll 5s)
             -> /v1/assets/{id}/chart -> candlestick chart
             -> /v1/assets/{id}/book  -> order book (poll 3s)

State Model

// src/api/state.ts - Recoil atoms for UI state only

type ExchangeState = {
  // Navigation (fetched once at boot)
  navigation: Navigation | null

  // UI selection state
  activeMarketRail: string | null    // "public" | "private" | "digital"
  activeCategory: string | null       // "stocks" | "crypto" | "privates" | ...
  selectedAssetIdByCategory: Record<string, string | null>

  // Server data (managed by hooks, not Recoil)
  // Hooks return { data, isLoading, error }
}

Key rule: Server data lives in hooks (useState + useEffect). Recoil is only for UI state (which rail, which category, which asset is selected).

API Layer

src/api/
  client.ts    - fetch wrapper with auth headers
  types.ts     - TypeScript types matching API responses
  hooks.ts     - React hooks: useNavigation, useAssetList, useAssetDetail,
                 useAssetQuote, useAssetChart, useOrderBook
  state.ts     - Recoil atoms for UI selection state

Component Contract

ComponentConsumesRenders
NavigationRailsuseNavigation()Top market tabs (Public, Private, Digital)
CategoryTabsuseNavigation() + activeMarketRailCategory tabs within rail
AssetListuseAssetList(rail, category)Scrollable asset list with prices
AssetDetailuseAssetDetail(assetId)Asset header, metadata
PriceTickeruseAssetQuote(assetId)Real-time price, change, volume
ChartuseAssetChart(assetId, range)Candlestick/line chart
OrderBookuseOrderBook(assetId)Bid/ask depth display
TradeFormuseAssetQuote(assetId)Buy/sell order form

What Was Deleted

The following legacy patterns were removed in the canonical migration:

Removed State

  • horsesState -- was Morning Line horse racing assets
  • privateState -- was private securities separate state
  • marketIndexesState -- was market indices separate fetch
  • watchList state that mixed with asset fetching
  • mapAssetDataStateAsPerTab -- complex tab-to-state mapping

Removed Endpoints

  • exchange-explorers -- replaced by /v1/assets?...
  • exchange-assets -- replaced by /v1/assets/{id}
  • stock-summaries -- replaced by /v1/assets?category=stocks
  • commodity-summaries -- same
  • forex-summaries -- same
  • market-index-summaries -- same
  • privates-summaries -- same
  • exchange-music -- same
  • real-estate-summaries -- same
  • exchange-orderbook -- replaced by /v1/assets/{id}/book

Removed Patterns

  • assestType enum (note: typo was in original code)
  • assetTabs mapping
  • getString() category label functions
  • Tab-to-endpoint switch statements
  • Asset-type-specific fetchers
  • Cross-category fallback selection logic
  • mapApiUrl chart URL mapping

Environments

EnvFrontendAPIIAM
nextexchange.next.satschel.comapi.next.satschel.com/v1iam.next.satschel.com
alphaexchange.alpha.satschel.comapi.alpha.satschel.com/v1iam.alpha.satschel.com
stageexchange.stage.satschel.comapi.stage.satschel.com/v1iam.stage.satschel.com

No .env files committed. Build injects VITE_API_HOST from branch name.

Build and Deploy

# Cloud Build (native amd64 on GCP)
gcloud builds submit --config=cloudbuild.yaml \
  --substitutions=BRANCH_NAME=next \
  --project=elliptical-feat-364815

# K8s deployment auto-restarts on image push
kubectl rollout restart deployment/frontend-exchange -n frontend-next

Image: us-docker.pkg.dev/elliptical-feat-364815/frontend/exchange:{branch}

Testing

# E2E tests (universe repo)
cd ~/work/liquidity/universe
E2E_BASE_URL=https://exchange.next.satschel.com npx playwright test

# Accreditation compliance tests
npx playwright test e2e/23-accreditation-guard.spec.ts

# Dividend label tests
npx playwright test e2e/24-dividend-labels.spec.ts

On this page