# 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: - Bare repo at `/srv/git/prism-v2.git` (push target) - Working tree at `/var/www/prism-v2/` owned by `www-data` (no `.git/` — populated by post-receive hook via `git --work-tree=... checkout -f`) - Backend on `127.0.0.1:8001`, frontend on `127.0.0.1:3001` - nginx terminates TLS and reverse-proxies `/api/` → backend, `/` → frontend Workflow: `git push prod master` on your laptop → post-receive hook checks out the tree into `/var/www/prism-v2/` and runs `scripts/deploy.sh`, which builds + restarts. ### First-time setup ```bash # 1. Create bare repo sudo mkdir -p /srv/git && sudo git init --bare /srv/git/prism-v2.git # 2. Create working tree dir sudo install -d -o www-data -g www-data /var/www/prism-v2 # 3. Push from your laptop so the working tree gets populated # (add the remote on your laptop: git remote add prod user@host:/srv/git/prism-v2.git) # git push prod master # 4. On the server: install systemd units + nginx site + build + start cd /var/www/prism-v2 sudo ./scripts/deploy.sh --install # 5. First-time TLS (Certbot edits the nginx server block in-place) sudo certbot --nginx -d prism.tylerhoang.xyz sudo systemctl reload nginx # 6. Install the post-receive hook so future pushes auto-deploy sudo cp /var/www/prism-v2/scripts/post-receive.sample /srv/git/prism-v2.git/hooks/post-receive sudo chmod +x /srv/git/prism-v2.git/hooks/post-receive # 7. Sudoers entry so the git-push user can run deploy.sh without a password # (replace GIT_USER with the account that owns /srv/git or receives the push) echo 'GIT_USER ALL=(root) NOPASSWD: /var/www/prism-v2/scripts/deploy.sh' | sudo tee /etc/sudoers.d/prism-v2-deploy sudo chmod 0440 /etc/sudoers.d/prism-v2-deploy ``` ### Subsequent deploys From your laptop: ```bash git push prod master # post-receive hook checks out + runs deploy.sh ``` Manual deploy on the server (e.g. retry after a failed build, or to refresh systemd/nginx): ```bash cd /var/www/prism-v2 sudo ./scripts/deploy.sh # build + restart + smoke check sudo ./scripts/deploy.sh --install # also refresh systemd units / nginx site ``` `deploy.sh` is idempotent: ensures ownership, builds the backend venv and `npm ci && npm run build` as `www-data` (with `HOME` + `NPM_CONFIG_CACHE` set), restarts both services, and curls `/health` and `/` before exiting. It does NOT touch git — the post-receive hook owns checkout. ### 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.