# TuneVault App-Wide Error & UI Sweep — 2026-05-11

**Task:** #1515184 — Audit every route for console errors, 404s, broken JS, hanging spinners, mobile responsiveness (375px / 768px). Fix anything broken.

---

## Summary of Fixes

| File | Issue | Fix |
|------|-------|-----|
| `db/ebs-deep.js` | `getEbsConnections` joined `health_checks` on column `hc.results` which does not exist → **500 on every EBS connections request** | Rewrote query to select directly from `oracle_connections WHERE is_ebs = true` |
| `public/nav-component.js` | `navRoot.style.padding = '16px 48px'` set as inline JS style — overrides all CSS `@media` rules → **nav unusable at 375px (96px padding consumed entire viewport)** | Responsive padding: `16px` at <600px, `24px` at <900px, `32/48px` at desktop |
| `public/ebs-deep.html` | Missing `overflow-x: hidden` on `body` | Added |
| `public/dashboard.html` | Missing `overflow-x: hidden` on `body` | Added |
| `public/report.html` | Missing `overflow-x: hidden` on `body` | Added |
| `public/pricing.html` | Missing `overflow-x: hidden` on `body` | Added |

---

## Route Audit

### `/` (index.html)
| Check | Status |
|-------|--------|
| Console errors | ✅ None — clean HTML, no broken JS references |
| 404s | ✅ All assets resolve (favicon.svg, nav-component.js, fonts) |
| Hanging spinners | ✅ No spinners on index page |
| Mobile 375px | ✅ `overflow-x: hidden` on body; responsive CSS present |
| Mobile 768px | ✅ Media queries at 768px confirmed |
| Auth-aware nav | ✅ `tvNav.init('public')` wired |

### `/login`
| Check | Status |
|-------|--------|
| Console errors | ✅ None |
| Magic link flow | ✅ POST `/api/auth/magic-link/request`, success message shown, button re-enables |
| Google OAuth | ✅ Hidden unless `GOOGLE_CLIENT_ID` configured (checked via `/api/auth/config`) |
| Error states | ✅ `?error=invalid_or_expired` etc. handled |
| Already logged in | ✅ Redirects to `/dashboard` if session active |

### `/pricing`
| Check | Status |
|-------|--------|
| Console errors | ✅ None |
| Razorpay integration | ✅ CDN script loaded, `typeof Razorpay === 'undefined'` guard present |
| Payment flow | ✅ Creates Razorpay order via `/api/razorpay-key`, verifies via `/api/verify-payment` |
| Mobile 375px | ✅ overflow-x: hidden added; pricing cards have responsive grid |
| Hanging spinners | ✅ None — payment button re-enables on error |

### `/dashboard`
| Check | Status |
|-------|--------|
| Console errors | ✅ None |
| Demo mode (`?demo=1`) | ✅ `window._autoRunDemo` flag gated on `checks.length === 0` — only fires for brand-new users |
| Spinner re-enable on error | ✅ All disabled buttons re-enabled in error branches of `runHealthCheck()` |
| Health check creation | ✅ Immediately redirects to `/report/:id` (no polling here) |
| EBS opt-in toggle | ✅ Wired to `/api/connections/:id/ebs-opt-in` |
| Connection wizard | ✅ Multi-step wizard with test connection, save, run flow; all spinners cleaned up |
| Mobile 375px/768px | ✅ overflow-x: hidden added; media queries at 900px and 768px |

### `/report/:id` and `/report/demo`
| Check | Status |
|-------|--------|
| Console errors | ✅ None |
| Spinner safety net | ✅ `REPORT_POLL_MAX = 45` (90s), `SUMMARY_POLL_MAX = 40` (80s) — fallback message on timeout |
| Demo mode | ✅ Fetches `/api/health-checks/demo` fixture |
| Real mode | ✅ Polls `/api/health-checks/:id` every 2s |
| EBS section | ✅ Detected Applications chip section shows when `ebs_detected=true` |
| PDF export | ✅ Wired to `/api/health-checks/:id/pdf` |
| XLSX export | ✅ Wired to `/api/health-checks/:id/xlsx` |
| Mobile 375px/768px | ✅ overflow-x: hidden added; responsive tables wrapped |

