<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Produção Archives - Leonardo Nascimento | Engenheiro de Software</title>
	<atom:link href="https://leonardonascimento.dev/categoria/producao/feed/" rel="self" type="application/rss+xml" />
	<link>https://leonardonascimento.dev/categoria/producao/</link>
	<description>Especializado em backend, APIs e sistemas escaláveis. Experiência em arquitetura de sistemas, integrações, mensageria, performance e aplicações de alta disponibilidade.</description>
	<lastBuildDate>Thu, 22 Jan 2026 16:49:59 +0000</lastBuildDate>
	<language>pt-BR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://leonardonascimento.dev/wp-content/uploads/2021/05/cropped-programming-32x32.png</url>
	<title>Produção Archives - Leonardo Nascimento | Engenheiro de Software</title>
	<link>https://leonardonascimento.dev/categoria/producao/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Como monitorar aplicação e servidor pelo WhatsApp (logs, erros e alertas)</title>
		<link>https://leonardonascimento.dev/blog/como-monitorar-aplicacao-e-servidor-pelo-whatsapp-logs-erros-e-alertas/</link>
					<comments>https://leonardonascimento.dev/blog/como-monitorar-aplicacao-e-servidor-pelo-whatsapp-logs-erros-e-alertas/#respond</comments>
		
		<dc:creator><![CDATA[Leonardo]]></dc:creator>
		<pubDate>Thu, 22 Jan 2026 15:19:35 +0000</pubDate>
				<category><![CDATA[Arquitetura]]></category>
		<category><![CDATA[Backend]]></category>
		<category><![CDATA[Produção]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Alertas]]></category>
		<category><![CDATA[logs]]></category>
		<category><![CDATA[monitoramento]]></category>
		<category><![CDATA[notifish]]></category>
		<category><![CDATA[produção]]></category>
		<category><![CDATA[WhatsApp]]></category>
		<guid isPermaLink="false">https://leonardonascimento.dev/?p=2290</guid>

					<description><![CDATA[<p>WhatsApp é um canal excelente para alerta porque ele tem uma característica que e-mail e dashboard não têm: chega onde você está. O problema é que a maioria das implementações vira bagunça rápido — alerta demais, duplicado, sem contexto, e em pouco tempo todo mundo ignora. A forma correta de fazer isso é tratar WhatsApp [&#8230;]</p>
<p>The post <a href="https://leonardonascimento.dev/blog/como-monitorar-aplicacao-e-servidor-pelo-whatsapp-logs-erros-e-alertas/">Como monitorar aplicação e servidor pelo WhatsApp (logs, erros e alertas)</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>WhatsApp é um canal excelente para alerta porque ele tem uma característica que e-mail e dashboard não têm: <strong>chega onde você está</strong>. O problema é que a maioria das implementações vira bagunça rápido — alerta demais, duplicado, sem contexto, e em pouco tempo todo mundo ignora.</p>



<p>A forma correta de fazer isso é tratar WhatsApp como <strong><a href="https://leonardonascimento.dev/blog/updown-io-receba-notificacao-no-whatsapp-caso-seu-site-fique-indisponivel/" type="post" id="164">camada de notificação</a></strong>, não como sistema de monitoramento. Você continua monitorando com ferramentas e sinais confiáveis (uptime, métricas, logs, filas, erros), mas centraliza o envio e a governança dos alertas em um lugar só — e aí o <a href="http://notifish.com/" type="link" id="http://notifish.com/" target="_blank" rel="noreferrer noopener nofollow">Notifish </a>entra bem.</p>



<p>A ideia é simples: <strong>qualquer evento relevante → vira um “evento de notificação” → Notifish entrega no WhatsApp</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-o-que-vale-a-pena-mandar-para-o-whatsapp-e-o-que-nao-vale">O que vale a pena mandar para o WhatsApp (e o que não vale)</h2>



<p>WhatsApp deve receber só o que exige ação ou atenção rápida. Em produção, eu separo em três níveis:</p>



<p><strong>Crítico (manda sempre):</strong></p>



<ul class="wp-block-list">
<li>aplicação fora do ar / endpoint crítico fora</li>



<li>erro 5xx em alta (explosão de taxa de erro)</li>



<li>fila parou de consumir / backlog crescendo rápido</li>



<li>disco quase cheio / risco de indisponibilidade</li>



<li>falha em integração crítica (pagamento, mensagens, etc.)</li>
</ul>



<p><strong>Alerta (manda com filtro):</strong></p>



<ul class="wp-block-list">
<li>latência acima do normal por X minutos</li>



<li>aumento gradual de erros específicos</li>



<li>Redis indisponível (com fallback) ou lento</li>



<li>uso de CPU/memória alto por período sustentado</li>
</ul>



<p><strong>Informativo (geralmente não manda no WhatsApp):</strong></p>



<ul class="wp-block-list">
<li>deploy realizado</li>



<li>logs de rotina</li>



<li>warnings esporádicos</li>
</ul>



<p>O que destrói o canal é “alerta informativo demais”. WhatsApp é para <strong>sinal forte</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-arquitetura-recomendada-sem-gambiarra">Arquitetura recomendada (sem gambiarra)</h2>



<p>O melhor padrão é este:</p>



<ol class="wp-block-list">
<li>Você tem fontes de evento (monitoramento/observabilidade):</li>
</ol>



<ul class="wp-block-list">
<li>Uptime/health-check (aplicação)</li>



<li>Métricas do servidor (CPU, RAM, disco)</li>



<li>Logs (erros específicos, padrões)</li>



<li>Erros de aplicação (exceptions)</li>



<li>Filas (backlog, falhas, retries)</li>
</ul>



<ol start="2" class="wp-block-list">
<li>Um “gerador de eventos” cria um evento padronizado.</li>



<li>Você envia esse evento para o <a href="https://developers.notifish.com/" type="link" id="https://developers.notifish.com/" target="_blank" rel="noreferrer noopener nofollow"><strong>Notifish via API</strong>.</a></li>



<li>Você define roteamento, deduplicação e templates</li>
</ol>



<ul class="wp-block-list">
<li>para qual número/grupo enviar</li>



<li>se deve agrupar, deduplicar, aplicar rate limit</li>



<li>qual template usar (curto, completo, escalonamento)</li>
</ul>



<p>Esse desenho escala porque você não espalha envio de WhatsApp por todo sistema. Você centraliza.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-como-fica-uma-mensagem-boa-no-whatsapp">Como fica uma mensagem boa no WhatsApp</h2>



<p>Uma mensagem útil precisa ter contexto mínimo e ação sugerida:</p>



<ul class="wp-block-list">
<li><strong>Título curto</strong> (o que aconteceu)</li>



<li><strong>Ambiente</strong> (prod, staging)</li>



<li><strong>Serviço</strong> (api, worker, site)</li>



<li><strong>Sintoma</strong> (erro, timeout, backlog)</li>



<li><strong>Impacto</strong> (estimado)</li>



<li><strong>Link</strong> (dashboard/logs, se existir)</li>



<li><strong>Ação recomendada</strong> (1 linha)</li>
</ul>



<p>Exemplo de payload humano:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>ALERTA CRÍTICO</strong>: API 5xx alto<br>Ambiente: prod | Serviço: api<br>Erros 5xx: 18% (últimos 5 min)<br>Endpoint: /api/orders<br>Ação: verificar logs + dependência “Payments”</p>
</blockquote>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-implementacao-via-api-com-notifish-modelo-pratico">Implementação via API com Notifish (modelo prático)</h2>



<p>Você pode integrar de dois jeitos:</p>



<h3 class="wp-block-heading" id="h-1-seu-sistema-envia-eventos-diretamente-laravel-cron-scripts">1) Seu sistema envia eventos diretamente (Laravel, cron, scripts)</h3>



<p>Bom quando você mesmo detecta (fila, logs, métricas internas).</p>



<h3 class="wp-block-heading" id="h-2-ferramentas-externas-chamam-o-notifish-uptime-monitoramento">2) Ferramentas externas chamam o Notifish (uptime/monitoramento)</h3>



<p>Bom para health-check e métricas do servidor (quando a ferramenta já faz o “detector”).</p>



<p>Como você pediu implementação via API, vou te mostrar um modelo que funciona bem</p>



<h3 class="wp-block-heading" id="h-payload-recomendado-evento">Payload recomendado (evento)</h3>



<p></p>



<pre class="wp-block-preformatted">{<br>  "message": "Sua mensagem de alerta",<br>  "identifier": "seu identificador único de disparo",<br>  "link": true,<br>  "typing": "composing",<br>  "delayMessage": 1200<br>}<br></pre>



<p><strong>Por que esse formato funciona:</strong></p>



<ul class="wp-block-list">
<li><strong>identifier</strong>: chave de deduplicação / idempotência do alerta</li>



<li><strong>message</strong>: texto já formatado com contexto (ambiente/serviço/ação)</li>



<li><strong>delayMessage/typing</strong>: ajustes de entrega (opcionais)</li>
</ul>



<h2 class="wp-block-heading">Exemplo em Laravel enviando evento ao Notifish</h2>



<pre class="wp-block-preformatted">class NotifishClient
{
    public function sendToGroups(string $message, string $identifier, bool $link = true, int $delayMs = 0, string $typing = 'composing'): void
    {
        $url = rtrim(config('services.notifish.base_url'), '/')
            . '/api/v2/' . config('services.notifish.instance')
            . '/whatsapp/message/groups';

        $payload = [
            'message' => $message,
            'identifier' => $identifier,
            'link' => $link,
            'typing' => $typing,
            'delayMessage' => $delayMs,
        ];

        $response = Http::withToken(config('services.notifish.token'))
            ->acceptJson()
            ->contentType('application/json')
            ->timeout(8)
            ->post($url, $payload);

        if (!$response->successful()) {
            logger()->error('Notifish send failed', [
                'status' => $response->status(),
                'body' => $response->body(),
                'identifier' => $identifier,
            ]);
        }
    }
}

</pre>



<h2 class="wp-block-heading">Regras importantes para não virar caos</h2>



<p>Se você fizer só “manda mensagem”, em 2 semanas o canal morre. Algumas regras que eu considero obrigatórias:</p>



<p><strong>1) Deduplicação</strong></p>



