Pular para o conteúdo
flutter test      3159 ok   7 pulados
supabase test db  1782 ok
node --test         82 ok   0 falhas

Cada ponto desta raposa é uma verificação que passou: 5.023 na última execução do CI da Mindy, em 12/10/2026.

João Leite, Desenvolvedor

Sou João Leite. Construo software para o dia em que algo dá errado.

A obra sem sinal. O pagamento avisado duas vezes. O dado que um morador não pode ver do outro. São problemas que já resolvi em sistemas reais, e dois deles você pode testar aqui.

O dia ruim.

Todo sistema funciona no dia bom. O trabalho de verdade é o que ele faz quando a internet cai, quando o aviso chega duas vezes, quando alguém tenta ver o que não é dele.

  1. Sem sinal na obra. O registro espera no aparelho e sobe sozinho quando a conexão volta, sem duplicar. Relatório diário de obraentrou em produção, emprego anteriorNext.js, Supabase, IndexedDB
  2. O pagamento avisado duas vezes. Aviso repetido, atrasado ou fora de ordem não desfaz pedido pago. Duas clientes não levam a última peça. Loja D'Andrade Modano arReact, Cloudflare Workers, D1
  3. O dado de um na tela do outro. O que é da casa aparece para todos. O que é seu fica seu, e quem garante é o banco. Mindybeta privado, pausadoFlutter, Postgres com RLS
  4. Total errado na nota fiscal. A IA lê. O código refaz a conta e marca na planilha o que não fecha. Extrator de notasdemonstraçãoPython, FastAPI, API de IA
  5. Site fora do ar no meio da coleta. Erro passageiro tenta de novo com espera crescente; erro definitivo para e avisa. E o robô vai devagar: quatro páginas por vez, com pausa entre elas. Coletor de catálogodemonstraçãoPython, Playwright
  6. Dois cliques no mesmo segundo. Nos links de anúncio, cada clique vai para o próximo consultor, mesmo ao mesmo tempo. E quem clica nunca vê erro se o banco demorar. Dermatech Medicalno arHTML puro, Cloudflare Worker, D1

Outros trabalhos

  • Plateia Protótipo em Flutter e Supabase, com a regra de acesso testada em Postgres. Ainda não rodou em um projeto real.
  • Automação de compras em ERP Experiência anterior: rotinas em Python e Playwright em sistema corporativo. Sem telas públicas e sem código para mostrar.

Tente quebrar.

Não acredite em mim. Estas peças rodam no seu navegador, com a lógica portada dos sistemas reais e dados fictícios. Cada uma diz o que é de verdade e o que é simulado.

Registre com a rede cortada. Perca a resposta do servidor. Tente duplicar.

O mesmo problema do app de obra: o registro espera no aparelho e nasce uma vez só no servidor.

Esta demonstração precisa de JavaScript. O resto da página funciona sem ele.

Ver o caso completo: Relatório diário de obra

Dispare avisos repetidos, atrasados e fora de ordem contra um pedido.

A regra de pagamento da loja, portada para o navegador: pedido pago não desfaz, e o estoque nunca fica negativo.

Esta demonstração precisa de JavaScript. O resto da página funciona sem ele.

Ver o caso completo: Loja D'Andrade Moda

Por dentro.

Número que importa é o que limita o código, não o que mede o volume. Cada um abaixo traz de onde saiu.

o_banco_da_so_o_que_as_policies_prometem

  • 3.159 testes do app
  • 1.782 asserções de banco
  • 82 testes das funções de borda

5.023

verificações passaram na última execução do CI da Mindy: 3.159 testes do app, 82 das funções de borda e 1.782 asserções de banco. Nenhuma falhou.

CI de 12/10/2026, commit 567a46a
3159 tests passed, 7 skipped.
Files=75, Tests=1782 ... Result: PASS
pass 82, fail 0

35,46%

é o que a camada escura ocupa na raposa. As asserções de banco são 35,48% do total. O símbolo já existia quando medi: é coincidência, e deixei assim.

159989 de 451150 pixels do símbolo
1782 de 5023 verificações

117/117

tabelas da Mindy têm RLS ligada: sem policy, a tabela fica fechada. O CI reprova a migration que criar tabela sem RLS, policy que libera tudo ou função com privilégio de dono sem caminho fixo.

SQL guards passed for 147 migration file(s).

3 de 117

tabelas aceitam escrita direta do app: duas do próprio perfil e a lista de espera. Todo o resto passa por função versionada, com a regra dentro do banco.

grant update on table public.profiles to authenticated;
grant update on table public.user_preferences to authenticated;
grant insert on table public.lista_de_espera to anon, authenticated;

