<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nayara Martins</title>
    <description>The latest articles on DEV Community by Nayara Martins (@nayaramartins).</description>
    <link>https://dev.to/nayaramartins</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4101035%2Fc4ae661b-c3b0-4d18-b6ce-13c6557950d1.jpeg</url>
      <title>DEV Community: Nayara Martins</title>
      <link>https://dev.to/nayaramartins</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nayaramartins"/>
    <language>en</language>
    <item>
      <title>Technical SEO Crawl Budget: How to Find Where Googlebot Is Wasting Crawls</title>
      <dc:creator>Nayara Martins</dc:creator>
      <pubDate>Sun, 20 Sep 2026 02:20:34 +0000</pubDate>
      <link>https://dev.to/nayaramartins/technical-seo-crawl-budget-how-to-find-where-googlebot-is-wasting-crawls-4ded</link>
      <guid>https://dev.to/nayaramartins/technical-seo-crawl-budget-how-to-find-where-googlebot-is-wasting-crawls-4ded</guid>
      <description>&lt;p&gt;The first sign that a site is outgrowing its architecture isn’t a drop in rankings—it’s a widening gap between the pages you publish and the pages Google actually knows exist. &lt;/p&gt;

&lt;p&gt;If you run a programmatic SEO setup, a large e-commerce catalog, or a platform with tens of thousands of dynamic URLs, you aren't just fighting for keywords. You are fighting for &lt;strong&gt;Googlebot's attention&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;This attention span is what we call the &lt;strong&gt;Crawl Budget&lt;/strong&gt;. Here is exactly how to diagnose where Googlebot is wasting resources on your server, how to track it without expensive enterprise tools, and how to fix it in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Symptom: Discovered - Currently Not Indexed
&lt;/h2&gt;

&lt;p&gt;When you open Google Search Console and see a massive spike under &lt;strong&gt;"Discovered - currently not indexed"&lt;/strong&gt;, Google is telling you two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It knows the URLs exist (it found them via sitemaps or internal links).&lt;/li&gt;
&lt;li&gt;It looked at your server, calculated the effort required to crawl them, and decided: &lt;em&gt;“Not today.”&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On small sites with less than 1,000 pages, crawl budget rarely matters. Googlebot will brute-force its way through your code. But on large-scale frameworks, crawl waste compounds. If Googlebot spends 80% of its daily requests hitting duplicate URLs, tracking parameters, or heavy redirect chains, your high-intent commercial pages will sit in the dark for months.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Diagnose Crawl Waste (The Source of Truth)
&lt;/h2&gt;

&lt;p&gt;Don't rely on third-party marketing crawlers to estimate your crawl budget. The only source of truth is your &lt;strong&gt;server access logs&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Googlebot leaves a digital footprint every time it requests a file. You can isolate these requests directly from your terminal.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Verify the Real Googlebot
&lt;/h3&gt;

&lt;p&gt;Before analyzing behavior, ensure you aren't looking at scraper bots spoofing their User-Agent. Run a reverse DNS lookup on the IP addresses hitting your server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;host 66.249.66.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;The output must resolve to a &lt;code&gt;googlebot.com&lt;/code&gt; or &lt;code&gt;google.com&lt;/code&gt; domain.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Extract Googlebot Activity from Logs
&lt;/h3&gt;

&lt;p&gt;If you are running an Nginx or Apache server, you can use a quick line of &lt;code&gt;grep&lt;/code&gt; to see exactly which URLs Googlebot spent its energy on today:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"Googlebot"&lt;/span&gt; /var/log/nginx/access.log | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $7}'&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-nr&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prints the top 20 most crawled URLs on your site by Googlebot. Look closely at the pattern. If you see query parameters (&lt;code&gt;?sort=price&lt;/code&gt;, &lt;code&gt;?ref=&lt;/code&gt;), session IDs, or internal search result pages dominating the top spots, you have found your crawl leak.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Culprits of Crawl Waste &amp;amp; How to Fix Them
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The Trailing Slash and Protocol Inconsistencies
&lt;/h3&gt;

&lt;p&gt;To a crawler, &lt;code&gt;https://yourdomain.com&lt;/code&gt; and &lt;code&gt;https://yourdomain.com/&lt;/code&gt; are two completely different locations. If your internal linking structure is inconsistent, Googlebot will fetch both, cutting your crawl efficiency exactly in half.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;The Fix:&lt;/strong&gt; Enforce a strict server-side redirect (301 or 308) to your preferred canonical structure via your server configuration or routing layer. Never let both return a &lt;code&gt;200 OK&lt;/code&gt; status.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Infinite Scroll and Faceted Navigation Filters
&lt;/h3&gt;

