# LiveTradingHours — Settings & Configuration Reference

**Last updated:** 2026-06-19  
**Purpose:** One place to remember what each setting does, where it lives, and when you need it.

---

## Quick cheat sheet

| What you want | Where to set it |
|---------------|-----------------|
| Run locally | `scripts/run_TimeZone_server.bat` or `npm start` → **http://localhost:4783** |
| Local env file | Copy `config/.env.example` → `server/.env` |
| Open design portal without login (dev only) | `ADMIN_ENABLED=true` in `server/.env` |
| Economic calendar on production | `RAPIDAPI_KEY` in Render dashboard |
| Google / Outlook calendars | OAuth vars in Render + provider console callback URLs |
| Public REST API access | User generates key in admin portal (OAuth) **or** static `API_KEYS` env |
| Check if server is healthy | `GET /api/public/status` |
| Check auth / admin gate | `GET /api/auth/status` |

---

## Local development

### Start and stop

| Action | Command |
|--------|---------|
| Start (Windows) | Double-click `scripts/run_TimeZone_server.bat` |
| Stop (Windows) | `scripts/stop_TimeZone_server.bat` or Ctrl+C in the server window |
| Start (any OS) | From repo root: `npm start` |
| Run tests | `npm test` (from repo root or `server/`) |

**Default URL:** http://localhost:4783  
**Port:** Set `PORT=4783` in `server/.env`. If you still have `PORT=8000`, change it or the app and scripts will disagree.

### First-time setup

```bash
# Windows
copy config\.env.example server\.env

# macOS / Linux
cp config/.env.example server/.env
```

Edit `server/.env`. Minimum for local dev:

```env
SESSION_SECRET=any-long-random-string-here
PORT=4783
```

Optional but useful locally:

```env
ADMIN_ENABLED=true          # Shows gear icon (design portal) without OAuth
RAPIDAPI_KEY=your_key       # Enables economic calendar section
```

**Never commit `server/.env`** — it may contain secrets.

---

## Server environment variables

File: **`server/.env`** (local) or **Render → Environment** (production).  
Template: **`config/.env.example`**

### Core server

| Variable | Required | Default | What it does |
|----------|----------|---------|--------------|
| `PORT` | No | `4783` | HTTP port. Render sets this automatically. |
| `NODE_ENV` | No | `development` | `production` enables stricter checks (Redis, session secret). |
| `SESSION_SECRET` | **Yes in production** | — | Signs session cookies. Render auto-generates via `render.yaml`. Dev fallback is insecure if unset. |
| `REDIS_URL` | **Yes in production** | — | Sessions, API key storage, holiday cache. Wired from Render Key Value in `render.yaml`. |

### Economic calendar