Byte a byte

é como a cifra de notificação da Mindy bate com o exemplo oficial da RFC 8291. Sem biblioteca, em 368 linhas.

encrypts the RFC 8291 example byte for byte

249

testes na loja D'Andrade, com pagamento e frete simulados. Host desconhecido lança erro: nenhum teste toca a rede.

npm test: 249 de 249, em 21 arquivos

E esta página?

Sem framework, sem biblioteca, sem rastreador, com as fontes servidas daqui. Esta página abre sem internet depois da primeira visita.

curl -s foxer.dev.br

O que quebrou.

Quebrou em aparelho real, em produção, no CI ou na primeira rodada. Cada caso deixou uma guarda para trás.

  1. 42501 permission denied for schema privateMindy

    Criar funcionava. Corrigir e excluir, não.

    Causa

    Um gatilho adiado roda no commit, já fora da função com permissão especial. Os testes de banco terminam em rollback, então nunca chegavam a dispará-lo, e a tela traduzia o erro como "você não tem acesso".

    O que ficou

    O gatilho passou a rodar como dono: o_gatilho_adiado_roda_como_dono. E a lição foi escrita onde o próximo teste lê.

  2. HTTP 2xx, e nada na telaMindy

    A Apple aceitou. O iPhone não mostrou.

    Causa

    O aparelho tinha três inscrições, duas órfãs, e o serviço de push responde sucesso até para inscrição órfã. Até a coluna de último uso mentia, porque também era escrita no registro.

    O que ficou

    Recibo em três camadas: aceito, mostrado e clicado. A coluna virou last_accepted_at e as órfãs são faxinadas.

  3. cross-database references are not implementedMindy

    O primeiro aparelho derrubaria a criação de tarefas.

    Causa

    extensions.net.http_post é lido como banco.schema.função. A linha só rodava com um aparelho inscrito, então nenhum teste chegava nela.

    O que ficou

    Nome certo e uma regra maior: a fila é a garantia, a chamada é a pressa. push_dispatch_never_costs_the_task.

  4. otp_expiredMindy

    O robô do provedor de e-mail gastou o link antes da pessoa.

    Causa

    Antivírus e pré-visualização abrem os links do e-mail sozinhos. O link de uso único morria antes do clique, e a pessoa só via "link expirado".

    O que ficou

    O link agora abre uma página minha, que troca o token por sessão com POST. Robô não faz POST. O defeito se reproduz em dois curl.

  5. Key is not 44 characters or its check digit is invalidExtrator

    A IA perdeu dígitos. O código pegou.

    Causa

    Na primeira rodada do extrator, a chave da nota veio com 42 e 43 dígitos. Nada na resposta indicava erro: só a conferência notou.

    O que ficou

    A chave é conferida em toda leitura. O relatório daquela rodada fica guardado com o código.

  6. NetworkFirst em /api/*/pdfApp de obra

    O relatório abria com os dados antigos.

    Causa

    A rota do PDF passava pelo cache do service worker, e alguns registros recebiam o arquivo velho.

    O que ficou

    PDF agora é NetworkOnly: nunca passa pelo cache.

  7. lang=en-USDermatech

    O Google guardou a página em inglês.

    Causa

    O robô do Google renderiza como en-US, e o site seguia o idioma do navegador.

    O que ficou

    O idioma inicial é sempre português. Quem escolhe outro continua nele ao navegar.

O que eu construo.

Também faço site para pequeno negócio e cuido de anúncios: sites e landing pages · tráfego pago

Quem responde é quem faz.

Retrato de João Leite em pontos

Sou João Leite, desenvolvedor em Embu das Artes (SP). A Foxer é a minha marca e não tem equipe por trás: quem responde é quem programa.

Antes, fui comprador e o único de TI numa multinacional. Li muita proposta de fornecedor, então escrevo as minhas do jeito que eu gostaria de receber: o que entra, o que fica de fora, o preço e a data.

Tela
React, TypeScript, Flutter
Servidor
Cloudflare Workers, Supabase, Python (FastAPI)
Banco
Postgres, SQLite (D1)
Campo
PWA offline, PDF no servidor
Automação
Playwright, Pydantic, APIs de IA
Formação
Tecnólogo em ADS na Descomplica, em andamento (previsão: dez/2026)
Idiomas
Português nativo, espanhol avançado, inglês intermediário e de preferência por escrito
Onde
Trabalho remoto, UTC-3

Me conta o problema.

Uma mensagem basta para começar. Eu mesmo respondo e, se fizer sentido, mando uma proposta por escrito: o que entra, o que fica de fora, prazo e preço.

WhatsApp (11) 99227-9903