# tssbot.web React + Vite + Tailwind v4 web shell for Toothless' TSS Bot. Routes: - `/` landing page - `/teams` TSS team leaderboard - `/teams/:teamname` generated team profile with roster, summary, rating history, and battle results - `/battle-logs` Battle Logs - `/viewers` public consented viewer analytics dashboard ## Local development ```sh npm install npm run dev ``` The development server runs on . By default, `/api/*` and `/health` requests are proxied to `http://localhost:6000`. Override that with `VITE_API_TARGET`: ```sh VITE_API_TARGET=http://localhost:8080 npm run dev ``` ## Production with PM2 ```sh npm install npm run build pm2 start ecosystem.config.cjs ``` The production server runs on . It serves `/health` locally and only proxies the API routes used by the app: - `GET /api/tss/leaderboard/teams?limit=1..100` - `GET /api/tss/teams/resolve?name=...` - `GET /api/tss/teams/:team` - `GET /api/tss/teams/:team/history` - `GET /api/tss/teams/:team/games` The proxy blocks cross-origin/API-navigation requests, strips CORS headers from the upstream response, rate limits callers, and caches successful GET responses briefly so public page traffic does not hammer the upstream API. Override the API target before starting PM2 if needed: ```sh API_UPSTREAM=http://127.0.0.1:8080 pm2 start ecosystem.config.cjs ``` Set `PUBLIC_ORIGIN` to the public site origin in production, especially behind a reverse proxy: ```sh PUBLIC_ORIGIN=https://your-domain.example pm2 start ecosystem.config.cjs ``` Optional API protection tuning: ```sh API_CACHE_TTL_MS=15000 API_RATE_LIMIT_WINDOW_MS=60000 API_RATE_LIMIT_MAX=120 ``` ## Uptime snapshots The production server samples uptime every 30 minutes and exposes the history at `/api/uptime`. Snapshots are stored in SQLite under `~/tsswebstorage` by default. Set `UPTIME_STORAGE_DIR` to choose a different folder: ```sh UPTIME_STORAGE_DIR=~/tsswebstorage UPTIME_DATABASE_FILE=uptime.sqlite UPTIME_SAMPLE_INTERVAL_MS=1800000 UPTIME_HISTORY_LIMIT=336 ``` The server creates the storage folder, SQLite database, and `uptime_snapshots` table automatically. ## Viewer analytics The site shows a centered cookie notice before analytics start. The first screen offers `Allow all` or `Configure`; detailed settings only appear after `Configure`. A necessary cookie remembers the visitor's choice. If a visitor allows analytics, the browser sends page-view and heartbeat events to `POST /api/viewers/event`. Visitors can choose whether to include browser/device, screen, language/timezone, referrer, and technical diagnostics. Technical diagnostics can include HTTP version, protocol headers, content negotiation headers, browser privacy signals, network quality, touch support, CPU/memory hints, and similar debugging fields. The public `/viewers` page reads `GET /api/viewers` and shows active pages, 24-hour page totals, top pages, and any consented client details. Viewer analytics are stored in SQLite under the same `UPTIME_STORAGE_DIR` by default. Raw IP addresses and IP hashes are not stored in viewer analytics. Withdrawing consent removes the local visitor ID and calls `POST /api/viewers/delete` to delete matching visitor/session analytics records. The `/privacy` page lists the controller, contact route, purposes, retention, rights, and complaint routes. ```sh ANALYTICS_DATABASE_FILE=viewers.sqlite ANALYTICS_RETENTION_DAYS=30 ANALYTICS_ACTIVE_WINDOW_SECONDS=75 ``` This is an implementation aid, not legal advice. For production GDPR compliance, keep the `/privacy` page aligned with the configured retention period, hosting setup, and actual data fields. ## GitHub webhook The webhook process listens on port `3011` at `/github`. Configure GitHub to send push events there. Set a webhook secret before starting PM2 if you want signature validation: ```sh GITHUB_WEBHOOK_SECRET=your-secret pm2 start ecosystem.config.cjs ``` On PowerShell, set `$env:GITHUB_WEBHOOK_SECRET = "your-secret"` before starting PM2, or put the value directly in `ecosystem.config.cjs`. The default deploy flow is: ```sh git pull --ff-only npm install --production=false --include=dev --include=optional npm run build pm2 reload tssbot-web --update-env ``` Only processes listed in `PM2_RESTART_TARGETS` are reloaded. The default is `tssbot-web`, so unrelated PM2 processes are left alone. The webhook exits after 24 hours so PM2 restarts it cleanly. When webhook code changes are deployed, restart the webhook process once so PM2 loads the updated listener: ```sh pm2 reload tssbot-webhook --update-env ``` The webhook listener reads `.env` on startup. To send Discord notifications for listener restarts and GitHub push deploy start/success/failure events, set: ```sh DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/... ``` Deploy completion and failure notifications include a changed-file summary and a truncated patch preview for the pushed diff.