Back to all docs

React Frontend Analysis & iMessage-like UX Improvement Plan

Date: 2025-11-30 Status: Phase A - Investigation Complete Priority: High - Core User Experience Enhancement


Executive Summary

The React frontend (/home/ubuntu/workplace/AhaiaApp/ide/web-react/) is a modern, mobile-first chat application built with React 19, TypeScript, Vite, Socket.IO, and Tailwind CSS. It provides an iMessage-like interface for interacting with git repositories via command execution.

Key Finding: The frontend currently uses the OLD WebSocket API and lacks critical features to achieve a true iMessage-like experience. Users cannot reconnect to running jobs, see job history, or work across multiple repositories while jobs run in the background.

The new Phase 1 backend API provides all the capabilities needed (job persistence, reconnection, history), but the frontend does not yet leverage any of these features.


Current Architecture

Technology Stack

Frontend Framework:  React 19.2.0 + TypeScript 5.9.3
Build Tool:          Vite 7.2.4
Routing:             React Router v7.9.6
WebSocket:           Socket.IO Client 4.8.1
Styling:             Tailwind CSS 3.4.18
UI Components:       Custom components with Lucide icons
State Management:    React Context API
Storage:             localStorage for message history & agent preferences
Testing:             Vitest + Playwright E2E

Application Structure

/home/ubuntu/workplace/AhaiaApp/ide/web-react/
├── src/
│   ├── App.tsx                    # Main app with routing
│   ├── main.tsx                   # Entry point
│   ├── contexts/                  # Context providers
│   │   ├── ChatContext.tsx        # WebSocket + message state (NEEDS UPDATE)
│   │   ├── RepositoryContext.tsx  # Repository list fetching
│   │   ├── AgentContext.tsx       # Agent registration & selection
│   │   └── DocsContext.tsx        # Documentation library
│   ├── pages/                     # Route pages
│   │   ├── ContactsPage.tsx       # Repository list (chat list)
│   │   ├── ChatPage.tsx           # Main chat interface
│   │   ├── DocsPage.tsx           # Documentation library
│   │   └── DocViewPage.tsx        # Individual doc viewer
│   ├── components/                # Reusable components
│   │   ├── JobMessage.tsx         # Job output UI (NEEDS UPDATE)
│   │   ├── UserMessage.tsx        # User message bubble
│   │   ├── SystemMessage.tsx      # System notifications
│   │   ├── SwipeableMessage.tsx   # Double-tap to delete messages
│   │   ├── AgentSelector.tsx      # Mode/agent picker
│   │   └── ...
│   └── types/                     # TypeScript types (NEEDS UPDATE)
│       └── index.ts
├── package.json
├── vite.config.ts
└── tailwind.config.js

Routes

/                   -> ContactsPage    (repository list)
/chat/:repoId       -> ChatPage        (chat with specific repo)
/docs               -> DocsPage        (documentation library)
/docs/:docId        -> DocViewPage     (view specific doc)

Current Features & UX Flow

What Works Well

1. iMessage-like Visual Design

2. Message Persistence (localStorage)

3. Multi-Repository Support

4. Dual Execution Modes

5. Job UI States

6. Message Management

7. Real-time Output Streaming


Current Limitations (Blocking iMessage-like UX)

CRITICAL GAPS - What Prevents iMessage Feel

1. No Job Reconnection After Disconnect

Problem:

// ChatContext.tsx lines 147-169
socket.on('job-started', (data: JobStartedEvent) => {
  console.log('Job started:', data.jobId)
})
socket.on('output', (data: OutputEvent) => {
  updateJobOutput(data.jobId, data.data)
})
socket.on('job-complete', (data: JobCompleteEvent) => {
  completeJob(data.jobId, data.exitCode, data.duration)
})

Impact:

User Story Broken:

"Start npm install in Repo A, switch to Repo B to fix a bug, come back to see install results"

Current behavior: Install output is lost when switching repos


2. No Job History Visible

