# Prism v2 Financial overview app. FastAPI backend (yfinance + SQLite watchlist) and Next.js frontend (Plotly chart, ticker search, market bar, watchlist). ## Stack - Backend: Python 3.14+, FastAPI, uvicorn, yfinance, SQLite - Frontend: Node 20+, Next.js (App Router), TypeScript - Production: systemd + nginx (TLS via certbot) ## Layout - `backend/app/` — FastAPI app, services, SQLite watchlist - `frontend/app/` — Next.js App Router; shared types in `frontend/types/api.ts` - `systemd/` — service units (`prismv2-backend.service`, `prismv2-frontend.service`) - `nginx/` — TLS server block (`/api/` → :8001, `/` → :3001) - `scripts/stack.sh` — local dev start/stop/restart/status - `design-system/` — brand tokens + Prism UI kit (mirrored to `frontend/public/design-system/`) ## Environment Copy `.env.example` → `.env`. Current feature set works without keys. - `NEXT_PUBLIC_API_BASE_URL` — leave empty in production (same-origin `/api/*` via nginx) - `FMP_API_KEY`, `FINNHUB_API_KEY` — reserved for future enrichment ## Local Development ```bash # Backend cd backend && python -m venv .venv && .venv/bin/pip install -r requirements.txt .venv/bin/uvicorn app.main:app --reload --host 127.0.0.1 --port 8001 # Frontend cd frontend && npm install NEXT_PUBLIC_API_BASE_URL=http://127.0.0.1:8001 npm run dev -- --hostname 127.0.0.1 --port 3001 ``` Or use `./scripts/stack.sh {start|stop|restart|status}` (logs in `.run/logs/`). ## API - `GET /health` - `GET /api/search?q=` - `GET /api/market/indices` - `GET /api/tickers/{symbol}/overview` - `GET /api/tickers/{symbol}/history?period=1m|3m|6m|1y|5y` - `GET|POST|DELETE /api/watchlist[/{symbol}]` (uppercase, capped at 10) SQLite lives at `backend/data/prism.db`. Backend seeds a `default` profile on startup. ## Production Deployment Target topology: backend on `127.0.0.1:8001`, frontend on `127.0.0.1:3001`, nginx terminates TLS and reverse-proxies. Code lives at `/var/www/prism-v2/` owned by `www-data`. Use `scripts/deploy.sh` on the server — it is idempotent and handles both initial install and redeploys. ### First-time setup on a fresh server ```bash # As root / via sudo mkdir -p /var/www && chown www-data:www-data /var/www sudo -u www-data git clone /var/www/prism-v2 cd /var/www/prism-v2 # Install systemd units + nginx site + build + start sudo ./scripts/deploy.sh --install # First-time TLS (Certbot edits the nginx server block in-place) sudo certbot --nginx -d prism.tylerhoang.xyz sudo systemctl reload nginx ``` ### Redeploy ```bash cd /var/www/prism-v2 sudo ./scripts/deploy.sh # pull + build + restart + smoke check sudo ./scripts/deploy.sh --no-pull # rebuild + restart without git pull sudo ./scripts/deploy.sh --install # also refresh systemd units / nginx site ``` The script runs all build steps as `www-data` (with `HOME` + `NPM_CONFIG_CACHE` set), restarts both services, and curls `/health` on the backend and `/` on the frontend before exiting. ### Ops ```bash sudo systemctl status prismv2-backend.service prismv2-frontend.service --no-pager sudo journalctl -u prismv2-backend.service -f sudo journalctl -u prismv2-frontend.service -f curl -i http://127.0.0.1:8001/health curl -i https://prism.tylerhoang.xyz/api/search?q=AAPL ``` ## Verification ```bash pytest # backend tests (pytest.ini sets pythonpath) cd frontend && npm run lint && npm run build ``` ## Production Rules - Do not hardcode a localhost API base in frontend browser code. `frontend/lib/api.ts` must default to empty so the browser hits same-origin `/api/*`. - Never commit `.env`, `node_modules/`, `backend/.venv/`, or `backend/data/prism.db`. - Watchlist is normalized to uppercase and capped at 10 symbols.