| Variable | Required | Default | What it does |
|----------|----------|---------|--------------|
| `RAPIDAPI_KEY` | No | empty | Server-side key for [RapidAPI Economic Calendar](https://rapidapi.com/yasimpratama88/api/economic-calendar-api). **Never stored in the browser.** |

If missing: economic news section loads empty; admin portal shows “not configured”.

### OAuth — Google Calendar

| Variable | Required | What it does |
|----------|----------|--------------|
| `GOOGLE_CLIENT_ID` | All three needed to enable | Google Cloud OAuth client |
| `GOOGLE_CLIENT_SECRET` | | |
| `GOOGLE_CALLBACK_URL` | | Must match Google console exactly, e.g. `http://localhost:4783/auth/google/callback` (local) or `https://livetradinghours.com/auth/google/callback` (prod) |

If any missing: Google login routes are not registered; “Connect Google” still visible in portal but redirect may fail.

### OAuth — Microsoft / Outlook

| Variable | Required | What it does |
|----------|----------|--------------|
| `MICROSOFT_CLIENT_ID` | All three needed to enable | Azure app registration |
| `MICROSOFT_CLIENT_SECRET` | | |
| `MICROSOFT_CALLBACK_URL` | | e.g. `http://localhost:4783/auth/microsoft/callback` or production URL |

### Security & API access

| Variable | Required | Default | What it does |
|----------|----------|---------|--------------|
| `API_KEYS` | No | empty | Comma-separated static keys for `/api/public/*`. Empty in dev = API key check relaxed for local testing. |
| `RATE_LIMIT_WINDOW` | No | `60000` | Rate limit window in milliseconds. |
| `RATE_LIMIT_MAX` | No | `100` | Max requests per IP per window. |
| `ALLOWED_ORIGINS` | No | — | Extra CORS origins (comma-separated), e.g. staging domain. |
| `APP_URL` | No | — | Primary site URL for CORS allowlist (e.g. `https://livetradinghours.com`). |

### Admin portal

| Variable | Required | Default | What it does |
|----------|----------|---------|--------------|
| `ADMIN_ENABLED` | No | off | Local dev only — full design portal without OAuth. **Never enable on Render.** |
| `DESIGN_PORTAL_EMAILS` | No | empty | Comma-separated emails that get **full** design portal in production (must match OAuth login). |

---

## Production (Render)

Blueprint: **`render.yaml`**

### Set automatically (do not type manually)

| Variable | Source |
|----------|--------|
| `NODE_ENV` | `production` |
| `SESSION_SECRET` | Auto-generated |
| `REDIS_URL` | Linked from `livetradinghours-redis` Key Value service |
| Health check | `/api/public/status` |

### You enter in Render dashboard

| Variable | Needed for |
|----------|------------|
| `RAPIDAPI_KEY` | Economic calendar |
| `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`, `GOOGLE_CALLBACK_URL` | Google Calendar |
| `MICROSOFT_CLIENT_ID`, `MICROSOFT_CLIENT_SECRET`, `MICROSOFT_CALLBACK_URL` | Outlook Calendar |
| `APP_URL` | Optional — CORS for custom domain |
| `ALLOWED_ORIGINS` | Optional — extra origins |
| `API_KEYS` | Optional — static keys instead of per-user keys |
| `DESIGN_PORTAL_EMAILS` | Your email(s) for full design portal (owner only) |

### Post-deploy checks

```bash
curl https://livetradinghours.com/api/public/status
curl https://livetradinghours.com/api/auth/status
```

- `/api/public/status` → `200` JSON → server up
- `/api/auth/status` → JSON (not `Cannot GET`) → correct service and Sprint 7+ code deployed
- Page source includes `main.js?v=20260619` (or newer) after gating fixes
- `economicCalendarConfigured: true` → `RAPIDAPI_KEY` is set
- `designPortalAvailable: true` → signed-in email matches `DESIGN_PORTAL_EMAILS` (or local `ADMIN_ENABLED`)
- Logged out: `designPortalAvailable: false` → gear shows limited mode (calendar + help only)

### Post-deploy checklist (Render dashboard)

1. **One web service** — GitHub auto-deploy and custom domain on the same service
2. **`REDIS_URL`** — linked from `livetradinghours-redis` (required; deploy crashes without it)
3. **`DESIGN_PORTAL_EMAILS`** — your Google/Microsoft login email for full design portal
4. **OAuth + `RAPIDAPI_KEY`** — copy from previous service if migrating
5. **Delete or suspend** any duplicate Blueprint web service (keep `livetradinghours-redis`)

---

## Deploy troubleshooting

| Symptom | Likely cause | Fix |
|---------|--------------|-----|
| `Cannot GET /api/auth/status` | Custom domain on old service, or deploy failed | Point domain at service with latest deploy; check build logs |
| Old UI after push (no settings gating) | Two web services; pushes go to wrong one | Consolidate to one service; verify `main.js` cache-bust version in page source |
| Deploy `Exited with status 1` | `[Startup] FATAL: REDIS_URL is required` | Link Key Value `livetradinghours-redis` in Environment before deploying |
| Domain already exists on another site | Domain still on duplicate service | Remove domain from old service, then add to target service |
| Blueprint created extra services | `render.yaml` synced with existing manual setup | Migrate env + domain; suspend duplicate web service only (keep Redis) |
| Settings visible when logged out | Old client bundle cached or old service | Hard refresh; confirm `/api/auth/status` returns JSON with `designPortalAvailable: false` |

---

## In-app UI: what is public vs gated

| Control | Who sees it |
|---------|-------------|
| **Theme toggle** (sun/moon) | Everyone |
| **Gear icon** | OAuth configured, signed in, or `ADMIN_ENABLED` (local dev) |
| **Design customization & API keys** | Owner email in `DESIGN_PORTAL_EMAILS` only |

### Gear portal modes

| Mode | When | What’s inside |
|------|------|----------------|
| **Limited** | Everyone (default, including after OAuth sign-in) | Calendar connect, enable calendars, settings reference |
| **Full** | Owner email + signed in, or `ADMIN_ENABLED` locally | Design colors, API keys, export/import |

---

## Browser storage (localStorage)

These persist **in your browser** on this device. They sync to the server when logged in (see `client/js/persistence.js`).

### Layout & display

| Key | Stores |
|-----|--------|
| `homeCity` | Home clock city name |
| `viewOffset` | UTC time-shift (hours) |
| `currentFilter` | Market filter: `all`, `stock`, `forex`, `crypto` |
| `currentPreset` | City preset name |
| `selectedCities` | JSON array of visible timezone cities |
| `customCities` | JSON array of user-added cities |
| `isManualOrder` | Whether timezone row order was dragged manually |
| `marketsVisible` | Markets section on/off |
| `timeZonesVisible` | Time zones section on/off |
| `strategyTemplatesVisible` | Strategy section on/off |
| `economicVisible` | Economic section on/off |
| `showPastEvents` | Show past calendar/economic events |
| `timeFormat` | `12h` or `24h` |

### Theme & design (admin portal)

| Key | Stores |
|-----|--------|
| `themeMode` | `dark` or `light` |
| `layoutSettings` | JSON — spacing, timeline sizes (non-color) |
| `darkColorSettings` | JSON — dark mode colors |
| `lightColorSettings` | JSON — light mode colors |
| `themeSettings` | Legacy combined theme blob (migrated on load) |

### Strategy templates

| Key | Stores |
|-----|--------|
| `strategyTemplates` | JSON — saved templates and notification prefs |
| `strategyOrder` | JSON — manual sort order |
| `isStrategyManualOrder` | Strategy list manually reordered |
| `templateNotifications` | Global template notification permission flag |

### Calendar (OAuth)

| Key | Stores |
|-----|--------|
| `enabledCalendars` | JSON array of calendar IDs shown on timeline |

Clears when you disconnect OAuth or sign out.

### Cache (safe to delete)

| Key | Stores |
|-----|--------|
| `economicNewsCache` | Cached economic API response (~15 min) |

**Removed in Sprint 7:** `rapidApiKey` — no longer used; key is server-only.

---

## Authentication & sessions

| Topic | Detail |
|-------|--------|
| **Browser session** | Cookie from `/api/public/session-touch` — used by the web UI for API calls |
| **OAuth login** | `/auth/google` or `/auth/microsoft` — stores tokens **server-side only** |
| **Token storage** | Redis (prod) or file store (dev). See [OAUTH_TOKENS.md](OAUTH_TOKENS.md) |
| **Status endpoint** | `GET /api/auth/status` → `{ authenticated, providers[], adminPortalAvailable, economicCalendarConfigured }` |
| **Disconnect** | `POST /auth/disconnect/google` or `.../microsoft` |
| **Logout** | `POST /auth/logout` — destroys session |

OAuth tokens are **never** sent to JavaScript or API JSON responses.

---

## API keys (two mechanisms)

| Type | Where | Who uses it |
|------|-------|-------------|
| **Per-user key** | Generated in admin portal after OAuth | Your scripts/apps — header `X-API-Key` |
| **Static keys** | `API_KEYS` env (comma-separated) | Server ops / integrations without OAuth |

Public endpoints: `/api/public/markets`, `/api/public/timezones`, etc.  
Docs: [API_README.md](API/API_README.md)

---

## Startup log (what the server prints)

On boot, the server logs OAuth and integration status:

```
--- [OAuth] Startup Status ---
Environment: DEVELOPMENT | PRODUCTION
Google OAuth: ENABLED | DISABLED (missing credentials)
Microsoft OAuth: ENABLED | DISABLED (missing credentials)
RapidAPI Key: CONFIGURED (...) | MISSING
Redis URL: CONFIGURED | MISSING
```

Use this to confirm `.env` is loaded correctly.

---

## Troubleshooting

| Symptom | Likely cause | Fix |
|---------|--------------|-----|
| Connection refused on :4783 | Server not running | Run `run_TimeZone_server.bat` or `npm start` |
| Connection refused on :8000 | Old bookmark or `PORT=8000` in `.env` | Use :4783 or update `PORT` |
| No gear icon | OAuth not configured on server and not signed in | Set Google/Microsoft env vars on Render, or `ADMIN_ENABLED=true` locally |
| Gear icon but “sign in required” | Stale page | Refresh; check `/api/auth/status` |
| Can't connect calendar | OAuth not configured | Add OAuth env vars; use gear → Calendar Integration |
| Economic section empty | No `RAPIDAPI_KEY` on server | Add to `server/.env` or Render |
| OAuth redirect error | Callback URL mismatch | Match env URL to Google/Azure console exactly |
| `REDIS_URL is required` on deploy | Production without Redis | Use `render.yaml` Key Value link |
| Port already in use | Second server instance | Run `stop_TimeZone_server.bat` or kill the process |

---

## Related documents

| Document | Contents |
|----------|----------|
| [README.md](../README.md) | Quick start, project overview |
| [ROADMAP.md](../ROADMAP.md) | Engineering backlog and sprint history |
| [config/.env.example](../config/.env.example) | Copy-paste env template |
| [OAUTH_TOKENS.md](OAUTH_TOKENS.md) | OAuth token lifecycle and security |
| [API/API_README.md](API/API_README.md) | REST API usage |
| [USER/USER_PERSISTENCE_SOLUTIONS.md](USER/USER_PERSISTENCE_SOLUTIONS.md) | Strategy notification persistence |

---

## File locations (quick map)

```
config/.env.example     ← template (commit this)
server/.env             ← your local secrets (never commit)
render.yaml             ← Render auto-config
scripts/*.bat           ← Windows start/stop
docs/SETTINGS.md        ← this file
client/js/admin-access.js   ← admin portal visibility gate
client/js/admin-handlers.js ← design portal + OAuth UI logic
server/config/env.js        ← reads all env vars
```