Problem:

// ChatContext.tsx - Messages are stored, but no way to view past jobs
const [messagesByRepo, setMessagesByRepo] = useState<Map<string, Message[]>>(...)

Impact:

User Story Broken:

"Show me all the tests I ran today and which ones failed"

Current behavior: Must scroll through chat messages to find jobs


3. No Background Job Notifications

Problem:

// ChatContext.tsx - completeJob() only updates state
const completeJob = useCallback((jobId: string, exitCode: number, duration: number) => {
  const repo = currentRepoRef.current
  if (!repo) return  // ⚠️ If user switched repos, completion is ignored

  setMessagesByRepo((prev) => {
    // Only updates messages for CURRENT repo
  })
}, [])

Impact:

User Story Broken:

"Run tests in Repo A, work in Repo B, get notified when tests finish"

Current behavior: No notification, must manually check back


4. No Visual Indicators for Running Jobs

Problem:

Impact:

User Story Broken:

"See which repos have running jobs from the repo list"

Current behavior: No visual indicator


5. Output Lost on Disconnect

Problem:

// ChatContext.tsx lines 151-154
socket.on('output', (data: OutputEvent) => {
  console.log('Output received:', data.jobId, data.data)
  updateJobOutput(data.jobId, data.data)  // Only appends if connected
})

Impact:

User Story Broken:

"WiFi dropped for 30 seconds during build - what errors occurred?"

Current behavior: Output from those 30 seconds is lost forever


6. No Job Persistence Across Page Refresh

Problem:

Impact:

User Story Broken:

"Accidentally refresh page during long test run"

Current behavior: Test continues on server, but UI shows frozen "Running..." forever


MEDIUM PRIORITY GAPS

7. No Global Job Dashboard

8. No Job Filtering/Search

9. No Job Metadata

10. Websocket Reconnection UX

// ChatContext.tsx lines 141-145
socket.on('disconnect', () => {
  console.log('Socket disconnected')
  setIsConnected(false)
})

Current WebSocket API Usage

Events Currently Used (Old API)

// OUTGOING (Client → Server)
socket.emit('execute', {
  repoPath: string,
  mode: 'shell' | 'agent',
  command?: string,      // shell mode
  agentCommand?: string, // agent mode
  userInput?: string,    // agent mode
  jobId: string          // client-generated
})

socket.emit('cancel', { jobId: string })

// INCOMING (Server → Client)
socket.on('job-started', ({ jobId }) => {...})
socket.on('output', ({ jobId, data, stream }) => {...})
socket.on('job-complete', ({ jobId, exitCode, duration }) => {...})
socket.on('job-cancelled', ({ jobId }) => {...})
socket.on('job-error', ({ jobId, error }) => {...})

Events NOT Used (New Phase 1 API)

// ❌ NOT IMPLEMENTED - Need to add these

// List jobs for reconnection
socket.emit('list-jobs', { repoId, status: 'running', limit: 50 })
socket.on('jobs-list', ({ jobs }) => {...})

// Subscribe to running/completed job
socket.emit('subscribe-job', { jobId })
socket.on('job-subscribed', ({ jobId, status, jobDetails }) => {...})

// Get buffered output
socket.emit('get-job-output', { jobId, fromSequence: 0, limit: 1000 })
socket.on('job-output', ({ jobId, outputs }) => {...})

// Unsubscribe when leaving
socket.emit('unsubscribe-job', { jobId })
socket.on('job-unsubscribed', ({ jobId }) => {...})

Code Locations Needing Changes

1. ChatContext.tsx

Location: /home/ubuntu/workplace/AhaiaApp/ide/web-react/src/contexts/ChatContext.tsx

Changes Needed:

Complexity: Medium-High (60-100 lines of new code)


2. JobMessage.tsx

Location: /home/ubuntu/workplace/AhaiaApp/ide/web-react/src/components/JobMessage.tsx

Changes Needed:

Complexity: Low (20-30 lines)


