# Phase D — Chart MVP (scope)

**Status:** Complete (v0.3.0)  
**Baseline rollback:** v0.2.0 @ `70c6e80` (Phase C application)

## Delivered

- Controlled **7 FX symbols** and **6 timeframes** (server-validated)
- `GET /api/candles?symbol=&timeframe=&count=` (optional count, capped)
- OANDA practice adapter unchanged in security model (server-only token)
- **TradingChart** UI: symbol/timeframe selects, manual **Refresh**, **Fit**
- Dynamic chart updates without full page reload; stale-response guard
- Short-lived in-memory cache + in-flight dedupe (30s TTL)
- Completed candles only (incomplete OANDA bars excluded)

## Supported symbols

| Symbol | OANDA practice (2026-10-02) |
|--------|-----------------------------|
| EUR_USD | PASS |
| GBP_USD | PASS |
| USD_JPY | PASS |
| AUD_USD | PASS |
| USD_CAD | PASS |
| USD_CHF | PASS |
| NZD_USD | PASS |

## Supported timeframes

| UI | OANDA granularity |
|----|-------------------|
| M5 | M5 |
| M15 | M15 |
| M30 | M30 |
| H1 | H1 |
| H4 | H4 |
| D | D |

## API

**Route:** `GET /api/candles`

| Query | Required | Notes |
|-------|----------|--------|
| `symbol` | Yes | Must be in supported list |
| `timeframe` | Yes | M5, M15, M30, H1, H4, D |
| `count` | No | Default **100**, max **500** |

## Refresh

- **Manual** Refresh button only (no auto-polling / no WebSocket in Phase D)
- Refresh bypasses client state; server cache may serve identical request within 30s TTL

## Caching (Phase D)

See [ADR-002](../decisions/ADR-002-phase-d-memory-cache.md).

## Out of scope (unchanged)

Phase E warehouse, indicators, backtest, auth, watchlists, alerts, FXCM, PWA, deploy.

## Tests

- 15 unit/integration tests (`npm test`)
- Live practice verification: all symbol × timeframe combinations (local `.env`)

## Known limitations

- Symbol list is fixed in code (not full OANDA catalog)
- Cache is process-local (not shared across server instances)
- No forming/incomplete candle on chart
