5.3 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Chad is a voice/video chat desktop app built with Tauri 2 + Nuxt 4 (SPA) + mediasoup-client. It uses an SFU (Selective Forwarding Unit) architecture for WebRTC media — each peer sends to the server, which forwards selectively to others.
Commands
| Command | Description |
|---|---|
yarn dev |
Start dev server (binds to all interfaces via --host) |
yarn generate |
Generate static site to .output/public |
yarn build |
Build for production |
yarn preview |
Preview production build |
npx eslint . |
Lint the project |
npx eslint --fix . |
Lint and auto-fix |
Tauri desktop build: yarn tauri build (runs yarn generate first automatically).
Package manager is Yarn 4.12.0. No test framework is configured.
Architecture
Composable-Based State (No Pinia/Vuex)
All state is managed through Vue composables using @vueuse/core's createGlobalState and createSharedComposable. Nuxt auto-imports all composables from app/composables/.
Dependency graph (arrows = "depends on"):
useAuth (foundation — user session)
└→ useSignaling (Socket.IO connection to /webrtc namespace)
└→ useClients (connected peer list)
└→ useMediasoup (transports, producers, consumers)
├← usePreferences (device IDs, audio effects, hotkeys)
│ └← useDevices (enumerates hardware via getUserMedia)
└← useSfx (Howler.js sound effects)
useApp (top-level orchestrator — mute/unmute, video/share toggles)
└→ depends on useClients, useMediasoup, useSignaling, useSfx
Composable Tiers
Global state (createGlobalState — single instance, persists for app lifetime):
useApp— ready state, input/output mute, video/share toggles, version infouseAuth—meref, login/register/logoutuseClients—clients[]array, add/remove/update peersusePreferences— device selections, audio effects, hotkeys (localStorage + server sync)useUpdater— Tauri app update checksuseFullscreenVideo— fullscreen video element control
Shared (createSharedComposable — single instance, disposed when last consumer unmounts):
useMediasoup— mediasoup Device, transports, producers, consumers, speaking stateuseSignaling— Socket.IO client, connect/disconnectuseSfx— sound effect playback via Howler.js
Per-instance (new instance per call):
useClient(socketId)— per-peer volume/mute (localStorage), filtered consumers/producersuseAudioContext(audioTrack)— Web Audio API gain node for per-client volumeuseDevices— media device enumeration
Initialization Flow
- Middleware (global, ordered by filename prefix):
00.updater— Tauri update check, redirects to/updaterif available01.auth— validates session viaGET /me, redirects guests to/login02.user-preferences— loads server-synced preferences for authenticated users
- Plugins: build info logging, Tauri hotkey registration
- Layout (
default.vue): callsuseApp()which triggersuseSignaling().connect() - Socket authenticated → mediasoup Device created → transports created →
join()→ mic enabled
mediasoup Integration
Producer types (tracked in appData.source):
- Microphone:
kind='audio',source='mic-video' - Camera:
kind='video',source='mic-video' - Screen share:
kind='video',source='share'
Consumer filtering uses kind + appData.source to distinguish audio/video/share streams.
Transports use emitWithAck() on the Socket.IO connection for all signaling (create, connect, produce, join, pause/resume/close).
API & Networking
- REST API:
shared/chad-api.ts—$fetchinstance withcredentials: 'include', base URL from__API_BASE_URL__build-time define - WebSocket: Socket.IO to
/webrtcnamespace for signaling - Vite proxy:
/api→ production API server (for dev)
Shared Types
shared/types.ts defines ChadClient, Consumer, Producer, AppData, UpdatedClient — used by both composables and components.
Code Conventions
- ESLint:
@antfu/eslint-configwith formatters enabled - Vue SFC block order:
<template>,<script>,<style>(enforced by ESLint) console.logallowed (no-console is off)- PrimeVue components are prefixed:
PrimeButton,PrimeCard, etc. - Icons:
lucide-vue-next+primeicons - Styling: Tailwind CSS 4 + PrimeVue Aura theme (Zinc palette, dark-first)
- Reactivity: mediasoup objects wrapped with
markRaw()to prevent deep reactivity;triggerRef()used for manual reactivity triggers on the clients array
Build-Time Defines
Set via .env or environment variables:
API_BASE_URL— backend API base (default:http://localhost:4000/chad)COMMIT_SHA— git commit hash (default:'local')
Tauri
- App identifier:
xyz.koptilnya.chad - Windows-only NSIS installer (
bundle.targets: ["nsis"]) - Plugins: global-shortcut, process, updater, single-instance, log
- Frontend dist:
.output/public(fromyarn generate) @tauri-apps/plugin-*packages provide JS bindings; usewindow.__TAURI__check or theuseTauri()composable for Tauri detection