O Vou Contigo acompanha pessoas mais velhas em consultas, exames, mercado, banco, farmácia e passeios — e avisa a família de tudo. Na v2 o próprio WhatsApp agenda, cancela, mostra horários livres e manda lembretes sozinho; a cobrança PIX vira Asaas e o familiar ganha um portal web.

O serviço é vendido para os filhos e familiares que não conseguem estar presentes. A plataforma organiza quem vai ser acompanhado, quando, por quem, quanto custou de verdade, e entrega o relatório do dia pronto para colar no WhatsApp da família.
Cada atendimento tem cliente, acompanhado, tipo, endereço de saída e destino, horário e um ciclo de estados claro: solicitado → agendado → confirmado → em andamento → concluído → relatado.
Ao finalizar, o sistema exige hora real, minutos de espera, km rodados, estacionamento, pedágio e nível de esforço. Depois de 10 a 20 atendimentos dá para revisar o preço sem chute.
O relatório sai montado no modelo da marca. Na v2 ele é enviado sozinho ao familiar assim que a acompanhante finaliza — por WhatsApp e, quando há e-mail cadastrado, também por e-mail.
Um bot de menu numérico agenda, cancela, mostra horários livres e informa saldo — pela Evolution API, com o número comum da empresa lido por QR. Quando alguém pede uma pessoa — ou escreve algo fora do menu — o bot se cala até a gestão liberar.
Pacote vira cobrança PIX no Asaas, com QR e copia-e-cola. O webhook marca como pago sozinho e o pacote novo só nasce quando o dinheiro entra.
Login por link mágico no e-mail: saldo, próximas visitas, histórico de relatórios em página imprimível, solicitar e cancelar visita, e o calendário em .ics.
A pessoa acompanhada não precisa de app, login nem celular — só de uma ficha bem feita. Quem usa a plataforma é a família (pelo WhatsApp), a acompanhante (pelo celular) e a gestora (pelo painel e pelo Telegram).
Filho, neta ou responsável. Solicita pela landing ou pelo WhatsApp, recebe confirmação, lembrete e o relatório de cada acompanhamento. No MVP tudo pelo WhatsApp, com uma pessoa do outro lado.
Quem executa. Usa o painel mobile-first na rua: vê a agenda do dia, aperta Iniciar, aperta Finalizar, preenche espera/km/custos e revisa o relatório. Ou faz o mesmo pelo bot de Telegram.
Organiza a agenda, aprova solicitações, vende pacotes, cobra e olha as métricas. Recebe cada lead e cada mudança de agenda no Telegram em menos de um minuto.
WhatsApp, Telegram e painel são canais para agir sobre o atendimento — não são o atendimento. É essa distinção que impede o sistema de virar “um chat com banco de dados”.
Nenhuma automação de WhatsApp: o cliente continua falando com um humano. O que o sistema faz é não deixar nada se perder.
Uma página mobile-first na paleta do logo: a dor, os serviços, os 3 passos, os planos, quem somos, o que não fazemos, FAQ e o botão fixo de WhatsApp com mensagem pré-preenchida. O formulário curto cria um lead e avisa a gestora no Telegram.
Login Supabase com papéis gestora e acompanhante. Agenda semana/dia, cadastro de clientes e acompanhados, pacotes e saldo de horas, financeiro manual em PIX, leads, configurações e métricas com exportação em CSV.
Tela feita para usar na rua: Iniciar grava a hora real, Finalizar exige espera, km, estacionamento, pedágio e esforço de 1 a 5. Daí saem receita por hora efetiva, média de espera e custo extra médio.
O texto do relatório vem pré-montado no modelo da marca a partir dos campos do atendimento. Um botão copia para o WhatsApp, outro marca como enviado — junto com os templates de confirmação, lembrete, saldo baixo e cobrança.
No grupo privado da gestão: avisa novo lead, atendimento criado ou cancelado, “amanhã tem X às Y”, relatório pendente há mais de 2 horas e saldo baixo. Com comandos para fazer tudo do celular.
Um job agendado bate na rota protegida por CRON_SECRET e dispara os avisos do dia: lembrete de véspera, lembrete de poucas horas antes e cobrança de relatório pendente. Na VPS é o cron do sistema; na Vercel, o Vercel Cron.
A automação não substitui a pessoa: ela tira da pessoa o trabalho repetitivo de confirmar, lembrar, cobrar e relatar.
Menu numérico de cinco opções pela Evolution API. Agendar oferece os horários realmente livres da agenda; cancelar já aplica a política e informa a taxa. Tudo gravado em RPCs do Postgres, não em regras soltas no app.
Confirmação ao aprovar a solicitação, lembrete na véspera, lembrete duas horas antes e o relatório ao finalizar — direto ao cliente, por WhatsApp e por e-mail quando houver.
Cobrança com QR, webhook autenticado que concilia o pagamento e cron de renovação dos pacotes mensais avisando alguns dias antes do vencimento.
Link mágico por e-mail, saldo, próximas visitas, relatórios do mês em página imprimível, solicitação e cancelamento, calendário .ics e escolha de receber horários por e-mail ou WhatsApp.
O painel ganhou caixa de entrada unificada (conversas de WhatsApp + leads), fila de solicitações para aprovar e timeline por cliente com tudo que aconteceu, em qualquer canal.
O destino é geocodificado e comparado com o endereço-base. O raio é informativo — avisa a gestora, não bloqueia. Taxa de cancelamento e espera após a tolerância são calculadas sozinhas.
A pessoa acompanhada continua sem precisar de app nenhum. Quem interage é o filho, a neta, o responsável — e do jeito que ele já usa o celular.
Menu numérico, sem precisar escrever frase nenhuma:
Oi, Ana! Sou o assistente do Vou Contigo. Como posso ajudar? 1. Agendar acompanhamento 2. Cancelar ou remarcar 3. Ver horários livres 4. Meu saldo e próxima visita 5. Falar com uma pessoa
Três coisas põem a conversa em modo humano: escolher 5, escrever texto livre no menu e ser um número sem cadastro. Aí o bot para de responder por completo — nem escrever “menu” o traz de volta — até a gestão mandar /liberar no Telegram. Já dentro de um fluxo (escolhendo tipo, dia ou horário), resposta inválida não escala: ele só pede o número de novo.
/minha-contaLogin por link mágico enviado no e-mail (o código por WhatsApp está marcado como “em breve” na própria tela). O e-mail precisa ser o mesmo que está na ficha do cliente no painel — é assim que a conta é ligada ao cadastro.
Lá dentro: saldo de horas, próximas visitas, histórico de relatórios, dados do acompanhado, solicitar e cancelar visita, e ainda:
/minha-conta/horarios — horários livres, com os botões receber por e-mail e receber por WhatsApp;/minha-conta/relatorios/[mes] — os relatórios do mês numa página feita para imprimir (ou salvar em PDF pelo próprio navegador);/minha-conta/calendario.ics — baixa as próximas visitas para a agenda do celular.Nada acontece sem que uma pessoa aprove: o bot recebe o pedido, a gestora decide. O que mudou na v2 é que decidir passou a ser um toque em um botão.
Cada solicitação chega no grupo com três botões inline: ✅ aprovar, ✏️ ajustar e ❌ recusar. Aprovar já dispara a confirmação automática no WhatsApp do familiar.
/conversas mostra quem está esperando gente de verdade, /responder manda a resposta pelo WhatsApp e /liberar devolve a conversa ao bot.
/resumo dá a visão operacional do dia e /financeiro, o dinheiro da última semana. O cron das 7h manda o resumo do dia sozinho; às segundas ele vem com o financeiro da semana fechada.
/painel/inboxCaixa de entrada unificada: conversas de WhatsApp e leads da landing no mesmo lugar, com o histórico de cada conversa e o botão de devolver ao bot quando o assunto se resolve.
/painel/solicitacoesA fila do que o bot agendou pelo WhatsApp e ainda depende de aprovação, para a gestora aprovar, ajustar ou recusar sem abrir cada atendimento.
Cada cliente tem uma linha do tempo com tudo que aconteceu em qualquer canal. No financeiro, a cobrança PIX do Asaas com QR e copia-e-cola, conciliada pelo webhook.
Nada de infraestrutura própria: Node para o Next.js, a CLI do Supabase para o banco local, um bot de Telegram e (para publicar) uma conta na Vercel ligada ao GitHub.
O projeto é Next.js 15 com App Router, TypeScript e Tailwind 4.
# confira a versão node -v npm -v
Postgres, Auth, Storage e RLS rodando em Docker pela CLI, sem precisar de projeto na nuvem para desenvolver.
# sobe o stack local npx supabase start
Um bot só do Vou Contigo, criado no @BotFather, e o id do grupo privado da gestão.
# no Telegram, fale com @BotFather → /newbot
Os passos 1 a 6 são a instalação, feita uma vez. O passo 7 é a rotina que se repete todo dia.
Baixe o repositório e instale as dependências.
git clone https://github.com/inematds/voucontigo.git cd voucontigo npm install
Copie o exemplo para .env.local. Ele já lista tudo que o projeto lê: Supabase, Telegram, cron e site.
cp .env.example .env.local # .env.local — o que preencher NEXT_PUBLIC_SUPABASE_URL= # Supabase > Settings > API NEXT_PUBLIC_SUPABASE_ANON_KEY= # idem SUPABASE_SERVICE_ROLE_KEY= # idem (nunca no cliente) TELEGRAM_BOT_TOKEN= # @BotFather TELEGRAM_WEBHOOK_SECRET= # invente uma string longa TELEGRAM_CHAT_GESTAO= # id do grupo da gestão CRON_SECRET= # segredo do Vercel Cron NEXT_PUBLIC_SITE_URL=https://voucontigo.inema.club NEXT_PUBLIC_WHATSAPP_EMPRESA=5551999999999 TZ=America/Sao_Paulo # fuso do processo # --- v2 (vazio = desligado, não quebra nada) --- WHATSAPP_PROVIDER=evolution # ou meta EVOLUTION_API_URL=http://evolution:8080 EVOLUTION_API_KEY= # mesma chave da Evolution EVOLUTION_INSTANCE=voucontigo WHATSAPP_WEBHOOK_TOKEN= # você inventa; vai na query do webhook ASAAS_API_KEY= # comece no sandbox ASAAS_WEBHOOK_TOKEN= # header asaas-access-token ASAAS_BASE_URL=https://sandbox.asaas.com/api/v3 RESEND_API_KEY= # opcional; vazio = sem e-mail EMAIL_FROM=Vou Contigo <contato@voucontigo.com.br> GEOCODER_EMAIL= # exigido pela política do Nominatim
start sobe o Postgres local e imprime as chaves; db reset recria o banco aplicando as migrações de supabase/migrations. Copie a URL e a anon key impressas para o .env.local.
npx supabase start npx supabase db reset # aplica migrações + seed
Suba o servidor de desenvolvimento e abra o painel. A conta é criada no Supabase Auth (Studio local em http://localhost:54323, aba Authentication → Add user); um gatilho cria o perfil com o papel padrão acompanhante, então a primeira conta é promovida a gestora por SQL.
npm run dev # http://localhost:3000 · painel em /painel # promover a primeira conta a gestora (SQL Editor do Studio) update public.perfil set papel = 'gestora' where id = (select id from auth.users where email = 'voce@exemplo.com');
No Supabase Cloud, em Authentication → URL Configuration → Redirect URLs, cadastre os dois retornos de link mágico, senão o e-mail volta com erro: ${NEXT_PUBLIC_SITE_URL}/entrar/callback (portal do familiar) e ${NEXT_PUBLIC_SITE_URL}/login/callback (painel da equipe).
No Telegram, chame o @BotFather, mande /newbot, escolha nome e usuário e guarde o token em TELEGRAM_BOT_TOKEN. Adicione o bot ao grupo privado da gestão e coloque o id do grupo em TELEGRAM_CHAT_GESTAO. Depois aponte o webhook para a rota do projeto.
# registra o webhook em NEXT_PUBLIC_SITE_URL/api/telegram npx tsx scripts/telegram-set-webhook.ts
Em desenvolvimento o Telegram precisa de uma URL pública — use um túnel (ex.: ngrok http 3000) e rode o script com NEXT_PUBLIC_SITE_URL apontando para ele.
Publicar é git push: o resto é webhook. Antes, cadastre as mesmas variáveis do .env.local no destino (com as chaves do Supabase de produção) e rode o script do webhook do Telegram de novo já com a URL final.
git add -A git commit -m "feat: v2.0.0 do Vou Contigo" git push # deploy automático · nada a fazer no dashboard # na VPS (é onde a Evolution vive) — Caddy do host faz TLS e proxy docker compose -p voucontigo -f docker-compose.vps.yml --env-file .env up -d --build # e os jobs viram cron do sistema: cp deploy/vps-cron.example /etc/cron.d/voucontigo
Use sempre -p voucontigo: o deploy/Caddyfile.snippet faz proxy para os containers voucontigo-app-1 e voucontigo-evolution-1, cujos nomes dependem desse prefixo. Na Vercel, o vercel.json já traz os três crons em UTC — mas o de hora em hora (lembrete “2h antes”) exige plano Pro; no Hobby só roda um cron por dia, sem horário garantido. Na VPS isso não é problema.
O ciclo completo de um atendimento, do primeiro contato ao relatório na mão da família.
# 1. chega o lead (formulário da landing ou WhatsApp) # → o bot avisa no grupo; a gestora responde pelo WhatsApp /lead # lista os leads novos # 2. agendar /agendar # assistente passo a passo (ou pelo painel) # 3. no dia — a acompanhante, do celular /hoje # agenda do dia, com os ids /iniciar 42 # grava a hora real de início # 4. ao terminar /finalizar 42 # pede espera, km, estacionamento, pedágio, esforço # 5. relatório /relatorio 42 # texto pronto para copiar e colar no WhatsApp da família # 6. saldo do pacote /saldo Maria # horas usadas e restantes
A Evolution roda ao lado do app, na mesma rede Docker, e conversa com o WhatsApp por um número comum — sem verificação na Meta, sem templates aprovados e sem custo por mensagem. A alternativa oficial (Meta Cloud API) continua suportada no código com WHATSAPP_PROVIDER=meta.
A imagem está fixada em atendai/evolution-api:v2.2.3, com um Postgres próprio (nada a ver com o Supabase). Cabe em cerca de 400 MB de memória ao lado do app.
cp .env.evolution.example .env.evolution # edite: EVOLUTION_SERVER_URL, EVOLUTION_API_KEY (string longa), EVOLUTION_DB_PASSWORD docker compose -p voucontigo -f docker-compose.evolution.yml \ --env-file .env.evolution up -d
Abra https://evolution.inema.club/manager e entre com a EVOLUTION_API_KEY. Crie a instância com o nome voucontigo — o mesmo valor de EVOLUTION_INSTANCE — peça o QR Code e leia com o celular do número do Vou Contigo (WhatsApp → Aparelhos conectados). A sessão fica no volume evolution_instances e sobrevive a reinícios.
O webhook global está desligado de propósito: ele é cadastrado na instância, pelo manager.
| Campo | Valor |
|---|---|
| URL | https://voucontigo.inema.club/api/whatsapp?token=<WHATSAPP_WEBHOOK_TOKEN> |
| Eventos | MESSAGES_UPSERT e MESSAGES_UPDATE |
webhook_by_events | false — todos os eventos na mesma URL |
webhook_base64 | false — nada de mídia em base64 |
A Evolution não assina o corpo da requisição, por isso o segredo viaja na query string: o mesmo WHATSAPP_WEBHOOK_TOKEN precisa estar no .env do app, que compara em tempo constante e devolve 401 se não bater. Mensagens de grupo, enviadas pelo próprio número ou sem texto são ignoradas com 200, e o id da mensagem garante que nada seja processado duas vezes.
As duas pilhas dividem a rede Docker, então o app fala com a Evolution pelo nome do serviço, sem passar pela internet.
WHATSAPP_PROVIDER=evolution EVOLUTION_API_URL=http://evolution:8080 EVOLUTION_API_KEY=# a MESMA AUTHENTICATION_API_KEY da Evolution EVOLUTION_INSTANCE=voucontigo WHATSAPP_WEBHOOK_TOKEN=# o mesmo da URL do webhook
Não é a API oficial: a Meta pode bloquear o número se o comportamento parecer spam. Regras de uso — responder apenas conversas iniciadas pelo cliente; enviar só mensagens sobre compromissos reais (confirmação, lembrete, relatório, cobrança do que foi contratado); nada de disparo em massa, lista de transmissão ou marketing; manter um número de reserva. Se o volume crescer, migrar para WHATSAPP_PROVIDER=meta.
O pacote de horas vira uma cobrança PIX com QR Code e copia-e-cola. Quando o cliente paga, o webhook do Asaas marca como pago e o pacote novo nasce — nunca antes.
Crie a conta, gere a API key do ambiente de testes e aponte a base para o sandbox. Só troque para produção depois de uma cobrança completa funcionando.
ASAAS_API_KEY=# chave do sandbox ASAAS_BASE_URL=https://sandbox.asaas.com/api/v3 ASAAS_WEBHOOK_TOKEN=# string longa que você inventa
No Asaas, aponte para a rota do app e defina o token de autenticação — ele chega no header asaas-access-token e é comparado com ASAAS_WEBHOOK_TOKEN (401 se não bater).
https://voucontigo.inema.club/api/asaas/webhook # header: asaas-access-token: <ASAAS_WEBHOOK_TOKEN>
Eventos que importam: PAYMENT_RECEIVED e PAYMENT_CONFIRMED marcam pago; PAYMENT_DELETED e PAYMENT_REFUNDED desfazem. A rota responde 200 sempre que autenticada — o Asaas trava a fila em qualquer resposta que não seja 2xx — e ignora eventos repetidos.
O cron /api/cron/renovacoes procura pacotes mensais que vencem em até renovacao_aviso_dias (padrão 3), gera a cobrança de renovação e manda ao cliente. Pacotes vencidos viram expirado, com aviso à gestão.
Trocar ASAAS_BASE_URL para https://api.asaas.com/v3, usar a chave de produção e registrar o ambiente na configuração asaas_ambiente do painel. O PIX manual da v1 continua existindo como alternativa.
Tudo que o bot faz, o painel também faz — o bot é o atalho no celular. Ele vive no grupo privado da gestora com a acompanhante.
| Comando | O que faz |
|---|---|
/hoje | Agenda de hoje, com horário, acompanhado, tipo, destino e status. |
/amanha | Agenda de amanhã — a base do lembrete da véspera. |
/semana | Visão dos próximos sete dias, para enxergar ocupação e buracos. |
/agendar | Assistente passo a passo: cliente, acompanhado, tipo, data e hora, saída e destino. |
/cancelar <id> | Cancela o atendimento e registra o motivo, aplicando a política de cancelamento. |
/iniciar <id> | Marca o início real — é o check-in da acompanhante. |
/finalizar <id> | Marca o fim real e pede espera, km, estacionamento, pedágio e esforço de 1 a 5. |
/relatorio <id> | Monta o relatório no modelo da marca para copiar e mandar à família. |
/saldo <cliente> | Horas contratadas, usadas e restantes do pacote daquele cliente. |
/lead | Lista os leads novos que chegaram pela landing, com o link do WhatsApp. |
| Novos na v2.0.0 | |
/solicitacoes | Solicitações pendentes vindas do WhatsApp, cada uma com os botões ✅ aprovar, ✏️ ajustar e ❌ recusar. Aprovar dispara a confirmação automática ao familiar. |
/conversas | Quem está aguardando atendimento humano — as conversas em que o bot se calou. |
/responder <whatsapp> <texto> | Manda a resposta pelo WhatsApp sem sair do Telegram. |
/liberar <whatsapp> | Devolve a conversa ao bot, tirando-a do modo humano. |
/resumo | Resumo operacional de hoje: agenda, pendências e o que já saiu. |
/financeiro | Resumo financeiro da última semana fechada. |
Além dos comandos, o bot avisa sozinho: novo lead, atendimento criado ou cancelado, nova solicitação do WhatsApp, pedido de atendimento humano, relatório pendente há mais de duas horas e saldo baixo de cliente. O cron das 7h manda o resumo do dia; às segundas, ele vem junto com o financeiro da semana.
Todas estão em .env.example. As da v2 seguem a regra “vazio = desligado”: o app sobe do mesmo jeito, só sem aquela automação.
| Variável | De onde vem · o que faz |
|---|---|
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYSUPABASE_SERVICE_ROLE_KEY | Supabase → Settings → API. A service role nunca vai para o cliente. |
TELEGRAM_BOT_TOKENTELEGRAM_WEBHOOK_SECRETTELEGRAM_CHAT_GESTAO | Token do @BotFather, um segredo inventado por você e o id do grupo privado da gestão. |
CRON_SECRET | Segredo que o cron envia como Authorization: Bearer …. Sem ele, as rotas de job respondem 401. |
NEXT_PUBLIC_SITE_URLNEXT_PUBLIC_WHATSAPP_EMPRESA | URL pública do site e o número da empresa no formato 55DDDNÚMERO. |
TZ | America/Sao_Paulo. Fuso do processo — defina também nas variáveis do projeto na Vercel. |
WHATSAPP_PROVIDER | evolution (padrão) ou meta. |
EVOLUTION_API_URLEVOLUTION_API_KEYEVOLUTION_INSTANCE | Endereço interno, a mesma chave da Evolution e o nome da instância criada no manager. |
WHATSAPP_WEBHOOK_TOKEN | Segredo do webhook de entrada; vai na query string porque a Evolution não assina o corpo. |
ASAAS_API_KEYASAAS_WEBHOOK_TOKENASAAS_BASE_URL | Asaas. Vazio = sem cobrança automática; o PIX manual da v1 continua. |
RESEND_API_KEYEMAIL_FROM | Resend via REST. Vazio = sem e-mail (tudo sai só por WhatsApp); o domínio do remetente precisa estar verificado. |
GEOCODER_PROVIDERGEOCODING_URLGEOCODER_EMAIL | Nominatim do OpenStreetMap, cuja política de uso exige um e-mail de contato. Vazio = raio nunca verificado. |
Falta ainda o que não é variável e sim configuração no painel: raio_km, lat_base/lng_base, tolerancia_espera_min, cancelamento_gratis_horas, cancelamento_taxa_percentual, chave_pix e enviar_horarios_semanal. Sem latitude e longitude da base, o raio nunca chega a ser conferido.
Isso não é letra miúda: é uma decisão de produto e de risco legal, e está gravada no próprio modelo de dados.
Não há aplicação de medicação, enfermagem, procedimentos nem cuidado clínico. O sistema não tem campos de medicação nem prontuário — só um campo de “restrições declaradas” em texto livre, com o mínimo necessário. A landing traz a seção “o que não fazemos” de propósito.
Dados de pessoas idosas, endereço e mobilidade são sensíveis. Coleta mínima, consentimento registrado no cadastro, fotos só com autorização explícita, exclusão a pedido, acesso ao painel apenas com login e isolamento por RLS no Supabase.
O MVP existe para operar uma acompanhante com organização e juntar os números que validam o preço. Só depois disso entra automação, e só depois dela entra rede.