3. ChatPage.tsx

Location: /home/ubuntu/workplace/AhaiaApp/ide/web-react/src/pages/ChatPage.tsx

Changes Needed:

Complexity: Medium (100-150 lines for new job history component)


4. ContactsPage.tsx

Location: /home/ubuntu/workplace/AhaiaApp/ide/web-react/src/pages/ContactsPage.tsx

Changes Needed:

Complexity: Low-Medium (30-50 lines)


5. types/index.ts

Location: /home/ubuntu/workplace/AhaiaApp/ide/web-react/src/types/index.ts

Changes Needed:

Complexity: Low (30-40 lines)


6. New Component: JobHistoryPanel.tsx

Location: /home/ubuntu/workplace/AhaiaApp/ide/web-react/src/components/JobHistoryPanel.tsx (NEW FILE)

Features:

Complexity: Medium (150-200 lines)


7. New Component: JobNotification.tsx

Location: /home/ubuntu/workplace/AhaiaApp/ide/web-react/src/components/JobNotification.tsx (NEW FILE)

Features:

Complexity: Low-Medium (80-100 lines)


8. New Hook: useJobReconnection.ts

Location: /home/ubuntu/workplace/AhaiaApp/ide/web-react/src/hooks/useJobReconnection.ts (NEW FILE)

Features:

Complexity: Medium (100-120 lines)


Improvement Plan - Detailed Design

Phase B Implementation Roadmap

Priority 1: Job Reconnection (Critical)

Goal: Users can reconnect to running jobs after disconnect/navigation

Tasks:

  1. Update TypeScript types with new Phase 1 event interfaces
  2. Add list-jobs emission on repository mount in ChatContext
  3. Subscribe to all running jobs found
  4. Fetch buffered output via get-job-output
  5. Handle job-subscribed event to receive buffered + new output
  6. Unsubscribe from jobs when switching repos
  7. Add visual indicator in JobMessage for reconnected jobs

Acceptance Criteria:

Files to Modify:

Estimated Effort: 3-4 hours


Priority 2: Job History UI (Important)

Goal: Users can browse past jobs and re-view outputs

Tasks:

  1. Create JobHistoryPanel.tsx component
  2. Add toggle button in ChatPage header
  3. Fetch job list via list-jobs (no status filter = all jobs)
  4. Display jobs with status icons, timestamps, durations
  5. Click job to scroll to it or expand full output
  6. Add filter buttons (All/Running/Completed/Failed)
  7. Implement pagination for large job lists

Acceptance Criteria:

Files to Create:

Files to Modify:

Estimated Effort: 4-5 hours


Priority 3: Background Job Notifications (Important)

Goal: Users get notified when jobs complete in background repos

Tasks:

  1. Create JobNotification.tsx toast component
  2. Track active repository in global state
  3. When job completes, check if user is viewing different repo
  4. Show toast notification with job details
  5. Click toast to navigate to that repo
  6. Support multiple notifications in queue
  7. Add dismiss/auto-dismiss logic

Acceptance Criteria:

Files to Create:

Files to Modify:

Estimated Effort: 3-4 hours


Priority 4: Running Job Indicators (Polish)

Goal: Show which repos have running jobs in repository list

Tasks:

  1. Fetch running job counts for all repos
  2. Add badge overlay on repository avatars
  3. Add spinner icon if jobs running
  4. Update badge count in real-time as jobs complete
  5. Optionally cache counts in localStorage for faster initial load

Acceptance Criteria:

Files to Modify:

Estimated Effort: 2-3 hours


Priority 5: Graceful Reconnection UX (Polish)

Goal: Seamless reconnection experience

Tasks:

  1. Show reconnecting modal/banner during disconnect
  2. On reconnect, re-subscribe to active jobs
  3. Fetch missed output
  4. Show "Syncing..." badge while catching up
  5. Animate output appearing (scroll smoothly)
  6. Handle edge case: job completed during disconnect

Acceptance Criteria:

Files to Modify:

Estimated Effort: 2-3 hours


Priority 6: Mobile Optimizations (Nice-to-Have)

Goal: Perfect mobile experience

Tasks:

  1. Add pull-to-refresh on ContactsPage
  2. Optimize job history panel for small screens (bottom drawer)
  3. Add haptic feedback on job completion (if supported)
  4. Test and optimize touch targets (min 44px)
  5. Ensure notifications don't block input
  6. Add swipe gesture to close job history panel

Acceptance Criteria:

Files to Modify:

Estimated Effort: 3-4 hours


Implementation Strategy

Step-by-Step Execution Plan

STEP 1: Update Type Definitions (30 min)

  1. Open src/types/index.ts
  2. Add new event interfaces (ListJobsRequest, JobsListEvent, etc.)
  3. Add JobData and OutputChunk interfaces
  4. Update ChatContextValue with new methods if needed

STEP 2: Implement Job Reconnection in ChatContext (2-3 hours)

  1. Add state for tracking active subscriptions
  2. Add fetchRunningJobs() method that emits list-jobs
  3. Add subscribeToJob(jobId) method that emits subscribe-job
  4. Add unsubscribeFromJob(jobId) method
  5. Add event handlers for jobs-list, job-subscribed, job-output
  6. Call fetchRunningJobs() when repository changes
  7. Call fetchRunningJobs() on socket reconnect
  8. Unsubscribe from old jobs when switching repos

STEP 3: Update JobMessage Component (30 min)

  1. Add prop for isReconnected boolean
  2. Show badge "Reconnected" if applicable
  3. Test with reconnected jobs

STEP 4: Test Reconnection (1 hour)

  1. Start long job (sleep 60)
  2. Refresh page → verify job still visible
  3. Switch repos → verify job continues
  4. Return to repo → verify job completion
  5. Disconnect WiFi → verify reconnection works

STEP 5: Create Job History Panel (3-4 hours)

  1. Create new component file
  2. Implement collapsible panel UI (drawer)
  3. Fetch jobs via ChatContext
  4. Display job list with icons/timestamps
  5. Implement filters (All/Running/Completed/Failed)
  6. Add click handler to scroll to job in chat
  7. Integrate into ChatPage

STEP 6: Test Job History (30 min)

  1. Run several jobs
  2. Open history panel
  3. Verify all jobs listed
  4. Test filters
  5. Test clicking jobs

STEP 7: Implement Background Notifications (2-3 hours)

  1. Create toast component
  2. Add global notification state
  3. Detect when job completes in background repo
  4. Show toast with details
  5. Implement click-to-navigate
  6. Test queue and auto-dismiss

STEP 8: Test Notifications (30 min)

  1. Run job in Repo A
  2. Switch to Repo B
  3. Wait for job completion
  4. Verify toast appears
  5. Click toast → verify navigation

STEP 9: Add Running Job Indicators (2 hours)

  1. Track running jobs globally
  2. Add badge to ContactsPage repo items
  3. Update counts in real-time
  4. Style spinner overlay

STEP 10: Polish & Mobile Testing (2-3 hours)

  1. Test all features on mobile device
  2. Fix touch target issues
  3. Optimize animations
  4. Add pull-to-refresh
  5. Test edge cases (rapid switching, multiple jobs, etc.)

Testing Checklist

Reconnection Tests

Job History Tests

Notification Tests

Running Job Indicators

Edge Cases


Backward Compatibility

Ensuring Old Backend Compatibility

The frontend should detect if the backend supports Phase 1 features:

// Feature detection
const hasPhase1Support = useRef(false)

useEffect(() => {
  // Try to list jobs - if it fails, backend doesn't support it
  socket.emit('list-jobs', { repoId: 'test' })

  const timeout = setTimeout(() => {
    hasPhase1Support.current = false
  }, 1000)

  socket.once('jobs-list', () => {
    hasPhase1Support.current = true
    clearTimeout(timeout)
  })

  socket.once('jobs-list-error', () => {
    hasPhase1Support.current = false
    clearTimeout(timeout)
  })
}, [])

