
Conectar canais (onboarding)
Aparece sem canais conectados ou antes da 1a varredura. Cada canal é um chip clicável "Conectar"; com pelo menos 1 conectado, "Analisar agora" habilita e leva à varredura.
Funcionalidade que reúne, num só lugar, os feedbacks que os clientes deixam nos canais do negócio (avaliações, comentários e mensagens), organiza por status e ajuda a responder com sugestões da MIA.
A funcionalidade tem três fases na rota raiz /feedback, controladas por um único estado (phase):
phase: "connect"): onboarding. O usuário escolhe de quais canais quer ouvir os clientes.phase: "scanning"): a Plataforma sincroniza os feedbacks dos últimos 7 dias dos canais conectados.phase: "dashboard"): o usuário trabalha a fila de feedbacks em formato de baralho (deck) e navega para as telas satélite.A partir do painel existem as telas satélite: Todos os Feedbacks, Feedbacks Ocultos, Detalhe do Feedback e Gerenciar canais.
Dois recortes da mesma jornada: o caminho feliz (tudo sincroniza e a fila é zerada) e o caminho triste (varredura lenta, resultado parcial, falha total ou perda de conexão).
Caminho feliz
Caminho triste
FeedbackItem)| Campo | Tipo | Observação |
|---|---|---|
id | string | Identificador único |
channelId | google-business | instagram | facebook | whatsapp | Canal de origem |
themeId | tema (atendimento, entrega, produto, qualidade, etc.) | Classificação do assunto |
authorName | string | Nome do cliente |
text | string | Conteúdo do feedback |
sentiment | positive | negative | neutral | Sentimento classificado |
interactionType | avaliacao | comentario | mensagem | Tipo da interação |
rating | number | null | Nota (só faz sentido em avaliações, ex.: Google) |
relativeTime | string | Tempo relativo exibido (ver ponto 9) |
postUrl | string | Link para o post/origem |
suggestedReplies | SuggestedReply[] | Sugestões de resposta da MIA |
Cada feedback carrega duas flags independentes:
responded: respondido (true) ou não respondido (false).hidden: oculto (true) ou visível (false).As combinações são todas válidas: um feedback pode estar respondido E oculto ao mesmo tempo. As flags ficam num mapa Record<feedbackId, { responded, hidden }>. Quando as duas voltam a false, a entrada é removida do mapa (estado limpo).
| Lista | Critério |
|---|---|
| Deck / Feedbacks Recentes | !responded && !hidden |
| Todos os Feedbacks | !hidden (visíveis) |
| Feedbacks Ocultos | hidden |
ReputationScore): fora do MVPA reputação não faz parte do MVP e não é exibida em nenhuma tela. O redesign multi-tela removeu a UI de score (e o filtro "Temas da semana"). O tipoReputationScoree o cálculo (computeReputation) permanecem na camada de dados apenas para não quebrar o reducer/serviço/testes, mas o valor é ignorado pela interface. Tratar como legado/futuro, não como funcionalidade do MVP.
Quando houver UI de reputação no futuro, o cálculo atual é: total, positivos, negativos, neutros e taxa de positividade; sem feedbacks polarizados, valor neutro (50); faixas crítico (<50), atenção (50 a 69), bom (70 a 84), excelente (>=85).
Google Meu Negócio (avaliações com nota), Instagram, Facebook e WhatsApp Business. Apenas Google Meu Negócio usa nota em estrelas; os demais usam comentário ou mensagem.
relativeTime; na integração real usar um postedAt/timestamp.)As três fases da raiz (connect,scanning,dashboard) compartilham a mesma URL/feedback/. A fase vem do estado persistido, não da URL. No desktop, as telas satélite aparecem com a navegação lateral; no mobile, comportam-se como modais com header fixo cobrindo a tela.

Aparece sem canais conectados ou antes da 1a varredura. Cada canal é um chip clicável "Conectar"; com pelo menos 1 conectado, "Analisar agora" habilita e leva à varredura.

Durante a sincronização. Barra de progresso animada com mensagens rotativas, teto 92% até os dados chegarem; contador "X de Y canais".

Após a varredura concluir. Deck no estilo baralho: o card do topo é o ativo (arrastar à direita responde, à esquerda oculta, tocar abre o detalhe). Atalhos para "Todos os feedbacks" e "Gerenciar canais".

