🔗 Backend Repository: StockX Backend
A modern, responsive single-page application for a stock-trading simulation platform.
Built with React 19, Vite 8, and Vanilla CSS with a premium dark/light design system.
- Overview
- Features
- Tech Stack
- Architecture
- Project Structure
- Getting Started
- Design System
- Routing & Navigation
- State Management
- API Integration
- Pages & Components
- Utilities
StockX Frontend is the client-side application for the StockX stock-trading simulation platform. It provides a rich, dashboard-style interface where users can:
- 🔐 Register & log in with JWT-based authentication
- 📊 Browse top stocks with real-time pricing data
- 🔍 Search across thousands of US-listed equities
- 💰 Buy & sell stocks with instant wallet debit/credit
- 📈 Track portfolio performance with P&L breakdowns
- 💳 Deposit funds via Stripe Checkout integration
- 📜 View transaction history with type filtering
- 👑 Admin dashboard for user management (admin role only)
- 🌗 Dark & light theme toggle with persistence
| Feature | Description |
|---|---|
| Premium Dark/Light UI | Curated design tokens with dark and light themes. Smooth transitions, glassmorphism, and a polished feel using Inter font. |
| Sidebar Navigation | Fixed sidebar with branded logo, navigation links, user profile card, wallet balance, and logout. Admin links appear for admin users. |
| Stock Search | Debounced search input that queries the backend for matching stocks. Click any result to open a detail modal. |
| Top Stocks Grid | Homepage displays the top 15 most-valued stocks as cards with price and change indicators. |
| Stock Detail Modal | Shows current price, exchange info, and a buy form — all in an animated modal overlay. |
| Trading (Buy/Sell) | Buy stocks from the market page. Sell from the portfolio page. Quantity validation and balance checks. |
| Portfolio Dashboard | Summary stats (total value, cost, P&L) plus a holdings table with per-stock profit/loss. |
| Wallet & Deposits | View balance, initiate Stripe Checkout deposits ($10–$10,000), and see a full transaction history. |
| Toast Notifications | Contextual success/error/info/warning toasts with auto-dismiss and manual close. |
| Route Guards | RequireAuth, RequireAdmin, and GuestOnly wrappers protect pages based on auth state and role. |
| Auto Token Validation | On mount, the app validates the stored JWT by calling /auth/me. Invalid tokens are cleared silently. |
| Global 401 Handling | Axios interceptor auto-clears auth and redirects to login on any 401 response. |
| Category | Technology | Version |
|---|---|---|
| UI Library | React | 19.2 |
| Build Tool | Vite | 8.0 |
| Routing | React Router | 7.13 |
| HTTP Client | Axios | 1.13 |
| Icons | Lucide React | 0.577 |
| Styling | Vanilla CSS with design tokens | — |
| Typography | Inter (Google Fonts) | — |
| Linting | ESLint 9 + React Hooks plugin | — |
The frontend follows a feature-based organization with clear separation between pages, components, services, context, hooks, and utilities.
┌─────────────────────────────────────────────────────────────────┐
│ Pages │
│ HomePage · MarketPage · PortfolioPage · WalletPage · Admin │
├─────────────────────────────────────────────────────────────────┤
│ Components │
│ Layout (Sidebar, Header, Footer, MainLayout) │
│ Market (StockSearch, TopStocks, StockCard, StockDetailModal, │
│ BuyStockForm) │
│ Portfolio (PortfolioSummary, PortfolioTable, HoldingCard, │
│ SellStockForm) │
│ Wallet (WalletBalance, DepositModal, TransactionHistory) │
│ Auth (LoginForm, RegisterForm, LogoutButton) │
│ Admin (AdminDashboard, UserManagementTable, UserDetailModal) │
│ Common (LoadingSpinner, ErrorAlert, SuccessAlert, │
│ ConfirmDialog) │
├─────────────────────────────────────────────────────────────────┤
│ Context (State) │
│ AuthContext · WalletContext · ThemeContext · │
│ NotificationContext │
├─────────────────────────────────────────────────────────────────┤
│ Custom Hooks │
│ useAuth · useWallet · useQuery · usePagination │
├─────────────────────────────────────────────────────────────────┤
│ API Services │
│ api.js (Axios instance) · authService · stockService │
│ tradingService · walletService · adminService │
├─────────────────────────────────────────────────────────────────┤
│ Utilities │
│ constants · formatters · validators · localStorage │
└─────────────────────────────────────────────────────────────────┘
Data Flow:
- Pages compose Components and wire up state
- Components call Services for API interaction
- Services use a shared Axios instance with JWT interceptors
- Context providers manage global state (auth, wallet, theme, notifications)
- Hooks abstract common patterns (data fetching, pagination)
StockX-Frontend/
├── public/
│ ├── favicon.svg # App favicon
│ └── icons.svg # SVG icon sprite
│
├── src/
│ ├── main.jsx # React DOM entry point
│ ├── App.jsx # Root component (providers + router)
│ ├── Router.jsx # Route definitions + guards
│ ├── index.css # Global design system (~400 lines)
│ ├── App.css # App-level overrides
│ │
│ ├── assets/ # Static assets
│ │ ├── hero.png # Hero image
│ │ ├── react.svg
│ │ └── vite.svg
│ │
│ ├── components/
│ │ ├── Admin/
│ │ │ ├── AdminDashboard.jsx # Dashboard layout wrapper
│ │ │ ├── UserManagementTable.jsx # Paginated user list with search
│ │ │ └── UserDetailModal.jsx # User detail drill-down modal
│ │ │
│ │ ├── Auth/
│ │ │ ├── LoginForm.jsx # Email/password login with validation
│ │ │ ├── RegisterForm.jsx # Registration with name/email/password
│ │ │ └── LogoutButton.jsx # Logout trigger
│ │ │
│ │ ├── Common/
│ │ │ ├── ConfirmDialog.jsx # Reusable confirmation modal
│ │ │ ├── ErrorAlert.jsx # Error message display
│ │ │ ├── LoadingSpinner.jsx # Animated loading indicator
│ │ │ └── SuccessAlert.jsx # Success message display
│ │ │
│ │ ├── Layout/
│ │ │ ├── MainLayout.jsx # Sidebar + Header + Footer + Toasts
│ │ │ ├── Sidebar.jsx # Fixed sidebar navigation
│ │ │ ├── Header.jsx # Top bar (title, balance, theme toggle)
│ │ │ └── Footer.jsx # Footer strip
│ │ │
│ │ ├── Market/
│ │ │ ├── StockSearch.jsx # Debounced search input + results list
│ │ │ ├── TopStocks.jsx # Top stocks grid (auto-fetching)
│ │ │ ├── StockCard.jsx # Individual stock card
│ │ │ ├── StockDetailModal.jsx # Stock price + buy form modal
│ │ │ └── BuyStockForm.jsx # Buy shares form with validation
│ │ │
│ │ ├── Portfolio/
│ │ │ ├── PortfolioSummary.jsx # Total value / cost / P&L stats
│ │ │ ├── PortfolioTable.jsx # Holdings table
│ │ │ ├── HoldingCard.jsx # Individual holding with sell trigger
│ │ │ └── SellStockForm.jsx # Sell shares form with validation
│ │ │
│ │ └── Wallet/
│ │ ├── WalletBalance.jsx # Balance display card
│ │ ├── DepositModal.jsx # Stripe Checkout deposit form
│ │ └── TransactionHistory.jsx # Filterable transaction list
│ │
│ ├── context/
│ │ ├── AuthContext.jsx # Auth state, login, register, logout
│ │ ├── WalletContext.jsx # Wallet balance state
│ │ ├── ThemeContext.jsx # Dark/light theme toggle
│ │ └── NotificationContext.jsx # Toast notification system
│ │
│ ├── hooks/
│ │ ├── useAuth.js # Shorthand for useContext(AuthContext)
│ │ ├── useWallet.js # Shorthand for useContext(WalletContext)
│ │ ├── useQuery.js # Data-fetching hook (loading, error, refetch)
│ │ └── usePagination.js # Pagination state (page, limit, offset)
│ │
│ ├── services/
│ │ ├── api.js # Axios instance + JWT/401 interceptors
│ │ ├── authService.js # register, login, getMe
│ │ ├── stockService.js # searchStocks, getTopStocks, getStockDetails
│ │ ├── tradingService.js # buyStock, sellStock, getPortfolio
│ │ ├── walletService.js # getBalance, initiateDeposit, getTransactions
│ │ └── adminService.js # getAdminUsers, getAdminUserDetail, etc.
│ │
│ └── utils/
│ ├── constants.js # API_URL, routes, roles, transaction types
│ ├── formatters.js # Currency, percent, date, relative time
│ ├── validators.js # Email, password, name, amount, quantity
│ └── localStorage.js # Token & user storage helpers
│
├── .env.local # Local environment variables
├── .env.production # Production environment variables
├── index.html # HTML entry point
├── vite.config.js # Vite configuration (port, proxy)
├── eslint.config.js # ESLint flat config
├── package.json
└── package-lock.json
| Tool | Version |
|---|---|
| Node.js | 18+ (LTS recommended) |
| npm | 9+ |
| StockX Backend | Running locally on http://localhost:5052 |
# Clone the repository
git clone https://github.com/<your-username>/StockX-Frontend.git
cd StockX-Frontend
# Install dependencies
npm installCreate a .env.local file in the project root:
# Base URL for API calls (proxied to backend in dev)
VITE_API_URL=/api
# Stripe publishable key (for client-side Checkout)
VITE_STRIPE_PUBLIC_KEY=pk_test_...For production, create .env.production:
VITE_API_URL=https://your-backend-domain.com/api
VITE_STRIPE_PUBLIC_KEY=pk_live_...Note: All environment variables must be prefixed with
VITE_to be exposed to the client bundle.
npm run devThe app starts at http://localhost:3000 with:
- Hot Module Replacement (HMR) enabled
- API proxy configured to forward
/api/*requests tohttp://localhost:5052
# Build for production
npm run build
# Preview the build locally
npm run previewThe build output is written to the dist/ directory and is ready for static hosting.
The application uses a comprehensive CSS design system defined in src/index.css (~400 lines) with the following features:
All colors, spacing, radii, shadows, and transitions are defined as CSS custom properties:
:root {
/* Background layers */
--bg-base, --bg-surface, --bg-elevated, --bg-card, --bg-overlay
/* Brand palette */
--brand (#6366f1), --brand-hover, --brand-dim, --brand-border
/* Semantic colors */
--green, --red, --amber, --blue (with -dim variants)
/* Typography */
--text, --text-muted, --text-subtle, --text-inverse
/* Spacing scale */
--sp-1 (4px) through --sp-16 (64px)
/* Border radius */
--r-sm (6px) → --r-full (9999px)
}Themes are toggled via data-theme="light" on <html>:
| Token | Dark | Light |
|---|---|---|
--bg-base |
#0a0b0f |
#f4f7fb |
--bg-surface |
#111318 |
#ffffff |
--brand |
#6366f1 |
#4f46e5 |
--text |
#e2e8f0 |
#0f172a |
The CSS provides pre-built classes for:
| Category | Classes |
|---|---|
| Buttons | .btn, .btn-primary, .btn-secondary, .btn-success, .btn-danger, .btn-ghost, .btn-sm, .btn-lg, .btn-icon |
| Forms | .form-group, .form-label, .form-input, .form-error, .form-hint |
| Cards | .card, .card-header |
| Badges | .badge, .badge-brand, .badge-green, .badge-red, .badge-amber, .badge-blue, .badge-muted |
| Tables | .table-wrap, standard table/thead/tbody styling |
| Modals | .modal-overlay, .modal, .modal-title, .modal-footer |
| Toasts | .toast-container, .toast, .toast-success, .toast-error, .toast-info, .toast-warning |
| Layout | .app-layout, .main-content, .page-container, .sidebar, .header |
| Stats | .stat-grid, .stat-card, .stat-label, .stat-value |
| Auth | .auth-page, .auth-card, .auth-form, .auth-logo |
| States | .empty-state, .skeleton (shimmer animation), .loading-spinner |
The layout switches from sidebar to full-width at 768px:
- Sidebar slides off-screen on mobile
- Main content takes full width
- Grid columns reduce from auto-fit to 1–2 columns
Routes are defined in src/Router.jsx with three guard types:
| Guard | Behavior |
|---|---|
RequireAuth |
Redirects to /login if not authenticated |
RequireAdmin |
Redirects to /login (unauthenticated) or /unauthorized (non-admin) |
GuestOnly |
Redirects to / if already authenticated |
| Path | Guard | Page | Description |
|---|---|---|---|
/login |
GuestOnly | LoginForm |
Login page |
/register |
GuestOnly | RegisterForm |
Registration page |
/ |
RequireAuth | HomePage |
Dashboard with top stocks & wallet |
/market |
RequireAuth | MarketPage |
Stock search & quick picks |
/portfolio |
RequireAuth | PortfolioPage |
Holdings & P&L summary |
/wallet |
RequireAuth | WalletPage |
Balance, deposits, transactions |
/admin |
RequireAdmin | AdminDashboardPage |
User management (admin only) |
/wallet/deposit/success |
RequireAuth | → /wallet?success=true |
Stripe success redirect |
/wallet/deposit/cancel |
RequireAuth | → /wallet?canceled=true |
Stripe cancel redirect |
/unauthorized |
— | UnauthorizedPage |
403 page |
/404 |
— | NotFoundPage |
404 page |
* |
— | NotFoundPage |
Catch-all |
Global state is managed through four React Context providers, nested in App.jsx:
BrowserRouter
└── ThemeProvider (dark/light theme)
└── NotificationProvider (toast notifications)
└── AuthProvider (user, login, logout)
└── WalletProvider (balance state)
| Context | State | Actions | Hook |
|---|---|---|---|
| AuthContext | user, loading, isAuthenticated, isAdmin |
login(), register(), logout(), refreshUser() |
useAuth() |
| WalletContext | balance, loadingBalance |
fetchBalance(), updateBalance() |
useWallet() |
| ThemeContext | theme, isLightMode |
toggleTheme() |
useTheme() |
| NotificationContext | notifications[] |
notify.success(), .error(), .info(), .warning(), dismiss() |
useNotification() |
All contexts persist relevant state to localStorage:
- Auth: JWT token (
stockx_token) and user object (stockx_user) - Theme: Theme preference (
stockx-theme)
A central Axios instance handles:
- Base URL: Reads from
VITE_API_URLenvironment variable (defaults to/api) - Request Interceptor: Attaches
Authorization: Bearer <token>header to every request - Response Interceptor: On 401 responses, clears auth storage and redirects to
/login
| Service | Methods | Backend Endpoints |
|---|---|---|
| authService | register(), login(), getMe() |
POST /auth/register, POST /auth/login, GET /auth/me |
| stockService | searchStocks(), getTopStocks(), getStockDetails() |
GET /stock/search, GET /stock/top, GET /stock/{symbol} |
| tradingService | buyStock(), sellStock(), getPortfolio() |
POST /trading/buy, POST /trading/sell, GET /portfolio |
| walletService | getBalance(), initiateDeposit(), getTransactions() |
GET /wallet/balance, POST /wallet/deposit/initiate, GET /transactions |
| adminService | getAdminUsers(), getAdminUserDetail(), updateUserActivation(), updateUserRole() |
GET /admin/users, GET /admin/users/:id, PUT /admin/users/:id/activate, PUT /admin/users/:id/role |
In development, Vite proxies all /api requests to the backend:
// vite.config.js
server: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:5052',
changeOrigin: true,
},
},
}| Page | Key Components | Description |
|---|---|---|
| HomePage | WalletBalance, TopStocks, StockDetailModal |
Welcome banner, wallet snapshot, top 15 stocks |
| MarketPage | StockSearch, StockDetailModal |
Search bar, quick-pick badges (AAPL, TSLA, etc.) |
| PortfolioPage | PortfolioSummary, PortfolioTable, HoldingCard, SellStockForm |
P&L stats grid, holdings list with sell action |
| WalletPage | WalletBalance, DepositModal, TransactionHistory |
Balance card, deposit button, filtered transaction list |
| AdminDashboardPage | AdminDashboard, UserManagementTable, UserDetailModal |
Paginated user table with search and detail drill-down |
| Component | Behavior |
|---|---|
| StockSearch | Debounced text input that fetches matching stocks as you type. Click a result to open the detail modal. |
| StockDetailModal | Fetches real-time price via getStockDetails(). Includes an inline BuyStockForm. |
| BuyStockForm | Validates quantity, shows estimated cost, confirms purchase, updates wallet balance. |
| SellStockForm | Shows owned quantity, validates sell amount, confirms sale, updates wallet. |
| DepositModal | Amount input ($10–$10,000), calls initiateDeposit(), redirects to Stripe Checkout. |
| TransactionHistory | Fetches transactions with type filter (all, deposit, trade). Paginated display. |
| UserManagementTable | Paginated user list with search. Click a row to open UserDetailModal. |
| Function | Example Output |
|---|---|
formatCurrency(175.1) |
$175.10 |
formatPercent(3.5) |
+3.50% |
formatLargeNumber(2500000000) |
$2.50B |
formatDate(timestamp) |
Apr 28, 2026, 10:30 AM |
formatRelativeTime(timestamp) |
5 minutes ago |
formatTransactionType('StockBuy') |
Buy |
profitLossClass(51) |
'positive' |
| Function | Rules |
|---|---|
validateEmail() |
Required, valid email format |
validatePassword() |
Required, min 8 chars, 1 uppercase, 1 number |
validateName() |
Required, min 2 chars |
validateDepositAmount() |
Required, $10–$10,000 range |
validateQuantity() |
Required, > 0, optional max check |
validateSymbol() |
Required, alphanumeric |
| Hook | Purpose |
|---|---|
useQuery(fetchFn, deps, options) |
Generic data fetcher with loading, error, data, refetch. Supports immediate fetch and refetchInterval. |
usePagination(initialPage, limit) |
Pagination state with nextPage, prevPage, goToPage, reset, and computed offset. |
| Command | Description |
|---|---|
npm run dev |
Start dev server on port 3000 with HMR |
npm run build |
Production build to dist/ |
npm run preview |
Preview production build locally |
npm run lint |
Run ESLint across all JS/JSX files |
Built with ❤️ using React 19 + Vite 8