Skip to main content

Frontend Architecture

How the Next.js 15 UI application is structured, fetches data, and manages state against the v2 API.

App Router Structure

InventoryAlert.UI/
├── src/
│ ├── app/
│ │ ├── (auth)/
│ │ │ ├── login/ ← JWT authentication form
│ │ │ └── register/ ← New account creation
│ │ ├── page.tsx ← Dashboard: Portfolio summary, watchlist strip, market status, news (Route: /)
│ │ ├── portfolio/ ← Paginated position list with trade history
│ │ │ └── [symbol]/ ← Position detail: chart, trades, alerts
│ │ ├── stocks/ ← Global StockListing catalog (browse + search)
│ │ │ └── [symbol]/ ← Stock detail: quote, profile, financials, earnings, peers
│ │ ├── watchlist/ ← Live watchlist with quick-add
│ │ ├── alerts/ ← Alert rule CRUD with toggle
│ │ ├── market/ ← Exchange status, news feed, earnings calendar, IPO calendar
│ │ ├── admin/ ← Admin only pages
│ │ │ └── health/ ← Real-time system health dashboard
│ │ └── layout.tsx ← Root layout with Navbar, Sidebar, MarketStatusBanner
│ ├── components/ ← Reusable UI components
│ ├── hooks/ ← Custom React hooks (useQuote, useNotifications)
│ └── lib/ ← API client (api.ts), auth helpers

Page → API Map

PageRouteKey API Calls
Dashboard/GET /portfolio/positions, GET /watchlist/, GET /market/status, GET /market/news
Portfolio/portfolioGET /portfolio/positions (paged), GET /portfolio/alerts
Position Detail/portfolio/[symbol]GET /portfolio/positions/{symbol}, GET /stocks/{symbol}/quote, GET /alertrules/
Stock Catalog/stocksGET /stocks/ (paged), GET /stocks/search
Stock Detail/stocks/[symbol]GET /stocks/{symbol}/quote, /profile, /financials, /earnings, /recommendation, /insiders, /peers, /news
Watchlist/watchlistGET /watchlist/, POST /watchlist/{symbol}, DELETE /watchlist/{symbol}
Alerts/alertsGET /alertrules/, POST /alertrules/, PUT /alertrules/{id}, PATCH /alertrules/{id}/toggle
Market/marketGET /market/status, /news, /calendar/earnings, /calendar/ipo, /holiday
Admin Health/admin/healthGET /health (via proxy or direct)

Component Library

ComponentDescription
NavbarTop bar: logo, nav links, user avatar menu, notification bell (polls /notifications/unread-count every 30s), GlobalSearch trigger
SidebarCollapsible left nav: Dashboard, Portfolio, Watchlist, Stocks, Alerts, Market
MarketStatusBannerColor-coded strip showing exchange name + open/closed state. Polls GET /market/status every 60s
GlobalSearchCmd+K modal. Debounce 300ms. Uses DB-first discovery flow via GET /stocks/search

Market Data Widgets

ComponentAPIDescription
StockQuoteCardGET /stocks/{symbol}/quotePrice, change, change%, high, low. Refreshes every 30s
PriceLineChartLocal PriceHistory dataRecharts AreaChart. 1D/1W/1M/3M/1Y range selector
Market News SyncPOST /eventsCQRS Command to trigger a Finnhub background sync. Issues a SyncMarketNewsRequested event.
EarningsBarChartGET /stocks/{symbol}/earningsGrouped bar: actual vs. estimate EPS per quarter
RecommendationDonutGET /stocks/{symbol}/recommendationRecharts PieChart — Strong Buy/Buy/Hold/Sell/Strong Sell
MetricsPanelGET /stocks/{symbol}/financialsP/E, P/B, EPS, Dividend Yield, 52w High/Low, Revenue Growth, Net Margin
InsiderTableGET /stocks/{symbol}/insidersSortable: Name, Date, Shares, Value, Code badge
PeersChipRowGET /stocks/{symbol}/peersClickable symbol chips → navigates to /stocks/[symbol]

Portfolio Components

ComponentAPIDescription
PositionTableGET /portfolio/positionsPaginated, searchable holdings table
TradeModalPOST /portfolio/{symbol}/tradesForm: Type, Quantity, Unit Price, Notes, Date
AddPositionModalPOST /portfolio/positionsSymbol discovery → quantity/price → confirm
BulkImportModalPOST /portfolio/bulkCSV drag-and-drop → preview → confirm with error summary
AlertBadgeGET /portfolio/alertsRed badge on positions that breached an AlertRule

Alert Rule Components

ComponentAPIDescription
AlertRuleTableGET /alertrules/Full list: Symbol, Condition, Target, Status, Last Triggered, Actions
AlertRuleFormPOST/PUT /alertrules/Symbol input (search optional) → Condition dropdown → Target value → TriggerOnce
AlertTogglePATCH /alertrules/{id}/toggleInline toggle switch with optimistic UI

State Management

ConcernToolRationale
Server data (quotes, portfolio, news)React QueryAuto-refresh, stale-while-revalidate, cache invalidation on mutations
UI state (modals, tabs, filters)ZustandLightweight, no boilerplate, easy DevTools
Auth tokenhttpOnly cookieSecure; never exposed to localStorage
Optimistic updatesReact Query onMutateAlert toggles, watchlist add/remove — feels instant
Quote pollingrefetchInterval: 30_000Active only when tab is visible (refetchIntervalInBackground: false)
Notification badgerefetchInterval: 30_000Polls /notifications/unread-count

Auth Flow in UI

The JWT access token is delivered via JSON body (stored in React Query state). The httpOnly refresh token cookie is set server-side by the API on login. The middleware.ts file protects all routes under /dashboard, /portfolio, /watchlist, /stocks, /alerts, and /market — redirecting unauthenticated users to /login.