Ao tocar em um card. Ordem vertical: card do feedback, ações (Ocultar/Mostrar e Marcar como Respondido), resposta da MIA (com "Copiar resposta") e navegação Anterior/Próximo.

Sempre acessível pelo painel. Lista os visíveis (não ocultos) em ordem cronológica, com filtros (Canal, Status, Sentimento), taxa de resposta e atalho para Feedbacks Ocultos.

A partir de Todos os Feedbacks. Lista os feedbacks com hidden = true; ao abrir o detalhe, o usuário pode torná-los visíveis de novo.

A partir do painel. Reaproveita a tela de conexão em modo "manage": conectar/desconectar reflete na hora (resync ao vivo, preservando flags). Desconectar pede confirmação.

Aparece na primeira vez que houver cards no deck. Três passos (Responder, Ocultar, Gerar resposta) com botões "Próximo"/"Entendi" e "Pular tutorial".

Ao clicar em "Desconectar" um canal. Avisa que os comentários e respostas sugeridas do canal vão sair da análise até você conectar de novo.

Sync acima do limiar de espera, sem falha. Mensagem persistente, progresso preso em 92% (nunca finge 100%) e "Voltar para canais" disponível.

Falha na sincronização (nenhum canal retornou). "Não foi possível concluir a varredura" com "Tentar de novo" e "Voltar para canais".

Painel sem nenhum canal conectado. "Nenhum canal conectado" com CTA para conectar.

Canais conectados, mas zero feedbacks em 7 dias. "Nenhum feedback no período".

Todos os feedbacks já tratados. "Tudo em dia por aqui!".

Conforme o caso na tela Todos (sem canais, sem visíveis ou sem resultado de filtro). Captura: sem feedbacks visíveis.

Nenhum feedback oculto. "Nenhum feedback oculto".

Feedback removido por nova varredura/desconexão. "Feedback não encontrado" com ação de voltar.

Ao menos 1 canal ok, outros falharam após backoff. Entra no painel com alerta "Perdemos a conexão com um canal" e atalho Gerenciar canais.

Conexão perdida com um canal conectado. Alerta no topo de Recentes; os feedbacks já sincronizados continuam visíveis.

Notificações transitórias, ex.: "Feedbacks atualizados." após a atualização, e ao copiar resposta no detalhe.

Dispara ao zerar a fila de feedbacks em aberto, sobre o estado "Tudo em dia por aqui!". Efeito canvas de chuva de confetes.
X de Y canais).
Ordem vertical da tela: card do feedback, ações, resposta da MIA, navegação.
?from=): Voltar retorna à origem; Anterior/Próximo navega pelo conjunto de Todos (quando origem deck/todos) ou pelos ocultos (quando origem ocultos). A lista é congelada (snapshot) durante a navegação para permitir voltar e corrigir.postUrl) em nova aba. Para WhatsApp, leva o usuário para o chat dentro da plataforma já com a resposta gerada pela MIA no input, restando clicar em enviar.
hidden = true.
Catálogo dos estados de vazio e erro, com a condição que os dispara e a mensagem exibida. As capturas reaproveitam as imagens da galeria 4.2.

Mensagem: "Nenhum canal conectado" + CTA conectar.

Mensagem: "Nenhum feedback no período".

Mensagem: "Tudo em dia por aqui!".

Mensagens: "Nenhum feedback ainda", "Nenhum canal conectado" + CTA, ou "Nenhum feedback para os filtros" + limpar.

Mensagem: "Nenhum feedback oculto".

Mensagem: "Feedback não encontrado" + voltar.

Mensagem: "Ainda estamos processando. Alguns canais demoram um pouco mais." (teto 92%).

Painel + alerta não bloqueante "Não foi possível sincronizar o canal X" + reconectar.

