Dois tipos
nps é a pergunta com escala fixa de 0 a 10 e aritmética fixa — é o tipo do qual a
tela de resultados consegue calcular um número. custom é qualquer outra coisa, onde
o verbatim costuma ser a resposta.
O tipo não pode mudar depois de criado: as notas já dadas foram dadas na escala
antiga.
Quando ela dispara
Uma pesquisa carrega até cinco gatilhos.
Os dois primeiros são casados por um consumidor conforme os fatos chegam, em
segundos. O terceiro é varrido, porque nada é publicado quando o trigésimo dia de
alguém chega — não há fato, já que nada aconteceu.
days_after_created só conta aniversários que caem depois de a pesquisa ter sido
escrita. Ligar “pergunte no dia 30” não questiona sua base inteira de uma vez, que é
o que uma implementação ingênua faz na primeira execução e não dá para desfazer.
Uma pessoa é perguntada uma vez por ocasião, para sempre: a primeira vez que
aquele fato é verdade sobre ela, a primeira vez que ela entra naquela audiência, o
seu N-ésimo dia. Reentrar num segmento não é nova ocasião — sair e voltar é ruído de
churn e não um momento.
Uma pesquisa recorrente (“pergunte o NPS de todo mundo a cada trimestre”) ainda
não existe, e um intervalo longo deliberadamente não a imita. Ela é um quarto tipo de
gatilho com um período na identidade, e até existir a resposta honesta é que isso não
pode ser perguntado.
O intervalo pertence à pessoa
cooldown_days (padrão 7) é por quanto tempo uma entrega fecha a porta para
qualquer pesquisa daquele contato — não para aquela pesquisa.
É essa a promessa inteira. “Ninguém é pesquisado duas vezes por semana” não é verdade
numa janela por pesquisa: três pesquisas perguntando no máximo uma vez por dia cada
estariam todas dentro do próprio limite e a pessoa seria perguntada três vezes. 0 é
permitido e significa sem intervalo, o que é uma resposta real para um ambiente
rodando exatamente uma pesquisa.
Reivindicar uma entrega é uma só instrução, e a contagem de linhas é a decisão. A
audiência, a identificação, a atividade e a janela são todas checadas dentro de um
INSERT, porque um SELECT seguido de INSERT são duas fotografias de uma tabela — e duas
entregas correndo sobre o mesmo contato encontrariam as duas nada pendente e as duas
escreveriam.
A leitura do widget
Onde o cartão é desenhado
position aceita center (padrão), bottom-right, bottom-center, bottom-left
ou inline.
Só o center toma a página. Ele escurece o fundo, leva o foco para dentro do
cartão e fecha no Esc ou num clique fora. Os dois cantos não escurecem nada, de
propósito: uma pergunta no canto é uma que a pessoa pode terminar a frase antes de
responder, e escurecer o produto para perguntar sobre o produto é o que faz um NPS de
cinco segundos parecer um pedágio. Eles são anunciados a um leitor de tela como
diálogo, mas não como modal — porque o resto do seu produto continua mesmo
disponível.
inline é o componente no seu próprio layout, que é o que ele fazia antes de haver
escolha — certo para uma tela de configurações ou qualquer lugar onde você já abriu
espaço para ele.
As três posições flutuantes saem da árvore do componente por portal, então nenhum
overflow ou contexto de empilhamento de um ancestral consegue recortá-las. Os
cantos ficam onde um launcher de suporte costuma ficar, então se você também desenha
o <HelpWidget /> à direita, ponha a pesquisa à esquerda.
Um diálogo no centro por vez, e há uma ordem. Três coisas se abrem sozinhas no
meio da página — um termo pendente, uma novidade não lida e esta pesquisa — e cada
uma descobre que quer a tela quando a resposta dela volta. Sem regra, as três
aparecem juntas, cada uma dizendo aria-modal="true" a um leitor de tela. O centro
passa a caber uma: a ordem padrão é agreements → whatsNew → survey (a condição
que o tenant declarou, depois o que ele publicou, depois o favor que ele está
pedindo), e quem espera não perde nada — a pesquisa só é gasta quando é
respondida, então ela aparece assim que a de cima sair, ou na próxima visita.
Quem já está na tela não é trocado por alguém de ordem maior que chegou depois:
puxar o cartão da mão de quem está lendo é pior do que a ordem sair imperfeita numa
visita. E um diálogo que a pessoa PEDIU — o seletor de metas do guia, por exemplo —
fura a fila, porque ele responde a um clique.
A fila é só do center. Um cartão no canto ou no fluxo não disputa palco com
ninguém. Para trocar a ordem:
@userkit/nextjs — é o mesmo componente, e em
modo proxy a leitura e a resposta são
encaminhadas pelos handlers como o resto da superfície do contato, com a sessão num
cookie httpOnly da sua própria origem.
pending nomeia uma ocasião, não uma pesquisa. Nada aqui pede uma — a API decide
quem é perguntado, a partir de um gatilho, uma audiência e o intervalo — que é por que
não existe requestSurvey e por que uma lista vazia é a resposta comum.
Uma entrega não respondida fica pendente por 14 dias. Uma pergunta que ninguém
respondeu em duas semanas não é uma pergunta que a pessoa ainda deve, e um widget que
abre uma pesquisa de março é um widget que as pessoas aprendem a dispensar sem ler. No
máximo cinco são devolvidas.
Responder gasta a entrega: uma segunda chamada responde not_found, que é
literalmente “você não foi perguntado isso” — a mesma coisa que uma ocasião retirada ou
vencida diz. Um widget clicado duas vezes escreve uma resposta, porque a escrita só
acontece se a entrega puder ser marcada como respondida por um UPDATE levando
responded_at IS NULL.
Uma pesquisa nps exige a nota. Uma escala respondida só com uma frase é um
verbatim sem nada para dividir, e deixar passar colocaria uma resposta no numerador de
uma taxa da qual ela não faz parte. Qualquer outro tipo aceita nota, comentário, ou os
dois.
Desligar uma pesquisa também faz suas entregas pendentes deixarem de ser pendentes.
Resultados
score é promotores menos detratores sobre scored, em porcentagem, e é null
quando ninguém pontuou — nunca 0. Zero é um NPS real e um número sobre o qual
alguém agiria; “ainda sem respostas” e “um resultado genuinamente neutro” não podem
ser desenhados iguais.
delivered é o denominador da sua taxa de resposta; scored é o denominador da
nota. Eles diferem sempre que alguém responde uma pesquisa custom só com palavras. A
tendência é semanal sobre os últimos 180 dias, em semanas UTC — a mesma meia-noite que
todo o resto usa.
A nota alcança o resto do produto por JOIN
A leitura de um contato levalatest_survey_score, e isso é um JOIN e não uma
coluna no contato. Deliberadamente: uma cópia é um segundo lugar que pode discordar,
alargaria a tabela mais quente do plano de clientes, e guardaria exatamente a única
resposta que o JOIN sempre consegue produzir. É null quando ninguém respondeu.
É isso que permite uma nota baixa ficar ao lado de sinais de churn na mesma tela sem
ninguém construir um pipeline.
survey.response_recorded é entregável como webhook, que é o
gancho para “encaminhe um detrator a um humano hoje”.
O que ainda não está aqui
Entrega por e-mail. Tudo acima é in-app: uma pesquisa é entregue a um widget que a pessoa abriu, e não existe versão dela por e-mail. O que existe ao lado são as campanhas, que podem enviar um template com a categoriasurveys — um público, uma sequência, um limite e um link de
descadastro. Isso é uma mensagem sobre perguntar; não cria uma entrega de pesquisa, e
uma resposta a ela não é uma resposta nos resultados acima.
Permissões
engagement:manage — owner e admin por padrão, compartilhada com checklists e o
changelog.