If Phase 1 not supported, gracefully disable:


Performance Considerations

State Management

WebSocket Efficiency

Rendering Optimization


Mobile PWA Considerations

Current PWA Setup

// package.json
"vite-plugin-pwa": "^1.1.0"

The app appears to be configured as a PWA. Future enhancements:


Visual Design Mock-ups

Job History Panel (Desktop)

┌─────────────────────────────────────────────────────┐
│  Repo: AhaiaApp              [X]                    │
├─────────────────────────────────────────────────────┤
│  Filters: [All] [Running] [Completed] [Failed]      │
├─────────────────────────────────────────────────────┤
│  Running (2)                                        │
│  ⚙ npm test              5m ago       [Cancel]      │
│  ⚙ git clone ...         10m ago      [Cancel]      │
│                                                     │
│  Recent (10)                                        │
│  ✓ npm install          1h ago      32s   exit 0   │
│  ✗ npm run build        2h ago      5m    exit 1   │
│  ✓ git status           3h ago      1s    exit 0   │
│  ...                                                │
│                                                     │
│  [Load More]                                        │
└─────────────────────────────────────────────────────┘

Background Notification (Toast)

┌─────────────────────────────────────────────┐
│  ✓ Build completed in Repo A                │
│     Exit code 0 · 2m 15s                    │
│                            [View] [Dismiss] │
└─────────────────────────────────────────────┘

ContactsPage with Job Indicators

┌─────────────────────────────────────────────┐
│  [AH]  AhaiaApp                    ⚙ 2    │
│        Running tests...                     │
│        main                                 │
├─────────────────────────────────────────────┤
│  [MR]  my-react-app                         │
│        Fix navbar styling                   │
│        feature/navbar                       │
└─────────────────────────────────────────────┘

Success Metrics

Before (Current State)

After (Target State)


Risk Assessment

Technical Risks

Risk 1: WebSocket Subscription Leaks

Risk 2: Rapid Repo Switching

Risk 3: Large Output Handling

Risk 4: Backward Compatibility


Dependencies to Install

No new dependencies required! All features can be built with existing stack:

Optional for performance:


Environment Variables

No new environment variables needed. Existing:

VITE_API_BASE_URL=http://localhost:3000  # Backend URL

Browser Compatibility

Target browsers:

All Phase 1 features use standard APIs (WebSocket, localStorage, React).


Conclusion - Phase A Summary

Current State

The React frontend is a well-architected, mobile-first chat application with excellent visual design and UX polish. It uses modern React patterns (hooks, context, router) and has a solid foundation.

Critical Gap

The frontend does NOT leverage the new Phase 1 backend API. It still uses the old real-time-only WebSocket pattern without job persistence, reconnection, or history.

What This Means

Users experience the same limitations that prompted the Phase 1 backend work:

The Good News

All the backend capabilities needed are ALREADY IMPLEMENTED and working. The frontend just needs to:

  1. Call the new WebSocket events (list-jobs, subscribe-job, get-job-output)
  2. Add UI components for job history and notifications
  3. Handle reconnection logic

Effort Estimate

Total Implementation Time: 18-24 hours

Recommendation

Proceed to Phase B. The implementation is straightforward, low-risk, and will dramatically improve the user experience to match the "iMessage for repos" vision.


Next Steps

User Decision Required:

Should I proceed with Phase B implementation?

If yes, I will:

  1. Start with Priority 1 (Job Reconnection) - the most critical feature
  2. Implement each priority sequentially with testing
  3. Provide progress updates after each major component
  4. Share screenshots/descriptions of new UI
  5. Create a testing checklist for you to validate

Estimated completion: Phase B can be completed in 1-2 days of focused work.


Document Status: Phase A Complete - Awaiting Phase B Authorization