# FXT Dashboard & CLI Completion Design

## Goal

Finalize `fxt` as a fully functional CLI with a live streaming dashboard (`fxt watch`) and all stub commands wired to real gRPC backends.

## Workstream 1: `fxt watch` — Ratatui Streaming Dashboard

### Architecture

Single-binary TUI using ratatui + crossterm. Event loop:

```
tokio::select! {
    msg = grpc_rx.recv()       => update state, mark dirty
    key = crossterm_events()   => handle tab switch / scroll / quit
    _ = tick_interval.tick()   => if dirty { render frame }
}
```

Tick rate: 200ms (5 fps). Only re-render when dirty.

### Tabs

**Tab 1 — Training** (default)
```
┌─ Training ──────────────────────────────────────┐
│ Model    Epoch  Loss     LR       ETA   GPU     │
│ DQN      34/100 0.0023   1e-4     12m   78%     │
│ PPO      12/50  -0.451   3e-4     8m    82%     │
│ TFT      7/200  0.0891   5e-4     45m   91%     │
├─────────────────────────────────────────────────┤
│ Loss ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁▂▃▄▅  (last 200 epochs)   │
│ GPU% ████████████░░░░░░░░  78%                   │
└─────────────────────────────────────────────────┘
```

Feeds: `StreamTrainingMetrics`

**Tab 2 — Trading**
```
┌─ Trading ───────────────────────────────────────┐
│ Symbol   Side  Qty   Entry    PnL     Status    │
│ ES.FUT   LONG  2     5,432    +$340   OPEN      │
│ NQ.FUT   SHORT 1     19,876   -$120   OPEN      │
├─────────────────────────────────────────────────┤
│ Recent Fills                                     │
│ 14:32:01  BUY  ES.FUT  2 @ 5,432  FILLED       │
│ 14:31:45  SELL NQ.FUT  1 @ 19,876 FILLED       │
├─────────────────────────────────────────────────┤
│ Day PnL: +$220  |  Realized: +$580  Unreal: -$360│
└─────────────────────────────────────────────────┘
```

Feeds: `StreamTradingUpdates`

**Tab 3 — Risk**
```
┌─ Risk ──────────────────────────────────────────┐
│ Portfolio VaR (95%): $2,340    Max DD: -3.2%    │
│ Kelly Fraction: 0.34          Leverage: 1.8x    │
├─────────────────────────────────────────────────┤
│ Circuit Breakers                                 │
│ ● Daily Loss      OK    ($220 / $5,000 limit)  │
│ ● Drawdown        OK    (3.2% / 10% limit)     │
│ ● Volatility      OK    (VIX 18.3 / 40 limit)  │
│ ○ Kill Switch     ARMED                         │
└─────────────────────────────────────────────────┘
```

Feeds: `StreamRiskMetrics`

**Tab 4 — System**
```
┌─ System ────────────────────────────────────────┐
│ Service              Status    Latency   Uptime │
│ api-gateway          ● UP      2ms       14d    │
│ trading-service      ● UP      1ms       14d    │
│ ml-training          ● UP      3ms       6h     │
│ trading-agent        ● UP      1ms       14d    │
├─────────────────────────────────────────────────┤
│ GPU: ████████████░░░░ 78%  VRAM: 32/48 GB      │
│ CPU: ██████░░░░░░░░░░ 38%  RAM:  42/128 GB     │
└─────────────────────────────────────────────────┘
```

Feeds: `StreamSystemHealth`, `StreamGpuMetrics`

### Key Bindings

`1-4` switch tabs, `j/k` scroll, `q` quit

### State Model

Single `DashboardState` with per-tab substates. Ring buffers (200 points) for chart data.

### gRPC Streams

One `tokio::spawn` per stream, all feed a single `mpsc::channel<StreamEvent>`. Reconnect with exponential backoff (1s→30s).

### Dependencies

`ratatui = "0.29"`, `crossterm = "0.28"` in `bin/fxt/Cargo.toml`.

## Workstream 2: Wire Stub Commands

### A. Uncomment Only

| Command | Fix |
|---------|-----|
| `fxt tune start --watch` | Uncomment `pub mod tune_stream;` in `commands/mod.rs:27`. Full implementation exists. |

### B. Wire to Existing RPCs

| Command | Current | Fix |
|---------|---------|-----|
| `fxt model list` | Placeholder text | Call `MLTrainingService::ListModels`. Display table. |
| `fxt agent allocate-portfolio` | Hardcoded mock assets | Replace mock block (agent.rs:192-212) with `GetSelectedAssets(selection_id)`. |
| `fxt auth login` (non-interactive) | Simulated JWT | Use same `LoginClient` as interactive path, pass args. |

### C. New Proto RPCs

| Command | RPC | Proto | Request | Response |
|---------|-----|-------|---------|----------|
| `fxt model approve` | `ApproveModel` | ml_training.proto | `{model_id, promoted_to}` | `{success, message}` |
| `fxt model reject` | `RejectModel` | ml_training.proto | `{model_id, reason}` | `{success, message}` |

Server handlers in `ml_training_service/`: move checkpoint, update DB status.

## Workstream 3: Testing

- Unit: state update functions with mock `StreamEvent` data
- Unit: all fixed commands with mock gRPC servers
- Integration: spawn mock server, run dashboard 2s, assert no panic
- Existing tests: 134 fxt tests must stay green

## Not In Scope

- Custom themes / color configuration
- Mouse support
- Persisted layout preferences
- Log file export from dashboard
