services: postgres: image: postgres:18-alpine container_name: b2bcall-postgres restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} ports: - "127.0.0.1:5432:5432" volumes: - postgres_data:/var/lib/postgresql healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] interval: 5s timeout: 5s retries: 10 redis: image: redis:7-alpine container_name: b2bcall-redis restart: unless-stopped command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}"] ports: - "127.0.0.1:6379:6379" volumes: - redis_data:/data healthcheck: test: ["CMD-SHELL", "redis-cli -a ${REDIS_PASSWORD} ping | grep -q PONG"] interval: 5s timeout: 5s retries: 10 fs-config: build: context: . dockerfile: apps/freeswitch-config/Dockerfile container_name: b2bcall-fs-config restart: unless-stopped depends_on: - postgres - redis environment: # Hostname interno do compose (postgres/redis/freeswitch), nao # localhost — ver docs/NETWORK_ARCHITECTURE.md. APP_DATABASE_URL: postgresql://${POSTGRES_APP_USER}:${POSTGRES_APP_PASSWORD}@postgres:5432/${POSTGRES_DB}?schema=public ENCRYPTION_KEY: ${ENCRYPTION_KEY} FS_CONFIG_USER: ${FS_CONFIG_USER} FS_CONFIG_PASSWORD: ${FS_CONFIG_PASSWORD} REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379 ESL_HOST: freeswitch ESL_PORT: "8021" ESL_PASSWORD: ${ESL_PASSWORD} SOFIA_EXTERNAL_GATEWAYS_DIR: /gateways CALLCENTER_QUEUES_DIR: /callcenter-queues volumes: # Compartilhado com o FreeSWITCH (agente.md secao 41-42): fs-config # escreve os XML de gateway aqui, o profile "external" ja inclui # sip_profiles/external/*.xml automaticamente (config vanilla). - freeswitch_external_gateways:/gateways # Compartilhado com o FreeSWITCH (agente.md secao 50-51): fs-config # escreve um XML de fila por arquivo aqui, incluido via # X-PRE-PROCESS no nosso callcenter.conf.xml (mesmo padrao acima). - freeswitch_callcenter_queues:/callcenter-queues # Sem porta publicada: so o FreeSWITCH (mesma rede do compose) chama isto. healthcheck: test: ["CMD", "node", "-e", "fetch('http://localhost:8080/health').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"] interval: 10s timeout: 5s retries: 10 start_period: 10s freeswitch: build: context: ./infrastructure/freeswitch secrets: - freeswitch_pat container_name: b2bcall-freeswitch restart: unless-stopped depends_on: - fs-config environment: ESL_PASSWORD: ${ESL_PASSWORD} FS_CONFIG_USER: ${FS_CONFIG_USER} FS_CONFIG_PASSWORD: ${FS_CONFIG_PASSWORD} volumes: - freeswitch_external_gateways:/etc/freeswitch/sip_profiles/external - freeswitch_callcenter_queues:/etc/freeswitch/autoload_configs/callcenter_queues.conf.d # Nenhuma porta publicada no host: SIP/RTP ainda não têm troncos reais # configurados, e o Event Socket (8021) só deve ser alcançável por outros # containers na rede interna do compose (agente.md secao 22). healthcheck: test: ["CMD-SHELL", "fs_cli -p \"$$ESL_PASSWORD\" -x status | grep -q 'is ready'"] interval: 10s timeout: 5s retries: 10 start_period: 20s fs-events: build: context: . dockerfile: apps/freeswitch-events/Dockerfile container_name: b2bcall-fs-events restart: unless-stopped depends_on: - freeswitch - redis - postgres environment: ESL_HOST: freeswitch ESL_PORT: "8021" ESL_PASSWORD: ${ESL_PASSWORD} APP_DATABASE_URL: postgresql://${POSTGRES_APP_USER}:${POSTGRES_APP_PASSWORD}@postgres:5432/${POSTGRES_DB}?schema=public # Hostnames internos do compose (freeswitch/redis), diferente do # REDIS_URL do .env que aponta pra localhost (uso pelo apps/api, que # ainda roda no host) — ver docs/NETWORK_ARCHITECTURE.md. REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379 predictive-dialer: build: context: . dockerfile: apps/predictive-dialer/Dockerfile container_name: b2bcall-predictive-dialer restart: unless-stopped depends_on: - freeswitch - redis - postgres environment: ESL_HOST: freeswitch ESL_PORT: "8021" ESL_PASSWORD: ${ESL_PASSWORD} APP_DATABASE_URL: postgresql://${POSTGRES_APP_USER}:${POSTGRES_APP_PASSWORD}@postgres:5432/${POSTGRES_DB}?schema=public REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379 # Real Outbound Safety (agente.md secao 186): as DUAS precisam estar # explicitamente ligadas pra originar PSTN de verdade — nunca ativado # por default. Ver docs/PREDICTIVE_DIALER.md. DIALER_SIMULATION: ${DIALER_SIMULATION:-true} ALLOW_REAL_OUTBOUND_CALLS: ${ALLOW_REAL_OUTBOUND_CALLS:-false} secrets: freeswitch_pat: environment: FREESWITCH_PAT volumes: postgres_data: redis_data: freeswitch_external_gateways: freeswitch_callcenter_queues: