System architecture
A small Node.js service serves the dashboard, gates a cosmetic login, serves the static data files, and proxies the two Polymarket APIs. nginx sits in front on port 80.
Request flow
browser
│ http://<server-ip>/
▼
nginx :80 reverse proxy
│ proxy_pass 127.0.0.1:3000
▼
Node / Express :3000
├─ GET / → dashboard HTML (display name injected)
├─ GET /login, POST /login, /logout → cosmetic session
├─ GET /docs/* → this documentation site (static)
├─ GET /forecasts.json → bundled forecast data (static)
├─ /api/gamma/* → proxied to gamma-api.polymarket.com
└─ /api/clob/* → proxied to clob.polymarket.com
Components
| Piece | Role |
|---|---|
server.js | The whole application: routing, login, static serving, name injection, API proxy. Its only dependency is Express. |
public/forecasting.html | The dashboard itself. The server injects the account bar (Docs + Login / signed-in name) just after <body> on each request. |
public/forecasts.json | Bundled forecast data, served statically. |
public/docs/ | This documentation website (static HTML + one CSS file). |
| nginx | Terminates port 80 (and TLS later) and forwards to the Node app on localhost. |
| systemd unit | Keeps the Node service running and restarts it on boot or failure. |
Authentication model
The login is intentionally lightweight and grants no privileges — the dashboard and all data are public. When credentials match, the server issues an HMAC-signed cookie carrying only the username and an expiry. On each request the cookie is verified; if valid, the header shows the signed-in name, otherwise it shows the Login button. There is no session store and no database.
The proxy
The two /api/* routes forward GET requests to Polymarket using the server's
built-in fetch and return the upstream response verbatim. This keeps API calls
server-side, sidestepping browser CORS limits and letting the dashboard work even where the
browser would be geo-blocked. Only GET is proxied, which is all the dashboard uses.
Design choices
- Single dependency. Only Express; sessions use Node's
cryptoand the proxy uses built-infetch(Node 18+). - Stateless auth. A signed cookie means restarts don't log you out and there's nothing to back up.
- Static-friendly. Data files and docs are plain static assets; missing optional files return a clean 404 that the dashboard handles.