<ul class="wp-block-list">
<li>Todo alerta precisa de <code>dedupe_key</code>.</li>



<li>Se o mesmo alerta acontecer 100 vezes, você manda 1 e “atualiza”/agrupa.</li>
</ul>



<p><strong>2) Rate limit por severidade</strong></p>



<ul class="wp-block-list">
<li>Crítico: pode repetir, mas com intervalo mínimo (ex.: 5–10 min).</li>



<li>Alerta: intervalo maior (ex.: 15–30 min).</li>



<li>Informativo: geralmente fora do WhatsApp.</li>
</ul>



<p><strong>3) Idempotência</strong></p>



<ul class="wp-block-list">
<li>Eventos iguais devem produzir o mesmo estado.</li>



<li>Se a chamada repetir, não deve disparar em duplicidade.</li>
</ul>



<p><strong>4) Conteúdo curto</strong><br>WhatsApp é leitura rápida. Se precisar detalhe, coloque em <code>meta</code> e mande link para logs/dashboard quando possível.</p>



<p><strong>5) Escalonamento</strong><br>Se continuar crítico por X tempo, notifica outro grupo/gestor.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">O que monitorar para disparar eventos úteis (fontes típicas)</h2>



<p>Você pode começar com estes gatilhos (são os que mais dão retorno):</p>



<ul class="wp-block-list">
<li><strong>Health-check HTTP</strong> (200/500, tempo de resposta, quedas)</li>



<li><strong>Taxa de erro</strong> (5xx e exceções por minuto)</li>



<li><strong>Fila</strong> (backlog, jobs failed, tempo médio)</li>



<li><strong>Banco</strong> (conexões, queries lentas, timeouts)</li>



<li><strong>Redis</strong> (latência, indisponibilidade, memória/eviction)</li>



<li><strong>Servidor</strong> (disco, load alto sustentado)</li>



<li><strong>Integrações externas</strong> (timeout e falha por janela)</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Monitorar “pelo WhatsApp” não é substituir observabilidade por chat. É transformar sinais importantes em alertas acionáveis, com governança. O Notifish entra como a peça que centraliza o envio e impede que cada sistema invente seu próprio jeito de notificar.</p>