### `/ebs-deep` (Monitor / Sanity / Control tabs)
| Check | Status |
|-------|--------|
| Console errors | ✅ None — all JS scoped in IIFEs |
| Monitor tab spinner | ✅ Cleared in `.finally()` via `setRefreshLoading(false)` |
| Sanity tab spinner | ✅ Cleared in `.finally()`, button re-enabled |
| Control tab | ✅ Static whitelist, no async state |
| 30s auto-refresh | ✅ Pauses on Sanity/Control tabs, resumes on Monitor |
| Hash routing | ✅ `#monitor`, `#sanity`, `#control` — persists on refresh |
| Sanity lazy-load | ✅ Loads latest run only on first Sanity tab open |
| Demo mode | ✅ `?demo=1` or `connection_id=0` handled in API |
| Mobile 375px/600px | ✅ Tabs stack vertically at ≤600px; grid adapts |

### `/report/ebs/:id` and `/report/ebs/demo`
| Check | Status |
|-------|--------|
| Console errors | ✅ No broken JS references seen |
| Demo mode | ✅ Route served from `ebs-deep-reports.js`, no auth required for demo |
| Real mode | ✅ Auth required, redirects to `/login` if unauthenticated |
| PDF export | ✅ Wired to `/api/ebs-deep/report/:id/pdf` |

### `/docs/oracle-setup` (and `/setup-guide` redirect)
| Check | Status |
|-------|--------|
| Console errors | ✅ None |
| Proxy downloads | ✅ `/downloads/oracle-proxy.py`, `/downloads/oracle-proxy.js`, `/downloads/oracle-proxy-install.sh` — all files exist on disk |
| Mobile | ✅ Code blocks have `overflow-x: auto` |

### `/admin/users`, `/admin/requests`, `/admin/payments/last-test`
| Check | Status |
|-------|--------|
| Console errors | ✅ None |
| Auth | ✅ All admin pages check `/api/auth/me` and redirect unauthorized users |
| Nav | ✅ Uses `tvNav.init('admin')` — now mobile-responsive after nav-component fix |
| Spinners | ✅ No long-running spinners; refresh buttons re-enable on error |
| 30s auto-refresh | ✅ `setInterval(loadUsers, 30000)` — acceptable for admin panel |

### `/features`
| Check | Status |
|-------|--------|
| Console errors | ✅ None |
| Mobile | ✅ Responsive layout present |

---

## Root Cause Analysis

### Bug 1: Production 500 on `/api/ebs-deep/connections`
**Symptom:** `column hc.results does not exist` in production logs at `2026-05-11T20:18:25`.

**Root cause:** `db/ebs-deep.js` `getEbsConnections()` joined `health_checks hc` and filtered on `(hc.results->>'ebs_detected')::text = 'true'`. The `results` column never existed in the `health_checks` schema (verified via `migrations/1714150000000_create_health_checks.js`). EBS detection is stored on `oracle_connections.is_ebs` (added in migration `1746800000000`).

**Fix:** Removed the health_checks JOIN entirely; query now reads `SELECT id, name, host, connection_type FROM oracle_connections WHERE user_id = $1 AND is_ebs = true`.

### Bug 2: Nav padding overrides media queries
**Symptom:** At 375px screen width, nav had 96px of horizontal padding (48px each side), leaving only 279px for logo + links — logo text truncated, navigation links overlapped.

**Root cause:** `nav-component.js:285` sets `navRoot.style.padding = '16px 48px'` as an inline style via JavaScript. Inline styles have higher CSS specificity than any `@media` rule, so all responsive padding rules in individual page stylesheets were silently ignored.

**Fix:** Added viewport-width check before setting padding. Now sets `16px` horizontal at <600px, `24px` at <900px, and `32px` (report) / `48px` (others) at desktop widths.

---

## No Issues Found (Confirmed Clean)

- `/health` — Render health check endpoint responds `{ status: 'healthy' }`
- `/signup`, `/signin` — redirect to `/login` (410 for POST password auth)
- `/sample-report` — 301 redirects to `/dashboard?demo=1`
- `/setup-guide` — 301 redirects to `/docs/oracle-setup`
- `/security` — static whitelist page, no async JS
- Magic link token verify (`/api/auth/magic-link/verify`) — error codes surface correctly on `/login?error=...`
- Google OAuth callback — 302 back to redirect param or `/dashboard`
- All `oracle_connections` credentials — encrypted AES-256-GCM at rest

---

*Audit conducted by TuneVault AI agent, 2026-05-11*
