1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
# 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`.
### 1. Initial install
```bash
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
# Backend
sudo -u www-data python3 -m venv backend/.venv
sudo -u www-data backend/.venv/bin/pip install -r backend/requirements.txt
# 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
```
### 2. systemd
```bash
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
```
### 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/
sudo certbot --nginx -d prism.tylerhoang.xyz # first time only
sudo nginx -t && sudo systemctl reload nginx
```
### 4. Redeploy
```bash
cd /var/www/prism-v2
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
```
### 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.
|