summaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
authorTyler Hoang <tyler@tylerhoang.xyz>2026-05-30 00:16:53 -0700
committerTyler Hoang <tyler@tylerhoang.xyz>2026-05-30 00:16:53 -0700
commit66acc6f7d18c93f4b7960682bea5bd5ff1545802 (patch)
treec34458c8e53470cf80b32ec15c16f5940ebcb954 /README.md
parent2222d8a5fac6850d7d924e9404a44a65cb10f68f (diff)
docs: tighten README, AGENTS, CLAUDE with production deploy instructions
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Diffstat (limited to 'README.md')
-rw-r--r--README.md237
1 files changed, 69 insertions, 168 deletions
diff --git a/README.md b/README.md
index fb492f8..9e7f689 100644
--- a/README.md
+++ b/README.md
@@ -1,226 +1,127 @@
# Prism v2
-Prism v2 is a monorepo rewrite of Prism's Overview experience with a FastAPI backend and a Next.js frontend. This first slice covers:
+Financial overview app. FastAPI backend (yfinance + SQLite watchlist) and Next.js frontend (Plotly chart, ticker search, market bar, watchlist).
-- ticker search
-- selected ticker profile and quote
-- market bar
-- historical price chart
-- overview signal and stat cards
-- persisted watchlist backed by SQLite
+## Stack
-The implementation copies and adapts finance logic from Prism v1 into `backend/`; it does not import code from the old repo at runtime.
+- Backend: Python 3.14+, FastAPI, uvicorn, yfinance, SQLite
+- Frontend: Node 20+, Next.js (App Router), TypeScript
+- Production: systemd + nginx (TLS via certbot)
-## Repo Layout
+## Layout
-- `backend/`
- - `app/main.py` FastAPI application and routes
- - `app/services/data_service.py` yfinance-backed Overview service layer with TTL caching
- - `app/db/watchlist.py` SQLite persistence for the default local profile
- - `data/prism.db` local watchlist database
- - `tests/` backend unit and API smoke tests
-- `frontend/`
- - `app/page.tsx` Overview shell
- - `components/PriceChart.tsx` Plotly price chart
- - `lib/api.ts` typed REST client
- - `types/api.ts` shared frontend response types
-- `scripts/stack.sh` unified start/stop/restart/status script
-- `systemd/` systemd unit files for running as a system service
-- `nginx/` nginx server block config (proxies `/api/` to backend, `/` to frontend)
-- `.env.example` optional environment variables
-- `pytest.ini` backend pytest import path config
-
-## Requirements
-
-- Python 3.14+
-- Node.js 20+
-- npm
+- `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` to `.env` if you want to set optional keys.
-
-Supported variable names are unchanged from Prism v1:
-
-- `FMP_API_KEY`
-- `FINNHUB_API_KEY`
-- `NEXT_PUBLIC_API_BASE_URL`
+Copy `.env.example` → `.env`. Current feature set works without keys.
-The current Overview slice works without FMP or Finnhub keys because it relies on yfinance for the active endpoints.
-
-## Backend Setup
-
-```bash
-cd backend
-python -m venv .venv
-source .venv/bin/activate
-pip install -r requirements.txt
-```
+- `NEXT_PUBLIC_API_BASE_URL` — leave empty in production (same-origin `/api/*` via nginx)
+- `FMP_API_KEY`, `FINNHUB_API_KEY` — reserved for future enrichment
-Run the API:
+## 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
```
-Primary endpoints:
+Or use `./scripts/stack.sh {start|stop|restart|status}` (logs in `.run/logs/`).
+
+## API
- `GET /health`
-- `GET /api/search?q=...`
+- `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 /api/watchlist`
-- `POST /api/watchlist/{symbol}`
-- `DELETE /api/watchlist/{symbol}`
-
-Notes:
-
-- SQLite lives at `backend/data/prism.db`
-- the backend seeds one `default` profile automatically
-- watchlist symbols are normalized to uppercase
-- watchlist size is capped at 10 symbols
-
-## Frontend Setup
+- `GET|POST|DELETE /api/watchlist[/{symbol}]` (uppercase, capped at 10)
-```bash
-cd frontend
-npm install
-```
+SQLite lives at `backend/data/prism.db`. Backend seeds a `default` profile on startup.
-Run the frontend against the local backend:
+## Production Deployment
-```bash
-NEXT_PUBLIC_API_BASE_URL=http://127.0.0.1:8001 npm run dev -- --hostname 127.0.0.1 --port 3001
-```
-
-The UI stores the selected ticker in the URL, for example `/?ticker=AAPL`.
+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`.
-Production frontend runtime:
+### 1. Initial install
```bash
-npm run build
-npm run start -- --hostname 127.0.0.1 --port 3001
-```
-
-Important API-base rule:
-
-- In production, browser requests should use same-origin `/api/*` through nginx.
-- Do not hardcode a localhost fallback API base in frontend browser code.
-- `frontend/lib/api.ts` should default to an empty base when `NEXT_PUBLIC_API_BASE_URL` is unset.
-
-## Quick Start
+sudo mkdir -p /var/www && sudo chown www-data:www-data /var/www
+sudo -u www-data git clone <repo> /var/www/prism-v2
+cd /var/www/prism-v2
-`scripts/stack.sh` manages both services as a local development stack:
+# Backend
+sudo -u www-data python3 -m venv backend/.venv
+sudo -u www-data backend/.venv/bin/pip install -r backend/requirements.txt
-```bash
-./scripts/stack.sh start # start backend + frontend in background
-./scripts/stack.sh stop # stop both
-./scripts/stack.sh restart # stop then start
-./scripts/stack.sh status # show running PIDs and URLs
+# Frontend (writable npm cache required for www-data)
+sudo mkdir -p frontend/.npm && sudo chown -R www-data:www-data frontend
+sudo -u www-data env HOME=/var/www/prism-v2/frontend NPM_CONFIG_CACHE=/var/www/prism-v2/frontend/.npm \
+ npm --prefix frontend ci
+sudo -u www-data env HOME=/var/www/prism-v2/frontend NPM_CONFIG_CACHE=/var/www/prism-v2/frontend/.npm \
+ npm --prefix frontend run build
```
-Notes:
-
-- expects `backend/.venv` and `frontend/node_modules` to already exist
-- default ports are backend `8001` and frontend `3001`
-- logs are written to `.run/logs/`
-- override hosts/ports via env vars: `BACKEND_HOST`, `BACKEND_PORT`, `FRONTEND_HOST`, `FRONTEND_PORT`
-
-## Running in Production (systemd + nginx)
-
-The production model is:
-
-- backend on `127.0.0.1:8001` via `uvicorn`
-- frontend on `127.0.0.1:3001` via `next start` (not `next dev`)
-- nginx TLS reverse proxy:
- - `/api/*` -> backend
- - `/` -> frontend
-
-Unit templates live in `systemd/` and nginx server block template lives in `nginx/`.
-
-Install system services:
+### 2. systemd
```bash
-sudo cp systemd/prismv2-backend.service /etc/systemd/system/
-sudo cp systemd/prismv2-frontend.service /etc/systemd/system/
+sudo cp systemd/prismv2-backend.service systemd/prismv2-frontend.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now prismv2-backend.service prismv2-frontend.service
```
-Install nginx site:
+### 3. nginx + TLS
```bash
sudo cp nginx/prism.tylerhoang.xyz.conf /etc/nginx/sites-available/prism.tylerhoang.xyz
-sudo ln -sf /etc/nginx/sites-available/prism.tylerhoang.xyz /etc/nginx/sites-enabled/prism.tylerhoang.xyz
-sudo nginx -t
-sudo systemctl reload nginx
-```
-
-Create writable npm cache for service user:
-
-```bash
-sudo mkdir -p /var/www/prism-v2/frontend/.npm
-sudo chown -R www-data:www-data /var/www/prism-v2/frontend
-```
-
-Service controls:
-
-```bash
-sudo systemctl status prismv2-backend.service --no-pager
-sudo systemctl status prismv2-frontend.service --no-pager
-sudo systemctl restart prismv2-backend.service prismv2-frontend.service
-sudo journalctl -u prismv2-backend.service -f
-sudo journalctl -u prismv2-frontend.service -f
+sudo ln -sf /etc/nginx/sites-available/prism.tylerhoang.xyz /etc/nginx/sites-enabled/
+sudo certbot --nginx -d prism.tylerhoang.xyz # first time only
+sudo nginx -t && sudo systemctl reload nginx
```
-Production deploy refresh:
+### 4. Redeploy
```bash
cd /var/www/prism-v2
-git pull origin master
-
-cd backend
-python3 -m venv .venv
-.venv/bin/pip install -r requirements.txt
-
-cd ../frontend
-npm ci
-npm run build
-
+sudo -u www-data git pull origin master
+sudo -u www-data backend/.venv/bin/pip install -r backend/requirements.txt
+sudo -u www-data env HOME=/var/www/prism-v2/frontend NPM_CONFIG_CACHE=/var/www/prism-v2/frontend/.npm \
+ npm --prefix frontend ci
+sudo -u www-data env HOME=/var/www/prism-v2/frontend NPM_CONFIG_CACHE=/var/www/prism-v2/frontend/.npm \
+ npm --prefix frontend run build
sudo systemctl restart prismv2-backend.service prismv2-frontend.service
-sudo systemctl reload nginx
```
-## Verification
-
-Backend:
+### Ops
```bash
-backend/.venv/bin/python -m py_compile backend/app/main.py backend/app/schemas.py backend/app/services/data_service.py backend/app/db/watchlist.py
-backend/.venv/bin/python -m pytest backend/tests
-```
-
-Frontend:
+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
-```bash
-cd frontend
-npm run lint
-npm run build
+curl -i http://127.0.0.1:8001/health
+curl -i https://prism.tylerhoang.xyz/api/search?q=AAPL
```
-Production smoke checks:
+## Verification
```bash
-curl -i http://127.0.0.1:8001/health
-curl -i "https://prism.tylerhoang.xyz/api/search?q=AAPL"
+pytest # backend tests (pytest.ini sets pythonpath)
+cd frontend && npm run lint && npm run build
```
-## Current Local URLs
-
-If port `8000` is already occupied on your machine, use:
-
-- backend: `http://127.0.0.1:8001`
-- frontend: `http://127.0.0.1:3001`
+## Production Rules
-Those are the ports used by the current local bootstrap.
+- 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.