# Programmer Guide

## 1. Codebase Model

`dash.html` is a single-page app with embedded script logic. State, rendering, API calls, and event handlers are in one file.

## 2. Key Runtime State

- `API_KEY`: active Finnhub key.
- `watchlists`: object map of listName -> symbols[]
- `prefs`: persisted UI/runtime preferences.
- `activeList`, `activeList1`, `activeList2`, `activeList3`: selected lists.
- `refreshInFlight`: refresh lock.

## 3. Critical Functions

### Data and API

- `fhFetch(path)`: API wrapper.
- `getQuote(symbol)`: quote retrieval.
- `fetchDjiFromEndpoint()`: dedicated DJI fetch via `api/getDji.php`.
- `fetchIndexFromEndpoint(indexKey)`: generic index fetch via `api/getIndex.php`.
- `fetchMarketStatus()`
- `fetchIndices()`
- `fetchGainersLosers()`
- `fetchWatchlistQuotes()`
- `fetchWatchlistQuotesForCard(cardNum)`

### DJI Dashboard Data Path

- The Dow card on the dashboard now prefers `api/getDji.php?id=a6qja2`.
- If the local endpoint is unreachable, `fetchIndices()` falls back to provider quote APIs.
- Endpoint candidates are attempted in this order:
  - `./api/getDji.php?id=a6qja2`
  - `/fidNew/dash/api/getDji.php?id=a6qja2`
  - `/downloads/dash/api/getDji.php?id=a6qja2`
  - `/api/getDji.php?id=a6qja2`
- The endpoint returns `close`, `change`, `pct`, which map to dashboard fields `c`, `d`, `dp`.

### Multi-Index Endpoint Path

- `fetchIndices()` now attempts endpoint-first fetch for `dji`, `nasdaq`, `sp500`, and `vix`.
- Endpoint URL is `api/getIndex.php?index=<key>`.
- Current MSN ID mappings in endpoint:
  - `dji` -> `a6qja2`
  - `nasdaq` -> `a3oxnm`
  - `sp500` -> `a33k6h`
- `vix` is served by endpoint fallback chain when MSN mapping is unavailable:
  - `stooq-vix-fallback`
  - `fred-vix-fallback`
  - `twelvedata-vix-fallback` (if Stooq returns N/D)
  - `msn-markets-fallback` (if other sources are unavailable)

### UI and Preferences

- `refreshAll()`
- `loadPrefs()`, `savePref()`
- `populateWLSelector()`, `populateWLSelectors()`
- `setActiveListForCard(cardNum, listName)`

### Diagnostics

- `debugLog(msg)`
- `runSelfTests()`
- `testApiCalls()`
- `testWatchlistIntegrity()`

## 4. Development Guidelines

1. Always avoid hardcoded user-input substitutes.
2. Guard all DOM assignments with null checks when applicable.
3. Keep error messages specific (component + symbol/list/card).
4. Keep fetch and render logic idempotent.
5. Persist any new user-facing selection in `savePref()` + `loadPrefs()`.

## 5. Safe Change Checklist

- [ ] Did you update both read and write preference paths?
- [ ] Did you preserve default behavior for empty/missing storage?
- [ ] Did you add debug lines for new async operations?
- [ ] Did you handle rejected promises and partial success?
- [ ] Did you validate selectors and IDs exist in markup?

## 6. Known Risk Areas

- Temporal Dead Zone issues from `let` globals used before initialization.
- Duplicate refresh calls causing mixed logs/results.
- Inconsistent list names between stored preferences and current lists.
- API rate limits causing partial watchlist population.

## 7. Suggested Next Step

Consider splitting script into modules:

- `state.js`
- `api.js`
- `render.js`
- `watchlists.js`
- `diagnostics.js`

This will make testing and maintenance easier.