<p>Se você faz dedupe, rate limit, severidade e contexto mínimo, o WhatsApp vira um canal confiável — e não um spam de produção.</p>
<p>The post <a href="https://leonardonascimento.dev/blog/como-monitorar-aplicacao-e-servidor-pelo-whatsapp-logs-erros-e-alertas/">Como monitorar aplicação e servidor pelo WhatsApp (logs, erros e alertas)</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://leonardonascimento.dev/blog/como-monitorar-aplicacao-e-servidor-pelo-whatsapp-logs-erros-e-alertas/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>O que é Lighthouse e como usar para melhorar seu site</title>
		<link>https://leonardonascimento.dev/blog/o-que-e-lighthouse-e-como-usar-para-melhorar-seu-site/</link>
					<comments>https://leonardonascimento.dev/blog/o-que-e-lighthouse-e-como-usar-para-melhorar-seu-site/#respond</comments>
		
		<dc:creator><![CDATA[Leonardo]]></dc:creator>
		<pubDate>Wed, 21 Jan 2026 23:20:00 +0000</pubDate>
				<category><![CDATA[API]]></category>
		<category><![CDATA[Arquitetura]]></category>
		<category><![CDATA[Backend]]></category>
		<category><![CDATA[Frontend]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Produção]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Seo & Marketing]]></category>
		<category><![CDATA[core web vitals]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[lighthouse]]></category>
		<category><![CDATA[otimização de sites]]></category>
		<category><![CDATA[performance web]]></category>
		<category><![CDATA[seo técnico]]></category>
		<guid isPermaLink="false">https://leonardonascimento.dev/?p=2318</guid>

					<description><![CDATA[<p>Performance, acessibilidade e boas práticas deixaram de ser “detalhes técnicos” e passaram a impactar diretamente tráfego, conversão e experiência do usuário. Para ajudar a medir esses pontos de forma objetiva, o Google criou o Google Lighthouse. Mais do que uma nota colorida, o Lighthouse é uma ferramenta de diagnóstico. Saber usá-lo corretamente evita decisões erradas [&#8230;]</p>
<p>The post <a href="https://leonardonascimento.dev/blog/o-que-e-lighthouse-e-como-usar-para-melhorar-seu-site/">O que é Lighthouse e como usar para melhorar seu site</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Performance, acessibilidade e boas práticas deixaram de ser “detalhes técnicos” e passaram a impactar diretamente tráfego, conversão e experiência do usuário. Para ajudar a medir esses pontos de forma objetiva, o Google criou o <strong>Google Lighthouse</strong>.</p>



<p>Mais do que uma nota colorida, o Lighthouse é uma ferramenta de diagnóstico. Saber usá-lo corretamente evita decisões erradas e otimizações inúteis.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-o-que-e-o-lighthouse">O que é o Lighthouse</h2>



<p>O Lighthouse é uma ferramenta automatizada de auditoria de páginas web. Ele analisa uma URL e gera um relatório com métricas e recomendações em cinco áreas principais:</p>



<ul class="wp-block-list">
<li><strong>Performance</strong></li>



<li><strong>Acessibilidade</strong></li>



<li><strong>Boas práticas</strong></li>



<li><strong>SEO</strong></li>



<li><strong>Progressive Web App (PWA)</strong></li>
</ul>



<p>O objetivo não é apenas pontuar o site, mas mostrar <strong>onde estão os gargalos reais</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-onde-o-lighthouse-esta-disponivel">Onde o Lighthouse está disponível</h2>



<p>Você pode usar o Lighthouse de várias formas:</p>



<ul class="wp-block-list">
<li><strong>Chrome DevTools</strong> (nativo do navegador)</li>



<li><strong>Linha de comando (CLI)</strong></li>



<li><strong>CI/CD</strong> (auditorias automatizadas)</li>



<li><strong>Ferramentas online baseadas no Lighthouse</strong></li>
</ul>



<p>Para a maioria dos casos, o DevTools já resolve bem.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-como-rodar-o-lighthouse-pelo-chrome">Como rodar o Lighthouse pelo Chrome</h2>



<ol class="wp-block-list">
<li>Abra o site no Chrome</li>



<li>Pressione <code>F12</code> ou <code>Ctrl + Shift + I</code></li>



<li>Vá até a aba <strong>Lighthouse</strong></li>



<li>Escolha o tipo de dispositivo (Mobile ou Desktop)</li>



<li>Clique em <strong>Generate report</strong></li>
</ol>



<p>Em poucos segundos, o relatório é gerado.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-as-metricas-mais-importantes-e-o-que-elas-significam">As métricas mais importantes (e o que elas significam)</h2>



<h3 class="wp-block-heading" id="h-performance">Performance</h3>



<p>Avalia tempo de carregamento e resposta da página. Algumas métricas-chave:</p>



<ul class="wp-block-list">
<li><strong>LCP (Largest Contentful Paint)</strong><br>Mede quando o maior elemento visível aparece. Impacta diretamente a percepção de velocidade.</li>



<li><strong>INP (Interaction to Next Paint)</strong><br>Avalia a resposta do site às interações do usuário.</li>



<li><strong>CLS (Cumulative Layout Shift)</strong><br>Mede instabilidade visual (elementos “pulando” na tela).</li>
</ul>



<p>Essas métricas fazem parte do <strong>Core Web Vitals</strong>, usados pelo Google como sinal de experiência.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading" id="h-acessibilidade">Acessibilidade</h3>



<p>Verifica se o site pode ser usado por pessoas com limitações visuais, motoras ou cognitivas. Exemplos de checagem:</p>



<ul class="wp-block-list">
<li>contraste de cores</li>



<li>textos alternativos em imagens</li>



<li>labels em formulários</li>



<li>estrutura semântica do HTML</li>
</ul>



<p>Mesmo que não seja um requisito legal em todos os casos, acessibilidade melhora usabilidade para todos.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading" id="h-boas-praticas">Boas práticas</h3>



<p>Aqui entram problemas mais técnicos, como:</p>



<ul class="wp-block-list">
<li>uso de APIs inseguras</li>



<li>imagens com proporções erradas</li>



<li>erros de console</li>



<li>bibliotecas desatualizadas</li>
</ul>



<p>É uma área que ajuda a manter o site saudável ao longo do tempo.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading" id="h-seo">SEO</h3>



<p>O Lighthouse não substitui ferramentas avançadas de SEO, mas valida o básico:</p>



<ul class="wp-block-list">
<li>meta tags essenciais</li>



<li>indexabilidade</li>



<li>uso correto de links</li>



<li>estrutura mínima de conteúdo</li>
</ul>



<p>Se o site falha aqui, dificilmente terá bom desempenho orgânico.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-o-erro-mais-comum-otimizar-so-para-a-nota">O erro mais comum: otimizar só para a nota</h2>



<p>Muita gente usa o Lighthouse como competição de pontuação. Isso é um erro.</p>



<p>Um site pode ter nota 100 e ainda assim:</p>



<ul class="wp-block-list">
<li>carregar dados desnecessários</li>



<li>ter arquitetura ruim</li>



<li>sofrer em cenários reais de tráfego</li>
</ul>



<p>O relatório deve ser lido como <strong>ferramenta de diagnóstico</strong>, não como objetivo final.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-mobile-vs-desktop-sempre-priorize-mobile">Mobile vs Desktop: sempre priorize mobile</h2>



<p>O Google avalia sites com <strong>mobile-first indexing</strong>. Isso significa que:</p>



<ul class="wp-block-list">
<li>o relatório mobile é mais relevante</li>



<li>problemas no mobile impactam mais SEO</li>



<li>otimizações devem começar pelo mobile</li>
</ul>



<p>Um site rápido no desktop e lento no celular está em desvantagem.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-lighthouse-em-producao-e-ci-cd">Lighthouse em produção e CI/CD</h2>



<p>Em projetos mais maduros, o Lighthouse pode rodar automaticamente:</p>



<ul class="wp-block-list">
<li>antes de deploy</li>



<li>após mudanças críticas</li>



<li>em pipelines de CI/CD</li>
</ul>



<p>Isso ajuda a evitar regressões de performance e garante que melhorias não sejam perdidas com o tempo.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-limitacoes-do-lighthouse">Limitações do Lighthouse</h2>



<p>Apesar de poderoso, o Lighthouse tem limites:</p>



<ul class="wp-block-list">
<li>roda em ambiente controlado</li>



<li>não reflete todos os cenários reais</li>



<li>não substitui métricas de usuários reais (RUM)</li>
</ul>



<p>O ideal é combiná-lo com dados reais de uso, como relatórios de experiência de campo.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-quando-o-lighthouse-faz-mais-diferenca">Quando o Lighthouse faz mais diferença</h2>



<p>Ele é especialmente útil para:</p>



<ul class="wp-block-list">
<li>identificar gargalos iniciais de performance</li>



<li>validar mudanças estruturais</li>



<li>educar times sobre impacto técnico</li>



<li>criar baseline de qualidade</li>
</ul>



<p>Não é uma bala de prata, mas é um excelente ponto de partida.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>O Lighthouse não serve para “tirar nota alta”, mas para <strong>entender como o site se comporta</strong> do ponto de vista do usuário. Quando usado com critério, ele direciona otimizações que realmente fazem diferença.</p>



<p>Ignorá-lo pode custar performance, experiência e visibilidade. Usá-lo mal pode custar tempo. O valor está em interpretar os dados, não apenas executá-los.</p>
<p>The post <a href="https://leonardonascimento.dev/blog/o-que-e-lighthouse-e-como-usar-para-melhorar-seu-site/">O que é Lighthouse e como usar para melhorar seu site</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://leonardonascimento.dev/blog/o-que-e-lighthouse-e-como-usar-para-melhorar-seu-site/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Deployment de Laravel no Cloud com CI/CD (GitHub Actions e GitLab CI)</title>
		<link>https://leonardonascimento.dev/blog/deployment-de-laravel-no-cloud-com-ci-cd-github-actions-e-gitlab-ci/</link>
					<comments>https://leonardonascimento.dev/blog/deployment-de-laravel-no-cloud-com-ci-cd-github-actions-e-gitlab-ci/#respond</comments>
		
		<dc:creator><![CDATA[Leonardo]]></dc:creator>
		<pubDate>Tue, 13 Jan 2026 15:26:32 +0000</pubDate>
				<category><![CDATA[Arquitetura]]></category>
		<category><![CDATA[Backend]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[Produção]]></category>
		<category><![CDATA[ci/cd]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[devops]]></category>
		<category><![CDATA[laravel]]></category>
		<category><![CDATA[produção]]></category>
		<guid isPermaLink="false">https://leonardonascimento.dev/?p=2295</guid>

					<description><![CDATA[<p>Deploy manual funciona até o dia em que deixa de funcionar. Enquanto o projeto é pequeno e o time é reduzido, subir código via SSH, rodar alguns comandos e torcer para dar certo parece aceitável. Em projetos reais, com mais gente mexendo, deploy frequente e produção rodando 24/7, isso vira risco operacional. CI/CD não é [&#8230;]</p>
<p>The post <a href="https://leonardonascimento.dev/blog/deployment-de-laravel-no-cloud-com-ci-cd-github-actions-e-gitlab-ci/">Deployment de Laravel no Cloud com CI/CD (GitHub Actions e GitLab CI)</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Deploy manual funciona até o dia em que deixa de funcionar. Enquanto o projeto é pequeno e o time é reduzido, subir código via SSH, rodar alguns comandos e torcer para dar certo parece aceitável. Em projetos reais, com mais gente mexendo, deploy frequente e produção rodando 24/7, isso vira risco operacional.</p>



<p>CI/CD não é sobre velocidade. É sobre <strong>previsibilidade, repetibilidade e segurança</strong> no processo de entrega.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-o-que-ci-cd-realmente-resolve-em-projetos-laravel">O que CI/CD realmente resolve em projetos Laravel</h2>



<p>Em aplicações Laravel, o pipeline de deploy resolve três problemas clássicos:</p>



<ol class="wp-block-list">
<li><strong>Ambiente inconsistente</strong><br>O código roda local, mas quebra em produção porque algo foi esquecido ou executado fora de ordem.</li>



<li><strong>Deploys inseguros</strong><br>Código sobe sem testes, sem validação, sem rollback fácil.</li>



<li><strong>Processo dependente de pessoas</strong><br>“Só fulano sabe fazer deploy”. Quando ele não está, ninguém sobe nada.</li>
</ol>



<p>CI/CD elimina esses pontos ao transformar deploy em <strong>processo automatizado</strong>, não em ritual manual.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-conceito-basico-do-pipeline-independente-da-ferramenta">Conceito básico do pipeline (independente da ferramenta)</h2>



<p>Antes de falar de GitHub Actions ou GitLab CI, é importante entender o fluxo lógico. Um pipeline de Laravel bem definido costuma ter estas etapas:</p>



<ol class="wp-block-list">
<li><strong>Checkout do código</strong></li>



<li><strong>Instalação de dependências</strong></li>



<li><strong>Execução de testes</strong></li>



<li><strong>Build (quando aplicável)</strong></li>



<li><strong>Deploy</strong></li>



<li><strong>Pós-deploy (migrations, cache, filas)</strong></li>
</ol>



<p>Se qualquer etapa falhar, o deploy <strong>não acontece</strong>. Isso é uma proteção, não um obstáculo.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading" id="h-estrutura-minima-de-um-deploy-laravel-saudavel">Estrutura mínima de um deploy Laravel saudável</h2>



<p>Independente de cloud ou CI, alguns princípios não mudam:</p>



<ul class="wp-block-list">
<li><code>composer install</code> sempre em modo produção</li>



<li><code>.env</code> nunca versionado</li>



<li><code>APP_ENV</code> e <code>APP_DEBUG</code> corretos</li>



<li>migrations rodando de forma controlada</li>



<li>cache/config/views limpos e recompilados</li>



<li>workers reiniciados corretamente</li>
</ul>



<p>Se isso não estiver automatizado, o risco é constante.</p>



<h2 class="wp-block-heading">Exemplo de pipeline com GitHub Actions</h2>



<p>Um pipeline simples, mas funcional, usando GitHub Actions:</p>



<pre class="wp-block-preformatted">name: Deploy Laravel<br><br>on:<br>  push:<br>    branches:<br>      - main<br><br>jobs:<br>  deploy:<br>    runs-on: ubuntu-latest<br><br>    steps:<br>      - name: Checkout<br>        uses: actions/checkout@v4<br><br>      - name: Setup PHP<br>        uses: shivammathur/setup-php@v2<br>        with:<br>          php-version: '8.2'<br>          extensions: mbstring, pdo, pdo_mysql<br><br>      - name: Install dependencies<br>        run: composer install --no-dev --optimize-autoloader<br><br>      - name: Run tests<br>        run: php artisan test<br><br>      - name: Deploy via SSH<br>        uses: appleboy/ssh-action@v1<br>        with:<br>          host: ${{ secrets.SERVER_HOST }}<br>          username: ${{ secrets.SERVER_USER }}<br>          key: ${{ secrets.SERVER_SSH_KEY }}<br>          script: |<br>            cd /var/www/app<br>            git pull origin main<br>            composer install --no-dev --optimize-autoloader<br>            php artisan migrate --force<br>            php artisan optimize<br>            php artisan queue:restart</pre>



<h2 class="wp-block-heading">Onde muita gente erra no deploy de Laravel</h2>



<h3 class="wp-block-heading">Rodar migration sem pensar em impacto</h3>



<p>Migration em produção pode travar tabela, gerar lentidão ou indisponibilidade. CI/CD não elimina isso. Ele apenas automatiza. Migration precisa ser escrita com consciência de produção.</p>



<h3 class="wp-block-heading">Cache mal tratado</h3>



<p>Não limpar/recriar cache de config e routes gera bugs difíceis de explicar. Cache antigo em produção é clássico.</p>



<h3 class="wp-block-heading">Workers esquecidos</h3>



<p>Deploy sobe código novo, mas workers continuam rodando código antigo. Resultado: comportamento inconsistente.</p>



<h3 class="wp-block-heading">Falta de rollback</h3>



<p>CI/CD sem rollback é metade da solução. Mesmo que seja manual, precisa existir um caminho claro para voltar.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Estratégia simples de rollback</h2>



<p>Mesmo sem blue/green ou canary, dá para ter rollback básico:</p>



<ul class="wp-block-list">
<li>manter tags ou releases</li>



<li>usar <code>git checkout</code> para versão anterior</li>



<li>rodar <code>php artisan migrate:rollback</code> quando aplicável</li>



<li>reiniciar workers</li>
</ul>



<p>O importante é <strong>ter plano</strong>. Não improvisar sob pressão.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">CI/CD não substitui observabilidade</h2>



<p>Deploy automatizado reduz erro humano, mas não impede bugs. Por isso, CI/CD precisa andar junto com:</p>



<ul class="wp-block-list">
<li>monitoramento de erros</li>



<li>alertas pós-deploy</li>



<li>logs estruturados</li>



<li>métricas de saúde</li>
</ul>



<p>Deploy sem visibilidade é só um erro mais rápido.</p>



<p>CI/CD em projetos Laravel não é luxo nem modinha. É uma camada básica de segurança operacional. Ele garante que o código passe sempre pelo mesmo caminho, reduz risco humano e cria previsibilidade no processo de entrega.</p>



<p>Quando o deploy deixa de ser um evento tenso e vira algo rotineiro, o time ganha confiança para evoluir o sistema. E isso, no fim, é o que permite crescer sem quebrar tudo a cada release.</p>
<p>The post <a href="https://leonardonascimento.dev/blog/deployment-de-laravel-no-cloud-com-ci-cd-github-actions-e-gitlab-ci/">Deployment de Laravel no Cloud com CI/CD (GitHub Actions e GitLab CI)</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://leonardonascimento.dev/blog/deployment-de-laravel-no-cloud-com-ci-cd-github-actions-e-gitlab-ci/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Na minha máquina funciona. Vamos levar sua máquina para o usuário então</title>
		<link>https://leonardonascimento.dev/blog/na-minha-maquina-funciona-vamos-levar-sua-maquina-para-o-usuario-entao/</link>
					<comments>https://leonardonascimento.dev/blog/na-minha-maquina-funciona-vamos-levar-sua-maquina-para-o-usuario-entao/#respond</comments>
		
		<dc:creator><![CDATA[Leonardo]]></dc:creator>
		<pubDate>Sat, 10 Jan 2026 21:35:00 +0000</pubDate>
				<category><![CDATA[Arquitetura]]></category>
		<category><![CDATA[Produção]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[ambiente de produção]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[boas práticas]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[produção]]></category>
		<guid isPermaLink="false">https://leonardonascimento.dev/?p=2277</guid>

					<description><![CDATA[<p>Todo desenvolvedor já disse ou ouviu essa frase: “Na minha máquina funciona”. Em ambiente local, com poucos dados, sem concorrência real e sem dependências instáveis, quase tudo funciona. O problema é que produção não tem nada a ver com o seu computador. Quando alguém usa “funciona local” como argumento técnico, geralmente está ignorando o contexto [&#8230;]</p>
<p>The post <a href="https://leonardonascimento.dev/blog/na-minha-maquina-funciona-vamos-levar-sua-maquina-para-o-usuario-entao/">Na minha máquina funciona. Vamos levar sua máquina para o usuário então</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Todo desenvolvedor já disse ou ouviu essa frase: <em>“Na minha máquina funciona”</em>. Em ambiente local, com poucos dados, sem concorrência real e sem dependências instáveis, quase tudo funciona. O problema é que <strong>produção não tem nada a ver com o seu computador</strong>.</p>



<p>Quando alguém usa “funciona local” como argumento técnico, geralmente está ignorando o contexto em que o sistema realmente vai operar. E é exatamente aí que os problemas começam.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Em local, você tem controle total. O banco está limpo, a latência é praticamente zero, não existem requisições concorrentes, não há retries, não há jobs acumulados, não há serviços externos oscilando. Você executa uma ação, olha o resultado e segue em frente. É um ambiente artificialmente perfeito.</p>



<p>Produção é o oposto disso.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>A primeira diferença aparece com <strong>concorrência</strong>. Localmente, você clica uma vez. Em produção, dezenas ou centenas de usuários fazem a mesma ação ao mesmo tempo. Jobs rodam em paralelo. Requests competem por recursos. Código que nunca apresentou problema começa a gerar condição de corrida, duplicidade de execução e dados inconsistentes. Nada disso aparece no teste local simples.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Outra diferença crítica é <strong>latência</strong>. Em local, chamadas HTTP e queries são praticamente instantâneas. Em produção, uma API externa pode demorar segundos para responder, ou responder de forma intermitente. Um banco pode ficar lento sob carga. Um cache pode expirar no pior momento. Código que assume resposta imediata funciona local, mas degrada ou trava em produção.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Existe também a questão do <strong>volume de dados</strong>. Local costuma ter poucos registros. Produção tem milhares ou milhões. Queries que pareciam inofensivas passam a consumir tempo e recursos. Loops simples viram gargalo. Processamentos que eram aceitáveis começam a estourar timeout. O problema não é o código “errado”, é o código <strong>não preparado para escala</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Dependências externas são outro ponto ignorado em ambiente local. Muitas vezes você testa com mock, sandbox ou serviço estável. Em produção, serviços externos falham, ficam lentos ou retornam dados inesperados. Se o sistema não foi desenhado para lidar com isso, o erro externo vira indisponibilidade interna.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Local também não expõe problemas de <strong>observabilidade</strong>. Em produção, quando algo dá errado, você precisa responder rápido: o que aconteceu, quando, com qual dado, em qual fluxo. Código que “funciona local” mas não gera logs úteis transforma qualquer incidente em uma investigação longa e cara.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Outro ponto comum é <strong>configuração e ambiente</strong>. Local costuma ter permissões amplas, cache limpo, variáveis simples. Produção tem múltiplos ambientes, secrets, variáveis diferentes, limites de recurso e regras de segurança. Código que assume configuração fixa funciona local e quebra fora dele.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Existe ainda o fator <strong>tempo</strong>. Local você testa agora. Produção roda por semanas ou meses. Vazamentos de memória, acúmulo de jobs, crescimento de filas e degradação progressiva só aparecem com o tempo. “Funciona local” raramente considera isso.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Nada disso significa que testar local não importa. Significa que <strong>teste local valida comportamento</strong>, não valida operação. Ele é necessário, mas está longe de ser suficiente.</p>



<p>Código pronto para produção é aquele que:</p>



<ul class="wp-block-list">
<li>lida bem com concorrência</li>



<li>assume latência e falha</li>



<li>escala com dados reais</li>



<li>é observável</li>



<li>se comporta de forma previsível sob estresse</li>
</ul>



<p>Sem isso, o “funciona local” vira apenas uma falsa sensação de segurança.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>“Funciona local” não é critério de qualidade. É apenas o primeiro degrau. Produção cobra decisões que local nunca vai cobrar: resiliência, previsibilidade e responsabilidade técnica.</p>



<p>Quando alguém entende isso, muda a forma de escrever código. Quando não entende, continua apagando incêndio e se perguntando por que algo que “funcionava perfeitamente” começou a falhar sem explicação.</p>
<p>The post <a href="https://leonardonascimento.dev/blog/na-minha-maquina-funciona-vamos-levar-sua-maquina-para-o-usuario-entao/">Na minha máquina funciona. Vamos levar sua máquina para o usuário então</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://leonardonascimento.dev/blog/na-minha-maquina-funciona-vamos-levar-sua-maquina-para-o-usuario-entao/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Como evitar duplicidade de processamento em jobs</title>
		<link>https://leonardonascimento.dev/blog/como-evitar-duplicidade-de-processamento-em-jobs/</link>
					<comments>https://leonardonascimento.dev/blog/como-evitar-duplicidade-de-processamento-em-jobs/#respond</comments>
		
		<dc:creator><![CDATA[Leonardo]]></dc:creator>
		<pubDate>Fri, 09 Jan 2026 16:28:42 +0000</pubDate>
				<category><![CDATA[Arquitetura]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[Produção]]></category>
		<guid isPermaLink="false">https://leonardonascimento.dev/?p=2274</guid>

					<description><![CDATA[<p>Duplicidade em job é uma das coisas mais comuns (e mais perigosas) em produção. E não adianta lutar contra isso achando que “não vai acontecer”. Vai. Worker cai, timeout estoura, conexão oscila, retry acontece, o mesmo evento chega duas vezes, o deploy reinicia processo no meio… e pronto: job roda de novo. O objetivo não [&#8230;]</p>
<p>The post <a href="https://leonardonascimento.dev/blog/como-evitar-duplicidade-de-processamento-em-jobs/">Como evitar duplicidade de processamento em jobs</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><a href="https://leonardonascimento.dev/blog/laravel-jobs-filas-e-processamento-assincrono-quando-usar-e-quando-evitar/" type="post" id="2271">Duplicidade em job </a>é uma das coisas mais comuns (e mais perigosas) em produção. E não adianta lutar contra isso achando que “não vai acontecer”. Vai. Worker cai, timeout estoura, conexão oscila, retry acontece, o mesmo evento chega duas vezes, o deploy reinicia processo no meio… e pronto: job roda de novo.</p>



<p>O objetivo não é “garantir que nunca execute duas vezes”. O objetivo é garantir que <strong>executar duas vezes não cause dano</strong>.</p>



<p>Abaixo estão as estratégias que realmente funcionam em projetos Laravel médios e grandes.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">1) Torne o job idempotente (regra número 1)</h2>



<p>Idempotência significa: <strong>rodar uma vez ou dez vezes dá o mesmo resultado final</strong>.</p>



<p>Isso é o que separa um job saudável de um job que vai te dar dor de cabeça.</p>



<p>Exemplos práticos:</p>



<ul class="wp-block-list">
<li>“enviar notificação”: marque como enviado e não envie novamente se já estiver enviado.</li>



<li>“gerar fatura”: use uma chave única e não crie duas faturas para o mesmo evento.</li>



<li>“sincronizar pedido”: atualize o registro existente em vez de criar um novo.</li>
</ul>



<p>Em termos práticos, idempotência quase sempre vira: <strong>checar estado antes de executar</strong> e <strong>persistir o estado depois</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">2) Use chave idempotente por evento (event_id / request_id)</h2>



<p>Toda vez que o seu sistema gera um job, ele deveria ter um identificador estável do evento.</p>



<p>Exemplo:</p>



<ul class="wp-block-list">
<li><code>event_id</code> do webhook recebido</li>



<li><code>message_id</code> da sua tabela</li>



<li><code>order_id</code> + <code>status</code> (depende do caso)</li>



<li>um UUID de “processamento” gerado quando o evento nasceu</li>
</ul>



<p>Aí você registra algo como:</p>



<ul class="wp-block-list">
<li>“event_id X já foi processado”</li>



<li>“order_id Y já teve ação Z executada”</li>
</ul>



<p>O melhor lugar para isso quase sempre é o banco, porque é fonte de verdade.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">3) Garanta unicidade no banco (constraints salvam sistemas)</h2>



<p>Se duplicidade causa duplicação de registro, não confie só em lógica de aplicação. Use o banco como proteção.</p>



<p>Exemplos:</p>



<ul class="wp-block-list">
<li>índice unique em <code>invoice(event_id)</code></li>



<li>unique em <code>notifications(message_id, channel)</code></li>



<li>unique em <code>syncs(external_id)</code></li>
</ul>



<p>A aplicação tenta criar; se já existe, você trata e segue.</p>



<p>Isso é robusto porque:</p>



<ul class="wp-block-list">
<li>funciona mesmo com múltiplos workers</li>



<li>não depende de timing perfeito</li>



<li>reduz risco de corrida</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">4) Locks distribuídos (Redis) para evitar concorrência</h2>



<p>Locks são úteis quando você quer garantir que <strong>apenas um worker execute determinada seção crítica</strong> ao mesmo tempo.</p>



<p>Exemplo:</p>



<ul class="wp-block-list">
<li>processar um mesmo <code>order_id</code></li>



<li>consolidar um relatório</li>



<li>importar lote único</li>
</ul>



<p><a href="https://leonardonascimento.dev/categoria/laravel/" type="category" id="44">Em Laravel</a>, dá pra fazer lock via cache (Redis):</p>



<ul class="wp-block-list">
<li>lock por chave: <code>lock:order:123</code></li>



<li>se não adquirir, outro worker já está executando</li>
</ul>



<p>Importante: lock não substitui idempotência. Ele reduz concorrência, mas não garante que um retry nunca vai rodar depois.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">5) Use “unique jobs” do Laravel (quando couber)</h2>



<p>Laravel tem suporte para jobs únicos (dependendo da versão/config), mas isso é mais útil para evitar enfileirar duplicado, não para evitar execução duplicada em qualquer cenário.</p>



<p>Use se:</p>



<ul class="wp-block-list">
<li>você quer impedir spam de job igual</li>



<li>o job é claramente único por chave</li>



<li>você entende as limitações (especialmente com retries e falhas)</li>
</ul>



<p>Mesmo com unique job, eu continuo recomendando idempotência + banco.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">6) Controle retries, timeout e backoff com critério</h2>



<p>Muita duplicidade aparece porque:</p>



<ul class="wp-block-list">
<li>job estoura timeout → worker mata → tenta de novo</li>



<li>job demora demais → você acha que falhou → reprocessa manualmente</li>



<li>dependência externa oscila → retries “na pancada”</li>
</ul>



<p>Ajuste bem:</p>



<ul class="wp-block-list">
<li><code>timeout</code> realista (nem baixo demais, nem infinito)</li>



<li><code>tries</code> coerente com o impacto</li>



<li><code>backoff</code> crescente para não sobrecarregar dependência externa</li>
</ul>



<p>O objetivo é evitar “tempestade de retries”.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">7) Separe “efeito colateral” do “estado principal”</h2>



<p>Quando duplicidade é perigosa, normalmente é porque o job faz um efeito colateral irreversível (ex: cobrar cartão, enviar WhatsApp, emitir nota). A abordagem mais segura é:</p>



<ol class="wp-block-list">
<li>persistir um estado interno (“pendente”, “processando”, “concluído”)</li>



<li>só então executar o efeito colateral</li>



<li>registrar resultado e contexto</li>
</ol>



<p>Isso cria trilha de auditoria e evita “executar no escuro”.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">8) Instrumente: trace por job e correlação</h2>



<p>Você só descobre duplicidade tarde se não tiver rastreabilidade.</p>



<p>Boas práticas:</p>



<ul class="wp-block-list">
<li><code>job_id</code>/<code>correlation_id</code> em logs</li>



<li>logar início/fim do job com chave do evento</li>



<li>métrica de “job duplicado evitado” (sim, isso ajuda muito)</li>
</ul>



<p>Quando dá problema, você quer saber: “por que rodou duas vezes?” em 2 minutos, não em 2 horas.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Um padrão simples que funciona muito bem</h2>



<p>Se eu tivesse que resumir num padrão prático:</p>



<ul class="wp-block-list">
<li><strong>chave idempotente</strong> (event_id)</li>



<li><strong>tabela de processamento</strong> (<code>processed_events</code>) com unique</li>



<li><strong>lock Redis</strong> opcional em trechos críticos</li>



<li><strong>constraints no banco</strong> para proteger criação duplicada</li>



<li><strong>logs com correlação</strong></li>
</ul>



<p>Isso cobre 95% dos casos reais.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p><a href="https://leonardonascimento.dev/tag/producao/" type="post_tag" id="205">Em produção</a>, duplicidade em job não é exceção. É comportamento esperado do mundo real (retries, falhas, concorrência). O caminho profissional é aceitar isso e desenhar o job para ser seguro.</p>



<p>Job bom é o que pode rodar duas vezes sem te acordar de madrugada.</p>
<p>The post <a href="https://leonardonascimento.dev/blog/como-evitar-duplicidade-de-processamento-em-jobs/">Como evitar duplicidade de processamento em jobs</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://leonardonascimento.dev/blog/como-evitar-duplicidade-de-processamento-em-jobs/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Boas práticas para estruturar projetos em Laravel de médio e grande porte</title>
		<link>https://leonardonascimento.dev/blog/boas-praticas-para-estruturar-projetos-em-laravel-de-medio-e-grande-porte/</link>
					<comments>https://leonardonascimento.dev/blog/boas-praticas-para-estruturar-projetos-em-laravel-de-medio-e-grande-porte/#respond</comments>
		
		<dc:creator><![CDATA[Leonardo]]></dc:creator>
		<pubDate>Wed, 07 Jan 2026 14:12:16 +0000</pubDate>
				<category><![CDATA[Arquitetura]]></category>
		<category><![CDATA[Backend]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Produção]]></category>
		<category><![CDATA[arquitetura]]></category>
		<category><![CDATA[boas práticas]]></category>
		<category><![CDATA[código sustentável]]></category>
		<category><![CDATA[escalabilidade]]></category>
		<category><![CDATA[estrutura de projeto]]></category>
		<category><![CDATA[laravel]]></category>
		<guid isPermaLink="false">https://leonardonascimento.dev/?p=2262</guid>

					<description><![CDATA[<p>Quando o projeto Laravel é pequeno, quase qualquer organização funciona. Você cria controllers, models, requests, alguns services, resolve tudo no “app/” e segue. O problema começa quando o sistema cresce: mais módulos, mais regras, integrações, filas, diferentes times mexendo no mesmo lugar… e, de repente, o que era simples vira uma base difícil de evoluir. [&#8230;]</p>
<p>The post <a href="https://leonardonascimento.dev/blog/boas-praticas-para-estruturar-projetos-em-laravel-de-medio-e-grande-porte/">Boas práticas para estruturar projetos em Laravel de médio e grande porte</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Quando o projeto <a href="https://leonardonascimento.dev/categoria/laravel/" type="category" id="44">Laravel </a>é pequeno, quase qualquer organização funciona. Você cria controllers, models, requests, alguns services, resolve tudo no “app/” e segue. O problema começa quando o sistema cresce: mais módulos, mais regras, integrações, filas, diferentes times mexendo no mesmo lugar… e, de repente, o que era simples vira uma base difícil de evoluir.</p>



<p>Estruturar um projeto Laravel bem não é sobre “<a href="https://leonardonascimento.dev/categoria/arquitetura/" type="category" id="217">inventar arquitetura</a>”. É sobre reduzir atrito: facilitar manutenção, evitar acoplamento desnecessário e deixar o código previsível para quem chega depois.</p>



<p>A seguir estão práticas que funcionam bem em projetos médios e grandes, especialmente quando já existe operação de produção, roadmap e mudanças frequentes.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Comece pela regra: controller não é lugar de lógica</h2>



<p>Controller deveria orquestrar: receber request, validar, chamar a camada certa e responder. Quando regra de negócio fica no controller, você cria um ponto de acoplamento difícil de testar e difícil de reutilizar. Em projeto grande isso vira padrão ruim rapidamente, porque todo mundo copia o que já existe.</p>



<p>O que funciona melhor é mover lógica para classes dedicadas (services/use cases/actions), e deixar o controller como uma “casca” fina. Você ganha clareza, reaproveitamento e testes mais simples.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Estruture por domínio (feature) quando o sistema crescer</h2>



<p>A estrutura padrão do Laravel (Controllers, Models, Jobs, etc.) é ótima até um certo ponto. Em sistemas grandes, ela tende a espalhar a mesma funcionalidade por várias pastas e o dev precisa “caçar” arquivos para entender um fluxo.</p>



<p>Uma abordagem que escala melhor é organizar por <strong>domínio/feature</strong>. Exemplo: tudo relacionado a “Billing” fica próximo (requests, actions, policies, resources, etc.). Isso reduz a fricção para manter e evoluir partes específicas do sistema.</p>



<p>Você não precisa mudar tudo de uma vez. Dá para começar com um ou dois domínios e ir migrando aos poucos, sem reescrever o projeto inteiro.</p>



<h3 class="wp-block-heading">Estrutura tradicional do Laravel (por tipo)</h3>



<pre class="wp-block-preformatted">app/<br>├── Http/<br>│   ├── Controllers/<br>│   ├── Requests/<br>│   └── Resources/<br>├── Models/<br>├── Jobs/<br>├── Policies/<br>├── Services/</pre>



<p>Problema em projeto grande:<br>para entender <strong>Billing</strong>, você precisa abrir 6 pastas diferentes.</p>



<p>Estrutura por domínio / feature</p>



<p>app/<br>└── Domains/<br>└── Billing/<br>├── Http/<br>│ ├── Controllers/<br>│ ├── Requests/<br>│ └── Resources/<br>├── Actions/<br>├── Jobs/<br>├── Policies/<br>├── Models/<br>└── Services/</p>



<p>Ou até mais simples:</p>



<pre class="wp-block-preformatted">app/<br>└── Billing/<br>    ├── BillingController.php<br>    ├── CreateInvoice.php<br>    ├── Invoice.php<br>    ├── InvoicePolicy.php<br>    ├── SendInvoiceJob.php<br>    └── InvoiceResource.php</pre>



<p>O Laravel não se importa com a pasta, desde que o namespace esteja correto.</p>



<h2 class="wp-block-heading">Por que isso escala melhor?</h2>



<p>Porque quando alguém entra no projeto e precisa mexer em Billing:</p>



<ul class="wp-block-list">
<li>não precisa caçar arquivos espalhados</li>



<li>não quebra coisas de outros domínios</li>



<li>entende o fluxo mais rápido</li>



<li>reduz medo de alterar código</li>
</ul>



<p>Em projeto grande, isso faz <strong>muita diferença</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Requests e validações como primeiro filtro</h2>



<p>Em projeto grande, dado ruim entrando vira bug caro. Centralizar validação em <strong>Form Requests</strong> mantém o controller limpo e torna regras de entrada explícitas.</p>



<p>Além disso, vale padronizar:</p>



<ul class="wp-block-list">
<li>mensagens de erro;</li>



<li>formatos de resposta (principalmente APIs);</li>



<li>validações compartilhadas (traits, rules customizadas).</li>
</ul>



<p>Quando a validação é consistente, o sistema vira mais previsível e o time para de reinventar a roda a cada endpoint.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Padronize respostas de API desde cedo</h2>



<p>Quando cada <a href="https://leonardonascimento.dev/tag/api/" type="post_tag" id="210">endpoint </a>responde de um jeito, cada client precisa de lógica diferente, e isso vira dívida técnica distribuída. Para projetos médios e grandes, uma camada consistente de resposta é obrigatória: Resources, transformers, ou uma padronização interna.</p>



<p>O ponto aqui não é “estética”. É operação. Quando algo quebra, você quer logs previsíveis, payload previsível, erros previsíveis. Isso reduz tempo de diagnóstico.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Regras de negócio: não misture persistência com decisão</h2>



<p>Um erro comum em Laravel é “decidir” coisas dentro de models e ao mesmo tempo persistir em todo lugar, sem fronteira clara. Em sistemas maiores, o ideal é separar:</p>



<ul class="wp-block-list">
<li><strong>Decisão / regra</strong> (o que pode ou não pode)</li>



<li><strong>Persistência</strong> (salvar, consultar)</li>



<li><strong>Orquestração</strong> (fluxo do caso de uso)</li>
</ul>



<p>Isso permite evoluir regra sem quebrar camada de persistência, e vice-versa. E facilita testar o que realmente importa: a regra.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Jobs, filas e idempotência não são detalhe</h2>



<p>Em projeto grande, você inevitavelmente vai para filas: e-mails, notificações, integrações, processamento pesado. O que quebra sistemas grandes não é “usar fila”. É usar fila sem cuidado com:</p>



<ul class="wp-block-list">
<li>idempotência (job rodar duas vezes sem duplicar efeito);</li>



<li>retries (quando deve tentar de novo e quando deve falhar);</li>



<li>timeouts;</li>



<li>dead letter / estratégia para falhas recorrentes;</li>



<li>logs por job.</li>
</ul>



<p>Se o seu projeto depende de integração externa, trate isso como cenário normal: o externo vai falhar. A fila é o lugar certo para absorver isso, desde que bem desenhado.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Serviços externos: isole e trate como dependência instável</h2>



<p>Integrações externas deveriam estar em classes próprias (clients/adapters), com:</p>



<ul class="wp-block-list">
<li>timeout explícito;</li>



<li>tratamento de erro consistente;</li>



<li>retry controlado quando fizer sentido;</li>



<li>logs contextualizados.</li>
</ul>



<p>Evite espalhar <code>Http::post()</code> por todo lugar. Em projeto grande isso vira caos, porque não existe ponto único para ajustar comportamento (ex: mudar header, adicionar auth, alterar timeout).</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Migrations, seeds e dados de referência bem cuidados</h2>



<p>Projeto grande normalmente tem muita migration. E migration desorganizada vira armadilha: ambientes quebram, dev novo não sobe projeto, staging fica inconsistente.</p>



<p>Boas práticas que ajudam:</p>



<ul class="wp-block-list">
<li>migrations com nomes claros;</li>



<li>dados de referência (enums/tabelas fixas) com seeders idempotentes;</li>



<li>evitar “seed que depende de estado manual”;</li>



<li>sempre testar “do zero” em ambiente limpo.</li>
</ul>



<p>Isso evita que o setup do projeto vire uma gincana.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Configuração: tudo em config e .env, nada hardcoded</h2>



<p>Quando cresce, o sistema precisa rodar em múltiplos ambientes e, muitas vezes, múltiplos clientes. Configuração hardcoded vira problema de deploy e vira risco de segurança.</p>



<p>Padronize:</p>



<ul class="wp-block-list">
<li><code>config/*.php</code> como fonte de configuração;</li>



<li><code>.env</code> apenas para valores variáveis;</li>



<li>nunca commitar senhas e keys;</li>



<li>e preferencialmente separar integrações por “config + service container”.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Observabilidade: logs estruturados desde o começo</h2>



<p>Em projetos grandes, o custo de “descobrir o que aconteceu” é alto. Sem logs bons você perde tempo, perde confiança e perde previsibilidade operacional.</p>



<p>O que vale padronizar:</p>



<ul class="wp-block-list">
<li>logs com contexto (tenant, user_id, request_id, correlation_id);</li>



<li>níveis corretos (info, warning, error);</li>



<li>logs de integrações e jobs;</li>



<li>e um formato consistente (para facilitar busca).</li>
</ul>



<p>Isso é o que transforma incidentes em diagnóstico rápido.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Testes: foque no que dá retorno real</h2>



<p>Não dá para testar tudo em projeto grande, e tentar fazê-lo costuma falhar. O que dá mais retorno é:</p>



<ul class="wp-block-list">
<li>testes de regras de negócio (unit/integration);</li>



<li>testes de fluxos críticos;</li>



<li>testes de contratos de API;</li>



<li>e testes de integração com serviços externos (com mocks ou ambientes controlados).</li>
</ul>



<p>Teste não é para “subir porcentagem”. É para reduzir risco onde mais dói.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Conclusão</h2>



<p>Projetos Laravel grandes não quebram porque Laravel é limitado. Eles quebram porque a base cresce sem estrutura, sem padrões e sem fronteiras claras entre responsabilidades.</p>



<p>Se você mantiver controllers finos, separar domínio/feature, isolar integrações, tratar filas com seriedade e padronizar validação/retorno/log, o projeto continua evoluindo sem virar um monstro. E o melhor: o time consegue manter velocidade sem sacrificar estabilidade.</p>
<p>The post <a href="https://leonardonascimento.dev/blog/boas-praticas-para-estruturar-projetos-em-laravel-de-medio-e-grande-porte/">Boas práticas para estruturar projetos em Laravel de médio e grande porte</a> appeared first on <a href="https://leonardonascimento.dev">Leonardo Nascimento | Engenheiro de Software</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://leonardonascimento.dev/blog/boas-praticas-para-estruturar-projetos-em-laravel-de-medio-e-grande-porte/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
