New features· 26 items

Version 1.46.0

The release notes are written in Portuguese, the language DeskcommCRM is built in. Your browser can translate them, or you can open this page already translated.

Open in Google Translate

Added3

Quando o telefone da conversa cai, dá para continuar o atendimento por outro número

No Inbox, o botão Transferir ganhou duas abas: Atendente, como antes, e Número. Na aba Número você escolhe outro número de WhatsApp da empresa e clica Continuar por este número: o sistema abre a conversa do mesmo cliente nesse número e já a mostra na tela. Se a conversa lá estiver livre, você fica como responsável e o atendimento automático daquele número não entra no meio; se ela já estiver com alguém, a tela diz com quem. Números desconectados aparecem na lista, mas não podem ser escolhidos. Quando o número da conversa aberta não está conectado e existe outro conectado, aparece acima do campo de digitar a faixa Responder por outro número, que leva direto para essa escolha. Antes não havia como responder: a conversa ficava presa ao número que caiu. O histórico antigo continua na conversa do número original. Crédito: @rafaelbatistazz.

Variável META_WEBHOOK_BASE_URL para separar a URL pública dos webhooks da Meta

Adiciona a variável opcional META_WEBHOOK_BASE_URL, permitindo configurar uma URL pública dedicada para o callback dos webhooks da Meta (WhatsApp Cloud API / canais oficiais), separada de NEXT_PUBLIC_APP_URL. Mantém compatibilidade total com instalações existentes por fallback automático.

