v0.6.5.0 ux: hardening pass for non-technical users (7 of 20 findings)#154
Merged
Conversation
Closes 7 of 20 findings from .context/ux-review/FINDINGS.md (the load-bearing ones); polish queued for a follow-up. All visible to non-technical users on first contact with the app. Centralized friendly errors (P0 #4) - New ApiError class with kind discriminant + friendlyMessage field. - "API proxy error" no longer leaks to users; translated to "Can't reach SkyTwin right now. We'll keep trying." - renderApiError(err, {context, retry}) + wireApiRetry give every page the same calm error card with a Try again button. Approvals/Decisions/Audit/Chat use the helper (P0 #5) - Pre-fix Approvals showed "0 waiting / You're all caught up" when API was down — indistinguishable from genuinely empty. Real approvals could be missed. Now: distinct offline state. UUID badge → friendly fallback (P0 #2) - Header user badge + Settings footer used to show raw "11111111-2222-..." when the user record couldn't load. - Now shows "You (1111…)" with userId in tooltip for devs. Connection status as actionable header banner (P1 #12) - Promoted out of bottom-left footer where most users wouldn't see. - Calm yellow banner with animated dot + Retry now button. - Hidden when connected so happy path has no extra chrome. - Respects prefers-reduced-motion. Demo preview card static fallback (P1 #6) - Pre-fix the "Try one — see how it thinks" card was hidden via display:none when /api/v1/demo/info failed. Onboarding step 1 became a wall of text. - Now: card always renders; clicks return pre-canned sample answers with the same visual treatment + "Live preview offline" caveat. Mobile bottom-nav fixes (P0 #3) - Replaced single-letter H/!/D/T/S icons with inline-SVG icons. - Added Chat link (was missing entirely from mobile). - Increased page-content padding-bottom 4rem → 5.5rem so the nav stops overlapping page content (composer hint was hidden under it). Voice mismatch (P1 #13) - Sidebar "My learnings" → "What I've learned", matches page header. Full backend test suite still green across 40 packages. Browser-agent visual verification screenshots in .context/ux-review/14- through 19-. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR hardens the web SPA for non-technical users by replacing raw/ambiguous failure states with friendlier UI, improving mobile navigation, and making onboarding/demo states degrade more gracefully when the API is unavailable.
Changes:
- Introduces centralized API error classification/rendering and applies it to Approvals, Decisions, Audit, and Assistant.
- Adds a header-level connection banner, friendlier user badge fallbacks, and onboarding static preview fallbacks.
- Reworks the mobile bottom nav with SVG icons, adds Chat there, and adjusts page padding to avoid nav overlap.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
VERSION |
Bumps app version to 0.6.5.0. |
CHANGELOG.md |
Documents the UX hardening changes shipped in this release. |
apps/web/public/js/pages/settings.js |
Updates Settings sign-in footer to show a friendlier identity fallback. |
apps/web/public/js/pages/onboarding.js |
Keeps demo preview visible and adds static fallback responses when the API is unavailable. |
apps/web/public/js/pages/decisions.js |
Replaces raw error banners with centralized friendly API error UI. |
apps/web/public/js/pages/audit.js |
Applies centralized friendly API error handling to audit loading. |
apps/web/public/js/pages/assistant.js |
Applies centralized friendly API error handling to assistant loading. |
apps/web/public/js/pages/approvals.js |
Stops rendering an empty approvals state when the pending approvals fetch fails. |
apps/web/public/js/app.js |
Renames Twin page title, adds user badge fallback logic, and introduces the connection banner/retry flow. |
apps/web/public/js/api-client.js |
Adds ApiError, HTTP/network error classification, shared error-card rendering, and retry button wiring. |
apps/web/public/index.html |
Renames the Twin nav label, adds the connection banner, and replaces the mobile bottom nav icons/links. |
apps/web/public/css/styles.css |
Styles the connection banner, SVG bottom-nav icons, and increases mobile content bottom padding. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <span class="bottom-nav-icon" aria-hidden="true"> | ||
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18M3 12h18M3 18h18"/></svg> | ||
| </span>Decisions | ||
| </a></li> |
Comment on lines
+280
to
+287
| // Triggers an immediate health check + re-renders the status. Skips | ||
| // the next backoff window the SSE client would otherwise wait through. | ||
| document.addEventListener('click', (e) => { | ||
| const target = e.target instanceof Element ? e.target : null; | ||
| if (!target) return; | ||
| if (target.getAttribute('data-action') !== 'connection-retry') return; | ||
| e.preventDefault(); | ||
| updateConnectionStatus(); |
| // Network unreachable (no DNS, no route, browser offline, etc.) | ||
| throw new ApiError({ | ||
| kind: 'offline', | ||
| friendlyMessage: "You appear to be offline. Check your connection — we'll retry automatically.", |
7 tasks
jayzalowitz
added a commit
that referenced
this pull request
May 5, 2026
Picks up the P1/P2 findings deferred from #154 (the hardening pass). 6 of the remaining UX review findings closed. Settings cleanup (P1 #7, #9) - Theme switcher relocated from page header (where it looked like a breadcrumb pill) to a dedicated "Visual theme" card in Settings. - AI provider section now titled "AI brain — needed for Chat (optional otherwise)" instead of just "(optional)" — the Chat feature requires it, the old title was misleading. Chat → Settings deep-link (P1 #9) - When POST /messages returns 409 "no AI provider configured", the chat bubble explains the dependency + footer link to Settings → AI brain. Previously the user got "No AI provider configured" with no path forward. Onboarding modal dimmer (P2 #15) - Bumped overlay rgba(0,0,0,.85) → .92 + backdrop-filter: blur(4px) so the sidebar/page behind the modal is properly muted (was bleeding through the glass effect at .85). Console error spam reduction (P2 #20) - New isApiKnownOffline() in api-client.js. Badge-poll loop in app.js backs off 10s → 60s when API is known down. Pre-fix produced 110+ console errors/min against a dead server. Date input theming on Audit (P1 #11) - New .themed-date class so native date inputs match the dark glass aesthetic (background, border, color-scheme for picker icon). - Webkit calendar-picker-indicator filter inverts the icon glyph on dark themes so it's actually visible. Tests: no new unit tests (browser-only). Backend suite still green across 40 packages. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
UX hardening driven by a browser-agent visual review of every SPA route — focused on what would confuse a non-technical user. 7 of 20 findings closed in this PR (the load-bearing ones); polish items (Settings consolidation, theme switcher relocation, auto-save, date input theming, etc.) queued for a follow-up. Full review with severity grades + screenshots in
.context/ux-review/FINDINGS.md.The single biggest finding from the review — Hosted OAuth (P0 #1) — needs a verified Google OAuth app + production hosting and isn't shippable from a worktree alone. Tracked separately.
What ships in this PR
1. Centralized friendly errors + Try Again (P0 #4)
New `ApiError` class with `kind` discriminant (`offline | auth | not-found | bad-request | server | unknown`) and a `friendlyMessage` field. The web dev proxy returns `{error: 'API proxy error'}` when the upstream API is down — pre-fix that string leaked verbatim to users on Chat / Decisions / Audit pages. Now translated to "Can't reach SkyTwin right now. We'll keep trying."
`renderApiError(err, { context, retry })` and `wireApiRetry(container, retry)` give every page the same calm error card with a "Try again" button.
2. Approvals stops lying (P0 #5)
Pre-fix the Approvals page showed "0 waiting / You're all caught up" when the API was down — indistinguishable from genuinely having nothing to do, so a user could miss real approvals. Now: a loaded-empty list looks different from an offline list, and Try again is one click away. Same treatment for Decisions, Audit, Chat.
3. UUID badge → friendly fallback (P0 #2)
Header user badge and Settings footer used to show raw `11111111-2222-…` when the user record couldn't be loaded. Now shows `You (1111…)` with the first 4 chars in a tooltip for devs.
4. Connection status as a header banner (P1 #12)
Calm yellow banner with animated dot + "Retry now" button, rendered below the page header when the API is unreachable. Promoted from the bottom-left footer (where most users wouldn't notice). Hidden when connected so the happy path has no extra chrome. Respects `prefers-reduced-motion`.
5. Onboarding works even when the API is down (P1 #6)
Pre-fix the "Try one — see how it thinks" preview card was rendered with `display: none` and only revealed by JS after a successful demo-info fetch. With the API down, the card never appeared — onboarding step 1 became a wall of text. Now: card always renders; clicks return pre-canned sample answers (recruiter / subscription / dinner) with the same visual treatment as the live engine, plus a small "Live preview offline — showing a sample answer" caveat.
6. Mobile bottom-nav fixes (P0 #3) — three at once
7. Voice mismatch (P1 #13)
Sidebar "My learnings" → "What I've learned", matches the page header.
Visual verification
Before/after screenshots in `.context/ux-review/`:
Test plan
What's queued for the next PR
From the same review (`FINDINGS.md` P1/P2 items):
🤖 Generated with Claude Code