Files
resolutionflow/docs/plans/ResolutionFlow_UX_Deep_Dive_Final_Plan.md
chihlasm aef40078d0 fix: UX deep dive — 28 fixes across authoring, navigation, consistency, and cleanup (#86)
* fix: tree editor authoring blockers - scroll trap, form density, branching hint

- Replace fixed viewport height with flex layout in NodeEditorPanel
- Make footer sticky so Save/Cancel always reachable
- Compact root node banner to single-line with InfoTip tooltip
- Reduce resolution note from callout box to inline text
- Add answer-first branching hint below options label

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: broken functionality - auth errors, toast logic, role update, routing, step library

- Extract backend error detail in auth store login/register
- Fix inverted 4xx toast logic and add 429 rate limit handling
- Send account_role field to match backend schema in role update
- Use type-aware routing for Repeat Last Session button
- Add step library placeholder page and route, remove dot badge

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: navigation correctness - back buttons, exit dialog, dedup nav, redirects

- Standardize all procedural back/exit paths to /trees (not /my-trees)
- Add exit button with ConfirmDialog to procedural session top bar
- Consolidate duplicate account links in sidebar and topbar
- Auto-redirect non-owners to personal analytics
- Add toast feedback before silent permission redirects in tree editor
- Delete orphaned AdminCategoriesPage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: shared components, ConfirmDialog migration, pinned flow fixes

- Create shared Spinner component with sm/md/lg sizes
- Migrate 13 page-level spinners to shared Spinner
- Promote EmptyState to shared component, adopt in MyShares and SessionHistory
- Replace window.confirm with ConfirmDialog in 3 files
- Fix PinnedFlow.tree_type to include maintenance, update emoji display
- Verify sidebar unpin handler already correct (no-op)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: visual consistency - toasts, typography, focus rings, container padding

- Remove richColors from Sonner toasts, limit stacking to 3
- Add font-heading to all page H1s (7 files)
- Add font-label (Outfit) to TagBadges component
- Fix focus ring tokens on analytics pages
- Replace deprecated glass-stat with design system tokens
- Standardize container padding on analytics pages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: backend alignment - remove drafts toggle, clean dead code, truncation indicator

- Remove non-functional drafts toggle and clean TreeFilters type
- Fix AccountInvite type to match backend schema
- Remove dead API methods: pinnedFlows.pin/reorder, trees.getSharedTree
- Remove unused types: SessionListResponse, RatingCreate.is_verified_use
- Add session list truncation indicator with size=51 lookahead

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove bg-black from PageLoader and RouteError, fix PageLoader height

PageLoader used h-screen inside a grid cell, causing it to overflow.
Changed to h-full so it fits within the main-content area. Removed
bg-black from both PageLoader and RouteError in favor of theme-aware
bg-background to prevent black flash during lazy loading.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: guard against Pydantic validation error objects in toast/error messages

FastAPI returns `detail` as an array of objects for 422 validation errors,
not a string. Passing these objects to toast.error() or rendering them in
JSX crashes React with Error #31 ("Objects are not valid as a React child").
Now checks typeof detail === 'string' before using it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: toast styling, node editor first-click, action node placeholder pattern

1. Toast fixes: Add theme="dark" to Sonner, use !important CSS overrides
   instead of zero-specificity :where() selectors, suppress noisy 4xx
   global toasts (pages handle their own errors)

2. Node editor first-click: Add node.type to draft initialization
   useEffect deps so draft resets when answer stub converts to real type

3. Action node redesign: Remove NodePicker dropdown, auto-create answer
   placeholder on save (matching decision node pattern). Users click the
   placeholder on canvas to choose type and fill in details.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: auto-seed test users when release command fails on PR envs

The background seeder now creates users directly via DB if login fails,
instead of silently aborting. This handles Railway PR environments where
the releaseCommand may not execute properly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove categories/tags from sidebar to prevent footer clipping

Categories and Tags sections were pushing Feedback, Account, and
Collapse off-screen when All Flows expanded its children. These
filters already exist on the TreeLibraryPage, so the sidebar
duplicates were removed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 22:10:47 -05:00

16 KiB

ResolutionFlow UX Deep Dive — Final Merged Implementation Plan

Date: 2026-02-19
Author: Michael Chihlas
Purpose: Comprehensive frontend UX sweep merging the original 35-issue audit with Codex-revised plan. Ordered by user impact, covering broken functionality, navigation, shared components, visual consistency, and backend alignment.


Locked Decisions

These decisions are finalized and should not be revisited:

  1. Canonical post-editor/post-session destination: /trees (the full flow library). /my-trees remains available for creator-specific management but is not a navigation target from editors or sessions.
  2. Step Library handling: Add a placeholder route now. Not hidden, not fully built.
  3. Cleanup strategy: Immediate removal of dead code and unused types. No staged deprecation. One final grep sweep before each deletion to confirm zero references.

Phase 0 — Tree Editor Authoring Blockers (Immediate)

Goal: Remove "can't reach bottom / too busy form" friction before the broader UX sweep. This phase was absent from the original audit and added by the Codex review.

0.1 Fix node editor scroll trap and bottom clipping

File: NodeEditorPanel.tsx

  • Replace fixed viewport math (h-[calc(100vh-105px)]) with h-full min-h-0
  • Keep body as the only scroll container (min-h-0 flex-1 overflow-y-auto)
  • Make footer sticky (sticky bottom-0) so Save/Cancel are always reachable
  • Add scroll-pb-24 on form body to prevent bottom fields hiding behind footer

0.2 Reduce instruction density in decision/action/resolution forms

Files: NodeFormDecision.tsx, NodeFormAction.tsx, NodeFormResolution.tsx

  • Convert long instructional copy to compact labels + InfoTip tooltips
  • Keep one short contextual hint per form section
  • Remove large always-visible prose blocks

0.3 Keep answer-first branching flow explicit

File: NodeEditorPanel.tsx

  • Preserve existing behavior: saving decision options without next_node_id auto-creates answer stubs
  • Add UI hint in decision form: "Options become answer placeholders you type later."

Phase 0 Verification

  • Open a long decision form → verify full vertical scroll to footer fields/buttons
  • Focus bottom fields → confirm they are visible (not clipped behind footer)
  • Decision instructions are compact with info tooltips (no walls of text)
  • Save a decision with two new options → two answer placeholders are auto-created

Phase 1 — Broken Functionality (Critical)

Goal: Fix features that are actively broken or silently wrong right now.

1.1 Register /step-library route

Sidebar links to /step-library but no route exists — users hit a blank page.

Changes:

  • router.tsx — add route with lazy-loaded StepLibraryPage.tsx placeholder shell
  • StepLibraryPage.tsx — create placeholder page (e.g., "Step Library — Coming Soon" with consistent layout)
  • Sidebar.tsx — remove badge="dot" while placeholder is live (no false "new feature" signal)

1.2 Preserve backend auth error detail in login/register flows

Login failures show "Request failed with status code 401" instead of "Invalid credentials."

File: authStore.ts (lines ~50-54, 63-67)

  • Extract error.response?.data?.detail before falling back to generic message
  • Apply to both login and register error paths

1.3 Fix inverted 4xx toast logic and add 429 handling

File: client.ts (lines ~36-43)

4xx errors with a detail message currently suppress the toast entirely (inverted condition). No 429 handler exists.

Behavior after fix:

Status Action
401 Suppressed (handled by token refresh flow)
429 Always toast: backend detail or "Rate limit exceeded, please retry shortly."
Other 4xx Toast detail if present, else "Invalid request."
5xx Existing generic server error toast (unchanged)

1.4 Fix role update payload contract mismatch

File: accounts.ts (line ~28)

Sends { role } but backend schema expects { account_role }. Role changes silently fail with 422.

  • Change to { account_role: role }

1.5 Fix "Repeat Last Session" broken for non-troubleshooting flows

File: TreeLibraryPage.tsx (line ~453)

Currently hardcodes /trees/:id/navigate — loses prefill state via safety redirect for procedural/maintenance flows.

  • Use getSessionResumePath() instead of hardcoded path

Phase 1 Verification

  • Step Library nav opens placeholder page from Sidebar, AppLayout mobile nav, and Quick Launch
  • Login with bad credentials shows backend detail string (e.g., "Invalid credentials"), not axios error
  • Force a 429 response and verify toast appears
  • Change a team member's role in Account Settings → confirm it actually saves (requires team_admin user)
  • Repeat Last Session works correctly for troubleshooting, procedural, and maintenance flow types

Phase 2 — Navigation Correctness (Medium Scope)

Goal: Fix cases where users end up at unexpected pages or lack navigation affordances.

2.1 Standardize editor/session back and exit targets to /trees

Files:

  • ProceduralEditorPage.tsx (lines ~86, 92, 157) — change /my-trees/trees
  • ProceduralNavigationPage.tsx (lines ~120, 180, 304, 330) — error, cancel, completion, and intake cancel paths all → /trees

2.2 Add explicit exit affordance during procedural session execution

Currently there is no way to leave a procedural session mid-execution except the browser back button.

File: ProceduralNavigationPage.tsx (top bar, ~line 345)

  • Add an Exit button to the top bar
  • If session has progress, exit opens a ConfirmDialog before navigating to /trees
  • If no progress, navigate directly

"Team" and "Settings" both point to /account. Same duplication in TopBar dropdown.

Files:

  • Sidebar.tsx (lines ~206-207) — consolidate footer to single "Account" item
  • TopBar.tsx — consolidate dropdown to single "Account" entry

2.4 Improve analytics routing for non-owners

Non-owners click Analytics, hit an access-denied wall, then must click through to personal stats.

File: TeamAnalyticsPage.tsx (lines ~48-65)

  • Auto-redirect non-owner/non-admin users to /analytics/me
  • Show an informational toast explaining the redirect (e.g., "Viewing your personal analytics")

2.5 Add feedback before permission redirects in tree editor

TreeEditorPage silently redirects when users lack permission — no feedback shown.

File: TreeEditorPage.tsx (lines ~143-146, 157-159)

  • Add toast.error("You don't have permission to edit this flow") before each navigate() call

2.6 Delete orphaned AdminCategoriesPage

Not connected to any route, superseded by admin/GlobalCategoriesPage.tsx.

  • Delete AdminCategoriesPage.tsx
  • Remove its export from index.ts if present

Phase 2 Verification

  • Procedural editor Back button → /trees (not /my-trees)
  • Procedural session cancel, exit, error, and completion → all route to /trees
  • Exit button is visible during procedural execution and prompts confirmation if session has progress
  • Sidebar footer shows one "Account" item (not "Team" + "Settings")
  • Non-owner clicks Analytics → auto-redirects to /analytics/me with toast
  • Unauthorized tree edit attempt → toast shown, then redirect

Phase 3 — Shared Components & Quick Consistency Wins (Medium Scope)

Goal: Build reusable infrastructure and fix small but important consistency issues.

3.1 Create shared Spinner component

Currently 4 different spinner implementations across 20+ files.

Create: Spinner.tsx with sm | md | lg sizes, default border-t-primary

Migrate page-level loading states in:

  • ProceduralNavigationPage.tsx
  • ProceduralEditorPage.tsx
  • TreeEditorPage.tsx
  • TreeNavigationPage.tsx
  • SessionHistoryPage.tsx
  • SessionDetailPage.tsx
  • MySharesPage.tsx
  • MyTreesPage.tsx
  • AccountSettingsPage.tsx
  • SharedSessionPage.tsx
  • PageLoader.tsx

Deferred: Leave tiny inline button spinners for later to avoid churn.

3.2 Promote EmptyState to shared component

Admin has a well-designed EmptyState; main app uses 3+ ad hoc patterns.

  • Move/create common/EmptyState.tsx
  • Re-export from admin's EmptyState.tsx for backward compatibility
  • Adopt in: MySharesPage.tsx, SessionHistoryPage.tsx, TreeLibraryPage.tsx

3.3 Replace native window.confirm() with design-system ConfirmDialog

3 places use native browser dialogs that break the design system.

Files:

  • MySharesPage.tsx (line ~81)
  • NodeEditorPanel.tsx (line ~87)
  • FolderSidebar.tsx (line ~286)

3.4 Fix sidebar optimistic unpin bug

State is removed immediately even if API call fails — the flow disappears permanently until page refresh.

File: Sidebar.tsx (lines ~105-113)

  • Move setPinnedFlows update to after successful await (not before)

3.5 Fix PinnedFlow.tree_type missing 'maintenance'

Maintenance flows can be pinned but navigation will use the wrong path.

Files:

  • pinnedFlows.ts (line ~7) — add 'maintenance' to the PinnedFlow.tree_type union type
  • PinnedFlowsSection.tsx — validate icon/path logic via getTreeNavigatePath handles maintenance correctly

Phase 3 Verification

  • All page-level loading states use the shared Spinner component (visual consistency)
  • Empty states in MyShares, SessionHistory, TreeLibrary use the shared EmptyState component
  • Deleting a share, removing a node, removing a folder → all show styled dialog (not browser native)
  • Unpin a flow while network is down → flow should NOT disappear (reverts on failure)
  • Pin a maintenance flow → clicking it navigates to the correct path

Phase 4 — Visual Consistency Sweep (Large Scope — Many Small Changes)

Goal: Design system compliance fixes. Each change is small but there are many files.

4.1 Fix Sonner toast styling

The richColors prop overrides custom CSS with garish built-in green/red backgrounds. Existing custom CSS in index.css (lines ~201-251) already defines themed toasts (bg-card, border-border, colored border accents) but richColors overrides them.

File: main.tsx

  • Remove richColors prop
  • Add visibleToasts={3} and gap={8}
  • Keep existing custom toast CSS in index.css; patch only if needed to ensure themed styles fully apply

4.2 Typography: Add font-heading to all page H1s

Missing from approximately half the pages.

Files to update:

  • MyTreesPage.tsx
  • TeamAnalyticsPage.tsx
  • MyAnalyticsPage.tsx
  • FeedbackPage.tsx
  • AccountSettingsPage.tsx
  • TeamCategoriesPage.tsx
  • admin/PageHeader.tsx

4.3 Typography: Add font-label to TagBadges component

Design system requires Outfit font for tags/badges.

File: TagBadges.tsx

4.4 Fix hardcoded light-mode button in TeamAnalyticsPage

Only hardcoded bg-white text-black button in the app — breaks in dark mode.

File: TeamAnalyticsPage.tsx (line ~59)

  • Replace with bg-gradient-brand text-white

4.5 Fix non-standard focus ring tokens

Analytics selects use focus:ring-ring instead of the standard token.

Files: TeamAnalyticsPage.tsx, MyAnalyticsPage.tsx

  • Change focus:ring-ringfocus:ring-primary/20

4.6 Replace deprecated glass-stat style

File: AccountSettingsPage.tsx (line ~588)

  • Replace glass-stat with bg-card border border-border

4.7 Standardize container/padding on analytics pages

Missing responsive padding.

Files: TeamAnalyticsPage.tsx, MyAnalyticsPage.tsx

  • Add container mx-auto px-4 py-6 sm:px-6 sm:py-8

Phase 4 Verification

  • Toast colors/borders follow custom theme (not Sonner rich presets) — check success, error, and info toasts
  • All page H1s use font-heading (Plus Jakarta Sans)
  • Tag badges use font-label (Outfit)
  • TeamAnalytics CTA button renders correctly in both light and dark mode
  • Focus rings on analytics selects use subtle primary/20 glow
  • No glass-stat class remains in the codebase
  • Analytics pages have consistent container spacing matching rest of app

Phase 5 — Backend Alignment & Cleanup (Immediate Removals)

Goal: API contract fixes and dead code removal. All removals are immediate (per locked decision #3), with a final grep sweep before each deletion.

5.1 Remove non-functional drafts toggle from library UI

Backend has no include_drafts parameter — the toggle does nothing.

Files:

  • TreeLibraryPage.tsx — remove showDrafts state and drafts filter UI
  • tree.ts (TreeFilters type) — remove include_drafts field

5.2 Align invite types with backend schema

invited_by_id and accepted_by_id not in backend response — always undefined.

File: account.ts — remove invited_by_id and accepted_by_id from AccountInvite type

5.3 Remove dead/unused client code

Before deleting each item, run a global grep to confirm zero consumers:

Item File What to Remove
pinnedFlowsApi.pin() pinnedFlows.ts Dead method (never called)
pinnedFlowsApi.reorder() pinnedFlows.ts Dead method (never called)
treesApi.getSharedTree() trees.ts Dead method (no route/consumer)
SessionListResponse sessions.ts Unused type
RatingCreate.is_verified_use step.ts Field ignored by backend
AdminCategoriesPage.tsx Orphaned file + export (if not already deleted in Phase 2)

5.4 Add session list truncation indicator

Session history silently truncates at the backend limit with no indication to the user.

File: SessionHistoryPage.tsx

  • Request size=51 from backend
  • If result length is 51: show "Showing first 50 sessions" indicator, render only first 50
  • If result length ≤ 50: show "Showing X sessions"
  • No backend API contract changes required (frontend lookahead strategy)

Phase 5 Verification

  • No drafts toggle visible in TreeLibrary UI
  • grep -r "include_drafts" frontend/src/ returns zero results
  • grep -r "invited_by_id\|accepted_by_id" frontend/src/ returns zero results for AccountInvite usage
  • grep for each removed method/type confirms zero references
  • Session history shows truncation indicator at 50+ results
  • Session history shows "Showing X sessions" at fewer than 50 results
  • cd frontend && npm run build passes with zero errors

Items Explicitly Deferred

Item Reason
Migrate 14+ custom modals to shared Modal component Very high effort, low breakage risk. Migrate incrementally on new work.
Standardize input border radius app-wide Cosmetic, low user impact
Standardize icon sizing method (className vs size prop) No visual difference
Session pagination (full load-more) Larger feature, beyond UX sweep scope
Inline button spinners Leave for later to avoid churn (Phase 3 note)
Full Step Library feature build Intentionally placeholder-only this cycle

Public APIs / Interfaces / Types Changed

Frontend routing:

  • Add new route /step-library in router.tsx

Type/interface updates:

  • TreeFilters in tree.ts: remove include_drafts
  • AccountInvite in account.ts: remove invited_by_id, accepted_by_id
  • PinnedFlow.tree_type in pinnedFlows.ts: add 'maintenance'
  • RatingCreate in step.ts: remove is_verified_use
  • Remove unused SessionListResponse in sessions.ts

Shared component surface:

  • Add Spinner component in Spinner.tsx
  • Add common EmptyState component in EmptyState.tsx

Cross-Phase Verification Checklist

Run after each phase is complete:

  1. Build: cd frontend && npm run build — must pass with zero errors
  2. Navigation: Test all sidebar items, back buttons, editor → library flow, procedural navigation exit
  3. Auth: Intentional wrong password → shows backend error detail
  4. Role change: Test in Account Settings (requires team_admin user)
  5. Visual spot-check: H1 fonts, spinner consistency, empty states, toast styling, dark mode
  6. Grep sweep: Before merging each phase, confirm no dead references remain for removed items

Assumptions

  • /trees is the canonical destination for broad flow browsing and all post-task returns
  • /my-trees remains available but is not a default navigation target
  • Step Library is placeholder-only this cycle — no full feature work
  • No backend API contract changes are required for any item in this plan
  • Session truncation uses the frontend lookahead strategy (size=51)
  • All cleanup is immediate with pre-deletion reference verification