Mensagem: "Não foi possível concluir a varredura" + tentar / voltar.
localStorage na chave biud:feedback-session:v1 (fase, canais, feedbacks, score, último scan, flags).biud:feedback-deck-tutorial:v1 ("seen").navigator.clipboard quando disponível (HTTPS ou localhost) e cai num fallback com textarea + execCommand quando o contexto não é seguro.Overlay com 3 passos, exibido na primeira vez que houver cards no deck:
Botões "Próximo" / "Entendi" e "Pular tutorial". Respeita prefers-reduced-motion.
services/) já abstrai a origem: cada integração real vira um adapter que produz FeedbackItem[] sem mexer na UI.Status possíveis: Tratado Intencional Conhecido (não tratado) Fora de escopo
| # | Edge case | Como visitar | Tratamento / status |
|---|---|---|---|
| 1 | Ação perdida durante a animação de swipe/carimbo | Deslizar um card e tocar imediatamente na navegação antes da animação terminar | Conhecido Os timers são limpos no unmount; o card volta como não tratado. Mitigar comprometendo a flag antes da animação. |
| 2 | Dessincronização entre abas (last-write-wins) | Abrir /feedback/ em duas abas, agir numa e observar a outra | Conhecido Não há listener de storage; a última escrita sobrescreve. Resolver ao escopar a sessão no backend. |
| 3 | Sessão não escopada por empresa | Trocar de empresa no dropdown do topo | Conhecido A sessão é global no mock. No produto, escopar por company_id. |
| 4 | Não existia atualização após o onboarding | Painel: usar o botão de atualizar no topo de Recentes | Tratado Botão de atualizar inline que re-sincroniza preservando flags. |
| 5 | Re-sincronizar apagava as flags | Marcar respondido/oculto e atualizar | Tratado A atualização preserva as flags; só a 1a varredura do onboarding zera. |
| 6 | Desconectar e reconectar zera o estado daquele canal | Gerenciar canais: desconectar e reconectar | Intencional Desconectar exclui feedbacks e flags do canal; reconectar traz tudo novo. |
| 7 | Celebração (confetti) inconsistente conforme o caminho | Tratar o último feedback pelo Detalhe e voltar ao painel | Tratado A celebração dispara sempre que a fila em aberto chega a zero por ação do usuário. |
| 8 | Contador de trial estático e sem gate | Observar "15 dias" no topo (mobile) | Fora de escopo Valor fixo; expiração não definida nessa funcionalidade. |
| 9 | relativeTime é texto fixo e não envelhece | Deixar a sessão por dias e reabrir | Conhecido O mock guarda string, não timestamp. Adicionar postedAt para tempo real. |
| 10 | Feedbacks persistidos podem ficar velhos | Carregar uma sessão antiga após mudança no shape | Conhecido Só a migração de flags legadas é defensiva; versionar o payload. |
| 11 | Recarregar no meio da varredura volta para "conectar" | Iniciar varredura e recarregar a página | Intencional Sem feedbacks ainda, a hidratação retorna ao estado de conexão. |
| 12 | Erro de varredura, retry e progresso em 92% | Erro total ?scanError=1; lenta ?scanSlow=1; backoff que recupera ?scanFlaky=instagram; parcial ?scanPartial=instagram | Tratado (mock) Contador "X de Y canais", "ainda processando", backoff/auto-retry e resultado parcial. Tela de erro cheia só quando nenhum canal retorna. Pendente: telemetria. |
| 13 | Perda de conexão com um canal conectado | ?channelError=instagram (canal precisa estar conectado) | Tratado Alerta na Recentes + estado de erro e "Reconectar" no Gerenciar canais. Feedbacks já sincronizados continuam visíveis. |
/feedback/?scanError=1 (com canal conectado e fase de varredura)./feedback/?scanSlow=1 para atrasar a sincronização além do limiar (~8s)./feedback/?scanFlaky=<id> (ex.: instagram). O canal falha nas primeiras tentativas e retorna numa seguinte; conclui em 100% sem marcar erro./feedback/?scanPartial=<id>. O(s) canal(is) falham permanentemente; os demais retornam e o usuário entra no painel com alerta de canal em erro./feedback/?channelError=<id> com o canal já conectado.localStorage.removeItem("biud:feedback-deck-tutorial:v1") e recarregar.localStorage.removeItem("biud:feedback-session:v1") e recarregar.| Item | Sandbox (hoje) | Produto (esperado) |
|---|---|---|
| Conexão de canal | Toggle simulado | OAuth em aba separada |
| Origem dos feedbacks | Dataset mockado | Adapters por canal (services/) |
| Classificação de sentimento e tema | Pré-definidos no seed | Serviço de NLP/LLM |
| Sugestões de resposta (MIA) | Pré-definidas no seed | Geração por modelo |
| Tempo relativo | String fixa | Derivado de postedAt |
| Escopo por empresa | Global | Por empresa (company_id) |
| Persistência | localStorage | Backend |
| Varredura lenta / tolerância | Contador "X de Y canais", "ainda processando" (~8s, ?scanSlow), backoff/auto-retry (?scanFlaky) e resultado parcial (?scanPartial); resta a telemetria | Backoff/auto-retry e resultado parcial reais por canal |
| Métricas/telemetria | Não instrumentado | Ver seção 12 |
Hoje a feature não está instrumentada; o que segue é a especificação do que deve ser enviado quando a telemetria for ligada. Toda métrica deve ser cortável pelas dimensões de negócio (porte, segmento, localização).
| Dimensão | Exemplos / valores | Origem |
|---|---|---|
company_id | identificador da empresa | sessão/empresa atual |
porte | MEI, ME, EPP, demais | cadastro da empresa |
segmento | CNAE / setor (ex.: alimentação, varejo, serviços) | cadastro |
localizacao | UF, município, região | cadastro |
plano / trial | em teste, pago, expirado, free; dias restantes de trial | billing |
canais_conectados | lista e contagem de canais | estado da feature |
dispositivo | mobile, desktop | client |
| Evento | Quando dispara | Propriedades | Métrica |
|---|---|---|---|
feedback_channel_connect_started | Clique em conectar canal | channel | Início de conexão por canal |
feedback_channel_connect_succeeded | OAuth concluído com sucesso | channel, duration_ms | Taxa de sucesso de conexão |
feedback_channel_connect_failed | Falha/cancelamento do OAuth | channel, reason | Atrito de conexão |
feedback_channel_disconnected | Confirmação de desconexão | channel, feedbacks_removidos | Churn de canal |
feedback_scan_started | Início da varredura | channels, channels_count | Funil de ativação |
feedback_scan_completed | Varredura concluída | duration_ms, feedbacks_count, por_canal, reputation_value | Volume e reputação inicial |
feedback_scan_failed | Erro na varredura | reason | Confiabilidade |
feedback_scan_retried | Clique em "Tentar de novo" | - | Recuperação de erro |
feedback_scan_slow | Varredura cruza o limiar de espera | elapsed_ms, channels_pending | Latência de sincronização |
feedback_scan_channel_retried | Auto-retry de um canal com backoff | channel, attempt | Resiliência |
feedback_scan_partial | Entra no painel com resultado parcial | channels_ok, channels_failed | Tolerância a falhas |
feedback_refresh_triggered | Botão atualizar no painel | novos_feedbacks, total | Recorrência de uso |
feedback_detail_opened | Abrir o detalhe | feedback_id, channel, sentiment, origem | Profundidade de uso |
feedback_reply_generated | MIA revela sugestão | feedback_id, tone | Uso da MIA |
feedback_reply_copied | Clique em "Copiar resposta" | feedback_id, channel, tone | Intenção de responder |
feedback_go_to_feedback_clicked | Clique em "Ir para o feedback" | feedback_id, channel, is_placeholder | Conversão para o canal |
feedback_marked_responded | Marcar respondido | feedback_id, channel, sentiment, interaction_type, via | Taxa de resposta |
feedback_unmarked_responded | Desmarcar respondido | feedback_id | Correções |
feedback_hidden | Ocultar | feedback_id, channel, sentiment | Taxa de ocultação |
feedback_unhidden | Tornar visível | feedback_id | Reversões |
feedback_deck_cleared | Fila em aberto chega a zero | total_tratados, tempo_sessao_ms | Conclusão da fila |
feedback_filter_applied | Aplicar filtro em Todos | canal, status, sentimento | Necessidade de filtragem |
feedback_tutorial_shown | Tutorial exibido | - | Alcance do onboarding |
feedback_tutorial_step | Avançar passo do tutorial | step | Engajamento no tutorial |
feedback_tutorial_completed | Concluir tutorial | - | Conclusão do tutorial |
feedback_tutorial_skipped | Pular tutorial | step | Abandono do tutorial |
feedback_scan_completed deve quebrar a contagem por canal.themeId) são dimensões ricas para cruzar com porte e segmento.postedAt (timestamp) para ordenação cronológica real e tempo relativo vivo.feedback_scan_slow, feedback_scan_channel_retried, feedback_scan_partial), que entra junto com a instrumentação geral (seção 12).Estimativa de esforço para trocar o mock por integrações reais. Baseado em conhecimento público até início de 2026. Políticas e endpoints mudam com frequência: sempre confirme na documentação oficial antes de planejar a engenharia.
| Canal | Lê via API? | Responde via API? | Auth | Gate de aprovação | Histórico retroativo | Complexidade | Prioridade |
|---|---|---|---|---|---|---|---|
| Google Play | Sim | Sim | Service account | Baixo | ~7 dias na API; histórico via relatórios | Média-baixa | Baixa |
| App Store | Sim | Sim | JWT key | Baixo | Amplo | Média-baixa | Baixa |
| Google Meu Negócio | Sim | Sim | OAuth 2.0 | Médio | Sim | Média | Alta |
| Mercado Livre | Parcial | Parcial | OAuth 2.0 | Baixo | Parcial | Média | Baixa |
| iFood | Sim | Sim | OAuth client credentials | Médio-alto | Sim (recentes) | Média-alta | Média |
| Facebook (Página) | Sim | Sim | OAuth Meta | Alto | Sim | Alta | Alta |
| Sim | Sim | OAuth Meta | Alto | Limitado | Alta | Alta | |
| WhatsApp Business | Só fluxo novo | Sim (janela 24h) | Meta WABA | Alto | Não | Alta | Alta |
| Reclame Aqui | Contratual | Contratual | Parceria/B2B | Comercial | Depende | Muito alta | Baixa |
reviews.list só traz avaliações recentes (~7 dias); histórico completo via export do Play Console.customerReviews + customerReviewResponses), JWT local, histórico amplo, sem App Review.business.manage; gate principal é a aprovação/quota do Google.A classificação de sentimento e a geração de respostas (hoje pré-definidas no seed) são os próximos blocos a trocar por um serviço real (NLP/LLM).
Recomendações de como a MIA deve julgar cada feedback como positivo, negativo ou neutro. No mock o sentimento já vem no seed; quando entrar um modelo real (NLP/LLM), usar estas diretrizes como base do prompt/treinamento. O sentimento define a cor do card e a separação "elogios vs oportunidades de melhoria".
Erros de classificação têm custo assimétrico: marcar um negativo como positivo faz uma reclamação parecer elogio e atrasa a resposta ao cliente insatisfeito. Na dúvida entre positivo e negativo, prefira sinalizar como negativo/atenção para não perder uma oportunidade de recuperação. O tema (themeId) é classificação complementar e não altera o sentimento.
Proposta de como avisar o lojista sobre novos feedbacks fora do app. Ainda não implementado (o MVP é só a tela). O princípio para o público (MPEs/SMBs) é avisar o que exige ação, sem virar ruído: o negativo chega na hora; o resto vira resumo.
| Evento | Cadência | Canais sugeridos (default) |
|---|---|---|
| Feedback negativo novo | Instantâneo | Push (on); WhatsApp (opt-in); e-mail no digest |
| Feedback positivo novo | Agrupado (não instantâneo) | Entra no digest; sem push individual |
| Avaliação com nota baixa (1 a 2) no Google | Instantâneo | Push; WhatsApp (opt-in); e-mail no digest |
| Resumo periódico (digest) | Semanal | |
| Fila acumulando (ex.: 10+ em aberto) | No máximo 1x/dia | Push ("você tem N feedbacks para responder") |
| Canal com conexão perdida (regra 15) | Instantâneo (1x, sem repetir) | Push + e-mail |
Por que assim: o negativo tem custo de não responder rápido, então vai instantâneo. O positivo não precisa interromper, então é agrupado. O digest semanal dá a visão geral sem pressão diária.
Métricas para acompanhar (ligam à seção 12): notificações enviadas/abertas por canal e tipo, tempo até a primeira resposta após a notificação, opt-out por tipo, e impacto na taxa de resposta. Cortar por porte, segmento e localização.