---
date: 2026-05-06
status: complete — M1 shipped (commit 04dde10); L1 watch
owner: jez+claude (interaction-first ux-audit)
url: https://vite-flare-starter.webfonts.workers.dev
viewport: 1440x900 (desktop)
verdict: Pass — 1 Medium (fixed), 1 Low (watch), no Critical or High
---

# UX Audit — vite-flare-starter live

## Verdict

**Pass with follow-ups.**

Hard gates: console errors **0**, console warnings **0**, network 5xx **0**, layout collapse **0** at desktop viewport. No Critical or High findings. One Medium (chat lazy-creation 404 noise), one Low (transient connection drop on first connectors-route hit).

## Interaction Manifest

Real interactions performed during the audit:

| # | Action | Verified |
|---|---|---|
| 1 | Hard reload `/dashboard` | 12 API calls all 200, page renders, sidebar + header + greeting + 4 dashboard cards visible |
| 2 | Navigate `/dashboard/chat` | NewChatRedirect mints UUID, redirects to `/chat/{uuid}`, empty-state renders ("What can I help with, Jeremy?" + chips + starter prompts) |
| 3 | Click chat input + type "say hi in 5 words" + press Enter | User message rendered, response streamed back ("Hello there, Jez! How are you?"), conversation auto-titled "Brief hello prompt", URL stable |
| 4 | Navigate `/dashboard/inbox` | Tabs (Undecided/Unread/All), importance filters (High/Medium/Low), keyboard-shortcut hints, 1 pending approval card visible |
| 5 | Navigate `/dashboard/findings` | Tabs (Findings/Learnings, All/Open/Recurred/Promoted/Dismissed), empty state with explainer + "Set up daily reflection" CTA |
| 6 | Navigate `/dashboard/projects` + click first project | List page (3 cards, search, sort), detail page renders chats inside the project |
| 7 | Navigate `/dashboard/spaces` | Pinned/All sections, 2 spaces (admin pinned, marketing-pod) |
| 8 | Navigate `/dashboard/routines` | List with status, schedule, last-run timestamp, "Success" badge |
| 9 | Navigate `/dashboard/connectors` | First attempt: `ERR_CONNECTION_CLOSED`. Retry: redirected to `/connections`, full page renders with workspace integrations + custom MCP UI |
| 10 | Navigate `/dashboard/skills` | List of 24 bundled skills with `/slash` triggers |
| 11 | Navigate `/dashboard/agents` | List of registered agents (Admin chat, AI assistant, Researcher, etc.) with persona + run-count + cost |
| 12 | Navigate `/dashboard/admin-chat` | Resolves to admin Space detail (`/dashboard/spaces/{adminId}`) |
| 13 | Navigate `/dashboard/settings` | Tabbed interface (Profile / Organization / Security / Sessions / API Tokens / Chat / Memory / Preferences), profile fields render |
| 14 | Open command palette via Cmd+K (synthetic) + type "projects" | Palette opens, search returns 2 results, first hit "New project" |
| 15 | Close palette + click first project card | Detail page loads with chats list |

## Findings

### Critical
None.

### High
None.

### Medium

**M1 — Routine 404 on `/api/conversations/{newId}` pre-fetch**
- Where: every fresh chat URL load (`/dashboard/chat/{uuid}` after NewChatRedirect)
- What happens: `useConversationMessages(urlConversationId)` fires on URL transition. The conversation row doesn't exist yet because `ChatAgent.onChatMessage` creates it lazily on the first turn. Result: predictable 404 in the network panel.
- Why it matters: pollutes the network panel for anyone debugging, would trigger spurious Sentry alerts if production has error tracking on, looks alarming in a screen-sharing demo.
- Fix options:
  - (a) Have `/api/conversations/:id` return `200` with `{ messages: [] }` when the row is missing for the authenticated user (recommended — symmetric with DO behaviour)
  - (b) Gate `useConversationMessages` on a separate "has the row been created" flag so the query doesn't fire pre-creation
  - (c) Drop `useConversationMessages` entirely and let `useAgentChat`'s `getInitialMessages` HTTP path be the only source of historical messages — already covers the legacy-D1-bridge case
- Severity rationale: not a hard-gate violation (404, not 5xx), routine, doesn't break any user flow

### Low

**L1 — Transient connection drop on first `/dashboard/connectors` navigation**
- Where: navigating from any other page directly to `/dashboard/connectors`
- What happened: first attempt returned `ERR_CONNECTION_CLOSED` (Chrome-level, not 5xx in the worker). Second attempt redirected `/connectors → /connections` cleanly and rendered.
- Why it might be: `/connectors` redirect chain may be slightly fragile (not reproducible on retry), OR a one-off Cloudflare colo blip
- Fix: low priority — re-test next session; if reproducible, look at the worker route ordering for `/dashboard/connectors`. Right now, treat as transient.

## Hard-gate evidence

| Gate | Threshold | Observed | Status |
|---|---|---|---|
| Console errors | 0 | 0 across all surfaces | ✓ |
| Console warnings | 0 | 0 across all surfaces | ✓ |
| Network 5xx | 0 | 0 across all surfaces (one expected 404 on lazy chat creation) | ✓ |
| Layout collapse | 0 | 0 desktop overflow on any surface | ✓ at desktop |

## What works well (preserve patterns)

- **Empty states are useful, not blank**. Findings shows what findings are + how to enable. Inbox shows real keyboard shortcuts. Chat shows capability chips + starter prompts. Projects shows search + sort even when only 3 cards exist.
- **First-time greeting is personal** ("Hello, Jeremy" / "What can I help with, Jeremy?"). Warmth without infantilising.
- **Auto-titling of conversations works** — first turn produced "Brief hello prompt" within seconds.
- **Visual hierarchy is consistent across all 14 surfaces** — h1 + 1-line description + actions + content. Nothing reinvents the wheel per page.
- **Sidebar navigation labels are nouns** (Home, Inbox, Findings, Projects, Spaces, Routines), not verbs or product jargon.
- **Performance**: every surface fully renders within 2-5s of navigation. No layout shift after data lands (skeletons or fast queries).
- **Command palette** opens via real Cmd+K and via the header button; search filters live as you type.

## Not verified (test-harness limitations)

These are caveats on the audit, not findings:

- **Mobile viewport (375px / 390px)**: `resize_window` to small dims didn't actually shrink the visible viewport (stayed at 1253px innerWidth). Mobile responsiveness is unverified at runtime; static CSS analysis would be needed for confident statement.
- **Chrome MCP keyboard shortcut `cmd+k`**: doesn't synthesise the meta key correctly (real users + JS-dispatched `KeyboardEvent({metaKey: true})` both work; Chrome MCP `key: cmd+k` action does not).
- **Chrome MCP `left_click` via element ref**: occasionally clicks miss the handler-bound element (verified by programmatic `el.click()` working when ref-click did not). Real-mouse user clicks unaffected.

These are the same harness quirks documented in yesterday's chat-migration audit. Not app bugs.

## Recommendations (priority order)

1. **Fix M1** — make `/api/conversations/:id` 200-empty for missing rows. ~10 min change. Removes the only routine 404 in the system.
2. **Re-test L1** next session to determine if reproducible. If yes, investigate the connectors→connections redirect.
3. **Future** — when Chrome DevTools Protocol viewport emulation lands in a future Chrome MCP version, redo this audit with a real 390px viewport for mobile responsiveness verification. Until then, manual responsiveness checks remain a developer concern.

