Files
pi-multifx-pedal/docs/api-frontend-gap-analysis.md
T

176 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` |
| G1G3 | 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 |