# Stack local de dependências externas para o DeskcommCRM. # # Sobe apenas o WAHA (Plus / NOWEB) pra desenvolvimento. Postgres + Auth + Storage # vêm do Supabase Cloud (ou supabase local CLI separadamente, conforme o time preferir). # # Uso: # 1. Copie .env.example -> .env.local e preencha WAHA_API_KEY (plaintext) # 2. Gere o hash: echo -n "$WAHA_API_KEY" | shasum -a 512 | awk '{print $1}' # 3. Cole esse hash em WAHA_API_KEY abaixo (NÃO o plaintext) # 4. docker compose up -d # 5. Acesse http://localhost:3030/dashboard/ (UI do WAHA Plus) # (host port 3030 — :3000 fica reservado pra outros dev tools como Remotion) # # Em prod, WAHA roda em VPS dedicada (Hostgator) atrás de Nginx (proxy_buffering off # pra SSE). docker-compose aqui é DEV ONLY. version: "3.9" services: waha: image: devlikeapro/waha:noweb platform: linux/amd64 container_name: deskcomm-waha restart: unless-stopped ports: - "3030:3000" environment: # Hash SHA512 hex da api key (NÃO plaintext). Cliente envia plaintext em X-Api-Key. WAHA_API_KEY: ${WAHA_API_KEY_SHA512} # Webhook base URL — precisa ser pública (use ngrok/cloudflared em dev). # host.docker.internal: o app Next roda no HOST em dev — localhost dentro do # container seria o próprio WAHA e o webhook nunca chegaria. Porta 3002: # a stack da fusão é isolada do checkout principal (3001 é do gov-loop). WHATSAPP_HOOK_URL: ${WAHA_HOOK_BASE_URL:-http://host.docker.internal:3003}/api/v1/webhooks/waha # `message.reaction` (#2797): sem ele na lista o WAHA NUNCA entrega o gesto, # e o CRM fica sem a resposta mais comum do WhatsApp. O roteador tem o ramo # próprio (`handleReaction`, lib/waha/ingest.ts): a reação vira linha # `type='reaction'` ligada ao alvo, e não carimba a conversa como mensagem. WHATSAPP_HOOK_EVENTS: "message.any,message.ack,message.edited,message.revoked,message.reaction,session.status,state.change" # HMAC SHA512 do payload, validado server-side via crypto.timingSafeEqual. # Nome EXATO da doc do WAHA (events#hmac-authentication): sem o _KEY ele ignora. WHATSAPP_HOOK_HMAC_KEY: ${WAHA_HMAC_SECRET} # Engine NOWEB por default (mais leve, ~150MB; estável). O env é # WHATSAPP_DEFAULT_ENGINE — WAHA_DEFAULT_ENGINE NÃO existe no WAHA e caía # silenciosamente no default WEBJS (browser, trava a sessão). WHATSAPP_DEFAULT_ENGINE: NOWEB # Storage de mídia: Supabase Storage via Backend (NÃO inline base64). WAHA_DASHBOARD_ENABLED: "true" # Sem isto o container volta (ou o Docker Desktop acorda) e as sessões # ficam STOPPED — o front abre em "Conectando…" e as mensagens do período # fora não chegam. True retoma as que já existiam; não pede QR de novo. WHATSAPP_RESTART_ALL_SESSIONS: "${WHATSAPP_RESTART_ALL_SESSIONS:-True}" extra_hosts: - "host.docker.internal:host-gateway" volumes: - waha-data:/app/.sessions - waha-media:/app/.media healthcheck: # /ping é o único endpoint sem auth desta build (api/health = 401/404). test: ["CMD", "curl", "-fsS", "http://127.0.0.1:3000/ping"] interval: 30s timeout: 5s retries: 3 start_period: 30s # Worker 24/7 do agent-engine (fusão Vendaval): fila, cron/follow-up, drain do # event_log e turnos do agente rico. Postgres = Supabase (SUPABASE_DB_URL no # .env.local). Sobe junto do WAHA: `docker compose up -d`. worker: build: context: . dockerfile: Dockerfile.worker container_name: deskcomm-agent-worker restart: unless-stopped env_file: - .env - .env.local environment: # dentro do container, localhost é o próprio worker — o WAHA está na rede # do compose (serviço waha, porta interna 3000). Sobrepõe o .env.local. WAHA_API_BASE_URL: http://waha:3000 ports: # Só 127.0.0.1: /healthz e /metrics do worker não têm autenticação e o # /metrics conta filas, sessões e custo de todas as empresas. Sem endereço # de bind o Docker publica em 0.0.0.0 — qualquer um na mesma rede (Wi-Fi # do café, LAN do escritório) lia os números. O healthcheck roda DENTRO do # container e não depende desta linha. - "127.0.0.1:8787:8787" healthcheck: # 127.0.0.1 explícito: localhost resolve p/ ::1 e o healthz escuta só IPv4. test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://127.0.0.1:8787/healthz"] interval: 30s timeout: 5s retries: 3 start_period: 20s volumes: waha-data: waha-media: