- Detecta WhatsApp Business (app) via getBusinessProfile no pós-conexão e
persiste em instances.isBusiness; painel mostra "Conta Business: sim/não"
(com nota Business App ≠ Business API).
- Painel avisa que trocar de API desconecta e exige escanear o QR novamente,
com confirmação antes de aplicar a troca.
- sendRichMessage agora monitora e loga erros especificamente quando a mensagem
tem botões/lista/carrossel (diagnóstico de rejeição de interativos por engine).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Instala baileys@7.0.0-rc13 sob alias 'baileys-official' (coexiste com a
'infinite' = baileys 7.0.0-rc.9 e a 'official' = @whiskeysockets/baileys 6.x).
Nova engine 'baileys7' (LID/username, app-state moderno) selecionável por
instância; validação do PATCH /engine e rich-message (botões nativos v7)
atualizados; opção adicionada ao seletor da ThinSidebar.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pin/arquivo/mute não vêm no history sync nem em chats.upsert — vivem no
app-state do WhatsApp. Adiciona syncChatStates() que faz resyncAppState das
collections critical_unblock_low/regular_high/regular (isoladas: uma falha não
derruba as outras); os pins chegam como chats.update e já são aplicados em
isPinned, subindo os fixados ao topo (ordenação já existente). Roda no
pós-conexão e reexecuta (3s/15s/40s) pois as app-state keys chegam após parear.
Obs.: depende da engine 'official' (a InfiniteAPI não sincroniza app-state).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Quando DISABLE_OUTBOUND=true, envolve sock.sendMessage na criação da sessão e
bloqueia QUALQUER envio ao WhatsApp — backstop universal, pois todo envio
(rotas, IA/secretária, chatbot, scheduler, warmer, plugins) usa este sock.
Evita que automações disparem mensagens a contatos/grupos reais ao conectar uma
sessão real em dev. Em produção a flag fica ausente/false (envios normais).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
src/ continha 114 artefatos (.js + .js.map) de builds antigos mal-configurados,
commitados por engano. Não são usados em runtime (dev usa tsx sobre .ts; prod usa
dist/, gerado por tsc com rootDir=src/outDir=dist). Remove todos e adiciona
backend/.gitignore para impedir que voltem.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Os avatares "não vinham todos" porque o enfileiramento era capado em 3
pontos, embora a fila (processAvatarQueue) já seja rate-limited e processe
tudo que entra:
- upsert: cap de 50 por batch (randomizado) -> enfileira todos os pendentes
- syncMissingAvatars: take 80 -> cobre TODOS (chats recentes primeiro +
varredura paginada de todos os contatos sem avatar)
- syncExpiredAvatars: take 200 + slice 80 -> varre paginado e renova todos
os avatares com URL do CDN do WhatsApp expirando (<48h)
A cobertura total não dispara ban: a fila mantém ~1 req/s (lotes + delay);
apenas leva mais tempo, em background.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Adiciona @@index nas FKs que sofrem cascade/SET NULL ao deletar instância:
messages.replyToId (self-ref, evitava O(n²) no SET NULL), chats.instanceId,
chats.contactId, contacts.instanceId, broadcasts.instanceId.
- InstanceRepository.delete agora apaga 'messages' em lotes (5k) antes do
cascade, evitando transação/locks gigantes em instâncias com dezenas de
milhares de mensagens. O restante (chats/contacts/...) sai pelo cascade,
agora rápido com os índices.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>