Contribuição de @webtecnica (#1554).

O link da imagem do modelo se salva na aba Templates, sem enviar nada

Em Conexões › Templates da Meta, cada modelo com imagem, vídeo ou documento no cabeçalho ganha um campo para o link público do arquivo e o botão Salvar link. Antes a única forma de salvar esse link era enviar o modelo numa conversa com a janela de 24 horas fechada — ou seja, era preciso disparar para um cliente só para deixar o modelo pronto. Agora o link fica salvo direto no modelo, e quando você escolhe esse modelo numa conversa o campo do link já vem preenchido. Apagar o campo e clicar em Remover link esquece o link. Salvar é do administrador, como sincronizar. Crédito: @rafaelbatistazz.

Fixed23

Extratores de atribuição deixam de gravar o id do anúncio como clique de origem

Quando uma mensagem com referral de anúncio chegava sem ctwa_clid, os extratores de atribuição (API oficial e WAHA) utilizavam o id do anúncio (source_id) como fallback para sourceId (ad_source_id), fazendo com que o envio de conversões reportasse o identificador do anúncio à plataforma como se fosse o identificador do clique. Agora os extratores gravam sourceId exclusivamente quando o clique (ctwa_clid / ctwaClid) estiver presente, mantendo o id do anúncio estritamente em adId (ad_id).

Contribuição de @webtecnica (#1552).

Na Agenda, o botão Confirmar volta a ser alcançável em janelas baixas

Em telas largas com pouca altura (por exemplo 1280×500 ou 1024×560), o formulário de "Novo agendamento" cortava a lista de horários e o botão Confirmar sem barra de rolagem: os campos acima do calendário ocupavam quase toda a altura e o painel ficava sem espaço. Agora o formulário inteiro rola, o painel de marcar mantém a altura do próprio conteúdo e a lista de horários continua com a sua rolagem própria.

O agente deixa de dizer que "vai ver os horários" sem consultar a agenda

O agente com ferramenta de agenda já era impedido de responder "vou verificar os horários" ou "estou confirmando a disponibilidade" sem ter consultado a agenda de verdade naquele turno. Uma forma parecida escapava: "Vou chamar a responsável pra ver os horários." A mensagem saía e o turno terminava sem consulta nenhuma: a promessa de olhar os horários ficava só na promessa. Agora essa forma também é barrada, e o agente é orientado a consultar a agenda e responder com os horários reais. A regra nova é estreita de propósito: frases em que quem vai ver é o cliente ("pra você ver a agenda do evento"), "nada a ver com o seu agendamento" e "vamos ver: o horário de funcionamento é…" continuam saindo normalmente. Não há nada a configurar.

Contribuição de @gyanu2507 (#972); relato de @spoliagency (#970).

Ação de automação assign_owner passa a ajustar owner_kind e limpar owner_agent_id

A ação de automação assign_owner atualizava owner_user_id diretamente no crm_leads sem ajustar owner_kind nem limpar owner_agent_id, violando a constraint crm_leads_owner_kind_coherence em leads previamente atribuídos a agentes de IA ou gerando incoerência em leads com dono sem tipo. Agora a ação roteia a atribuição por resolveOwnerPatch, garantindo a coerência do trio owner_user_id, owner_kind e owner_agent_id.

Contribuição de @webtecnica (#1549).

A atualização para de refazer no banco o que já estava pronto

Toda atualização reaplica o esquema do banco inteiro com o sistema no ar. Alguns trechos dele desfaziam e refaziam, a cada atualização, coisas que já estavam no formato final: a tabela de compromissos da agenda era regravada inteira, uma coluna da tabela de membros da equipe era criada e apagada, e duas proteções da agenda e do follow-up eram reconstruídas. Enquanto isso acontecia, quem usava a agenda ou fazia login podia ficar esperando, e cada passada consumia de novo recursos do banco.

Agora esses trechos conferem o banco antes e só agem quando ele ainda não chegou ao formato final. O resultado final é o mesmo de antes; a atualização só deixa de repetir esse trabalho. Nada precisa ser feito por quem opera a instalação.

Rodar a atualização de novo remove o aviso de manutenção que ficou preso

Se uma atualização era interrompida depois de pôr no ar o aviso de manutenção, o aviso ficava de pé e o CRM respondia 503 para todo mundo (site, rotinas e webhooks do WhatsApp); rodar o update.sh de novo dizia "Nada a atualizar" e saía sem tocar nele. Agora essa mesma saída remove o aviso preso, avisa quem está operando e diz como concluir a atualização interrompida. Medido numa VPS real, onde o CRM ficou 6h30 fora do ar por isso.

Contribuição de @gideony (#1524).

O aviso de "sem chave de IA" no onboarding deixa de dizer "chave de da Anthropic"

Quem instala sem chave de IA e cria o primeiro atendente vê um aviso explicando que ele ficou como rascunho. A frase juntava duas preposições e saía "Não achei chave de da Anthropic (Claude)" — e, em espanhol, "No encontré ninguna clave de de la Anthropic". Agora sai "Não achei chave da Anthropic (Claude)". Nenhum comportamento muda: é só o texto do aviso.

crm_find_free_slots tolera dia e dias_a_frente juntos priorizando dia

A ferramenta MCP crm_find_free_slots não recusa mais chamadas com periodo_ambiguo quando o modelo de IA preenche dia e dias_a_frente simultaneamente, priorizando o campo mais específico (dia) e documentando a precedência no schema da ferramenta.

Contribuição de @webtecnica (#1555).

Atualizar a instalação não duplica mais as demandas do Radar

Cada atualização da VPS criava uma segunda demanda para toda conversa nova que já tinha a sua, e o Radar passava a mostrar o dobro de demandas abertas sem próximo passo (o índice de atrito também contava em dobro). A atualização agora só cria demanda para conversa que não tem nenhuma, e a duplicata que as atualizações anteriores deixaram é apagada sozinha na próxima atualização. Só sai a cópia que ninguém tocou: demanda com próximo passo, responsável, lead ou caso fica como está, e a cópia que já virou o atendimento em curso da conversa também fica, para não interromper acompanhamento nenhum. Depois de atualizar, a contagem do Radar pode cair, e o número novo é o correto.

O "digitando…" aparece no WhatsApp do cliente enquanto a IA prepara a resposta

O indicador de "digitando…" praticamente nunca aparecia quando o agente de IA respondia: ele só era acionado se sobrasse tempo de espera depois que a IA terminava de pensar, e quase nunca sobrava. Agora ele acende no começo do atendimento de cada mensagem, cobrindo os segundos em que o cliente espera a resposta. Crédito: @rafaelbatistazz.

Extensão removida deixa de aparecer como instalada no painel do dono do servidor

Remover uma extensão marca a instalação como removida, mas a linha continua no banco. A tela /admin/extensoes lia todas as linhas, então uma extensão já removida seguia listada como instalada, junto com a contagem de empresas dela. Agora a tela ignora as instalações removidas, do mesmo jeito que o restante do sistema de extensões já fazia.

As fotos do produto não passam mais do limite de mensagens por resposta

Quando a descrição de um produto era longa demais para ir como legenda da foto, o texto saía numa mensagem à parte e as fotos vinham depois sem contar essa mensagem. Com o limite de 3 mensagens por resposta, um produto com 3 fotos chegava ao cliente em 4 mensagens, acima do ritmo que protege o número de bloqueio. Agora o limite é conferido antes de cada foto, já contando o texto. Crédito: @bonito-system.

Freio de envio por token aplicado antes de abrir conversa e teto por organização

Ao iniciar conversa e envio por token (crm_start_conversation_and_send), o freio de ritmo e teto diário do número passa a ser checado antes de registrar a abertura da conversa no banco, impedindo conversas vazias residuais quando o envio for retido por limite de taxa (429). Além disso, a rota /api/v1/messages agora respeita um teto global por organização além do teto por token individual.

Contribuição de @webtecnica (#1556).

Textos longos sem espaços no Inbox não estouram mais a largura da tela

No Inbox, mensagens com sequências longas e contínuas de caracteres sem espaço (como códigos Pix copia-e-cola de 150+ caracteres) estufavam a bolha de mensagem para além da coluna de conversa, desalinhando o layout e ocultando os botões de ação do topo. A coluna da conversa, o scroller e a bolha ganharam contenção de largura mínima, e o texto ganhou quebra forçada (wrap-anywhere): o layout fica íntegro no desktop (medido em 1024 e 1280 px).

Contribuição de @webtecnica (#1508); relato de @tec7alex (#1451).

O modelo de mensagem volta a sair pelo WhatsApp oficial da Meta

Desde a 1.45.0, todo envio de modelo aprovado por um número conectado ao WhatsApp oficial da Meta falhava com "template_missing", e a conferência dos valores do modelo deixava de acontecer. Como o modelo é o único jeito de voltar a falar com um cliente depois de 24 horas sem resposta, essas conversas ficavam sem saída. Agora o envio acha o modelo que a sincronização da Meta trouxe, e quem usa também um canal parceiro com um modelo de mesmo nome continua com cada número usando a própria definição. Crédito: @bonito-system.

Importar uma skill recusa, já na leitura do pacote, nome que o Storage não aceita

O pacote de skill vira chave de objeto no Storage ({organização}/{nome}/{versão}/{caminho}), e o Storage tem alfabeto próprio para nome de arquivo. Um zip com assets/ícone.png — ou uma skill chamada Relatório de vendas — passava pela conferência do pacote e só quebrava adiante, na hora de subir o arquivo, com um erro que não ensinava o que fazer. Agora a recusa acontece na leitura do zip, antes de qualquer envio, e a mensagem diz qual nome está fora do alfabeto e o que usar no lugar. Quem envia pacote com letras sem acento, números, ponto, hífen, sublinhado ou espaço não vê diferença nenhuma.

Contribuição de @webtecnica (#1346), no passo que a #686 pedia.

Validação de credenciais OpenRouter passa a aceitar gateways compatíveis sem rota /key

Quando OPENROUTER_BASE_URL aponta para um gateway próprio OpenAI-compatível (LiteLLM, vLLM, proxy interno), a validação de credenciais em IA › Credenciais falhava com provider_status_404 porque a rota /key é exclusiva do OpenRouter oficial. O validador agora detecta a ausência de /key em bases customizadas e valida a autenticidade e catálogo via GET /models, permitindo validar e publicar agentes contra gateways privados.

Contribuição de @webtecnica (#1376).

O painel "Como está indo" do papel Operador passa a contar só o agente aberto

Na página de um agente, a aba de operação mostrava os números do papel Operador somando todos os agentes da organização. Com dois ou mais agentes, o painel de um mandava marcar capacidades nele por causa de conversas de outro, e um agente parado não aparecia enquanto outro trabalhasse. Agora cada agente vê só as conversas dele.

Os números passam a contar a partir desta versão: as execuções registradas antes dela não diziam qual agente atendeu, então o painel de cada agente começa do zero e se preenche com as próximas conversas (a janela é de 30 dias).

Evento do WhatsApp que chega num formato inesperado fica guardado e marcado como recusado

Quando o WhatsApp manda um evento num formato que o CRM não reconhece, o CRM recusa o evento e guarda uma cópia dele para quem for investigar. Isso tinha três falhas. No endereço de recebimento próprio de cada número, um campo que esse endereço nem usa podia fazer o evento ser recusado antes de a cópia ser guardada, e ela se perdia. Quando a cópia era guardada, ficava marcada como "recebida", igual a um evento que deu certo, e depois ninguém conseguia separar um do outro. E um evento malformado, que qualquer pessoa pode mandar antes de o CRM conferir a assinatura, aparecia no registro do servidor como erro.

Agora a cópia é guardada nesses casos, a recusa fica marcada como erro junto com os nomes dos campos que vieram diferentes (nunca o conteúdo, que é dado do cliente), e a recusa que acontece antes da assinatura aparece no registro como aviso. Mensagens no formato normal seguem entrando exatamente como antes.

Etapa criada pela tela gera slug com hífen e normaliza busca em agendamento e handoff

A geração de slug de etapa na interface (lib/leads/stage-editing.ts) utilizava sublinhado (_), enquanto os módulos de movimentação automática por agendamento (lib/leads/appointment-stage-move.ts) e de handoff (lib/leads/handoff-stage-move.ts) procuravam slugs padronizados com hífen (agendamento-solicitado e chamar-humano). Agora o gerador produz slugs com hífens e os consumidores passam a buscar também etapas legadas com sublinhado como fallback, garantindo compatibilidade total sem quebras. Funis novos também passam a nascer com slug de hífen, porque usam o mesmo gerador; slugs já gravados não mudam.

Contribuição de @webtecnica (#1548); relato de @franceschini-lucas (#1542).

Transcrição aceita base URL com ou sem /v1 e sem duplicar caminho

Ao configurar uma URL base customizada para transcrição de áudio (ex.: Groq ou Whisper próprio, como sugerido no .env.example), o provedor de transcrição concatenava /v1/audio/transcriptions sem normalizar o sufixo /v1 ou barras finais, resultando em /v1/v1/audio/transcriptions e gerando erro 404. O provedor agora normaliza a base removendo barras finais e o sufixo /v1, suportando tanto URLs com quanto sem /v1.

Contribuição de @webtecnica (#1550).

e2e do Trunk SIP garante dígito no sufixo e remove host na varredura de chave crua

A spec tests/e2e/trunk-sip-config.spec.ts passa a garantir um dígito no sufixo aleatório derivado de Date.now().toString(36) e a limpar ocorrências de host em corpoSemOBloco, evitando que nomes de host gerados casem com o padrão de chave de tradução crua (a.b.c).

Contribuição de @webtecnica (#1553).

Atualização de modelo pelo Zernio passa a filtrar pela conexão correspondente

A sincronização de status de modelo vinda de webhook do Zernio (lib/channels/zernio/avisos.ts) atualizava o espelho local (meta_templates) filtrando apenas por organização e nome. Em organizações com mais de uma conexão espelhando modelos de mesmo nome (ou conexões com múltiplos idiomas), o estado recebido do Zernio podia sobrescrever a linha de outro canal. Agora a atualização filtra por channel_session_id e idioma, isolando as conexões.

Contribuição de @webtecnica (#1551).

← Back to all releasesView on GitHub