Files
chatwoot/docker-compose.production.yaml
T
tds-1androot 5e5dc21f2f feat(whatsapp-call): add server-side WebRTC media server for call persistence
Implements a Pion Go B2BUA media server sidecar that sits between Meta's
WhatsApp Cloud API and the agent's browser, enabling call persistence
across page reloads, server-side recording, multi-participant support,
audio injection, and AI integration readiness.

Go Media Server (enterprise/media-server/):
- Pion WebRTC v4 B2BUA with Peer A (Meta) and Peer B (Agent) connections
- Real-time OGG/Opus recording with crash recovery
- Audio bridge with multi-peer fan-out and AudioConsumer plugin interface
- Audio injection from OGG files with loop support for hold music
- Session manager with graceful shutdown and orphaned recording recovery
- HTTP API with Bearer token auth, health checks, and metrics

Rails Integration:
- Whatsapp::MediaServerClient HTTP client for Go sidecar communication
- Dual-mode CallService: legacy browser-direct and server-relay paths
- Media server callback controller for agent disconnect/recording/terminate
- CallRecordingFetchJob: downloads OGG from Go server to ActiveStorage/S3
- CallCleanupJob: sweeps stale ringing and in-progress calls
- New endpoints: active, agent_answer, reconnect, join, play_audio
- DB migration: media_session_id column with indexes

Frontend:
- Dual-mode composable auto-detecting legacy vs server-relay
- handleAgentOffer() for receiving SDP from media server
- useCallReconnection composable for page reload recovery
- Removed terminateCallOnUnload in server-relay mode
- Simplified outbound call flow in ConversationHeader
- New ActionCable event: whatsapp_call.agent_offer

Documentation:
- Server-side WebRTC architecture spec (1505 lines)
- Implementation plan with 119 trackable checklist items
- Feature spec, PR breakdown, and relay architecture docs
2026-04-21 04:47:53 +00:00

91 lines
2.3 KiB
YAML

version: '3'
services:
base: &base
image: chatwoot/chatwoot:latest
env_file: .env ## Change this file for customized env variables
volumes:
- storage_data:/app/storage
rails:
<<: *base
depends_on:
- postgres
- redis
ports:
- '127.0.0.1:3000:3000'
environment:
- NODE_ENV=production
- RAILS_ENV=production
- INSTALLATION_ENV=docker
entrypoint: docker/entrypoints/rails.sh
command: ['bundle', 'exec', 'rails', 's', '-p', '3000', '-b', '0.0.0.0']
restart: always
sidekiq:
<<: *base
depends_on:
- postgres
- redis
environment:
- NODE_ENV=production
- RAILS_ENV=production
- INSTALLATION_ENV=docker
command: ['bundle', 'exec', 'sidekiq', '-C', 'config/sidekiq.yml']
restart: always
postgres:
image: pgvector/pgvector:pg16
restart: always
ports:
- '127.0.0.1:5432:5432'
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=chatwoot
- POSTGRES_USER=postgres
# Please provide your own password.
- POSTGRES_PASSWORD=
redis:
image: redis:alpine
restart: always
command: ["sh", "-c", "redis-server --requirepass \"$REDIS_PASSWORD\""]
env_file: .env
volumes:
- redis_data:/data
ports:
- '127.0.0.1:6379:6379'
# Optional: WhatsApp Calling media server (server-side WebRTC relay)
# Uncomment to enable call persistence across page reloads and server-side recording.
# media-server:
# image: chatwoot/media-server:latest
# env_file: .env
# ports:
# - '4000:4000'
# - '10000-10100:10000-10100/udp'
# environment:
# - AUTH_TOKEN=${MEDIA_SERVER_AUTH_TOKEN}
# - RAILS_CALLBACK_URL=http://rails:3000
# - RECORDINGS_DIR=/recordings
# - LOG_LEVEL=info
# - UDP_PORT_MIN=10000
# - UDP_PORT_MAX=10100
# - PUBLIC_IP=${MEDIA_SERVER_PUBLIC_IP}
# - STUN_SERVERS=stun:stun.l.google.com:19302
# volumes:
# - media_recordings:/recordings
# restart: always
# healthcheck:
# test: ['CMD', 'wget', '--spider', '-q', 'http://localhost:4000/health']
# interval: 10s
# timeout: 5s
# retries: 3
volumes:
storage_data:
postgres_data:
redis_data:
# media_recordings: