Files
DeskcommCRM/evidence/canal-no-onboarding-4-codigo-no-celular.png
Rafael MelgaçoandClaude Opus 5 6f82e97b6e feat(onboarding): o passo do telefone pergunta COMO se conecta, em vez de assumir
O produto conecta um número de três formas, e a tela de Conexões oferece as
três. O wizard oferecia uma — e nem isso: ele não perguntava.

`_client.tsx` montava e o primeiro efeito já disparava
`POST /api/v1/onboarding/whatsapp/session`. A rota grava a linha em
`channel_sessions` sem informar `provider`, e a coluna nasce com o default do
transporte por código. Ou seja: **o canal nascia só de a pessoa pisar na rota**.
Quem tem conta oficial na Meta já estava no caminho errado antes de clicar em
coisa nenhuma, e só descobria depois, em outra tela, com o funcionário montado
por cima.

Medido na jornada, contando linhas do banco numa organização recém-criada:

    CANAIS CRIADOS SEM ESCOLHER: 0        (era 1)
    CANAIS APOS NAVEGAR PELOS TRES RAMOS: 0
    CANAIS APOS ESCOLHER O CODIGO: 1

A do meio é a que importa: passear pelos três ramos não deixa canal pendurado.

── Três coisas que a medição decidiu, contra o palpite ─────────────────────

1. NÃO se aponta para Conexões. Era o desenho óbvio — perguntar e encaminhar —
   e ele é impossível: `app/app/layout.tsx:51` devolve `/app/*` para
   `/onboarding` enquanto `onboarded_at` for nulo. O botão voltaria ao próprio
   passo, que é o controle decorativo do PR #295. Os clientes de Conexões são
   montados AQUI, inteiros, sem cópia — os dois são "use client", não recebem
   prop e buscam o próprio estado.

2. A escolha NÃO é gravada. `cumprido` do passo é `Boolean(state.whatsapp)`:
   persistir no clique marcaria o passo como resolvido, e quem fechasse o
   navegador cairia no passo seguinte sem telefone e sem volta, porque o
   roteador só devolve o primeiro passo NÃO cumprido. Vive em `useState`, e o
   caso "dá para voltar e trocar de forma" é o que guarda isso.

3. O caminho oficial avisa ANTES. O `install.sh` não escreve
   `META_WEBHOOK_VERIFY_TOKEN`, então em instalação fresca esse canal envia e
   nunca recebe. Dizer isso depois de a pessoa buscar três credenciais no painel
   da Meta é tarde; a tela diz antes, e aponta o caminho que funciona hoje.

── Forma ───────────────────────────────────────────────────────────────────

`<label>` com radio nativo, copiado de `app/app/settings/atendimento/_form.tsx`.
Não é `RadioGroup` porque esse componente não existe neste repo — instalá-lo
criaria um quarto dialeto de escolha ao lado de três iguais. E não é `<Card>`:
o wizard usa a div crua `rounded-lg border bg-background p-6`, 14 vezes.

O QR ficou onde estava, de propósito. Extraí-lo obrigaria a apagar a linha 106
de `scripts/lint-channels.ts` e a reescrever três comentários corretos só para
escapar de um regex — e o cabeçalho daquele arquivo registra que reescrever
prosa correta para fugir do gate piora o código.

── Verificação ─────────────────────────────────────────────────────────────

`pnpm test:unit` 5338 (+9), typecheck limpo, `pnpm lint` 0 erros,
`pnpm lint:channels` ok nas duas direções da catraca.

Pela TELA, em `next start` de produção contra Supabase local com o
`baseline.sql`, sem WAHA, sem chave de IA e sem `META_*` — o estado de quem
acabou de instalar: `wizard-do-funcionario.spec.ts` 13/13, evidência em
`evidence/canal-no-onboarding.md`.

`vps-fresh-onboarding.spec.ts` (a P0 da doutrina de QA Visual) precisou de um
clique novo: ela esperava o código aparecer sozinho e teria quebrado EM
SILÊNCIO, porque não roda no CI.

Sabotagem: devolver o POST para a montagem reprova 4 dos 9 casos do teste novo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0126ezJHDNKTi7J1EM2GpfvJ
2026-08-24 22:21:12 -03:00

57 KiB
1280x720px