# Setup — Backend ## Pré-requisitos - Node.js 18+ (ver `engines.node` no `package.json`) - MySQL 8+ acessível na rede - Qdrant rodando (padrão: `http://localhost:6333`) - Ollama rodando com os modelos necessários: ```bash ollama pull nomic-embed-text ollama pull llama3.1 ``` ## Instalação ```bash cd backend npm install ``` ## Variáveis de ambiente Crie o arquivo `backend/.env` com base nas variáveis abaixo: ### Servidor | Variável | Descrição | Exemplo | |---|---|---| | `PORT` | Porta HTTP da API | `3001` | | `CORS_ORIGIN` | Origem permitida pelo CORS | `http://localhost:5173` | | `API_KEY` | Chave de API opcional | — | | `RATE_LIMIT_PER_MINUTE` | Limite de requisições por minuto (`0` desativa) | `0` | ### Banco de dados (MySQL) | Variável | Descrição | Exemplo | |---|---|---| | `DB_HOST` | Host do MySQL | `localhost` | | `DB_PORT` | Porta do MySQL | `3306` | | `DB_USER` | Usuário do banco | `root` | | `DB_PASS` | Senha do banco | `senha` | | `DB_SCHEMA` | Nome do schema/database | `oracle` | | `DB_SSL_REJECT_UNAUTHORIZED` | Ativa SSL na conexão MySQL e valida o certificado do servidor (setar sozinho já liga SSL, mesmo sem `DB_SSL_CA`) | — | | `DB_SSL_CA` | Caminho de um certificado CA para validar o servidor MySQL (se ele não usar CA público) | `./certs/rds-ca.pem` | ### Qdrant (busca vetorial) | Variável | Descrição | Exemplo | |---|---|---| | `QDRANT_URL` | URL do Qdrant | `http://localhost:6333` | | `QDRANT_COLLECTION` | Nome da collection (default no código: `oraculo_docs`) | `empresa_docs` | | `QDRANT_API_KEY` | Chave de API do Qdrant (opcional) | — | ### Ollama (LLM local) | Variável | Descrição | Exemplo | |---|---|---| | `OLLAMA_URL` | URL do Ollama | `http://localhost:11434` | | `OLLAMA_EMBEDDINGS_MODEL` | Modelo para embeddings | `nomic-embed-text` | | `OLLAMA_CHAT_MODEL` | Modelo para chat | `llama3.1` | | `OLLAMA_VISION_MODEL` | Modelo de visão (default `llava:latest`) | `llava:latest` | | `OLLAMA_ATENDENTE_MODEL` | Modelo usado na sugestão de resposta ao atendente (default `star-atendente`) | `llama3.1` | | `OLLAMA_TIMEOUT_MS` | Timeout (ms) para chamadas não-streaming ao Ollama (default `180000`) | `180000` | | `OLLAMA_STREAM_IDLE_TIMEOUT_MS` | Timeout (ms) de inatividade no streaming do chat — reinicia a cada chunk recebido (default `60000`) | `60000` | | `OLLAMA_EMBED_QUERY_PREFIX` | Prefixo prependado à query antes de gerar embedding (modelos assimétricos, ex.: e5) | — | | `OLLAMA_EMBED_PASSAGE_PREFIX` | Prefixo prependado à passagem indexada antes de gerar embedding | — | ### RAG Contexto do pipeline (rewrite, HyDE, rerank) em [architecture.md](architecture.md). | Variável | Descrição | Exemplo | |---|---|---| | `RAG_QUERY_REWRITE` | Reescrever query antes da busca, considerando o histórico da conversa (resolve follow-ups tipo "e o segundo caso?") | `true` | | `RAG_HISTORY_LIMIT` | Quantidade de mensagens recentes do histórico incluídas no prompt de rewrite/chat (default `6`) | `6` | | `RAG_TOP_K` | Número de chunks recuperados (default `8`) | `8` | | `RAG_MIN_SCORE` | Score mínimo de similaridade (default `0.40`) | `0.40` | | `RAG_CHUNK_SIZE` | Tamanho de cada chunk (caracteres) | `900` | | `RAG_CHUNK_OVERLAP` | Sobreposição entre chunks | `150` | | `RAG_RERANK` | Reordenar os chunks recuperados por relevância via LLM antes de montar o contexto | `true` | | `RAG_RERANK_TOP_N` | Quantos chunks manter após o reranking (default = `RAG_TOP_K`) | `8` | | `RAG_HYDE` | HyDE: gera um trecho hipotético de resposta via LLM e usa ele para o embedding de busca (custa uma chamada LLM extra por pergunta) | `false` | ### LLM (parâmetros de geração) | Variável | Descrição | Exemplo | |---|---|---| | `LLM_TEMPERATURE` | Criatividade das respostas (0–1); baixo = mais fiel à fonte (default `0.2`) | `0.2` | | `LLM_TOP_P` | Nucleus sampling | `0.9` | | `LLM_NUM_PREDICT` | Máximo de tokens gerados | `2048` | | `LLM_REPEAT_PENALTY` | Penalidade de repetição | `1.1` | ### Autenticação (JWT) Fluxo completo e níveis de acesso em [auth.md](auth.md). | Variável | Descrição | Exemplo | |---|---|---| | `AUTH_MODE` | Modo de auth (`jwt` ou `none`) | `jwt` | | `JWT_SECRET` | Chave secreta para assinar tokens | `trocar-em-producao` | | `JWT_ISSUER` | Issuer do token | `oraculo-api` | | `JWT_ACCESS_TTL_SECONDS` | Duração do access token em segundos | `900` (15 min) | | `JWT_REFRESH_TTL_SECONDS` | Duração do refresh token em segundos | `2592000` (30 dias) | | `JWT_REFRESH_TTL_SHORT_SECONDS` | Duração do refresh token quando `rememberMe=false`/ausente no login | `86400` (1 dia) | > **Atenção:** `AUTH_MODE=none` desativa a autenticação completamente. Nunca usar em produção. ### Ifbot (sincronização de atendimentos) | Variável | Descrição | Exemplo | |---|---|---| | `IFBOT_BASE_URL` | URL base da API do ifbot (default `https://star.ifbot.com.br/api`) | `https://star.ifbot.com.br/api` | | `IFBOT_TOKEN` | Token de autenticação da API do ifbot | — | | `IFBOT_AUTH_HEADER` | Nome do header de autenticação (default `Authorization`) | `Authorization` | | `IFBOT_MEDIA_BASE_URL` | Base pública dos arquivos de mídia (`/data/img`, `/data/aud`); default é `IFBOT_BASE_URL` sem o sufixo `/api` | `https://star.ifbot.com.br` | | `ATENDIMENTOS_SYNC_INTERVAL_MINUTES` | Intervalo (min) do job de sincronização de atendimentos (`0` desativa) | `30` | ### RAG de atendimentos Ingestão de conversas no Qdrant, em uma collection separada da de documentos. | Variável | Descrição | Exemplo | |---|---|---| | `ATENDIMENTOS_RAG_SEARCH_ENABLED` | Habilita a busca vetorial no modo "atendimentos" do chat | `false` | | `ATENDIMENTOS_RAG_COLLECTION` | Nome da collection no Qdrant | `atendimentos_rag` | | `ATENDIMENTOS_RAG_INTERVAL_MINUTES` | Intervalo (min) do job de ingestão | `60` | | `ATENDIMENTOS_RAG_BATCH` | Tamanho do lote por execução | `10` | | `ATENDIMENTOS_RAG_CHUNK_SIZE` | Tamanho de cada chunk (caracteres) | `1800` | | `ATENDIMENTOS_RAG_CHUNK_OVERLAP` | Sobreposição entre chunks | `200` | | `ATENDIMENTOS_RAG_TOP_K` | Número de chunks recuperados | `20` | | `ATENDIMENTOS_RAG_MIN_SCORE` | Score mínimo de similaridade | `0.5` | | `ATENDIMENTOS_RAG_HYDE` | HyDE aplicado à busca de atendimentos | `false` | ### WhatsApp Cloud API (Meta) Usada pelo chat de Atendimentos (`/api/conversas`) e pelo webhook em `/webhooks/whatsapp` (fora de `/api`, sem JWT — protegido por `hub.verify_token` na verificação e, opcionalmente, assinatura HMAC no recebimento). Valores vêm do painel da Meta (`developers.facebook.com/apps//whatsapp-business/wa-dev-console/`). | Variável | Descrição | Exemplo | |---|---|---| | `WHATSAPP_API_VERSION` | Versão da API (default `v21.0`) | `v25.0` | | `WHATSAPP_PHONE_NUMBER_ID` | ID do número, aba "API Setup" | — | | `WHATSAPP_TOKEN` | Token de acesso, aba "API Setup" (o temporário expira em 24h; gerar um permanente em System Users antes de produção) | — | | `WHATSAPP_VERIFY_TOKEN` | Valor arbitrário definido por você; colar o mesmo valor no painel da Meta em Webhook → "Verify token" | — | | `WHATSAPP_APP_SECRET` | Aba "App settings → Basic", campo "App Secret"; valida a assinatura `X-Hub-Signature-256` (vazio desativa a validação) | — | | `WHATSAPP_BUSINESS_ACCOUNT_ID` | Opcional, não usado ainda; reservado para gestão de templates/perfil de negócio | — | ### Integrador IXC (Alfred) Usadas só pelo seed (`npm run seed:run`), que provisiona a linha na tabela `integracao`. Em runtime o service lê Url/Login/Senha/Token do banco, não do `.env` (o token sobrevive a restart). Rodar o seed de novo com Login/Senha diferentes força um novo login e invalida o token cacheado. | Variável | Descrição | Exemplo | |---|---|---| | `IXC_INTEGRADOR_BASE_URL` | URL base do integrador | `http://localhost:4001/` | | `IXC_INTEGRADOR_LOGIN` | Login do integrador | — | | `IXC_INTEGRADOR_SENHA` | Senha do integrador | — | ### Whisper (transcrição de áudio local) Fallback usado quando o ifbot não traz a transcrição do áudio. Requer `brew install whisper-cpp ffmpeg` e o modelo baixado em `WHISPER_MODEL_PATH`. | Variável | Descrição | Exemplo | |---|---|---| | `WHISPER_TRANSCRICAO_ENABLED` | Liga a feature (default `false`) | `true` | | `WHISPER_BINARY_PATH` | Caminho do binário `whisper-cli` (default `whisper-cli`) | `whisper-cli` | | `WHISPER_FFMPEG_PATH` | Caminho do binário `ffmpeg` (default `ffmpeg`) | `ffmpeg` | | `WHISPER_MODEL_PATH` | Caminho do modelo Whisper | `whisper_models/ggml-small.bin` | | `WHISPER_VAD_MODEL_PATH` | Caminho do modelo VAD (detecção de voz) | `whisper_models/ggml-silero-vad.bin` | | `WHISPER_TIMEOUT_MS` | Timeout (ms) da transcrição (default `60000`) | `60000` | ## Rodando localmente ```bash # Criar as tabelas no banco (rodar uma vez ou após novas migrations) npm run migrate:latest # Modo desenvolvimento (hot reload) npm run dev # Modo produção npm start ``` A API estará disponível em `http://localhost:3001`. Para verificar o status dos serviços: ``` GET http://localhost:3001/health ``` ## Comandos disponíveis | Comando | Descrição | |---|---| | `npm run dev` | Inicia com hot reload (`node --watch`) | | `npm start` | Inicia sem hot reload | | `npm run migrate:latest` | Aplica todas as migrations pendentes | | `npm run migrate:rollback` | Reverte a última migration | | `npm run seed:run` | Executa os seeds do banco |