A minimal, scalable stock-tracker web app with:
- Backend (Node + Express): Caching, rate limiting, clean OOP services, single API provider adapter (Finnhub) you can swap later.
- Frontend (React + Vite): Watchlist UI, quote cards, tiny chart, localStorage persistence.
- DRY & Modular: Clear separation of concerns; easily extensible to more endpoints/providers.
- API Safety: Requests are cached per-symbol and throttled to avoid timeouts/rate limits.
⚠️ You will need a free API key from Finnhub. Create a.envin theserver/folder based on.env.example.
cd server
npm install
cp .env.example .env
# edit .env and set FINNHUB_API_KEY=your_key_here
npm run dev # or: npm startThis starts the backend at http://localhost:5050.
cd ../client
npm install
npm run devThis starts the React dev server at something like http://localhost:5173. The app will call the backend at http://localhost:5050.
- Host the backend (Node) on a service like Render/Fly/Heroku/Vercel functions.
- Host the frontend as static (Vite build output) on Netlify/Vercel/S3+CloudFront.
- Set
VITE_API_BASE_URLin the frontend.envto the deployed backend URL.
stock-app/
server/
src/
services/
Cache.js # TTL cache (per-key)
FinnhubClient.js # Provider adapter
QuoteService.js # Business logic with caching
controllers/
QuoteController.js # Express handlers
middlewares/
errorHandler.js # Unified error responses
rateLimiter.js # Express rate-limit config
utils/
symbols.js # Helpers (e.g., normalize symbols)
index.js # Express app wiring
config.js # Config/env
client/
src/
components/
TickerForm.jsx
Watchlist.jsx
StockCard.jsx
PriceChart.jsx
services/
ApiClient.js
WatchlistStore.js
App.jsx
main.jsx
styles.css
index.html
vite.config.js
- Caching: Default TTL 15 seconds (configurable). Prevents spamming the provider.
- Batching:
/api/quotes?symbols=AAPL,MSFT,TSLAreturns multiple quotes at once, each cached individually. - Swappable Provider: Replace
FinnhubClientwith another provider by matching the small interface. - Persistence: Frontend watchlist persists in localStorage.
Enjoy! PR to yourself later for charts, historical data, websockets, auth, etc.