176 lines
9.2 KiB
Markdown
176 lines
9.2 KiB
Markdown
# API ↔ Frontend Gap Analysis — Pi Multi-FX Pedal Web UI
|
||
|
||
**Date:** June 14, 2026
|
||
**Scope:** All backend API routes vs. calls from Legacy Jinja2 UI + React SPA
|
||
|
||
---
|
||
|
||
## Summary
|
||
|
||
| Metric | Count |
|
||
|--------|-------|
|
||
| Total backend API routes | **76** |
|
||
| Routes called by at least one frontend | **57** |
|
||
| Routes with NO frontend consumer | **10** (+ 2 alias endpoints) |
|
||
| Critical bugs found | **2** |
|
||
| Missing features (backend exists, no UI) | **5** |
|
||
|
||
---
|
||
|
||
## Changes Applied — Fixed Items
|
||
|
||
| # | Item | Status | Files Changed |
|
||
|---|------|--------|--------------|
|
||
| B1 | IR Install on IRs page broken — `installToneIR` added to irs.js | ✅ Fixed | `irs.js`, `models.js` |
|
||
| G6 | Tuner pitch display — note + cents bar + string indicator on dashboard | ✅ Added | `app.js`, `dashboard.html`, `style.css` |
|
||
| G1–G3 | Audio profile selector — dropdown with JACK status in Settings > Audio | ✅ Added | `app.js`, `settings.html`, `style.css` |
|
||
| G4 | FX chain clickable toggles — each block toggles ON/OFF via `PATCH /api/blocks` | ✅ Added | `app.js`, `style.css` |
|
||
| O1 | FX type labels — proper label map (FX_TYPE_LABELS) instead of `replace(/_/g,' ')` | ✅ Added | `app.js` |
|
||
| B2 | `installToneIR` removed from models.js (was duplicated, used wrong localStorage key) | ✅ Fixed | `models.js` |
|
||
|
||
---
|
||
|
||
## 1. Backend APIs NOT Called by Any Frontend
|
||
|
||
These are routes defined in `server.py` that neither the legacy UI (`static/`) nor the React SPA (`ui-dist/`) ever calls.
|
||
|
||
### Tier 1 — Full Features Without UI
|
||
|
||
| # | Route | Method | Endpoint exists but | Why it matters |
|
||
|---|-------|--------|--------------------|---------------|
|
||
| G1 | `/api/audio/profile` | GET | No UI to read current audio profile | Users can't see what latency profile is active |
|
||
| G2 | `/api/audio/profiles` | GET | No UI to list available profiles | Users can't see what options exist |
|
||
| G3 | `/api/audio/profile` | POST | No UI to switch profiles | Users can't switch between standard/low latency! |
|
||
| G4 | `PATCH /api/blocks` | PATCH | No UI to enable/disable individual FX blocks | FX chain shown on dashboard is display-only — can't toggle blocks on/off |
|
||
| G5 | `PATCH /api/block` | PATCH | No UI to update individual block params | Can't tweak per-block settings (drive, level, mix, etc.) |
|
||
| G6 | `GET /api/tuner/pitch` | GET | No tuner pitch display UI | Tuner toggle works but you can't *see* what note you're playing |
|
||
|
||
### Tier 2 — Secondary / Alternative Endpoints
|
||
|
||
| # | Route | Method | Notes |
|
||
|---|-------|--------|-------|
|
||
| G7 | `GET /api/routing` | GET | Both UIs only POST routing changes and rely on WS for state — GET is defined but never read separately |
|
||
| G8 | `GET /api/channel-mode` | GET | SPA POSTs to set channel mode but never GETs current mode — relies on `/api/state` snapshot |
|
||
| G9 | `POST /api/bypass/toggle` | POST | Alias — both UIs call `/api/bypass` directly |
|
||
|
||
### Tier 3 — External Content Sources (No UI)
|
||
|
||
| # | Route | Method | Notes |
|
||
|---|-------|--------|-------|
|
||
| G10 | `GET /api/tonedownload/status` | GET | Tone3000 connection status — never queried by UI |
|
||
| G11 | `GET /api/tonehub/search` | GET | ToneHub search — never called (Tone3000 preferred) |
|
||
| G12 | `GET /api/tonehub/search/irs` | GET | ToneHub IR search — never called |
|
||
|
||
### Tier 4 — Unused Alias
|
||
|
||
| # | Route | Method | Notes |
|
||
|---|-------|--------|-------|
|
||
| G13 | `POST /api/volume` | POST | POST alias for volume — legacy UI calls `apiPut('/volume')`, SPA... see below |
|
||
|
||
---
|
||
|
||
## 2. Critical Bugs Found
|
||
|
||
### Bug B1 — IR Install on IRs Page is Broken
|
||
|
||
**File:** `src/web/static/irs.js:197` calls `installToneIR()` but function only exists in `models.js:235`
|
||
|
||
**Root cause:** The Tone3000 IR search results on the `/irs` page render "Install" buttons that call `installToneIR()`. This function is defined in `models.js`, which is loaded on the **Models page** (`/models`). The **IRs page** (`/irs`) loads `irs.js`, which does NOT define `installToneIR()` — the function appears in `irs.js` only as a call reference (line 197), not a definition.
|
||
|
||
**Impact:** Clicking "Install" on any Tone3000 IR result from the IRs page throws `ReferenceError: installToneIR is not defined`. The button action silently fails.
|
||
|
||
**Fix:** Either (a) copy the entire `installToneIR()` function (lines 235-256) from `models.js` into `irs.js`, or (b) extract the shared Tone3000 install logic into a shared module loaded by both pages.
|
||
|
||
```bash
|
||
# Confirm the gap
|
||
grep -n 'function installToneIR' src/web/static/*.js
|
||
# → only in models.js:235, NOT in irs.js
|
||
grep -n 'installToneIR' src/web/static/irs.js
|
||
# → line 197 is a CALL to it (onclick=...), not a definition
|
||
```
|
||
|
||
### Bug B2 — `installToneIR` Duplicated Across Files
|
||
|
||
**File:** Models page (`/models`) also has IR install logic.
|
||
|
||
`installToneIR` is defined in `models.js:235` (not just `installToneModel`). This means the Models page can install IR files via the Tone3000 button embedded in model search results — which makes no sense. The function is cargo-culted but only the `installToneModel` variant is relevant to the Models page.
|
||
|
||
---
|
||
|
||
## 3. Underserved Features (Present in Backend, Weak UI)
|
||
|
||
| # | Feature | Has UI? | Details |
|
||
|---|---------|---------|---------|
|
||
| F1 | **Tuner pitch display** | ❌ | `GET /api/tuner/pitch` returns frequency, note name, cents, string — but zero UI renders it. The tuner toggle exists but you get no visual feedback about what note you're playing |
|
||
| F2 | **Per-block FX control** | ❌ | `PATCH /api/blocks` (toggle) and `PATCH /api/block` (params) are never called. The dashboard shows an FX chain but it's display-only — can't toggle blocks or tweak knobs from the web UI |
|
||
| F3 | **Audio profile switching** | ❌ | `GET/POST /api/audio/profile` and `GET /api/audio/profiles` exist but no UI anywhere. Users must use curl to switch latency profiles |
|
||
| F4 | **Channel mode display** | ⚠️ | SPA shows channel mode in the header (STEREO badge or GUITAR/BASS toggle). But `GET /api/channel-mode` is never called — the value comes from the `/api/state` snapshot. Legacy UI has no channel mode awareness at all |
|
||
| F5 | **Snapshots** | ⚠️ | Snapshots exist in SPA only (save/recall/rename/delete via modal). Legacy UI has zero snapshot support |
|
||
|
||
---
|
||
|
||
## 4. Feature Parity: Legacy UI vs React SPA
|
||
|
||
| Feature | Legacy (`static/`) | React SPA (`ui-dist/`) |
|
||
|---------|-------------------|----------------------|
|
||
| Dashboard + status | ✅ Full | ✅ Full |
|
||
| Preset browse + activate | ✅ Full | ✅ Full |
|
||
| Preset edit (rename, volume) | ✅ Modal-based | ✅ Inline |
|
||
| Preset create | ❌ | ✅ "New Preset" button |
|
||
| Preset delete | ✅ With confirm | ✅ With confirm (inline) |
|
||
| Model browse + load | ✅ Full | ✅ Full |
|
||
| Model upload | ✅ | ✅ |
|
||
| Tone3000 search (models) | ✅ | ✅ |
|
||
| Tone3000 install (models) | ✅ | ✅ |
|
||
| IR browse + load | ✅ Full | ✅ Full |
|
||
| IR upload | ✅ | ✅ |
|
||
| Tone3000 search (IRs) | ✅ | ❌ Broken (Bug B1) |
|
||
| Tone3000 install (IRs) | ❌ Broken (Bug B1) | ✅ |
|
||
| Bypass toggle | ✅ | ✅ |
|
||
| Volume control | ✅ | ✅ |
|
||
| Tuner toggle | ✅ | ✅ |
|
||
| **Tuner pitch display** | **❌** | **❌** |
|
||
| 4CM routing toggle | ✅ | ✅ |
|
||
| **Per-block FX toggle** | **❌** | **❌** |
|
||
| **Per-block param edit** | **❌** | **⚠️** (block-params schema fetched) |
|
||
| **Audio profile switch** | **❌** | **❌** |
|
||
| WiFi scan + connect | ✅ | ✅ |
|
||
| Hotspot enable/disable | ✅ | ✅ |
|
||
| Bluetooth scan + pair + connect | ✅ | ✅ |
|
||
| Bluetooth MIDI enable/disable | ✅ | ✅ |
|
||
| Snapshots save/recall | ❌ | ✅ Full (CRUD) |
|
||
| Capture/record audio | ❌ | ✅ Full (start/stop/list/play) |
|
||
| Channel mode (dual-mono/stereo) | ❌ | ✅ (Settings → Routing) |
|
||
|
||
---
|
||
|
||
## 5. Source of Truth Verification
|
||
|
||
```bash
|
||
# Complete list of backend API routes:
|
||
grep -oP '@app\.\w+\(["'"'"']/api/[^"'"'"']+' src/web/server.py | sed "s/@app\.//" | sort
|
||
|
||
# Complete list of API calls from legacy JS:
|
||
grep -roP "apiGet\('/[^']+|apiPost\('/[^']+|apiPut\('/[^']+|apiDelete\('/[^']+|fetch\('/api[^']+" src/web/static/ | sed "s/.*api\(Get\|Post\|Put\|Delete\)('//;s/fetch('/\/api/" | sort -u
|
||
|
||
# Complete list of API calls from React SPA bundle:
|
||
grep -oP '`/api/[^`]+`' src/web/ui-dist/assets/index-CxlwZhqE.js | sort -u
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Remaining Gaps (Not Addressed)
|
||
|
||
These are lower-priority items that still have no frontend consumer:
|
||
|
||
| # | Route | Method | Notes |
|
||
|---|-------|--------|-------|
|
||
| G7 | `GET /api/routing` | GET | Both UIs only POST routing and rely on WS for state — GET exists but is redundant |
|
||
| G8 | `GET /api/channel-mode` | GET | SPA POSTs to set mode but gets current state from `/api/state` snapshot — low value |
|
||
| G9 | `POST /api/bypass/toggle` | POST | Alias endpoint — both UIs call `/api/bypass` directly |
|
||
| G10 | `GET /api/tonedownload/status` | GET | Tone3000 connection status — no UI indicator, minor |
|
||
| G11 | `GET /api/tonehub/search` | GET | ToneHub — never wired up in favor of Tone3000 |
|
||
| G12 | `GET /api/tonehub/search/irs` | GET | ToneHub IR search — never wired up |
|
||
| G13 | `POST /api/volume` | POST | POST alias — legacy calls PUT, SPA calls POST; both work |
|
||
| G14 | Per-block param editing (`PATCH /api/block`, `GET /api/block-params/{fx_type}`) | PATCH/GET | Block param sliders still need a UI — tracked in UX review test plan |
|