# Phase C — Development foundation (scope)

**Status:** **Complete** (v0.2.0)  
**Prerequisite:** Phase A–B gate closed (v0.1.0 @ `bc3795f`).

## Implemented deliverable

```text
Next.js 15 + TypeScript app
  → GET /api/candles?symbol=EUR_USD&timeframe=H1
  → OANDA practice adapter (server-only token)
  → normalized OHLC (tick volumeType)
  → Lightweight Charts candlestick (EUR/USD H1)
```

## Data flow

```text
Browser (EurUsdChart client)
  → fetch /api/candles?symbol=EUR_USD&timeframe=H1
  → app/api/candles/route.ts
  → validatePhaseCChartRequest()
  → getPhaseCCandles()
  → fetchOandaCandles()  [count=100, complete bars only]
  → normalizeOandaCandle()  (mid prices, volumeType=tick)
  → JSON ChartCandle[] to client
  → Lightweight Charts CandlestickSeries
```

## Endpoint

| Method | Path | Query | Phase C values |
|--------|------|-------|----------------|
| GET | `/api/candles` | `symbol`, `timeframe` | `EUR_USD`, `H1` only |

**Success (200):** `{ symbol, timeframe, source, volumeType, candles: [{ time, open, high, low, close }] }`  
**Errors:** `{ error: { code, message } }` — codes: `VALIDATION_ERROR`, `CONFIG_MISSING`, `CONFIG_INVALID`, `AUTH_FAILED`, `PROVIDER_ERROR`, `APP_ERROR`

## Environment variables (server-only)

| Variable | Required | Notes |
|----------|----------|--------|
| `OANDA_API_TOKEN` | Yes | Practice personal access token |
| `OANDA_ENVIRONMENT` | Yes | Must be `practice` in Phase C |
| `OANDA_ENV` | Fallback | Alias for environment |
| `OANDA_ACCOUNT_ID` | No | Not used for instrument candles |

Copy `.env.example` → `.env` (never commit `.env`).

**OANDA practice base URL (hard-coded for Phase C):** `https://api-fxpractice.oanda.com`  
**Upstream:** `GET /v3/instruments/{instrument}/candles?price=M&granularity=H1&count=100`

## Code map

| Area | Path |
|------|------|
| API route | `app/api/candles/route.ts` |
| OANDA adapter | `lib/brokers/oanda/adapter.ts` |
| Config | `lib/brokers/oanda/config.ts` |
| Normalization | `lib/brokers/oanda/normalize.ts` |
| Validation | `lib/market/validation.ts` |
| Types | `lib/market/types.ts` |
| Chart UI | `components/EurUsdChart.tsx` |
| Page | `app/page.tsx` |

## Dependencies (Phase C)

| Package | License | Role |
|---------|---------|------|
| next | MIT | App + API routes |
| react / react-dom | MIT | UI |
| lightweight-charts | Apache-2.0 | Chart engine |
| typescript | Apache-2.0 | Types |
| vitest | MIT | Unit tests |
| eslint-config-next | MIT | Lint |

No database, Redis, auth, or paid services.

## Tests

```bash
npm test          # normalization, validation, API (mocked fetch)
npm run typecheck
npm run lint
npm run build
```

## Verification checklist

- [x] `npm run build` PASS
- [x] `npm test` PASS
- [x] Missing `OANDA_API_TOKEN` → controlled 503 CONFIG_MISSING
- [x] Invalid symbol → 400 VALIDATION_ERROR
- [x] API response never contains bearer token (automated test)
- [x] Live OANDA chart with user practice token (manual — requires local `.env`)

## LIVE OANDA PRACTICE VERIFICATION

**Date:** 2026-10-02  
**Environment:** OANDA Practice (`OANDA_ENVIRONMENT=practice`, local `.env`)  
**Symbol:** EUR_USD  
**Timeframe:** H1  

| Check | Result |
|-------|--------|
| Live API (practice) | PASS — 99 complete H1 bars returned |
| Normalization | PASS — `source=oanda`, `volumeType=tick`; OHLC + unix `time` on candles |
| Chart rendering | PASS — candlesticks visible, not blank |
| Interaction | PASS — Lightweight Charts default pan/zoom/crosshair (visual verification) |
| Credential exposure | PASS — no token/Bearer in `/` HTML or `/api/candles` JSON |
| Application `/` | PASS — HTTP 200 |
| Build | Previously PASS (v0.2.0) |
| Automated tests | Previously 9/9 PASS |

**Note:** Run `npm run dev` from `TradingBite-Platform` and use the URL printed in the terminal (if port 3000 is busy, Next.js may use 3003+). Stale servers on other ports may show old loading UI without `.env`.

## Gate C (Phase C)

**Small history proof:** **100** complete H1 bars per request (not warehouse / not 1-year download).

## Explicitly still out of scope

Phases D+ (multi-TF UI, warehouse, indicators, drawings, backtest, auth, FXCM, alerts, watchlists).

## Known limitations

- Single symbol/timeframe hard-validated server-side.
- Incomplete (forming) OANDA candles excluded from series.
- Live chart verification depends on user-supplied practice token in local `.env`.
- Mid prices only (`price=M`).
