Files
mercado.clube67.com/docs/TAREFAS.md
T

14 KiB
Raw Blame History

Tarefas — Alemão Conveniências Admin

Última atualização: 2026-04-26


Legenda

  • [ ] Pendente
  • [~] Em andamento
  • [x] Concluído

Concluído

Correções de Auth

  • Corrigir 401 em /api/admin/nw/auto-reply-mode para funcionários (verifyAnyToken)
  • Corrigir 401 nas rotas /api/admin/inbox/* para funcionários
  • Login de funcionário (secretaria Monique) — senha redefinida pelo painel admin

WhatsApp Inbox

  • Nome do colaborador em negrito no início de cada mensagem WhatsApp enviada
  • Pausa automática da IA ao enviar mensagem (handoff dispara sem clicar no botão)
  • Botão de handoff fica laranja imediatamente após envio
  • Timer do handoff corrigido para 15 minutos (estava exibindo 30 por erro de cálculo)
  • Handoff salvo no banco local (nw_handoff) — independente do motor NewWhats
  • Webhook-receiver verifica handoff local antes de chamar a IA

Inbox Interna

  • Cores ajustadas para padrão branco/cinza do WhatsApp
  • Layout coluna única (lista ou mensagens, sem duas colunas lado a lado)

Fase 1 — Escalação & Protocolos

  • Botão "Assumir" no toast de escalação — cria thread + pausa IA + agenda expiração BullMQ
  • ref_id preenchido automaticamente ao assumir (protocolo ↔ Inbox Interna)
  • Transferência de protocolo entre atendentes — modal com seleção de conta e mensagem de contexto
  • Timer de expiração do handoff via BullMQ (15 min) com notificação SSE ao frontend

Fase 2 — IA & Conhecimento

  • Brain do setor injetado no contexto da IA (sector_brain_nodessystemExtra no motor)
  • Human API com timeout — IA solicita resposta humana, BullMQ expira em 5 min, SSE notifica
  • Endpoint de resposta Human API — colaborador responde pela Inbox Interna, entrega à IA
  • Setor identificado pela IA sincronizado de volta ao banco local (nw_chat_sectors)
  • SLA por setor — cron a cada minuto, alerta SSE sla.breach quando ultrapassado

🔴 Alta Prioridade

  • Quando human_api.timeout: notificar motor para retomar conversa sem resposta humana

🟢 Relatórios & Métricas de Atendimento

Fase 3 — Concluído

  • Contador de atendimentos por colaborador — escalações assumidas, msgs enviadas, Human API respondidas
  • Ranking de atendimentos — tabela por colaborador com tempo médio de 1ª resposta
  • SLA breach por setor — contagem de escalações fora do prazo por setor
  • Dashboard de atendimento — aba "Métricas" com cards resumo + tabelas por colaborador e setor
  • Filtro por período — Hoje / 7 dias / 30 dias
  • Human API stats — total, respondidas, timeout, % de resposta

Fase 4 — Concluído

  • Nota por atendimento — cliente avalia 15 após encerramento via WhatsApp; capturado no webhook
  • Registro de reclamações / sugestões / elogios — botão Flag no ThreadPanel com nota opcional
  • Encerrar protocolo — botão no ThreadPanel envia pesquisa + zera handoff + retoma IA
  • Aprendizado de conhecimento — botão "Brain" no ThreadPanel salva resposta; opção de promover para sector_brain_nodes
  • Gráfico temporal — barras de escalações por dia no MetricasTab
  • Métricas de flags e ratings — cards de satisfação, reclamações, sugestões, elogios no dashboard

🔵 Baixa Prioridade

  • Tempo médio de resolução — AVG(pr.sent_at - esc.first_escalation) no endpoint /api/admin/metrics/attendance; card "Tempo médio de resolução" no MetricasTab
  • Multi-tenant — tenant_id adicionado a nw_event_logs e nw_auto_replies via migration; queries de auto-reply filtradas por tenant; protocol_ratings/protocol_flags/internal_messages já isoladas
  • Histórico de avaliações de satisfação — endpoint /api/admin/metrics/ratings-history com paginação e filtro por nota; tabela paginada com estrelas, status e atendente no MetricasTab

📝 Notas Técnicas

Infraestrutura

  • Motor NewWhats: http://127.0.0.1:8008 — IA, conversas e envio de mensagens
  • Servidor satélite: node server.js em /sistema-nuvem/ na porta 4001
  • Frontend buildado em /sistema-nuvem/public/admin-v2/assets/
  • Banco: PostgreSQL alemao, usuário newwhats, senha em .envPG_PASSWORD
  • Redis: 127.0.0.1:6379 — usado pelo BullMQ (configurável via REDIS_HOST/REDIS_PORT)

Jobs BullMQ (Redis)

Queue Trigger Delay Ação
handoff-expire PATCH /api/nw/handoff/:chatId com mode=humano ou botão Assumir 15 min Zera nw_handoff.human_until; SSE handoff.expired
human-api-timeout POST /api/human-api/request (interno, via webhook-receiver) 5 min Marca human_api_requests.status='timeout'; insere msg sistema; SSE human_api.timeout

Crons (node-cron, server.js)

Schedule O que faz
* * * * * (todo minuto) Verifica escalações abertas sem resposta humana que ultrapassaram sectors.sla_minutes; emite SSE sla.breach para todos os clientes conectados

Eventos SSE (/api/sse)

Evento Payload Quem consome
handoff.expired { chatId } WhatsAppInbox → toast + refresh HandoffButton
human_api.new { requestId, threadId, question, sectorName } WhatsAppInbox → toast com botão "Ver Inbox"
human_api.answered { requestId, threadId, answer } — (reservado)
human_api.timeout { requestId, threadId } WhatsAppInbox → informativo
sla.breach { threadId, sectorId, sectorName, slaMins, elapsedMins } WhatsAppInbox → toast de alerta

Tabelas criadas / alteradas (Fases 14)

Tabela Propósito
nw_handoff Pausa da IA por chat (human_until TIMESTAMPTZ)
nw_chat_sectors Setor identificado pela IA por chat (chat_id → sector_id)
human_api_requests Pedidos da IA para resposta humana (status, timeout_at, answer)
internal_messages Inbox interna — threads de escalação, colaboração, human_api, ajuda
sector_brain_nodes Base de conhecimento por setor, injetada no system prompt da IA
protocol_ratings Avaliações de satisfação (15) enviadas ao cliente ao encerrar protocolo
protocol_flags Flags de protocolo: reclamação, sugestão ou elogio registrado pelo atendente
knowledge_learning Respostas humanas salvas para promoção à base de conhecimento

Fluxo Human API

  1. Motor retorna { humanApiRequest: { question, sectorName } } em /secretaria/ask
  2. webhook-receiver.js chama POST /api/human-api/request (interno)
  3. Banco: cria human_api_requests + thread internal_messages (type=human_api)
  4. BullMQ agenda timeout de 5 min; SSE human_api.new notifica colaboradores
  5. Colaborador responde pela Inbox Interna → POST /api/human-api/answer/:id
  6. Banco: atualiza status para answered; cancela job BullMQ; SSE human_api.answered
  7. (próximo passo) Resposta re-injetada na conversa do motor via /secretaria/ask

🐛 Revisão de Bugs — 2026-04-20

Revisão completa do código encontrou 40 bugs. Organizados abaixo por prioridade.

🔴 Crítico — Segurança Grave (9)

  • BUG-06 — Adicionar verificação HMAC no webhook Asaas de rifas (controllers/webhookController.js:8) — fraude de pagamento
  • BUG-07 — Adicionar verificação HMAC no webhook Asaas do clube (controllers/clubController.js:445) — fraude de assinatura
  • BUG-04 — Trocar JWT secrets fracos no .env por valores fortes e aleatórios (.env:13,23)
  • BUG-01 — Eliminar interpolação direta em queries SQL; usar apenas parâmetros $N (server.js:863, models/Analytics.js:6, models/ClubMember.js:99)
  • BUG-02 — Configurar CORS com origens explícitas (server.js:28)
  • BUG-03 — Adicionar secure: true e sameSite: 'lax' em todos os cookies (controllers/adminController.js:37, controllers/usersController.js:12)
  • BUG-05 — Substituir autenticação do webhook interno: header x-internal-secret com INTERNAL_WEBHOOK_SECRET do env (server.js:373,454)
  • BUG-08 — Corrigir skip do rate limiter: verifica JWT com jwt.verify() antes de bypassar (server.js:40)
  • BUG-09.gitignore criado em sistema-nuvem/ protegendo .env, node_modules e logs

🟠 Alto — Bugs Funcionais (13)

  • BUG-10 — Corrigir JWT_SECRET indefinido em signTeamToken → usa TEAM_SECRET (middleware/teamAuth.js:75)
  • BUG-13 — Corrigir .rows duplicado no webhookControllerquery() já retorna array (controllers/webhookController.js:31)
  • BUG-23 — Corrigir campos no context-builder.js: name/phonenome/telefone; findActivePlan usa club_plans e user_cpf (plugins/newwhats/context-builder.js:42)
  • BUG-30 — Proteger GET /api/raffle/tickets com verifyToken (routes/apiRaffle.js:9)
  • BUG-33 — Substituir localhost:4001 por process.env.APP_URL (controllers/webhookController.js)
  • BUG-21 — Cleanup de Order órfã com Order.delete() se Ticket.reserve falhar (controllers/raffleController.js:83)
  • BUG-11 — Incluir offset na query SQL de ClubMember.listByClub (models/ClubMember.js:55)
  • BUG-12 — Adicionar titulo à query do sorteio em RaffleResult.draw (models/RaffleResult.js:12)
  • BUG-16 — Adicionar filtro tenant_id em adminUpdateJob, adminDeleteJob, adminToggleJob (controllers/jobController.js)
  • BUG-17 — Adicionar filtro tenant_id em cancelMyApplication (controllers/jobController.js:189)
  • BUG-18 — Adicionar filtro tenant_id em adminGetApplication e adminUpdateApplication (controllers/jobController.js)
  • BUG-19 — Verificação de tenant em adminSaveContent (controllers/clubController.js:351)
  • BUG-20 — Permite reativação de membros suspended/pending_payment; só bloqueia status active (controllers/clubController.js:65)

🟡 Médio — Qualidade e Tratamento de Erros (11)

  • BUG-25tenantMiddleware retorna 503 em vez de next() sem req.tenant (middleware/tenant.js:66)
  • BUG-29clubAsaasService aceita apiKey por chamada; clubController passa req.tenant.asaas_key (services/clubAsaasService.js)
  • BUG-15 — Comparação corrigida: active === 'true' (controllers/equipeController.js:54)
  • BUG-22 — Notificação ao ganhador movida para fora da transação com setImmediate após COMMIT (models/RaffleResult.js)
  • BUG-26validateCPF adicionada e aplicada em subscribe e getCard (controllers/clubController.js)
  • BUG-27 — Mínimo de senha de admins elevado para 8 caracteres em createAdmin e updateAdmin
  • BUG-28 — Verifica searchRes.ok antes de acessar searchData.data (services/asaasService.js:30)
  • BUG-31limit máximo de 1000; offset mínimo de 0 em notification-errors (server.js)
  • BUG-32REDIS_PORT parseado com parseInt (services/whatsappService.js:10)
  • BUG-24verifyAnyToken rejeita imediatamente com 401 se cloud_token inválido (middleware/teamAuth.js)
  • BUG-35 — Promoção de conhecimento sem sector_id retorna 400 (server.js)

🟢 Baixo — Melhorias (7)

  • BUG-36 — Usar crypto.timingSafeEqual na comparação de chaves em nwAuth (plugins/newwhats/auth.js:27)
  • BUG-37 — Adicionar filtro tenant_id em deleteTicket (controllers/raffleController.js:211)
  • BUG-38 — Não assumir opt-in quando usuário com CPF não é encontrado (services/whatsappService.js:244)
  • BUG-39 — Substituir interpolação de promoted por parâmetro $2 (server.js:641)
  • BUG-40 — Reduzir expiração do cookie de usuário e adicionar revogação de token (controllers/usersController.js:12)
  • BUG-14 — Refatorar declaração de sseHandoffQueue para antes das rotas que a usam (server.js:271)
  • BUG-34 — Escapar caracteres especiais de LIKE (%, _) no context-builder.js (plugins/newwhats/context-builder.js:45)

Resumo

Prioridade Total
🔴 Crítico 9
🟠 Alto 13
🟡 Médio 11
🟢 Baixo 7
Total 40

📬 Inbox Interna — v2 (Pendente)

Referência: inbox-interna.md
Contexto: rota /admin-v2/cotacao/inbox

INB-SSE — SSE real-time para DMs

  • INB-SSE-01 Adicionar evento direct_message.new ao endpoint SSE existente (/api/sse) — emitir para o destinatário ao receber nova DM
  • INB-SSE-02 No CollaboratorsPanel.tsx, subscrever SSE e atualizar badge de não-lidas em tempo real (substituir o auto-refresh de 30s)
  • INB-SSE-03 No DMConversationView.tsx, subscrever SSE e appendar nova mensagem em tempo real quando a conversa está aberta
  • INB-SSE-04 Testar isolamento: evento SSE deve chegar apenas ao to_account correto (não broadcast global)

INB-GC — Group Chat por Setor (v2.2)

  • INB-GC-01 Criar tabela group_chats (id, tenant_id, sector_id, name, created_at)
  • INB-GC-02 Membros via team_members existente — sem tabela extra necessária
  • INB-GC-03 Criar tabela group_messages (id, tenant_id, group_chat_id, from_account, content, created_at)
  • INB-GC-04 Endpoints: GET /groups, GET /groups/:id/messages, POST /groups/:id/message, GET /groups/:id/members
  • INB-GC-05 Evento SSE group_message.new — notifica membros do setor (via sseSend por membro)
  • INB-GC-06 Suporte a @menção — detectar @nome no content e emitir SSE group_mention para o mencionado
  • INB-GC-07 Frontend: GroupChatView.tsx + tab "Grupos" no InboxInternaTab
  • INB-GC-08 Seed automático: grupo criado para cada setor ativo no initialize()

INB-BC — Broadcast (v2.2)

  • INB-BC-01 Criar tabela broadcasts (id, tenant_id, from_account, content, created_at)
  • INB-BC-02 Endpoint POST /api/admin/inbox/broadcast — restrito a roles owner e manager
  • INB-BC-03 Evento SSE broadcast.sent via sseBroadcastTenant — notifica todos do tenant
  • INB-BC-04 Frontend: tab "Avisos" visível para todos; campo de envio apenas para owner/manager com confirmação
  • INB-BC-05 Broadcasts exibidos como cards destacados com borda âmbar no BroadcastPanel