Frontend Developer Guide
Technology Stacks
- React 18 with TypeScript
- Vite for fast development builds
- Tailwind CSS + ShadCN UI for components
- Axios (
src/services/api.js) as the centralized HTTP client - Lightweight Charts for candlestick and line charts
Project Structure
frontend/
├── src/
│ ├── pages/ # Route-level page components
│ ├── components/ # Reusable UI components
│ ├── services/
│ │ └── api.js # All API calls (Axios instance + method map)
│ ├── hooks/ # Custom React hooks
│ ├── types/ # TypeScript interfaces
│ └── App.tsx # Root component + router
├── public/
├── index.html
├── vite.config.ts
└── package.json
Key Pages
| Page | File | Description |
|---|---|---|
| BhavDownloader | src/pages/BhavDownloader.tsx | NSE sync + AMI data download |
| Dashboard | src/pages/Dashboard.tsx | Market summary |
| TradeEntry | src/pages/TradeEntry.tsx | Trade journal |
| OptionChain | src/pages/OptionChain.tsx | F&O chain viewer |
Navigation & access control
Page links live in src/components/Sidebar.jsx, not a top nav bar — it renders only when the logged-in user's rank is DEVELOPER or higher (rankOf(user?.catcode) >= RANK.DEVELOPER, checked in Layout.jsx). A FREE/PAID/POWER/anonymous viewer gets no sidebar at all — just Header.jsx and full-width content. Desktop renders it as a fixed left column; below md it collapses to an off-canvas drawer toggled by a hamburger button in the header.
Asset Allocation is the one exception — it's linked directly from Header.jsx, not the sidebar, because it's the one page visible to every viewer regardless of rank (see User System Design "Public surface in v2.0").
src/constants/rank.js exports the RANK map (ANON..ADMIN) and a rankOf(catcode) helper — mirrors backend/app/auth/deps.py's RANK constant, and is the single copy Sidebar.jsx/Layout.jsx/ProtectedRoute.jsx all import, instead of each keeping its own.
src/components/UserMenu.jsx is the top-right account control: avatar (initial) + email + role badge, click-to-open dropdown with Profile/Sign Out, renders the old "Sign In" button when logged out.
src/components/AdminUserManagement.jsx is ADMIN-only — see teudb Overview "Admin API reference" for the endpoints it drives and where it's mounted.
API Service Pattern
All API calls go through src/services/api.js:
const apiClient = axios.create({
baseURL: import.meta.env.VITE_API_URL || 'http://localhost:8000/api',
});
export const api = {
bhavDownloader: {
triggerDownload: async (date, testingMode) => { ... },
getStatus: async () => { ... },
getAmiFiles: async () => { ... },
}
};
Polling Pattern (BhavDownloader)
Background tasks use a polling loop with a hasSeenRunning guard to prevent premature termination on stale stats.json:
const startPolling = useCallback((alreadyRunning = false) => {
let hasSeenRunning = alreadyRunning;
pollingRef.current = setInterval(async () => {
const res = await api.bhavDownloader.getStatus();
if (res.status === 'RUNNING') {
hasSeenRunning = true;
// Update UI...
} else if (hasSeenRunning) {
// Task completed — stop polling
stopPolling();
}
// If !hasSeenRunning and not RUNNING: task hasn't started writing yet — continue polling silently
}, 1500);
}, []);
Environment Variables
| Variable | Description |
|---|---|
VITE_API_URL | Backend API base URL |
Set in .env or .env.local at frontend/.
Running the Frontend
cd frontend
npm install
npm run dev # dev server at http://localhost:5173
npm run build # production build → dist/
npm run preview # preview production build locally