Files
mesh/client/CLAUDE.md
Gilles Soulier 1d177e96a6 first
2026-01-05 13:20:54 +01:00

6.6 KiB

CLAUDE.md — Mesh Client

This file provides client-specific guidance for the Mesh web application.

Client Role

The Mesh Client is a web application (React/TypeScript) that provides:

  • User interface for chat, audio/video calls, screen sharing
  • WebRTC media plane: Direct P2P audio/video/screen connections
  • WebSocket connection to server for control plane
  • Integration with desktop agent for advanced features

Critical: The client handles WebRTC media directly (P2P). File/folder/terminal sharing is delegated to the desktop agent via QUIC.

Technology Stack

  • React 18 with TypeScript
  • Vite for build tooling
  • React Router for navigation
  • TanStack Query for server state management
  • Zustand for client state management
  • simple-peer for WebRTC abstraction
  • Monokai-inspired dark theme

Project Structure

client/
├── src/
│   ├── main.tsx              # App entry point
│   ├── App.tsx               # Main app component
│   ├── pages/
│   │   ├── Login.tsx         # Login page
│   │   └── Room.tsx          # Main room interface
│   ├── components/
│   │   ├── Chat/             # Chat components
│   │   ├── Video/            # Video call components
│   │   ├── Participants/     # Participant list
│   │   └── Controls/         # Call controls
│   ├── lib/
│   │   ├── websocket.ts      # WebSocket client
│   │   ├── webrtc.ts         # WebRTC manager
│   │   └── events.ts         # Event handlers
│   ├── stores/
│   │   ├── authStore.ts      # Auth state
│   │   ├── roomStore.ts      # Room state
│   │   └── callStore.ts      # Call state
│   ├── hooks/
│   │   ├── useWebSocket.ts   # WebSocket hook
│   │   └── useWebRTC.ts      # WebRTC hook
│   ├── types/
│   │   └── events.ts         # Event type definitions
│   └── styles/
│       ├── global.css        # Global styles
│       └── theme.css         # Monokai theme
├── public/
├── index.html
├── package.json
├── tsconfig.json
├── vite.config.ts
└── CLAUDE.md

Development Commands

Setup

cd client
npm install
# or
pnpm install

Run Development Server

npm run dev
# Opens at http://localhost:3000

Build for Production

npm run build
# Output in dist/

Type Checking

npm run type-check

Linting

npm run lint

Design System - Monokai Dark Theme

The UI uses a Monokai-inspired color palette defined in src/styles/theme.css:

Colors:

  • Background Primary: #272822
  • Background Secondary: #1e1f1c
  • Text Primary: #f8f8f2
  • Accent Primary (cyan): #66d9ef
  • Accent Success (green): #a6e22e
  • Accent Warning (orange): #fd971f
  • Accent Error (pink): #f92672

Typography:

  • System font stack with fallbacks
  • Fira Code for code/monospace elements

WebSocket Integration

The client maintains a persistent WebSocket connection to the server for control plane events.

Connection flow:

  1. Authenticate with JWT (obtained from login)
  2. Send system.hello with peer type and version
  3. Receive system.welcome with assigned peer_id
  4. Join room with room.join
  5. Listen for events and send messages

See protocol_events_v_2.md for complete event protocol.

Key events to handle:

  • system.welcome - Store peer_id
  • room.joined - Update participant list
  • chat.message.created - Display message
  • rtc.offer/answer/ice - WebRTC signaling
  • presence.update - Update participant status

WebRTC Implementation

Call flow:

  1. Request capability token from server (via REST API)
  2. Create local media stream (getUserMedia)
  3. Create peer connection with ICE servers
  4. Send rtc.offer with capability token
  5. Receive rtc.answer
  6. Exchange ICE candidates via rtc.ice
  7. Connection established, media flows P2P

Screen sharing:

  • Use getDisplayMedia instead of getUserMedia
  • Same signaling flow with screen capability token

Important:

  • Always include capability token in WebRTC signaling messages
  • Handle ICE connection failures gracefully
  • Implement reconnection logic
  • Clean up media streams on disconnect

State Management

Zustand stores:

// authStore.ts
{
  user: User | null,
  token: string | null,
  peerId: string | null,
  login: (username, password) => Promise<void>,
  logout: () => void
}

// roomStore.ts
{
  currentRoom: Room | null,
  participants: Participant[],
  messages: Message[],
  joinRoom: (roomId) => void,
  sendMessage: (content) => void
}

// callStore.ts
{
  activeCall: Call | null,
  localStream: MediaStream | null,
  remoteStreams: Map<peerId, MediaStream>,
  startCall: (peerId, type) => Promise<void>,
  endCall: () => void
}

Component Guidelines

  1. Functional components with TypeScript
  2. Use hooks for side effects and state
  3. CSS Modules for component-scoped styles
  4. Semantic HTML
  5. Accessibility: ARIA labels, keyboard navigation
  6. Error boundaries for graceful error handling

Security Considerations

  • Never store JWT in localStorage (use httpOnly cookies or memory)
  • Validate all incoming WebSocket messages
  • Sanitize user-generated content (messages, usernames)
  • Verify WebRTC fingerprints (optional, V1+)
  • No sensitive data in console logs

Performance Optimization

  • Lazy load routes with React.lazy
  • Virtualize long lists (messages, participants)
  • Debounce input handlers
  • Memoize expensive computations (useMemo)
  • Avoid unnecessary re-renders (React.memo)

Testing Strategy

  1. Unit tests: Components, hooks, utilities
  2. Integration tests: WebSocket flows, WebRTC signaling
  3. E2E tests: Complete user journeys (login, join room, send message, call)

Browser Support

  • Chrome/Edge: 90+
  • Firefox: 88+
  • Safari: 15+

WebRTC requires modern browsers. Provide warning for unsupported browsers.

Environment Variables

Create .env.local for development:

VITE_API_URL=http://localhost:8000
VITE_WS_URL=ws://localhost:8000/ws

Build & Deployment

The client builds to static files that can be served via:

  • Nginx/Caddy
  • CDN (CloudFront, Cloudflare)
  • Docker container with nginx

Important: Configure CORS on the server to allow client origin.


Remember: The client handles only WebRTC media (audio/video/screen) in P2P mode. File/folder/terminal sharing requires the desktop agent.