&lt;p&gt;Faceted navigation (filters for color, price, size) can generate millions of URL permutations from a single category page. If Googlebot starts crawling every possible combination of filters, it will exhaust its budget before hitting your main products.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;The Fix:&lt;/strong&gt; Use &lt;code&gt;robots.txt&lt;/code&gt; to block parameter patterns that don't hold organic search value:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User-agent: Googlebot
Disallow: /*?sort=
Disallow: /*?price=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. High-Latency Server Responses
&lt;/h3&gt;

&lt;p&gt;Crawl budget is heavily tied to server performance. If your backend takes 1.5 seconds to respond (Time to First Byte - TTFB) due to heavy database queries or unoptimized loops, Googlebot will throttle its crawl rate to prevent crashing your site.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;The Fix:&lt;/strong&gt; Move your programmatic page generation closer to the edge. Use static generation pipelines, implement aggressive redis caching for database-heavy elements, and ensure your Core Web Vitals are green at the server level.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Verification: What to Measure Next
&lt;/h2&gt;

&lt;p&gt;Fixing crawl budget is an architectural change, not a content edit. Once you deploy your routing cleanups and block parameter leaks, monitor these two metrics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Average Response Time in GSC:&lt;/strong&gt; Go to &lt;em&gt;Settings &amp;gt; Crawl Stats&lt;/em&gt;. You should see a downward trend in response times and an upward trend in the total number of pages crawled per day.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Log File Cohorts:&lt;/strong&gt; Run your log analysis scripts weekly. The share of requests going to junk URLs or parameters should drop to zero, forcing Googlebot to spend 100% of its budget on your indexable, money-making pages.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you don't want to waste engineering hours guessing where your indexation is failing, treat SEO as a system architecture problem. Fix the pipeline, and the rankings will follow.&lt;/p&gt;

</description>
      <category>technicalseo</category>
      <category>webdev</category>
      <category>performance</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Automação para o agronegócio: onde faz sentido para o pequeno e para o grande produtor</title>
      <dc:creator>Nayara Martins</dc:creator>
      <pubDate>Fri, 04 Sep 2026 03:11:47 +0000</pubDate>
      <link>https://dev.to/nayaramartins/automacao-para-o-agronegocio-onde-faz-sentido-para-o-pequeno-e-para-o-grande-produtor-2noi</link>
      <guid>https://dev.to/nayaramartins/automacao-para-o-agronegocio-onde-faz-sentido-para-o-pequeno-e-para-o-grande-produtor-2noi</guid>
      <description>&lt;p&gt;Quando se fala em automação no agronegócio, a imagem que vem à cabeça é trator autônomo, drone e sensor de solo. Isso é automação de hardware, um mercado especializado que não é o meu. O que eu construo é a camada de integração de sistemas: conectar dado, decisão e aviso sem depender de planilha solta ou de alguém checando manualmente todo dia. Nessa camada, o espaço real muda dependendo do porte do produtor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Para o pequeno produtor: automação de decisão simples
&lt;/h2&gt;

&lt;p&gt;O pequeno produtor não precisa de um ERP agrícola completo pra começar a automatizar. O ganho real está em três frentes baratas de montar:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alerta de preço de commodity.&lt;/strong&gt; Integrar a cotação pública (CEPEA, B3) com um gatilho automático que avisa no WhatsApp quando o preço bate um patamar definido. Isso substitui checar cotação manualmente todo dia, e ajuda a decidir a hora de vender sem depender só de intuição ou de ligar pro comprador.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alerta climático automatizado.&lt;/strong&gt; APIs meteorológicas públicas (INMET, entre outras) permitem montar um aviso automático de geada, chuva forte ou período de seca prolongada, direto no WhatsApp do produtor, sem custo de assinatura de plataforma cara.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Substituir a planilha solta por um registro simples e automatizado.&lt;/strong&gt; Não é ERP completo: é um formulário conectado a um banco simples que registra colheita, insumo aplicado e custo por talhão, sem depender de arquivo Excel espalhado entre celular e computador.&lt;/p&gt;

&lt;h2&gt;
  
  
  Para o grande produtor ou cooperativa: automação de escala
&lt;/h2&gt;

&lt;p&gt;Quando o volume de dados e de talhões cresce, o problema muda de "não tenho registro" para "tenho registro em sistemas que não conversam entre si". Aí a automação de integração vale mais:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Estoque de insumo com pedido automático.&lt;/strong&gt; Conectar o controle de estoque com um gatilho que dispara pedido de compra (ou pelo menos um alerta pro responsável) quando o nível de um insumo crítico cai abaixo do necessário pra próxima etapa da safra.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consolidação de dados de múltiplos talhões e fazendas.&lt;/strong&gt; Em vez de esperar relatório manual de cada unidade, um pipeline automatizado que junta os dados num painel único, atualizado sem intervenção manual toda semana.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rastreabilidade e compliance.&lt;/strong&gt; Exportação e certificação exigem rastreabilidade documentada (origem, insumo aplicado, movimentação). Automatizar esse registro no momento em que o evento acontece evita reconstrução manual de histórico sob pressão de auditoria ou prazo de exportação.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automação financeira com cooperativa ou trading.&lt;/strong&gt; Conciliar contrato (CPR ou equivalente) com o que foi efetivamente entregue e pago, do mesmo jeito que idempotência e reconciliação valem pra qualquer automação financeira: nunca dar baixa duas vezes, sempre com fonte de verdade auditável.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que muda no agro em relação a outros setores
&lt;/h2&gt;

&lt;p&gt;Duas particularidades pesam mais aqui do que numa automação urbana comum:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conectividade instável.&lt;/strong&gt; Internet no campo cai com frequência maior que num escritório. Automação que depende de conexão constante sem fallback perde eventos. Faz mais sentido registrar localmente primeiro e sincronizar quando a conexão volta, do que depender de tudo em tempo real.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decisão automática tem limite mais baixo aqui também.&lt;/strong&gt; Alertar sobre geada é automação segura. Decidir sozinha quando aplicar defensivo ou colher não é: isso é julgamento agronômico, com consequência direta na safra, e precisa de humano confirmando, do mesmo jeito que uma automação de cobrança não deveria decidir sozinha sobre cancelar um contrato.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ferramentas que fazem sentido nesse cenário
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;n8n:&lt;/strong&gt; pra orquestrar a integração entre a fonte de dado (clima, cotação, estoque) e o canal de aviso (WhatsApp, e-mail), sem precisar de uma plataforma agrícola fechada e cara pra um fluxo simples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;APIs públicas de clima e cotação:&lt;/strong&gt; INMET e CEPEA como fonte gratuita, antes de considerar qualquer serviço pago de dado climático ou de mercado.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evolution API ou API oficial do WhatsApp:&lt;/strong&gt; como canal de aviso, porque é o canal que o produtor já usa no dia a dia, sem exigir que ele abra um aplicativo novo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cuidados que custam caro se ignorados
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Não prometer automação de decisão agronômica crítica.&lt;/strong&gt; Alertar é seguro, decidir sozinho sobre aplicação de insumo ou colheita não é.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Planejar fallback pra internet instável&lt;/strong&gt;, com registro local e sincronização posterior, em vez de assumir conexão constante.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reconciliação financeira com cooperativa ou trading segue os mesmos princípios de qualquer automação de cobrança&lt;/strong&gt;: idempotência por identificador de operação, nunca por valor e data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Automação no agro que realmente ajuda não tenta substituir o conhecimento de quem trabalha a terra. Ela tira do produtor o trabalho de ficar checando manualmente o que pode ser avisado sozinho, e devolve esse tempo pra decisão que só ele pode tomar.&lt;/p&gt;




&lt;p&gt;Nayara Martins, desenvolvedora de sistemas sob medida em Assis, SP. Mais em prospectia.space.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>productivity</category>
      <category>software</category>
    </item>
    <item>
      <title>Automação de atendimento no WhatsApp: o que decidir antes de deixar a IA responder sozinha</title>
      <dc:creator>Nayara Martins</dc:creator>
      <pubDate>Fri, 04 Sep 2026 03:01:25 +0000</pubDate>
      <link>https://dev.to/nayaramartins/automacao-de-atendimento-no-whatsapp-o-que-decidir-antes-de-deixar-a-ia-responder-sozinha-255k</link>
      <guid>https://dev.to/nayaramartins/automacao-de-atendimento-no-whatsapp-o-que-decidir-antes-de-deixar-a-ia-responder-sozinha-255k</guid>
      <description>&lt;p&gt;Automação de atendimento no WhatsApp não é só "responder rápido". É decidir o que a automação pode prometer sozinha, o que precisa de um humano, e como não perder a conta no processo.&lt;/p&gt;

&lt;p&gt;Depois de rodar automação de WhatsApp em produção, essas são as decisões que separam um atendimento automático que funciona de um que gera reclamação ou perde o número.&lt;/p&gt;

&lt;h2&gt;
  
  
  API oficial ou não oficial: o trade-off real
&lt;/h2&gt;

&lt;p&gt;A API oficial do WhatsApp (Cloud API / Business API) é estável, tem suporte da Meta e não corre risco de ban por uso legítimo. O custo é rigidez: mensagem fora da janela de 24 horas de uma conversa precisa ser um template pré-aprovado, e aprovar template novo leva tempo.&lt;/p&gt;

&lt;p&gt;A API não oficial (baseada em Baileys, como a Evolution API) simula um cliente WhatsApp Web de verdade. É flexível, manda qualquer mensagem a qualquer momento, mas roda numa zona cinzenta dos termos de uso da Meta. O risco não é teórico: um número pode ser banido, e não existe recurso formal quando isso acontece numa API não oficial.&lt;/p&gt;

&lt;p&gt;A escolha certa depende de quanto a operação perde se o número for banido de repente. Se a resposta for "muito", API oficial. Se for um projeto pequeno, testando um fluxo, a não oficial resolve mais rápido.&lt;/p&gt;

&lt;h2&gt;
  
  
  Número novo precisa de aquecimento, não de volume
&lt;/h2&gt;

&lt;p&gt;O erro mais comum ao automatizar WhatsApp é ligar um número novo e já mandar centenas de mensagens no primeiro dia. Isso é exatamente o padrão de comportamento que os sistemas antiban da própria Meta foram feitos pra detectar.&lt;/p&gt;

&lt;p&gt;O que funciona: começar com poucas conversas por dia, aumentar aos poucos ao longo de uma a duas semanas, variar o intervalo entre mensagens (nunca disparo instantâneo em massa), e priorizar conversas iniciadas pelo próprio cliente em vez de mensagem fria. Número aquecido aguenta volume real depois. Número novo tratado como se já tivesse volume real não aguenta nem a primeira semana.&lt;/p&gt;

&lt;h2&gt;
  
  
  Webhook de mensagem também precisa de idempotência
&lt;/h2&gt;

&lt;p&gt;O mesmo problema de webhook duplicado que existe em pagamento existe em WhatsApp: instabilidade de rede e retry do provedor podem entregar a mesma mensagem duas vezes pro seu sistema. Se a automação responde a cada webhook recebido sem checar, o cliente recebe a mesma resposta repetida, o que parece bug (e é).&lt;/p&gt;

&lt;p&gt;A chave de idempotência aqui é o ID da mensagem que a própria API do WhatsApp gera. Antes de processar, checar se aquele ID já foi tratado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Onde termina o que a IA pode responder sozinha
&lt;/h2&gt;

&lt;p&gt;Uma IA respondendo atendimento no WhatsApp economiza tempo real, mas o limite entre "responder dúvida" e "assumir compromisso" precisa estar definido antes de colocar em produção, não descoberto depois de um problema.&lt;/p&gt;

&lt;p&gt;O que eu deixo a IA responder sozinha: dúvida sobre horário de funcionamento, status de pedido, perguntas frequentes já mapeadas. O que eu nunca deixo: prometer prazo específico, negociar preço, confirmar cancelamento ou reembolso. Esse tipo de resposta tem consequência financeira ou contratual, e "a IA respondeu errado" não é uma desculpa que resolve o problema depois que o cliente já recebeu a promessa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opt-in não é detalhe jurídico, é o que evita denúncia em massa
&lt;/h2&gt;

&lt;p&gt;Mandar mensagem fria pra uma lista comprada ou raspada é o jeito mais rápido de acumular denúncia de spam, e denúncia em volume é o principal gatilho de ban, mais até que volume de mensagens em si.&lt;/p&gt;

&lt;p&gt;A régua segura é: só automatizar conversa que o próprio cliente iniciou, ou que ele deu consentimento explícito pra receber (cadastro em formulário, opt-in confirmado). Lista fria automatizada é a forma mais eficiente de queimar um número novo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ferramentas que eu recomendo de verdade
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Evolution API self-hosted&lt;/strong&gt;: pra quem precisa de flexibilidade e aceita o risco da API não oficial, é a que uso, com sessão autenticada e monitoramento de status de conexão, porque a sessão cai e precisa de reconexão automática.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;n8n&lt;/strong&gt;: pra orquestrar o fluxo de decisão (responder sozinho, escalar pra humano, aguardar), sem misturar essa lógica com o código de integração da API em si.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DeepSeek ou outro modelo de linguagem&lt;/strong&gt;: como motor de resposta pras perguntas que a automação pode responder sozinha, sempre com um conjunto fechado de respostas permitidas pros tópicos sensíveis, não geração livre.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cuidados que custam caro se ignorados
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nunca automatizar mensagem fria em massa sem opt-in.&lt;/strong&gt; É o caminho mais direto pra denúncia e ban.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aquecer número novo antes de escalar volume.&lt;/strong&gt; Comportamento de disparo em massa desde o primeiro dia é o padrão mais fácil de detectar como automação.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nunca deixar a IA prometer prazo, preço ou cancelamento sozinha.&lt;/strong&gt; Definir isso como regra de código, não como instrução de prompt que pode ser ignorada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webhook de mensagem também precisa de idempotência por ID&lt;/strong&gt;, senão o cliente recebe resposta duplicada.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Atendimento automatizado bem feito é o cliente nem perceber que está falando com uma automação até que isso realmente importe, e nesse ponto, sempre poder falar com uma pessoa.&lt;/p&gt;




&lt;p&gt;Nayara Martins, desenvolvedora de sistemas sob medida em Assis, SP. Mais em prospectia.space.&lt;/p&gt;

</description>
      <category>api</category>
      <category>automation</category>
      <category>software</category>
    </item>
    <item>
      <title>Automação de cobrança: o que decidir antes de deixar o sistema cobrar sozinho</title>
      <dc:creator>Nayara Martins</dc:creator>
      <pubDate>Fri, 04 Sep 2026 02:54:16 +0000</pubDate>
      <link>https://dev.to/nayaramartins/automacao-de-cobranca-o-que-decidir-antes-de-deixar-o-sistema-cobrar-sozinho-58p5</link>
      <guid>https://dev.to/nayaramartins/automacao-de-cobranca-o-que-decidir-antes-de-deixar-o-sistema-cobrar-sozinho-58p5</guid>
      <description>&lt;p&gt;Automação de cobrança não é "mandar boleto sozinho". É garantir que o valor certo seja cobrado da pessoa certa, uma única vez, e que o seu sistema saiba com certeza quando isso realmente aconteceu, sem depender de alguém checando o extrato manualmente.&lt;/p&gt;

&lt;p&gt;Depois de integrar gateway de pagamento e montar régua de cobrança automática em produção, essas são as decisões que separam uma automação confiável de uma que assusta o cliente com cobrança errada.&lt;/p&gt;

&lt;h2&gt;
  
  
  O webhook de pagamento precisa de assinatura validada
&lt;/h2&gt;

&lt;p&gt;Todo gateway sério (PIX, boleto, cartão) manda um webhook quando o status de um pagamento muda: pago, cancelado, estornado. O erro mais comum é tratar esse POST como verdade absoluta só porque chegou na URL certa.&lt;/p&gt;

&lt;p&gt;Qualquer pessoa pode descobrir a URL do seu webhook e mandar um POST forjado dizendo "isso foi pago". A defesa é validar a assinatura que o gateway envia junto (normalmente um header com hash HMAC do corpo da requisição, calculado com uma chave secreta que só você e o gateway conhecem). Se a assinatura não bate, o evento é descartado, não processado.&lt;/p&gt;

&lt;p&gt;Isso não é paranoia: é o mesmo princípio que uso pra validar licença por HMAC quando o dado de verificação passa por um canal que eu não controlo totalmente. Se alguém pode forjar o payload, alguém vai tentar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Idempotência por ID da transação, nunca por valor
&lt;/h2&gt;

&lt;p&gt;Webhook de pagamento é reenviado com frequência, por instabilidade de rede, por retry automático do próprio gateway, por timeout na sua resposta. Se a automação processa "cobrança recebida" cada vez que o webhook chega, uma cobrança de R$ 200 pode virar duas baixas de R$ 200 no seu financeiro.&lt;/p&gt;

&lt;p&gt;A chave de idempotência aqui é o ID da transação que o gateway gera, nunca o valor ou a data. Dois pagamentos diferentes podem ter o mesmo valor no mesmo dia (dois clientes pagando a mesma mensalidade), então "valor + data" não identifica uma cobrança de forma única. Antes de dar baixa, checar se aquele ID de transação já foi processado. Se já foi, responder OK pro gateway sem repetir a ação.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que fazer quando o webhook não chega
&lt;/h2&gt;

&lt;p&gt;Servidor fora do ar no segundo exato em que o webhook chegou, fila travada, deploy no meio da hora errada: existe sempre uma chance real do evento se perder. Se a única fonte de verdade for o webhook, uma cobrança pode ficar marcada como pendente pra sempre mesmo tendo sido paga de verdade.&lt;/p&gt;

&lt;p&gt;O fallback que uso é reconciliação periódica: um job que roda algumas vezes por dia e consulta a API do gateway perguntando o status real de toda cobrança ainda marcada como pendente há mais de X horas. O webhook resolve a velocidade, a reconciliação resolve a confiabilidade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nunca guarde dado de cartão, use o token do provedor
&lt;/h2&gt;

&lt;p&gt;Isso não é sobre boa prática abstrata, é sobre responsabilidade legal. Guardar número de cartão, CVV ou qualquer dado sensível de pagamento no seu próprio banco te coloca dentro do escopo de PCI-DSS, que é caro e complexo de cumprir corretamente.&lt;/p&gt;

&lt;p&gt;Todo gateway sério oferece tokenização: você recebe um token que representa aquele cartão, sem nunca tocar no dado real. Guarde o token, não o cartão. Se um dia o seu banco de dados vazar, o token sozinho não serve pra nada fora do seu gateway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Régua de cobrança automática sem virar spam
&lt;/h2&gt;

&lt;p&gt;Automatizar a cobrança de inadimplência é onde mais vejo automação boa virar automação que afasta cliente. Enviar lembrete todo dia, em todos os canais ao mesmo tempo, sem limite, transforma uma régua de cobrança em assédio.&lt;/p&gt;

&lt;p&gt;O que funciona: espaçamento crescente entre tentativas (não o mesmo intervalo toda vez), limite máximo de tentativas antes de escalar pra um humano decidir o próximo passo, e canal condizente com o valor e o tempo de atraso (mensagem simples pros primeiros dias, contato mais direto quando o atraso é longo). A régua automática deve saber quando parar de insistir sozinha.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ferramentas que eu recomendo de verdade
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Asaas&lt;/strong&gt;: gateway brasileiro com PIX, boleto e cartão, webhook nativo pra cada mudança de status, e ambiente de sandbox real pra testar antes de ir pra produção. Prefiro ele quando o cliente já opera com CPF/CNPJ brasileiro e precisa de PIX como opção principal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;n8n&lt;/strong&gt;: pra orquestrar a régua de cobrança em si (quando mandar o próximo lembrete, por qual canal, quando escalar pra humano) sem deixar essa lógica espalhada em código dentro do backend principal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Supabase&lt;/strong&gt;: como registro histórico de cada tentativa de cobrança e cada webhook recebido, mesmo os que não geraram ação. Esse histórico é o que permite reconstruir "o que aconteceu" quando um cliente questiona uma cobrança.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cuidados que custam caro se ignorados
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nunca processe webhook sem validar assinatura.&lt;/strong&gt; Um POST forjado marcando uma cobrança como paga sem ter sido pode liberar produto ou serviço de graça.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nunca logue dado de pagamento em texto puro&lt;/strong&gt;, nem token, nem os últimos dígitos completos do cartão, em nenhum log de debug.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotência por ID de transação, nunca por valor e data.&lt;/strong&gt; Já expliquei o porquê acima, mas vale repetir: é o erro mais fácil de cometer e mais caro de descobrir tarde.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reconciliação periódica não é opcional&lt;/strong&gt; se o webhook é a única fonte de verdade da automação.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Automação de cobrança bem feita é invisível: o cliente paga, o sistema sabe, ninguém precisa conferir extrato na mão. Ela aparece exatamente quando um desses cuidados foi ignorado, e nesse caso aparece do jeito mais caro possível.&lt;/p&gt;




&lt;p&gt;Nayara Martins, desenvolvedora de sistemas sob medida em Assis, SP. Mais em prospectia.space.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>backend</category>
      <category>production</category>
    </item>
    <item>
      <title>Automação entre sistemas: o que decidir antes de conectar A com B</title>
      <dc:creator>Nayara Martins</dc:creator>
      <pubDate>Fri, 04 Sep 2026 02:39:31 +0000</pubDate>
      <link>https://dev.to/nayaramartins/automacao-entre-sistemas-o-que-decidir-antes-de-conectar-a-com-b-hak</link>
      <guid>https://dev.to/nayaramartins/automacao-entre-sistemas-o-que-decidir-antes-de-conectar-a-com-b-hak</guid>
      <description>&lt;p&gt;Automação entre sistemas não é, na prática, "conectar A com B". É decidir onde mora a verdade quando os dois lados podem estar certos ao mesmo tempo: o CRM diz que o negócio fechou, o banco de dados ainda não sabe disso, e alguma automação no meio precisa garantir que os dois concordem sem duplicar nem perder informação.&lt;/p&gt;

&lt;p&gt;Depois de anos ligando sistemas diferentes (CRM, banco próprio, WhatsApp, planilha, e-mail) numa stack real, essas são as decisões que importam antes de sair conectando webhook em tudo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Webhook, polling ou fila
&lt;/h2&gt;

&lt;p&gt;A primeira decisão, e a mais ignorada, é como um sistema avisa o outro que algo mudou.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Webhook&lt;/strong&gt; é a opção certa quando o sistema de origem oferece o recurso e você precisa de reação quase instantânea (um pagamento aprovado, uma mensagem de WhatsApp recebida). O problema: se o seu servidor estiver fora do ar no exato segundo em que o webhook chega, o evento pode se perder pra sempre, a menos que o sistema de origem faça retry sozinho (nem todos fazem).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Polling&lt;/strong&gt; (perguntar de tempos em tempos "mudou alguma coisa?") é mais lento, mas mais resiliente: se a automação cair por uma hora, ela pega tudo que passou assim que voltar. Faz sentido quando o sistema de origem não tem webhook, ou quando o atraso de alguns minutos não importa.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fila&lt;/strong&gt; (Redis, RabbitMQ, ou até uma tabela de banco fazendo esse papel) entra quando o volume é alto ou quando o processamento de cada evento pode demorar. Em vez do webhook processar tudo na hora e travar se algo demorar, ele só empilha o evento e devolve resposta rápida pra quem chamou. Um worker separado consome a fila no próprio ritmo.&lt;/p&gt;

&lt;p&gt;Não existe escolha certa universal: existe a pergunta "o que acontece se esse evento se perder ou chegar atrasado", e a resposta define qual dos três você precisa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Idempotência: a automação não pode ter memória curta
&lt;/h2&gt;

&lt;p&gt;Esse é o ponto onde a maioria das automações que eu já vi quebrar, quebrou. Se um webhook é reenviado (e gateways de pagamento, WhatsApp e a maioria dos CRMs reenviam sim, isso é esperado, não bug), a sua automação processa esse mesmo evento duas vezes. Se a ação for "criar um registro", agora tem um duplicado. Se for "cobrar um cliente", pior ainda.&lt;/p&gt;

&lt;p&gt;A solução é sempre a mesma: toda automação que executa uma ação (não que só lê) precisa de uma chave de idempotência: um identificador único do evento (o próprio ID do webhook, ou um hash do conteúdo) que você guarda antes de agir e checa antes de agir de novo. Se a chave já existe, você responde "ok" sem repetir a ação.&lt;/p&gt;

&lt;p&gt;Isso vale tanto pra criar quanto pra atualizar. "Se não existe, cria" parece inofensivo, mas duas execuções simultâneas do mesmo evento podem checar "não existe" ao mesmo tempo e criar dois registros antes que qualquer uma das duas termine de escrever. A checagem e a escrita precisam estar dentro da mesma transação, ou usar uma constraint única no banco que rejeita o duplicado na marra.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retry e backoff: o outro sistema vai cair, e está tudo bem
&lt;/h2&gt;

&lt;p&gt;Todo sistema externo cai em algum momento: API de pagamento, CRM, servidor de e-mail. A pergunta não é "como evitar isso", é "o que a minha automação faz quando isso acontece".&lt;/p&gt;

&lt;p&gt;Retry sem controle é tão perigoso quanto não ter retry: se a chamada falha e você tenta de novo imediatamente, em loop, você pode derrubar ainda mais o sistema que já estava com problema, ou consumir toda a sua cota de requisições em segundos. O padrão que funciona é backoff exponencial: tenta de novo em 1 segundo, se falhar de novo espera 2, depois 4, depois 8, com um limite de tentativas antes de desistir e alertar alguém.&lt;/p&gt;

&lt;p&gt;E "alertar alguém" é a parte que mais fica de fora. Uma automação que falha silenciosamente e nunca mais tenta é pior que uma que nunca existiu, porque todo mundo assume que ela está funcionando.&lt;/p&gt;

&lt;h2&gt;
  
  
  Autenticação entre sistemas: a decisão que ninguém revisita depois
&lt;/h2&gt;

&lt;p&gt;API key fixa é simples de implementar, e é exatamente por isso que ela vaza: aparece em log, em variável de ambiente commitada por engano, em print de tela. OAuth com token de curta duração e refresh automático dá mais trabalho de configurar, mas limita o estrago se vazar, porque o token expira sozinho.&lt;/p&gt;

&lt;p&gt;A regra prática que eu sigo: se a integração é entre dois sistemas que eu controlo os dois lados, API key com rotação manual periódica já resolve. Se um dos lados é de terceiro (gateway de pagamento, provedor de e-mail, WhatsApp), prefiro sempre o que o provedor oferecer de mais seguro, mesmo que dê mais trabalho, porque o vazamento ali afeta cliente de verdade, não só o meu ambiente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observabilidade: saber que a automação parou antes do cliente perceber
&lt;/h2&gt;

&lt;p&gt;A automação mais perigosa não é a que quebra fazendo barulho, é a que quebra em silêncio. Ela para de rodar numa terça-feira qualquer e ninguém percebe até um cliente reclamar que não recebeu um e-mail, ou que um pagamento não foi processado.&lt;/p&gt;

&lt;p&gt;O mínimo que eu considero aceitável em produção: log de toda execução (sucesso e falha, não só falha), e um alerta ativo (e-mail, Telegram, o que for) quando uma automação crítica falha ou fica um tempo sem rodar. Não adianta o log existir se ninguém olha ele até o problema já ter afetado alguém.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ferramentas que eu recomendo de verdade
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;n8n self-hosted&lt;/strong&gt;: pra orquestrar fluxos entre sistemas diferentes sem escrever cola de código pra cada integração nova. A vantagem de rodar self-hosted, em vez do plano cloud, é dado sensível não sair do seu próprio servidor, e não ter limite de execução por plano. O custo é você virar responsável pela manutenção do servidor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Supabase (Realtime + Edge Functions)&lt;/strong&gt;: quando o sistema de origem e destino já são o seu próprio banco, o Realtime evita polling: qualquer mudança numa tabela dispara evento na hora. Edge Functions são úteis quando a lógica de automação é pequena e não vale a pena subir um serviço separado só pra ela.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redis como fila&lt;/strong&gt;: quando o volume justifica, uma fila simples em Redis (com uma lib como BullMQ) resolve o problema de "o webhook precisa responder rápido mas o processamento demora" sem precisar de infraestrutura de mensageria pesada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cuidados que custam caro se ignorados
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nunca chame uma API só pra checar se algo existe antes de decidir o que fazer&lt;/strong&gt;, se isso puder ser evitado com um retorno de erro tratado. Uma chamada de verificação a mais, multiplicada por milhares de execuções, pode sobrecarregar um serviço que não foi dimensionado pra esse tráfego extra.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Segredo de API nunca vai em log&lt;/strong&gt;, nem em modo debug. Sanitizar o payload antes de logar é trabalho extra que compensa na primeira vez que alguém precisa investigar um incidente sem expor credencial no processo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeout precisa de valor explícito.&lt;/strong&gt; Uma chamada sem timeout definido pode travar a automação inteira esperando resposta de um sistema que nunca vai responder.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Automação entre sistemas bem feita não aparece: ninguém elogia a automação que nunca falhou. Aparece exatamente quando um desses cuidados foi ignorado.&lt;/p&gt;




&lt;p&gt;Nayara Martins, desenvolvedora de sistemas sob medida em Assis, SP. Mais em prospectia.space.&lt;/p&gt;

</description>
      <category>api</category>
      <category>architecture</category>
      <category>automation</category>
      <category>backend</category>
    </item>
    <item>
      <title>A versão de API que vence sem avisar</title>
      <dc:creator>Nayara Martins</dc:creator>
      <pubDate>Sun, 30 Aug 2026 06:31:10 +0000</pubDate>
      <link>https://dev.to/nayaramartins/a-versao-de-api-que-vence-sem-avisar-4ao</link>
      <guid>https://dev.to/nayaramartins/a-versao-de-api-que-vence-sem-avisar-4ao</guid>
      <description>&lt;p&gt;Um script meu que publicava conteúdo via API do LinkedIn parou de funcionar do nada. Nenhuma linha mudou. O erro voltou assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;426&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"NONEXISTENT_VERSION"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Requested version 20250601 is not active"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Não tinha bug de código nenhum. A versão da API que eu tinha fixado no script simplesmente saiu da janela de suporte.&lt;/p&gt;

&lt;h3&gt;
  
  
  Como uma API versionada por data quebra sozinha
&lt;/h3&gt;

&lt;p&gt;A API REST do LinkedIn exige um cabeçalho &lt;code&gt;LinkedIn-Version&lt;/code&gt; no formato ano-mês, tipo &lt;code&gt;202506&lt;/code&gt;. Isso não é um número de versão semântica que você escolhe uma vez e esquece. É uma janela de tempo. Passado um certo período, aquela versão sai de circulação e a API recusa a chamada, mesmo que o resto do payload esteja perfeito.&lt;/p&gt;

&lt;p&gt;O código nunca mudou entre o dia em que funcionava e o dia em que parou. O relógio do calendário é que mudou.&lt;/p&gt;

&lt;h3&gt;
  
  
  Por que isso engana quem debuga
&lt;/h3&gt;

&lt;p&gt;O reflexo natural ao ver um erro de API é revisar o código: campo errado, token expirado, permissão faltando. Nenhuma dessas hipóteses batia. O token era válido, os escopos estavam certos, o payload era idêntico ao de uma chamada que tinha funcionado antes.&lt;/p&gt;

&lt;p&gt;A mensagem de erro ajudou bastante aqui, porque nomeou exatamente o campo problemático (&lt;code&gt;Requested version 20250601&lt;/code&gt;) e o motivo (&lt;code&gt;is not active&lt;/code&gt;). Sem prestar atenção nela e ir direto pro código, essa causa levaria muito mais tempo pra aparecer.&lt;/p&gt;

&lt;h3&gt;
  
  
  A correção
&lt;/h3&gt;

&lt;p&gt;Trocar o valor fixo do cabeçalho pela versão atual, no mesmo formato ano-mês. Nada mais no código precisou mudar.&lt;/p&gt;

&lt;p&gt;O detalhe que fica de lição: esse valor não é constante de verdade, é uma data disfarçada de configuração. Documentei isso direto no comentário ao lado da constante, pra próxima vez que o mesmo erro aparecer a causa já estar escrita ali, em vez de descoberta de novo do zero.&lt;/p&gt;

&lt;h3&gt;
  
  
  A lição
&lt;/h3&gt;

&lt;p&gt;Nem todo bug tem código culpado. Uma integração que depende de versão de API, certificado, ou qualquer coisa com data de validade pode quebrar sem que uma única linha do seu sistema tenha mudado. Antes de caçar bug no próprio código, vale checar se alguma dependência externa simplesmente venceu.&lt;/p&gt;




&lt;p&gt;Nayara Martins, desenvolvedora de sistemas sob medida em Assis, SP. Mais em &lt;a href="https://prospectia.space" rel="noopener noreferrer"&gt;prospectia.space&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>api</category>
      <category>linkedin</category>
      <category>debugging</category>
    </item>
    <item>
      <title>O dicionário que corrige acento errado sozinho</title>
      <dc:creator>Nayara Martins</dc:creator>
      <pubDate>Sun, 30 Aug 2026 06:26:56 +0000</pubDate>
      <link>https://dev.to/nayaramartins/o-dicionario-que-corrige-acento-errado-sozinho-55n5</link>
      <guid>https://dev.to/nayaramartins/o-dicionario-que-corrige-acento-errado-sozinho-55n5</guid>
      <description>&lt;p&gt;Um script meu corrige acentuação automática em português usando um dicionário de mais de noventa mil palavras. Ele existe justamente para consertar texto gerado por IA, que às vezes esquece acento. Só que hoje descobri que o próprio dicionário estava trocando "pele" por "Pelé" e "teve" por "tevê".&lt;/p&gt;

&lt;p&gt;O corretor não tinha bug de lógica nenhum. O dado dentro dele é que estava errado.&lt;/p&gt;

&lt;h3&gt;
  
  
  Como um dicionário de correção vira fonte de erro
&lt;/h3&gt;

&lt;p&gt;O dicionário foi gerado a partir de uma lista ampla de palavras em português, mapeando a forma sem acento pra forma com acento correspondente. Para a maioria das palavras isso funciona bem: uma palavra comum sem acento tem sempre a mesma forma acentuada certa, sem exceção.&lt;/p&gt;

&lt;p&gt;O problema aparece em palavra que também é nome próprio. "Pele" sem acento é ambíguo: pode ser a palavra comum (pele, órgão do corpo) ou o apelido do jogador, que leva acento (Pelé). Na hora de montar o dicionário, alguma etapa do processo escolheu a forma acentuada como "a certa" para aquela entrada, sem checar que a forma comum, sem acento, é muito mais frequente no uso real.&lt;/p&gt;

&lt;p&gt;Mesma história com "teve" (passado do verbo ter) virando "tevê" (forma informal de televisão).&lt;/p&gt;

&lt;h3&gt;
  
  
  Por que isso é mais perigoso que parecer
&lt;/h3&gt;

&lt;p&gt;Um erro de dicionário desse tipo não quebra nada visivelmente. O texto sai fluente, gramaticalmente correto, sem nenhum sinal de que uma palavra foi trocada por engano. Quem lê rápido não percebe. Isso é o oposto de um erro de sintaxe, que pelo menos avisa que algo está errado.&lt;/p&gt;

&lt;p&gt;A única forma de achar foi ler o texto gerado com atenção, palavra por palavra, depois de já ter rodado o corretor automático. O corretor não se autodenuncia.&lt;/p&gt;

&lt;h3&gt;
  
  
  Onde traçar a linha entre corrigir e não mexer
&lt;/h3&gt;

&lt;p&gt;Nem toda ambiguidade é bug. Uma palavra genuinamente ambígua, tipo "e" (conjunção "e" vs verbo "é"), "esta" (demonstrativo vs verbo "está") ou "pais" (progenitores vs "país"), não tem solução de dicionário. Só quem lê a frase inteira sabe qual acento é o certo. Forçar uma escolha automática aí erra tanto quanto deixar sem acento.&lt;/p&gt;

&lt;p&gt;A correção certa, então, tem duas partes diferentes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bug de verdade&lt;/strong&gt; (palavra não ambígua mapeada errado, tipo pele/teve): remover a entrada errada do dicionário. Ela nunca devia ter sido adicionada daquele jeito.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ambiguidade real&lt;/strong&gt;: não tentar resolver automaticamente. Documentar a lista de palavras que exigem leitura humana antes de publicar qualquer texto gerado.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A lição
&lt;/h3&gt;

&lt;p&gt;Uma ferramenta que existe pra corrigir erro pode, ela mesma, ser a origem do erro. Isso não é motivo pra desconfiar de toda automação, é motivo pra sempre ter uma segunda checagem que não depende da mesma lógica da primeira. Se o corretor e a checagem final usam a mesma fonte de verdade, um erro nela passa despercebido duas vezes.&lt;/p&gt;




&lt;p&gt;Nayara Martins, desenvolvedora de sistemas sob medida em Assis, SP. Mais em &lt;a href="https://prospectia.space" rel="noopener noreferrer"&gt;prospectia.space&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>debugging</category>
      <category>automation</category>
    </item>
    <item>
      <title>O bug que corrige sozinho o arquivo, mas não o e-mail que ele gera</title>
      <dc:creator>Nayara Martins</dc:creator>
      <pubDate>Sun, 30 Aug 2026 06:17:59 +0000</pubDate>
      <link>https://dev.to/nayaramartins/o-bug-que-corrige-sozinho-o-arquivo-mas-nao-o-e-mail-que-ele-gera-33ph</link>
      <guid>https://dev.to/nayaramartins/o-bug-que-corrige-sozinho-o-arquivo-mas-nao-o-e-mail-que-ele-gera-33ph</guid>
      <description>&lt;p&gt;Um sistema meu estava mandando e-mail em português com acentuação errada. Não era acento faltando, era acento &lt;em&gt;trocado&lt;/em&gt;: "operação" virava "operaÃ§Ã£o" em alguns lugares e simplesmente sumia em outros. O arquivo CSV de onde os dados vinham parecia correto quando eu abria ele. O bug só aparecia na saída final.&lt;/p&gt;

&lt;p&gt;A causa não era o arquivo. Era a leitura dele.&lt;/p&gt;

&lt;h3&gt;
  
  
  O sintoma
&lt;/h3&gt;

&lt;p&gt;O script lia um CSV com &lt;code&gt;encoding="latin1"&lt;/code&gt; e escrevia de volta com &lt;code&gt;encoding="latin1"&lt;/code&gt;. Isso rodava há meses sem erro, sem exceção, sem log estranho. Só que o arquivo, na verdade, sempre foi UTF-8.&lt;/p&gt;

&lt;p&gt;Por que isso nunca quebrou? Porque &lt;strong&gt;UTF-8 lido como Latin-1 é um round-trip estável&lt;/strong&gt;. Cada caractere acentuado em UTF-8 ocupa dois bytes. Latin-1 é uma tabela de um byte só, mas cobre justamente a faixa 0x80-0xFF, então cada um daqueles dois bytes vira um caractere Latin-1 válido, só que errado (tipo "Ã" e "§" no lugar de "ç"). Escrever esses dois caracteres de volta como Latin-1 produz exatamente os mesmos dois bytes originais. O arquivo nunca corrompe. Ele só mente pra quem olha.&lt;/p&gt;

&lt;h3&gt;
  
  
  Onde o estrago aparece
&lt;/h3&gt;

&lt;p&gt;O estrago só ficou visível quando esse texto mal lido saiu para um lugar que realmente decodifica como UTF-8: um prompt de LLM, um log em UTF-8, um e-mail. Aí os dois bytes viram os dois caracteres errados de verdade, visíveis, feios.&lt;/p&gt;

&lt;p&gt;Ler &lt;code&gt;raw.decode('latin1')&lt;/code&gt; nunca lança exceção, mesmo com dado sujo. Isso é o motivo do bug ter sobrevivido tanto tempo: não existe erro pra investigar, só resultado sutilmente errado.&lt;/p&gt;

&lt;h3&gt;
  
  
  O diagnóstico que separou hipótese de fato
&lt;/h3&gt;

&lt;p&gt;Antes de mexer em qualquer script, decodifiquei o arquivo inteiro como UTF-8 puro, sem passar por nenhum código do sistema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dados.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;texto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# se isso não lançar erro, o arquivo já é UTF-8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Decodificou limpo, zero exceção, em um arquivo de mais de cem mil caracteres. Isso provou duas coisas de uma vez: o arquivo sempre foi UTF-8 correto, e o problema inteiro estava nos scripts que liam ele errado. Não havia dado real pra recuperar ou consertar, só a leitura errada pra corrigir.&lt;/p&gt;

&lt;h3&gt;
  
  
  A correção
&lt;/h3&gt;

&lt;p&gt;Trocar &lt;code&gt;encoding="latin1"&lt;/code&gt; por &lt;code&gt;encoding="utf-8"&lt;/code&gt; em cada ponto que abria aquele arquivo específico. Nada mais. Nenhuma linha de dado foi reescrita.&lt;/p&gt;

&lt;p&gt;O jeito de confirmar que a correção funcionou não foi só rodar sem erro. Foi gerar conteúdo de verdade a partir do fluxo completo, com vocabulário que nunca tinha passado por ali antes, e ler o resultado num lugar que expõe o problema visualmente, no caso, o corpo de um e-mail de teste.&lt;/p&gt;

&lt;h3&gt;
  
  
  A lição que fica
&lt;/h3&gt;

&lt;p&gt;Round-trip estável esconde bug. Se ler errado e escrever errado sempre voltam pro mesmo byte, o sistema parece saudável em todo teste que só olha o arquivo. O bug só aparece no consumidor final, e só se alguém realmente olhar o resultado, não só o código de saída do processo.&lt;/p&gt;

&lt;p&gt;Antes de assumir que um dado está corrompido, vale testar a hipótese mais simples primeiro: talvez o dado esteja certo, e a leitura é que está errada.&lt;/p&gt;




&lt;p&gt;Nayara Martins, desenvolvedora de sistemas sob medida em Assis, SP. Mais em &lt;a href="https://prospectia.space" rel="noopener noreferrer"&gt;prospectia.space&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>python</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
