[{"content":"Rode IA Local no Arch Linux: LM Studio + Open WebUI Quer rodar modelos de linguagem no seu próprio computador, sem depender de nuvem e sem pagar por API? Neste guia você vai instalar o LM Studio, baixar um modelo e deixar tudo acessível via uma interface bonita usando o Open WebUI com Docker.\nO que você vai precisar Arch Linux (ou derivados como Manjaro, EndeavourOS) Uma GPU razoável ou uma CPU moderna com bastante RAM (8 GB no mínimo, 16 GB recomendado) Docker instalado Vontade de brincar com IA local 🤖 Parte 1 — Instalando o LM Studio O LM Studio é um aplicativo gráfico que facilita baixar, gerenciar e rodar modelos de linguagem localmente. Ele funciona como um servidor local de IA, compatível com a API do OpenAI.\nVia AUR (jeito Arch) Se você usa yay ou paru, é direto ao ponto:\nyay -S lmstudio ou com paru:\nparu -S lmstudio Aguarde a compilação e instalação. Pode demorar um pouco na primeira vez.\nVia AppImage (alternativa) Se preferir não usar o AUR, você pode baixar o AppImage direto do site oficial:\nAcesse lmstudio.ai e baixe o arquivo .AppImage para Linux. Dê permissão de execução: chmod +x LM_Studio-*.AppImage Execute: ./LM_Studio-*.AppImage 💡 Dica: Para integrar melhor ao sistema, você pode usar o appimaged ou criar um .desktop manualmente em ~/.local/share/applications/.\nParte 2 — Baixando um modelo Com o LM Studio aberto, você vai ver uma interface bem amigável. Veja como baixar seu primeiro modelo:\nClique na aba de busca (ícone de lupa ou \u0026ldquo;Discover\u0026rdquo;) na barra lateral esquerda. Pesquise um modelo. Boas pedidas para começar: mistral — leve e eficiente llama3 — da Meta, muito capaz phi3 — surpreendentemente bom para o tamanho gemma — da Google, ótimo custo-benefício Escolha a versão correta para sua máquina: Q4_K_M — bom equilíbrio entre velocidade e qualidade Q8_0 — mais qualidade, precisa de mais RAM Modelos com 7B no nome têm 7 bilhões de parâmetros (mais leve); 13B é mais pesado mas melhor Clique em Download e aguarde. Os modelos costumam ter entre 4 GB e 10 GB. 💡 Quanto de RAM eu preciso? Uma regra prática: um modelo 7B Q4 precisa de cerca de 5–6 GB de RAM (ou VRAM se usar GPU). Um 13B Q4 precisa de ~9 GB.\nParte 3 — Rodando o servidor local Para que o Open WebUI consiga se comunicar com o LM Studio, você precisa ativar o servidor local dele:\nVá na aba \u0026ldquo;Local Server\u0026rdquo; (ícone \u0026lt;-\u0026gt; na barra lateral). Selecione o modelo que você baixou no menu suspenso. Clique em \u0026ldquo;Start Server\u0026rdquo;. O servidor vai subir na porta 1234 por padrão, acessível em http://localhost:1234.\nVocê pode testar se está funcionando abrindo o terminal e rodando:\ncurl http://localhost:1234/v1/models Se aparecer uma lista de modelos em JSON, está tudo certo! ✅\nParte 4 — Instalando o Docker Se você ainda não tem o Docker no Arch, é rapidinho:\nsudo pacman -S docker sudo systemctl enable --now docker sudo usermod -aG docker $USER ⚠️ Importante: Depois de rodar o usermod, faça logout e login novamente (ou reinicie) para que seu usuário reconheça o grupo docker. Caso contrário, você precisará usar sudo em todos os comandos Docker.\nParte 5 — Rodando o Open WebUI O Open WebUI é uma interface web estilo ChatGPT que se conecta ao seu servidor local. Com ele você tem:\nHistórico de conversas organizado Suporte a múltiplos modelos Upload de documentos (RAG) Interface muito mais agradável que o terminal Para subir o container, rode:\ndocker run -d -p 3000:8080 \\ --add-host=host.docker.internal:host-gateway \\ -v open-webui:/app/backend/data \\ --name open-webui \\ --restart always \\ ghcr.io/open-webui/open-webui:main O que cada parte faz:\nOpção O que faz -d Roda em segundo plano -p 3000:8080 Expõe na porta 3000 do seu PC --add-host=host.docker.internal:host-gateway Permite o container acessar o LM Studio no host -v open-webui:/app/backend/data Salva seus dados (conversas, config) em um volume persistente --restart always Reinicia automaticamente com o sistema Aguarde o download da imagem (pode demorar alguns minutos na primeira vez) e depois acesse:\nhttp://localhost:3000 Parte 6 — Conectando o Open WebUI ao LM Studio Acesse http://localhost:3000 no navegador. Na primeira vez, crie uma conta local (não precisa de email real, é só para o sistema local). Vá em Configurações → Connections (ou Conexões). Em OpenAI API, coloque a URL: http://host.docker.internal:1234/v1 No campo de API Key, coloque qualquer coisa (ex: lmstudio) — o LM Studio não valida isso. Clique em Save e depois em Verify Connection. Se aparecer um ✅ verde, está conectado! Agora você pode voltar para a tela principal e já vai ver o modelo disponível para conversar.\nDicas Finais Para parar o Open WebUI:\ndocker stop open-webui Para iniciar novamente:\ndocker start open-webui Para ver os logs se algo der errado:\ndocker logs open-webui Usando GPU NVIDIA?\nInstale o nvidia-container-toolkit e adicione --gpus all no comando do Docker para acelerar bastante a inferência:\nsudo pacman -S nvidia-container-toolkit docker run -d \\ --name open-webui \\ --network host \\ --restart always \\ -v open-webui:/app/backend/data \\ ghcr.io/open-webui/open-webui:main Note que no caso com GPU, a imagem muda para :cuda.\nConclusão Agora você tem uma stack completa de IA rodando 100% local no seu Arch Linux:\nLM Studio gerencia e serve os modelos Open WebUI entrega uma interface rica e completa Docker mantém tudo isolado e fácil de gerenciar Seus dados ficam no seu computador, você não paga por token e pode experimentar dezenas de modelos diferentes. Bem-vindo ao mundo da IA local! 🚀\n","permalink":"https://maggioni.dev/pt-br/posts/dev/ai-running-offline-pllama/","summary":"Tenha sua própria IA rodando localmente na sua máquina, offline e grátis!","title":"Como ter sua própria LLM rodando offline na sua máquina?"},{"content":" Handy IA speech to text (opensource)\n","permalink":"https://maggioni.dev/pt-br/posts/dev/useful-offline-tools/","summary":"\u003cul\u003e\n\u003cli\u003eHandy\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003eIA speech to text (opensource)\u003c/p\u003e\u003c/blockquote\u003e","title":"Ferramentas Offline Úteis pra Caramba!"},{"content":"Eu recentemente comprei um 8BitDo Ultimate 2 e um Machenike G5 Pro 🎮 pra usar no meu CachyOS.\nO 8BitDo funcionou perfeito de primeira. O Machenike também\u0026hellip; menos a vibração 😭 Via cabo funcionava, mas no dongle 2.4GHz ele se recusava a vibrar.\nComecei diagnosticando assim:\ndmesg -w Depois conectei o controle e percebi que ele entrava em:\n2345:e02e hid-generic em vez de:\n2345:e00b xpad Xbox 360 Controller for Windows Também testei o force feedback:\nsudo pacman -S linuxconsole fftest /dev/input/eventXX e recebia:\nFunction not implemented ou seja: o Linux estava carregando hid-generic em vez do xpad, então não existia suporte real a rumble/vibração.\nEncontrei a solução no reddit e consegui fazer funcionar.\nPrimeiro forcei o modo Xbox no controle:\nconectei via cabo USB liguei segurando Home + A Depois adicionei quirks USB temporários:\necho -n \u0026#34;2345:e00b:ik,2345:e02e:ik,2345:e02f:ik\u0026#34; | sudo tee /sys/module/usbcore/parameters/quirks Criei uma regra udev:\nArquivo: /etc/udev/rules.d/98-joystick.rules\nConteúdo:\nACTION==\u0026#34;add\u0026#34;, ATTRS{idVendor}==\u0026#34;2345\u0026#34;, ATTRS{idProduct}==\u0026#34;e02e\u0026#34;, RUN+=\u0026#34;/sbin/modprobe xpad\u0026#34;, RUN+=\u0026#34;/bin/sh -c \u0026#39;echo 2345 e02e \u0026gt; /sys/bus/usb/drivers/xpad/new_id\u0026#39;\u0026#34; Depois adicionei no GRUB:\nArquivo: /etc/default/grub\nNa linha GRUB_CMDLINE_LINUX_DEFAULT:\nusbcore.quirks=2345:e00b:ik,2345:e02e:ik,2345:e02f:ik Regenerei o grub:\nsudo grub-mkconfig -o /boot/grub/grub.cfg Recarreguei o udev:\nsudo udevadm control --reload-rules sudo udevadm trigger Depois disso:\no controle virou Xbox 360 Controller for Windows o driver xpad carregou corretamente a vibração passou a funcionar a Steam reconheceu normal o fftest finalmente detectou force feedback Pra testar vibração:\nfftest /dev/input/by-id/usb-MACHENIKE_Xbox_360_Controller_for_Windows_*-event-joystick Talvez ajude alguém sofrendo com esse controle no Linux 😭\n","permalink":"https://maggioni.dev/pt-br/posts/linux/resolvendo-problema-de-vibra%C3%A7%C3%A3o-dongle-2.4ghz-machenike-g5-pro-no-cachyos/","summary":"\u003cp\u003eEu recentemente comprei um 8BitDo Ultimate 2 e um Machenike G5 Pro 🎮 pra usar no meu CachyOS.\u003c/p\u003e\n\u003cp\u003eO 8BitDo funcionou perfeito de primeira. O Machenike também\u0026hellip; menos a vibração 😭\nVia cabo funcionava, mas no dongle 2.4GHz ele se recusava a vibrar.\u003c/p\u003e\n\u003cp\u003eComecei diagnosticando assim:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-plain\" data-lang=\"plain\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003edmesg -w\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eDepois conectei o controle e percebi que ele entrava em:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-plain\" data-lang=\"plain\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e2345:e02e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ehid-generic\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eem vez de:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-plain\" data-lang=\"plain\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e2345:e00b\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003expad\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eXbox 360 Controller for Windows\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eTambém testei o force feedback:\u003c/p\u003e","title":"Resolvendo problema de vibração dongle 2.4GHz MACHENIKE G5 PRO no CachyOS"},{"content":" Vamos do zero ao fundo do poço.\nIntrodução O que é Go Go (ou Golang, como é frequentemente chamada fora da comunidade oficial) é uma linguagem compilada, estaticamente tipada, com garbage collector, desenvolvida na Google e lançada publicamente em 2009. Ela produz binários nativos, tem suporte de primeira classe a concorrência e foi projetada com uma filosofia quase filosófica de que complexidade é o inimigo principal do software.\nSe você vem de Python ou JavaScript, Go vai parecer verbosa e rígida no começo. Se você vem de C++ ou Java, vai parecer estranhamente simples. Essa sensação é intencional.\nHistória da Linguagem Go foi criada por Robert Griesemer, Rob Pike e Ken Thompson - três gigantes da computação. Ken Thompson co-criou o Unix e a linguagem C. Rob Pike trabalhou no Plan 9 (o sucessor conceitual do Unix) e no UTF-8. Griesemer trabalhou no V8, o engine JavaScript do Chrome.\nEles estavam frustrados. Na Google de 2007, compilar grandes projetos em C++ levava minutos. A linguagem acumulava décadas de complexidade. Python era rápido de escrever mas lento de executar. Java carregava um ecossistema pesado.\nA pergunta que eles fizeram foi: \u0026ldquo;Se projetássemos uma linguagem hoje, em 2007, sabendo tudo que sabemos, o que faríamos diferente?\u0026rdquo;\nA resposta foi Go.\nFilosofia do Go Go tem uma filosofia explícita e bastante opiniosa, que pode ser resumida em alguns princípios:\nClareza é mais importante que esperteza. Em Go, o código óbvio é preferível ao código \u0026ldquo;elegante\u0026rdquo;. Se você precisa pensar muito para entender um trecho de código, algo está errado.\nMenos features, não mais. Go deliberadamente não tem herança de classes, não tem sobrecarga de operadores, não tem generics por muitos anos (até Go 1.18), não tem exceções no sentido tradicional. Cada feature que não existe é uma feature que não precisa ser aprendida, debugada ou mal utilizada.\nCompilação rápida é um requisito, não um bônus. A arquitetura de imports do Go foi projetada para que o compilador nunca precise processar o mesmo arquivo duas vezes.\nConcorrência como cidadã de primeira classe. Go foi construída num mundo de CPUs multi-core. Goroutines e channels são parte da linguagem, não uma biblioteca.\nErros são valores. Não existem exceções em Go. Erros são retornados explicitamente como valores, tornando o fluxo de controle transparente.\nPor que Go Existe A maioria das linguagens foi projetada por cientistas da computação interessados em problemas computacionais. Go foi projetada por engenheiros de sistemas interessados em problemas de produção: servidores que precisam responder em milissegundos, sistemas que precisam escalar para milhões de conexões, equipes de centenas de desenvolvedores trabalhando no mesmo codebase.\nO contexto importa. Na Google, existiam binários C++ que levavam 45 minutos para compilar. Existiam codebases onde ninguém sabia mais o que era seguro mudar. Existiam sistemas de CI que custavam fortunas só em tempo de compilação.\nGo resolve esses problemas específicos muito bem. Isso explica tanto seus pontos fortes quanto suas limitações.\nProblemas que Go Tenta Resolver Velocidade de compilação: um projeto Go de tamanho médio compila em segundos Legibilidade em escala: gofmt garante que todo código Go tem a mesma formatação Gerenciamento de dependências: go mod é simples e reproduzível Concorrência segura: o modelo de goroutines + channels reduz classes inteiras de bugs Deploy simples: um binário estático que roda em qualquer máquina Linux, sem JVM, sem interpretador Cross-compilation trivial: compilar para Windows estando no Linux é uma variável de ambiente Instalando Go Linux # Baixe a versão mais recente em https://go.dev/dl/ wget https://go.dev/dl/go1.22.0.linux-amd64.tar.gz # Remove instalação anterior (se houver) e descompacta sudo rm -rf /usr/local/go sudo tar -C /usr/local -xzf go1.22.0.linux-amd64.tar.gz # Adicione ao seu .bashrc ou .zshrc export PATH=$PATH:/usr/local/go/bin Recarregue o shell e verifique:\ngo version # go version go1.22.0 linux/amd64 macOS A forma mais limpa no Mac é via Homebrew:\nbrew install go go version Ou baixe o instalador .pkg diretamente em go.dev/dl.\nWindows Baixe o instalador .msi em go.dev/dl. Ele configura o PATH automaticamente. Após a instalação, abra um novo terminal e verifique:\ngo version GOPATH e GOROOT Dois conceitos que confundem bastante no começo:\nGOROOT é onde Go está instalado. Você raramente precisa se preocupar com isso. É /usr/local/go no Linux por padrão.\nGOPATH era onde seus projetos e dependências ficavam antes do Go Modules (antes do Go 1.11). Era a grande fonte de confusão da época: todo código precisava estar em $GOPATH/src/github.com/usuario/projeto. Hoje, com módulos, você pode colocar seu projeto em qualquer diretório.\nO GOPATH ainda existe e ainda é usado para guardar binários instalados via go install. Por padrão é ~/go. Você pode verificar tudo com:\ngo env Isso lista todas as variáveis de ambiente que Go usa. Algumas importantes:\nGOROOT=/usr/local/go # onde Go está instalado GOPATH=/home/user/go # diretório de trabalho GOOS=linux # sistema operacional alvo GOARCH=amd64 # arquitetura alvo GOMODCACHE=/home/user/go/pkg/mod # cache de módulos Primeiro Programa Hello World Crie um diretório, inicialize um módulo, escreva o código:\nmkdir hello \u0026amp;\u0026amp; cd hello go mod init github.com/seunome/hello Crie o arquivo main.go:\n// Todo programa Go executável começa com o package main. // Sem isso, o compilador não sabe que esse é um ponto de entrada. package main // import traz pacotes externos ou da biblioteca padrão. // \u0026#34;fmt\u0026#34; significa \u0026#34;formatted I/O\u0026#34; - é o pacote de formatação básica. import \u0026#34;fmt\u0026#34; // A função main() é o ponto de entrada do programa. // Não recebe argumentos aqui (argumentos de linha de comando // ficam em os.Args). func main() { fmt.Println(\u0026#34;Hello, World!\u0026#34;) } Para rodar:\ngo run main.go # Hello, World! Para compilar:\ngo build -o hello main.go ./hello # Hello, World! Como a Compilação Funciona Quando você roda go build, acontece uma sequência interessante:\nO compilador lê seu código fonte e os imports Resolve o grafo de dependências (cada pacote importado tem seus próprios imports) Compila cada pacote exatamente uma vez (essa é a chave da velocidade de compilação do Go) Liga tudo em um único binário estático A palavra \u0026ldquo;estático\u0026rdquo; aqui é crucial. O binário resultante contém:\nSeu código compilado Todo código de biblioteca que você usou O runtime do Go (scheduler, garbage collector, etc.) Isso significa que você pode copiar o binário para qualquer máquina com a mesma arquitetura e ele vai rodar. Sem instalar Go. Sem instalar dependências. É o sonho do deploy.\nCross Compilation Uma das features mais práticas do Go. Para compilar para um sistema diferente do seu:\n# Compila para Windows, mesmo estando no Linux GOOS=windows GOARCH=amd64 go build -o hello.exe main.go # Compila para Linux ARM (Raspberry Pi) GOOS=linux GOARCH=arm64 go build -o hello-arm main.go # Compila para macOS GOOS=darwin GOARCH=amd64 go build -o hello-mac main.go Isso funciona sem nenhuma configuração adicional porque o compilador Go inclui suporte a múltiplas arquiteturas por padrão. Em C/C++, cross-compilation é um pesadelo de toolchains. Em Go, é uma variável de ambiente.\nFundamentos da Linguagem Variáveis Go tem algumas formas de declarar variáveis, e a escolha entre elas não é arbitrária:\npackage main import \u0026#34;fmt\u0026#34; func main() { // Forma longa: var nome tipo = valor // Use quando você quer ser explícito sobre o tipo, // especialmente em variáveis de package (fora de funções). var idade int = 30 // Forma curta: inferência de tipo // Use dentro de funções para a maioria dos casos. // O compilador infere que \u0026#34;nome\u0026#34; é string. nome := \u0026#34;Alice\u0026#34; // Declaração sem valor inicial: zero value // Em Go, toda variável tem um valor padrão. Não existe \u0026#34;undefined\u0026#34;. var ativo bool // false var contador int // 0 var texto string // \u0026#34;\u0026#34; fmt.Println(nome, idade, ativo, contador, texto) // Declaração múltipla com var var ( x, y int = 10, 20 z = 30.5 // float64 inferido ) fmt.Println(x, y, z) // Múltipla atribuição curta a, b := 1, 2 fmt.Println(a, b) // Swap idiomático - sem variável temporária a, b = b, a fmt.Println(a, b) // 2, 1 } Regra prática: use := dentro de funções para quase tudo. Use var quando precisar de zero value explícito, quando precisar especificar o tipo explicitamente, ou em declarações de nível de pacote.\nTipos Básicos // Inteiros com tamanho explícito var i8 int8 // -128 a 127 var i16 int16 // -32768 a 32767 var i32 int32 // -2 bilhões a 2 bilhões var i64 int64 // enorme // int e uint: tamanho depende da arquitetura (32 ou 64 bits) // Na prática, use sempre \u0026#34;int\u0026#34; para inteiros de propósito geral var n int = 42 // Ponto flutuante var f32 float32 // ~7 dígitos de precisão var f64 float64 // ~15 dígitos de precisão - use esse por padrão // Booleano var ok bool = true // String: imutável, sequência de bytes UTF-8 var s string = \u0026#34;Olá, mundo\u0026#34; // byte = alias para uint8 (um byte) // rune = alias para int32 (um codepoint Unicode) var b byte = \u0026#39;A\u0026#39; var r rune = \u0026#39;🚀\u0026#39; // Para saber o tamanho de um tipo: import \u0026#34;unsafe\u0026#34; fmt.Println(unsafe.Sizeof(int64(0))) // 8 bytes A escolha entre int32 e int64 importa em contextos de performance e serialização, mas no código de aplicação comum, use int e float64 e não pense mais nisso.\nInferência de Tipos O compilador Go infere tipos em tempo de compilação, não em tempo de execução como Python. Isso significa zero custo de runtime:\nx := 42 // int (não int8, não int32 - sempre int) y := 3.14 // float64 (não float32) z := \u0026#34;texto\u0026#34; // string w := true // bool // Cuidado: a inferência pode surpreender com constantes numéricas a := 1 // int b := 1.0 // float64 c := int32(1) // int32 explícito Constantes Constantes em Go são mais poderosas do que parecem:\n// Constante tipada const Pi float64 = 3.14159265358979 // Constante não tipada - tem \u0026#34;precisão arbitrária\u0026#34; // pode ser usada com qualquer tipo numérico compatível const MaxItems = 1000 // iota: gerador de constantes inteiras sequenciais // Muito usado para enumerações type DiaDaSemana int const ( Domingo DiaDaSemana = iota // 0 Segunda // 1 Terca // 2 Quarta // 3 Quinta // 4 Sexta // 5 Sabado // 6 ) // iota com expressões const ( _ = iota // ignora o primeiro valor (0) KB = 1 \u0026lt;\u0026lt; (10 * iota) // 1 \u0026lt;\u0026lt; 10 = 1024 MB // 1 \u0026lt;\u0026lt; 20 GB // 1 \u0026lt;\u0026lt; 30 TB // 1 \u0026lt;\u0026lt; 40 ) Constantes em Go são avaliadas em tempo de compilação. Isso significa que KB * 1024 numa constante é calculado pelo compilador, não pelo programa em execução.\nZero Values Esta é uma das features mais subestimadas de Go. Toda variável declarada tem um valor inicial definido, nunca lixo de memória:\nvar i int // 0 var f float64 // 0.0 var b bool // false var s string // \u0026#34;\u0026#34; var p *int // nil var sl []int // nil (slice nil, não slice vazio) var m map[string]int // nil var fn func() // nil Isso parece pequeno, mas elimina toda uma classe de bugs que em C aparecem como comportamentos aleatórios (\u0026ldquo;funcionou no meu computador\u0026rdquo;). Em Go, o comportamento de um valor não inicializado é 100% previsível.\nPor que isso importa em structs:\ntype Servidor struct { Host string Port int TLS bool } // Funciona perfeitamente - todos os campos têm zero values var s Servidor fmt.Println(s.Port) // 0 fmt.Println(s.TLS) // false Conversão de Tipos Go não faz conversão implícita de tipos. Nunca. Isso é intencional:\nvar i int = 42 var f float64 = float64(i) // conversão explícita obrigatória var u uint = uint(f) // explícita novamente // Isso NÃO compila: // var f float64 = i // erro: cannot use i (type int) as type float64 // String para/de bytes s := \u0026#34;hello\u0026#34; b := []byte(s) // converte string para slice de bytes s2 := string(b) // converte slice de bytes para string // rune (Unicode codepoint) para string r := \u0026#39;🚀\u0026#39; sr := string(r) // \u0026#34;🚀\u0026#34; A ausência de conversão implícita parece irritante no início, mas elimina bugs sutis de overflow e perda de precisão que em outras linguagens passam silenciosamente.\nEscopo Go usa escopo léxico com blocos definidos por {}:\npackage main import \u0026#34;fmt\u0026#34; // Variável de pacote: visível em todo o pacote var versao = \u0026#34;1.0.0\u0026#34; func main() { x := 10 // escopo: função main if x \u0026gt; 5 { y := 20 // escopo: bloco if fmt.Println(y) // ok } // fmt.Println(y) // erro: y não existe aqui // Variável declarada no if é visível apenas dentro dele // Mas há uma forma útil de declarar no próprio if: if resultado, err := algumaFuncao(); err != nil { // resultado e err existem apenas aqui fmt.Println(\u0026#34;erro:\u0026#34;, err) } else { // resultado ainda existe no bloco else fmt.Println(\u0026#34;ok:\u0026#34;, resultado) } // resultado e err não existem aqui } func algumaFuncao() (int, error) { return 42, nil } Como Memória Funciona Esta seção é onde muitos tutoriais falham: ensinam a sintaxe mas não explicam o que acontece embaixo. Entender memória em Go vai te ajudar a escrever código mais eficiente e a entender por que certas práticas idiomáticas existem.\nRAM, Stack e Heap Pense na memória de um processo rodando como dois grandes espaços com propósitos diferentes:\nMemória do processo ┌────────────────────────────┐ │ Stack │ ← rápido, tamanho limitado, automático │ (cresce para baixo ↓) │ ├────────────────────────────┤ │ │ │ (espaço) │ │ │ ├────────────────────────────┤ │ Heap │ ← mais lento, tamanho \u0026#34;ilimitado\u0026#34;, gerenciado │ (cresce para cima ↑) │ └────────────────────────────┘ Stack (pilha): cada goroutine tem sua própria stack. Variáveis locais vivem na stack. Quando uma função é chamada, um \u0026ldquo;frame\u0026rdquo; é empurrado na stack com todas as variáveis locais daquela função. Quando a função retorna, o frame é descartado instantaneamente - sem garbage collection, sem malloc, sem free. É simplesmente um ajuste de um ponteiro (o stack pointer). Por isso é tão rápido.\nA stack tem tamanho limitado (no Go, começa pequena - 2KB ou 8KB - e cresce dinamicamente, mais sobre isso adiante).\nHeap: quando um objeto precisa sobreviver além da função que o criou, ou quando é grande demais para a stack, ele vai para o heap. O heap é gerenciado pelo garbage collector. Alocar no heap é mais custoso porque envolve encontrar espaço, potencialmente rodar o GC, etc.\nPonteiros Ponteiro é uma variável que guarda um endereço de memória, não um valor diretamente:\npackage main import \u0026#34;fmt\u0026#34; func main() { // x é um int na stack, com valor 42 x := 42 // p é um ponteiro para int - guarda o ENDEREÇO de x // \u0026amp; é o operador \u0026#34;address of\u0026#34; p := \u0026amp;x fmt.Println(x) // 42 - o valor fmt.Println(p) // 0xc000018058 - o endereço (vai variar) fmt.Println(*p) // 42 - dereferenciando: \u0026#34;o valor no endereço p\u0026#34; // Modificar através do ponteiro modifica o original *p = 100 fmt.Println(x) // 100 } Por que ponteiros existem? Para dois propósitos principais:\nCompartilhar dados sem copiar: se você tem uma struct de 10KB e passa por valor para uma função, Go copia 10KB. Se você passa um ponteiro, copia 8 bytes (o endereço). Modificar o original: funções recebem cópias dos argumentos. Para modificar a variável original, você precisa do ponteiro. // Esta função não modifica o original - recebe uma CÓPIA func dobrarErrado(n int) { n = n * 2 // modifica apenas a cópia local } // Esta função modifica o original - recebe o ENDEREÇO func dobrarCerto(n *int) { *n = *n * 2 // modifica o valor no endereço recebido } func main() { x := 10 dobrarErrado(x) fmt.Println(x) // 10 - não mudou dobrarCerto(\u0026amp;x) fmt.Println(x) // 20 - mudou } Escape Analysis Esta é a parte que a maioria dos tutoriais ignora completamente.\nO compilador Go decide automaticamente se uma variável vive na stack ou no heap através de um processo chamado escape analysis. Você não precisa gerenciar isso manualmente (diferente de C), mas entender como funciona te ajuda a escrever código mais eficiente.\nRegra geral: se uma variável \u0026ldquo;escapa\u0026rdquo; do escopo onde foi criada - ou seja, alguma referência a ela pode ser usada depois que a função retornar - ela precisa ir para o heap.\n// Exemplo 1: fica na stack func semEscape() int { x := 42 // x fica na stack return x // retorna o VALOR, não o ponteiro } // frame da função é descartado, x some // Exemplo 2: escapa para o heap func comEscape() *int { x := 42 // x PRECISA ir para o heap! return \u0026amp;x // retorna o ENDEREÇO de x } // a função retorna, mas alguém tem o endereço de x // Go não pode descartá-la - ela vai para o heap No segundo caso, a variável x \u0026ldquo;escapa\u0026rdquo; para o heap porque seu endereço é retornado e pode ser usado depois que a função terminar.\nPara ver o que o compilador decidiu, use a flag de análise:\ngo build -gcflags=\u0026#39;-m\u0026#39; main.go # Output típico: # ./main.go:9:2: moved to heap: x Algumas situações que causam escape para o heap:\nRetornar um ponteiro para variável local Armazenar um ponteiro em uma interface Passar para interface{} (porque o compilador perde rastreabilidade do tipo) Closures que capturam variáveis Slices que crescem além do tamanho inicial (com append) Por que isso importa para performance? Alocações no heap têm custo duplo: o custo da alocação em si e o custo do GC para eventualmente coletar. Código de alta performance em Go tenta minimizar alocações no heap.\nGarbage Collector do Go O GC do Go usa um algoritmo chamado tri-color mark-and-sweep com suporte a concorrência. Em termos práticos, o que você precisa saber:\nComo funciona em alto nível:\nMark phase (fase de marcação): o GC começa pelas \u0026ldquo;raízes\u0026rdquo; (variáveis globais, stacks de goroutines, registradores) e percorre o grafo de objetos, marcando tudo que é alcançável como \u0026ldquo;vivo\u0026rdquo; Sweep phase (fase de varredura): tudo que não foi marcado é considerado lixo e a memória é liberada O algoritmo tri-color usa três conjuntos:\nBranco: ainda não visitado (candidato a coleta) Cinza: visitado, mas ainda tem filhos para processar Preto: visitado e todos os filhos processados (definitivamente vivo) O que torna o GC do Go especial: ele roda concorrentemente com o programa. O \u0026ldquo;stop the world\u0026rdquo; (pausar todas as goroutines) é extremamente curto - sub-milissegundo na maioria dos casos. O trabalho pesado da marcação acontece em paralelo com a execução do programa.\nPara um serviço web, latências de GC raramente são perceptíveis. Para sistemas de trading de alta frequência ou jogos em tempo real, você precisa ser mais cuidadoso com alocações.\nComo reduzir pressão no GC:\n// Ruim: cria uma nova slice em cada chamada func processarItens(ids []int) []Resultado { resultados := make([]Resultado, 0) // alocação for _, id := range ids { resultados = append(resultados, processar(id)) } return resultados } // Melhor: pré-aloca com tamanho conhecido func processarItens(ids []int) []Resultado { resultados := make([]Resultado, 0, len(ids)) // capacidade pré-alocada for _, id := range ids { resultados = append(resultados, processar(id)) } return resultados } // Melhor ainda em hot paths: reutiliza com sync.Pool (ver seção de performance) Controle de Fluxo if // if básico - sem parênteses (diferente de C/Java/JS) if x \u0026gt; 10 { fmt.Println(\u0026#34;grande\u0026#34;) } // if-else if x \u0026gt; 10 { fmt.Println(\u0026#34;grande\u0026#34;) } else if x \u0026gt; 5 { fmt.Println(\u0026#34;médio\u0026#34;) } else { fmt.Println(\u0026#34;pequeno\u0026#34;) } // Forma idiomática: declaração + condição no mesmo if // Muito comum para verificar erros if err := fazerAlgo(); err != nil { return fmt.Errorf(\u0026#34;ao fazer algo: %w\u0026#34;, err) } // A variável err existe apenas dentro do if // Isso mantém o escopo limpo if usuario, err := buscarUsuario(id); err != nil { return nil, err } else { // usuario existe aqui também return usuario, nil } switch O switch em Go é bem mais poderoso e elegante que em C:\n// switch com valor switch status { case \u0026#34;ativo\u0026#34;: fmt.Println(\u0026#34;usuário ativo\u0026#34;) case \u0026#34;inativo\u0026#34;, \u0026#34;suspenso\u0026#34;: // múltiplos valores numa case fmt.Println(\u0026#34;usuário não pode acessar\u0026#34;) default: fmt.Println(\u0026#34;status desconhecido\u0026#34;) } // Sem break! Go não faz fallthrough por padrão. // Se quiser fallthrough explícito, use a keyword `fallthrough` // switch sem valor: funciona como if-else encadeado switch { case x \u0026lt; 0: fmt.Println(\u0026#34;negativo\u0026#34;) case x == 0: fmt.Println(\u0026#34;zero\u0026#34;) case x \u0026gt; 0: fmt.Println(\u0026#34;positivo\u0026#34;) } // type switch: extremamente útil com interfaces func descrever(i interface{}) { switch v := i.(type) { case int: fmt.Printf(\u0026#34;inteiro: %d\\n\u0026#34;, v) case string: fmt.Printf(\u0026#34;string: %q\\n\u0026#34;, v) case bool: fmt.Printf(\u0026#34;bool: %t\\n\u0026#34;, v) default: fmt.Printf(\u0026#34;tipo desconhecido: %T\\n\u0026#34;, v) } } for Go tem apenas um tipo de loop: for. Mas ele cobre todos os casos:\n// Loop clássico estilo C for i := 0; i \u0026lt; 10; i++ { fmt.Println(i) } // Loop \u0026#34;while\u0026#34; (apenas condição) n := 1 for n \u0026lt; 1000 { n *= 2 } // Loop infinito for { // só sai com break ou return if condicao { break } } // range: itera sobre slices, arrays, maps, strings, channels // Com slice/array: retorna índice e valor numeros := []int{10, 20, 30} for i, v := range numeros { fmt.Println(i, v) // 0 10, 1 20, 2 30 } // Se não precisa do índice, use _ for _, v := range numeros { fmt.Println(v) } // Se não precisa do valor for i := range numeros { fmt.Println(i) } // range em map: ordem NÃO é garantida m := map[string]int{\u0026#34;a\u0026#34;: 1, \u0026#34;b\u0026#34;: 2} for k, v := range m { fmt.Println(k, v) // ordem aleatória } // range em string: itera por rune (codepoint Unicode), não byte // Importante para strings com caracteres multibyte for i, r := range \u0026#34;olá\u0026#34; { fmt.Printf(\u0026#34;%d: %c (%d)\\n\u0026#34;, i, r, r) // 0: o (111) // 1: l (108) // 2: á (225) \u0026lt;- byte index 2, não 3, porque \u0026#39;á\u0026#39; é 2 bytes } Uma armadilha clássica com range:\n// ARMADILHA: o range faz CÓPIA do valor type Pessoa struct{ Nome string } pessoas := []Pessoa{{\u0026#34;Alice\u0026#34;}, {\u0026#34;Bob\u0026#34;}} for _, p := range pessoas { p.Nome = \u0026#34;modificado\u0026#34; // modifica a CÓPIA, não o original! } fmt.Println(pessoas[0].Nome) // \u0026#34;Alice\u0026#34; - não mudou! // CORRETO: use índice para acessar o original for i := range pessoas { pessoas[i].Nome = \u0026#34;modificado\u0026#34; // modifica o original } // OU: use ponteiro na slice pessoas2 := []*Pessoa{{\u0026#34;Alice\u0026#34;}, {\u0026#34;Bob\u0026#34;}} for _, p := range pessoas2 { p.Nome = \u0026#34;modificado\u0026#34; // p é um ponteiro - modifica o original } defer defer agenda uma chamada de função para executar quando a função atual retornar. É uma das features mais elegantes de Go:\nfunc lerArquivo(caminho string) (string, error) { f, err := os.Open(caminho) if err != nil { return \u0026#34;\u0026#34;, err } defer f.Close() // vai executar quando lerArquivo retornar // independente de como retornar (normal ou com erro) // ... lê o arquivo ... return conteudo, nil } Sem defer, você precisaria chamar f.Close() em cada ponto de retorno. Com múltiplos caminhos de erro, isso é propenso a esquecimento.\nDefers são empilhados (LIFO):\nfunc exemploDefers() { defer fmt.Println(\u0026#34;terceiro\u0026#34;) // executado por último defer fmt.Println(\u0026#34;segundo\u0026#34;) defer fmt.Println(\u0026#34;primeiro\u0026#34;) // executado primeiro fmt.Println(\u0026#34;durante\u0026#34;) } // Output: // durante // primeiro // segundo // terceiro defer avalia os argumentos imediatamente:\n// Armadilha: o valor de i é capturado no momento do defer for i := 0; i \u0026lt; 3; i++ { defer fmt.Println(i) // imprime 2, 1, 0 - não o valor futuro } // Para capturar o valor futuro, use closure for i := 0; i \u0026lt; 3; i++ { i := i // cria nova variável i local ao loop defer func() { fmt.Println(i) // captura a variável do closure }() } defer com named returns para limpeza de erros:\nfunc transacao(db *sql.DB) (err error) { tx, err := db.Begin() if err != nil { return } defer func() { if err != nil { tx.Rollback() // faz rollback se houve erro } else { err = tx.Commit() // faz commit, e se commit falhar, // o erro é propagado pelo named return } }() // ... executa operações ... return nil } Funções Múltiplos Retornos Esta é uma das features que mais define o estilo de código Go:\n// Função com múltiplos retornos func dividir(a, b float64) (float64, error) { if b == 0 { return 0, errors.New(\u0026#34;divisão por zero\u0026#34;) } return a / b, nil } func main() { resultado, err := dividir(10, 2) if err != nil { log.Fatal(err) } fmt.Println(resultado) // 5 // Use _ para descartar valores que não precisa_ _ resultado2, _ := dividir(10, 4) fmt.Println(resultado2) // 2.5 } Named returns (retornos nomeados):\n// Os valores de retorno têm nomes - são variáveis declaradas func minMax(arr []int) (min, max int) { // min e max são inicializadas com zero value if len(arr) == 0 { return // \u0026#34;naked return\u0026#34; - retorna min e max com seus valores atuais } min, max = arr[0], arr[0] for _, v := range arr[1:] { if v \u0026lt; min { min = v } if v \u0026gt; max { max = v } } return // retorna min e max } Use named returns com cuidado. Eles melhoram a legibilidade quando os nomes são descritivos, mas \u0026ldquo;naked returns\u0026rdquo; em funções longas tornam o código opaco.\nClosures Uma closure é uma função que \u0026ldquo;fecha\u0026rdquo; sobre variáveis do escopo externo:\n// Gerador de IDs sequenciais func novoGerador() func() int { id := 0 // esta variável é capturada pelo closure return func() int { id++ // modifica a variável capturada return id } } func main() { gerarID := novoGerador() fmt.Println(gerarID()) // 1 fmt.Println(gerarID()) // 2 fmt.Println(gerarID()) // 3 // Outro gerador tem sua própria variável id independente outroGerador := novoGerador() fmt.Println(outroGerador()) // 1 } Closures são fundamentais para alguns padrões em Go, como decoradores de funções, callbacks e geração lazy de valores.\nArmadilha clássica com closures em loops:\n// PROBLEMA: todas as goroutines capturam a MESMA variável i funcs := make([]func(), 3) for i := 0; i \u0026lt; 3; i++ { funcs[i] = func() { fmt.Println(i) // quando executar, i vale 3 (valor final do loop) } } for _, f := range funcs { f() // imprime 3, 3, 3 } // SOLUÇÃO 1: crie uma cópia de i dentro do loop for i := 0; i \u0026lt; 3; i++ { i := i // shadowing: nova variável i para cada iteração funcs[i] = func() { fmt.Println(i) // captura a variável LOCAL, não a do loop } } // SOLUÇÃO 2: passe como argumento for i := 0; i \u0026lt; 3; i++ { funcs[i] = func(n int) func() { return func() { fmt.Println(n) } }(i) // chama imediatamente com o valor atual de i } Funções Variádicas // ... antes do tipo indica variádica // args é uma slice dentro da função func soma(args ...int) int { total := 0 for _, v := range args { total += v } return total } func main() { fmt.Println(soma(1, 2, 3)) // 6 fmt.Println(soma(1, 2, 3, 4, 5)) // 15 // Expandir uma slice para argumentos variádicos numeros := []int{1, 2, 3, 4} fmt.Println(soma(numeros...)) // 10 - o ... expande a slice } fmt.Println é variádica (func Println(a ...interface{}) (n int, err error)). Esse é o padrão para funções que aceitam número variável de argumentos homogêneos.\nFunções como Valores Em Go, funções são valores de primeira classe:\n// Tipo de função type Transformador func(int) int // Função que recebe função como argumento (higher-order function) func aplicar(numeros []int, fn Transformador) []int { resultado := make([]int, len(numeros)) for i, v := range numeros { resultado[i] = fn(v) } return resultado } func dobrar(n int) int { return n * 2 } func quadrado(n int) int { return n * n } func main() { numeros := []int{1, 2, 3, 4, 5} dobrados := aplicar(numeros, dobrar) fmt.Println(dobrados) // [2 4 6 8 10] quadrados := aplicar(numeros, quadrado) fmt.Println(quadrados) // [1 4 9 16 25] // Função anônima inline triplicados := aplicar(numeros, func(n int) int { return n * 3 }) fmt.Println(triplicados) // [3 6 9 12 15] } Structs e Modelagem Structs Struct é a forma de criar tipos compostos em Go. Não existe classe. Não existe herança. Só structs e composição.\n// Definição de struct type Usuario struct { ID int Nome string Email string Ativo bool } // Inicialização u1 := Usuario{ ID: 1, Nome: \u0026#34;Alice\u0026#34;, Email: \u0026#34;alice@exemplo.com\u0026#34;, Ativo: true, } // Inicialização posicional (não recomendada - frágil a mudanças) u2 := Usuario{1, \u0026#34;Bob\u0026#34;, \u0026#34;bob@exemplo.com\u0026#34;, false} // Zero value de struct var u3 Usuario // todos os campos com zero values Comparação com classes em outras linguagens:\nEm Java ou Python, você teria uma classe com construtor, campos privados, getters/setters. Em Go, você tem uma struct e funções. O encapsulamento é por pacote, não por objeto: campos e funções com letra minúscula são privados ao pacote.\n// Convenção Go: campos exportados começam com maiúscula // campos não exportados começam com minúscula type conta struct { ID int // exportado saldo float64 // não exportado (privado ao pacote) } Métodos Método é uma função com um receiver (receptor):\ntype Retangulo struct { Largura float64 Altura float64 } // Método com value receiver // Recebe UMA CÓPIA do Retangulo func (r Retangulo) Area() float64 { return r.Largura * r.Altura } // Método com pointer receiver // Recebe o PONTEIRO para o Retangulo - pode modificar func (r *Retangulo) Escalar(fator float64) { r.Largura *= fator r.Altura *= fator } func main() { ret := Retangulo{Largura: 10, Altura: 5} fmt.Println(ret.Area()) // 50 ret.Escalar(2) fmt.Println(ret.Area()) // 200 } Value Receiver vs Pointer Receiver Esta escolha tem implicações de performance e semântica:\nUse pointer receiver quando:\nO método precisa modificar o receiver O struct é grande (evita cópia desnecessária) Por consistência: se algum método precisa de pointer receiver, todos deveriam usar Use value receiver quando:\nO struct é pequeno (int, float, struct com 2-3 campos primitivos) O método não precisa modificar o receiver Você quer que o receiver seja imutável (o método recebe uma cópia) // Convenção: seja consistente // Se um método usa pointer receiver, todos devem usar type Ponto struct{ X, Y float64 } // INCONSISTENTE (não faça isso): func (p Ponto) String() string { ... } // value func (p *Ponto) Mover(dx, dy float64) { ... } // pointer // CONSISTENTE: func (p *Ponto) String() string { ... } // pointer func (p *Ponto) Mover(dx, dy float64) { ... } // pointer Composição Go não tem herança. Tem embedding (incorporação) e composição, que é mais flexível:\n// Animal base type Animal struct { Nome string } func (a Animal) Respirar() { fmt.Printf(\u0026#34;%s está respirando\\n\u0026#34;, a.Nome) } // Cachorro embeds Animal type Cachorro struct { Animal // embedding - não é herança, é composição Raca string } // Cachorro tem um método próprio func (c Cachorro) Latir() { fmt.Printf(\u0026#34;%s: Au au!\\n\u0026#34;, c.Nome) // acessa Nome do Animal embedded } func main() { c := Cachorro{ Animal: Animal{Nome: \u0026#34;Rex\u0026#34;}, Raca: \u0026#34;Labrador\u0026#34;, } c.Respirar() // método promovido do Animal c.Latir() // método próprio do Cachorro c.Animal.Respirar() // acesso explícito também funciona } A diferença entre embedding e herança é sutil mas importante:\nHerança cria uma relação \u0026ldquo;é-um\u0026rdquo; (Dog is-an Animal) Embedding cria uma relação \u0026ldquo;tem-um\u0026rdquo; com promoção de métodos (Dog has-an Animal, e os métodos de Animal são acessíveis diretamente) Embedding não cria um tipo pai/filho. Você não pode usar um Cachorro onde um Animal é esperado (a menos que seja através de uma interface que ambos satisfaçam).\nInterfaces Profundamente Interfaces em Go são diferentes de quase toda outra linguagem que as tem. Entender isso é crucial.\nDuck Typing e Interfaces Implícitas Em Java, para implementar uma interface você declara explicitamente:\n// Java class Cachorro implements Animal { ... } Em Go, uma interface é satisfeita implicitamente:\n// Define a interface type Barulhento interface { FazerBarulho() string } // Cachorro não declara que implementa Barulhento // mas implementa o método FazerBarulho type Cachorro struct{ Nome string } func (c Cachorro) FazerBarulho() string { return \u0026#34;Au!\u0026#34; } // Gato também, sem declarar nada type Gato struct{ Nome string } func (g Gato) FazerBarulho() string { return \u0026#34;Miau!\u0026#34; } // Qualquer tipo com FazerBarulho() string satisfaz Barulhento func fazerBarulhos(animais []Barulhento) { for _, a := range animais { fmt.Println(a.FazerBarulho()) } } func main() { animais := []Barulhento{ Cachorro{Nome: \u0026#34;Rex\u0026#34;}, Gato{Nome: \u0026#34;Mimi\u0026#34;}, } fazerBarulhos(animais) // Au!, Miau! } Por que isso é poderoso? Porque você pode criar interfaces para tipos que você não controla. Um tipo em outra biblioteca que tem o método certo automaticamente satisfaz sua interface.\n// A interface io.Writer da biblioteca padrão é apenas: type Writer interface { Write(p []byte) (n int, err error) } // Qualquer coisa que implementa Write() satisfaz io.Writer: // os.File satisfaz // bytes.Buffer satisfaz // net.Conn satisfaz // http.ResponseWriter satisfaz // Seus próprios tipos também podem satisfazer Interfaces Pequenas A comunidade Go tem uma preferência forte por interfaces pequenas. A famosa frase de Rob Pike:\n\u0026ldquo;The bigger the interface, the weaker the abstraction.\u0026rdquo;\nInterfaces com um ou dois métodos são mais reutilizáveis porque mais tipos as satisfazem:\n// Ruim: interface gigante - poucos tipos satisfazem isso type Repositorio interface { Criar(u Usuario) error Buscar(id int) (Usuario, error) Listar() ([]Usuario, error) Atualizar(u Usuario) error Deletar(id int) error BuscarPorEmail(email string) (Usuario, error) // ... mais 10 métodos } // Melhor: interfaces focadas type Criador interface { Criar(u Usuario) error } type Buscador interface { Buscar(id int) (Usuario, error) } type RepositorioCompleto interface { Criador Buscador // ... } // A função que só precisa criar aceita Criador - mais testável, mais flexível Interface Vazia e any // interface{} aceita qualquer tipo - é o \u0026#34;any\u0026#34; do Go // A partir do Go 1.18, \u0026#34;any\u0026#34; é um alias para interface{} func imprimirQualquer(v interface{}) { fmt.Printf(\u0026#34;tipo: %T, valor: %v\\n\u0026#34;, v, v) } // Ou com any (preferível no Go moderno) func imprimirQualquer(v any) { fmt.Printf(\u0026#34;tipo: %T, valor: %v\\n\u0026#34;, v, v) } imprimirQualquer(42) // tipo: int, valor: 42 imprimirQualquer(\u0026#34;hello\u0026#34;) // tipo: string, valor: hello imprimirQualquer([]int{1}) // tipo: []int, valor: [1] Cuidado com interface vazia: quando você aceita any, você perde a verificação de tipos em compile time. É útil em casos como serialização, containers genéricos (antes de Go ter generics), e código de infraestrutura. Não use no código de domínio.\nType Assertion e Type Switch // Type assertion: extrai o valor concreto de uma interface var i interface{} = \u0026#34;hello\u0026#34; // Forma \u0026#34;segura\u0026#34; - retorna valor e ok s, ok := i.(string) if ok { fmt.Println(s) // \u0026#34;hello\u0026#34; } // Forma \u0026#34;unsafe\u0026#34; - panic se o tipo não bater s2 := i.(string) // ok n := i.(int) // panic! i não é int // Type switch: pattern mais idiomático para múltiplos tipos func processar(v interface{}) string { switch val := v.(type) { case nil: return \u0026#34;nulo\u0026#34; case int: return fmt.Sprintf(\u0026#34;inteiro: %d\u0026#34;, val) case float64: return fmt.Sprintf(\u0026#34;float: %.2f\u0026#34;, val) case string: return fmt.Sprintf(\u0026#34;string: %q\u0026#34;, val) case []int: return fmt.Sprintf(\u0026#34;slice de int com %d elementos\u0026#34;, len(val)) default: return fmt.Sprintf(\u0026#34;tipo desconhecido: %T\u0026#34;, val) } } Interface Nil: Uma Armadilha Sutil // ARMADILHA CLÁSSICA type MeuErro struct{ Msg string } func (e *MeuErro) Error() string { return e.Msg } func podeRetornarNil() error { var err *MeuErro = nil // ponteiro nil para MeuErro return err // retorna como interface error // MAS: a interface retornada NÃO é nil! // Ela tem tipo (*MeuErro) com valor nil } func main() { err := podeRetornarNil() if err != nil { fmt.Println(\u0026#34;erro!\u0026#34;) // isso EXECUTA - err não é nil! } } Por que? Uma interface em Go internamente tem dois campos: o tipo e o valor. Uma interface só é nil quando ambos são nil. Quando você retorna (*MeuErro)(nil) como error, o tipo é *MeuErro (não nil) mesmo que o valor seja nil.\nSolução: sempre retorne nil diretamente, não um ponteiro tipado nil:\nfunc podeRetornarNil() error { // ... if semErro { return nil // retorna interface nil diretamente } return \u0026amp;MeuErro{\u0026#34;algo deu errado\u0026#34;} } Arrays, Slices e Maps Arrays Arrays em Go têm tamanho fixo e fazem parte do tipo:\nvar a [5]int // array de 5 ints - zero value b := [3]string{\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;, \u0026#34;c\u0026#34;} c := [...]int{1, 2, 3, 4} // ... infere o tamanho (4) fmt.Println(len(b)) // 3 // [3]string e [4]string são TIPOS DIFERENTES // Não são compatíveis entre si // Arrays são copiados quando atribuídos ou passados para funções x := [3]int{1, 2, 3} y := x // cópia completa y[0] = 99 fmt.Println(x[0]) // 1 - não mudou Na prática, você raramente usa arrays diretamente em Go. Slices são a estrutura dominante.\nSlices: O Coração do Go Slice é uma abstração sobre array. Entender a estrutura interna de um slice é fundamental:\nSlice internamente: ┌──────────────────────┐ │ ptr → array subjacente│ ponteiro para o array │ len = comprimento │ quantos elementos são visíveis │ cap = capacidade │ quantos elementos o array tem no total └──────────────────────┘ // Criando slices s1 := []int{1, 2, 3} // slice literal s2 := make([]int, 5) // len=5, cap=5, zeros s3 := make([]int, 3, 10) // len=3, cap=10 fmt.Println(len(s1), cap(s1)) // 3, 3 fmt.Println(len(s2), cap(s2)) // 5, 5 fmt.Println(len(s3), cap(s3)) // 3, 10 // Slicing: cria um novo slice que aponta para o mesmo array a := []int{1, 2, 3, 4, 5} b := a[1:3] // b = [2, 3], len=2, cap=4 (do índice 1 ao fim do array) b[0] = 99 fmt.Println(a) // [1, 99, 3, 4, 5] - MODIFICOU O ORIGINAL! Por que modificar o sub-slice modifica o original? Porque ambos apontam para o mesmo array subjacente. Essa é a armadilha mais comum com slices.\n// Para fazer uma cópia independente: c := make([]int, len(b)) copy(c, b) // ou mais conciso: c := append([]int(nil), b...) append e Crescimento de Capacidade s := make([]int, 0, 3) // len=0, cap=3 // append adiciona elementos s = append(s, 1) // len=1, cap=3 (ainda cabe) s = append(s, 2, 3) // len=3, cap=3 (cheio) s = append(s, 4) // len=4, cap=6 (dobrou!) // Quando cap está cheio, Go aloca um novo array maior // e copia todos os elementos para ele // A capacidade geralmente dobra (mas o algoritmo é mais complexo em versões recentes) Implications de performance:\nCada realocação é uma alocação de heap + cópia de todos os elementos. Para slices grandes, isso pode ser custoso. Se você sabe o tamanho final, pré-aloque:\n// Ruim: muitas realocações resultado := []int{} for i := 0; i \u0026lt; 1000; i++ { resultado = append(resultado, i) } // Realoca ~10 vezes (3, 6, 12, 24, 48, 96, 192, 384, 768, 1536) // Bom: uma única alocação resultado := make([]int, 0, 1000) for i := 0; i \u0026lt; 1000; i++ { resultado = append(resultado, i) } // Nenhuma realocação Armadilha de memória com sub-slices:\n// Lê um arquivo de 1GB em memória dados := lerArquivoGrande() // []byte, 1GB // Extrai os primeiros 100 bytes header := dados[:100] // PROBLEMA: header ainda referencia o array de 1GB! // O GC não pode liberar o 1GB enquanto header existir. dados = nil // isso NÃO libera - header ainda aponta para o array // SOLUÇÃO: copie o que precisa header = append([]byte(nil), dados[:100]...) dados = nil // agora o 1GB pode ser coletado Maps Maps em Go são tabelas hash implementadas com uma estrutura de buckets:\n// Criação m1 := map[string]int{ \u0026#34;alice\u0026#34;: 30, \u0026#34;bob\u0026#34;: 25, } m2 := make(map[string]int) // map vazio, pronto para uso // Operações básicas m1[\u0026#34;carol\u0026#34;] = 35 // inserção/atualização idade := m1[\u0026#34;alice\u0026#34;] // leitura (30) delete(m1, \u0026#34;bob\u0026#34;) // remoção // IMPORTANTE: leitura de chave inexistente retorna zero value // Não retorna erro, não causa panic x := m1[\u0026#34;ninguem\u0026#34;] // x = 0 (zero value de int) // Para saber se a chave existe: valor, ok := m1[\u0026#34;alice\u0026#34;] if ok { fmt.Println(\u0026#34;alice tem\u0026#34;, valor, \u0026#34;anos\u0026#34;) } else { fmt.Println(\u0026#34;alice não encontrada\u0026#34;) } Ordem de iteração é aleatória por design:\nm := map[string]int{\u0026#34;c\u0026#34;: 3, \u0026#34;a\u0026#34;: 1, \u0026#34;b\u0026#34;: 2} for k, v := range m { fmt.Println(k, v) // ordem não determinística } // Isso é intencional: evita que código dependa de ordem acidental // Para ordem determinística, ordene as chaves: keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { fmt.Println(k, m[k]) } Maps não são thread-safe. Leituras concorrentes são ok, mas leituras e escritas concorrentes causam panic:\n// PANIC: concurrent map read and map write m := map[string]int{} go func() { m[\u0026#34;a\u0026#34;] = 1 }() go func() { _ = m[\u0026#34;a\u0026#34;] }() // Use sync.Map ou sync.RWMutex para acesso concorrente Internamente, como maps funcionam:\nUm map em Go é implementado como um array de buckets. Cada bucket guarda até 8 pares chave-valor. Quando você acessa uma chave, o hash da chave determina qual bucket verificar. Com muitas colisões ou muitas entradas, os buckets transbordam para buckets extras encadeados. Quando o fator de carga excede ~6.5, o map é redimensionado e todos os elementos são redistribuídos. Esse redimensionamento é incremental para evitar pauses longas.\nConcorrência em Go Esta é a seção mais importante da linguagem. Go foi projetada com concorrência no centro.\nGoroutines Uma goroutine é uma thread leve gerenciada pelo runtime do Go. A analogia comum é: goroutines são para o Go o que threads são para o OS, mas ordens de magnitude mais leves.\n// Iniciar uma goroutine é trivial: keyword go + chamada de função func fazerAlgo() { fmt.Println(\u0026#34;fazendo algo em paralelo\u0026#34;) } func main() { go fazerAlgo() // inicia goroutine - retorna imediatamente // goroutine anônima go func() { fmt.Println(\u0026#34;goroutine anônima\u0026#34;) }() time.Sleep(time.Millisecond) // espera as goroutines (jeito errado) fmt.Println(\u0026#34;fim\u0026#34;) } Por que goroutines são tão baratas?\nUma thread do OS começa com ~1-8MB de stack. Uma goroutine começa com ~2KB de stack. O runtime do Go pode ter centenas de milhares de goroutines ativas ao mesmo tempo.\nA stack de goroutines também é segmentada e dinâmica: ela começa pequena e cresce conforme necessário (até um limite configurável, padrão 1GB). Não há desperdício de memória por goroutines que nunca usam muita stack.\nO Scheduler do Go (M:N Threading) O runtime do Go usa um modelo M:N: M goroutines mapeadas para N threads do OS. Isso é gerenciado pelo scheduler do Go, que implementa o algoritmo GOMAXPROCS.\nModelo M:N do Go: Goroutines (leves, milhares) G1 G2 G3 G4 G5 G6 G7 G8 \\ | / \\ | / \\ | / [ P1 ] [ P2 ] [ P3 ] (fila) (fila) (fila) \\ | / \\ | / [Thread OS] [Thread OS] [Thread OS] (M1) (M2) (M3) Os três componentes principais:\nG (Goroutine): a unidade de concorrência - tem stack, estado, código a executar M (Machine/Thread): thread do OS - executa goroutines P (Processor): contexto de execução - tem uma fila de goroutines prontas para rodar. GOMAXPROCS define quantos P existem (padrão = número de CPUs) O scheduler funciona assim:\nCada P tem uma fila local de goroutines prontas M executa goroutines da fila do seu P Quando uma goroutine faz uma operação bloqueante (I/O, sleep, channel op), ela é suspensa e M pode pegar outra goroutine Se um P fica sem trabalho, ele tenta \u0026ldquo;roubar\u0026rdquo; goroutines de outros P (work stealing) Isso é cooperativo-preemptivo: goroutines cedem voluntariamente em pontos de preempção (function calls, channel ops, etc.), mas o scheduler também pode preemptá-las em pontos seguros desde Go 1.14.\nimport \u0026#34;runtime\u0026#34; func main() { // Quantas CPUs usar (padrão: todas) runtime.GOMAXPROCS(4) // Número de goroutines ativas fmt.Println(runtime.NumGoroutine()) } Channels Channels são o mecanismo de comunicação entre goroutines. O lema do Go:\n\u0026ldquo;Do not communicate by sharing memory; instead, share memory by communicating.\u0026rdquo;\n// Channel unidirecional de ints ch := make(chan int) // Channel bufferizado buffered := make(chan int, 10) // buffer de 10 elementos // Envio (bloqueia se o channel estiver cheio) ch \u0026lt;- 42 // Recebimento (bloqueia se o channel estiver vazio) v := \u0026lt;-ch // Fechar um channel close(ch) // Receber com verificação de fechamento v, ok := \u0026lt;-ch if !ok { fmt.Println(\u0026#34;channel fechado\u0026#34;) } Channel não bufferizado vs bufferizado:\nChannel não bufferizado (make(chan int)): - Envio bloqueia até alguém receber - Recebimento bloqueia até alguém enviar - Sincronização \u0026#34;ponto a ponto\u0026#34; Channel bufferizado (make(chan int, N)): - Envio bloqueia apenas quando buffer está cheio - Recebimento bloqueia apenas quando buffer está vazio - N operações podem acontecer sem sincronização Exemplo prático: producer-consumer\nfunc produtor(ch chan\u0026lt;- int, n int) { // chan\u0026lt;- : channel somente de envio (restrição de tipo) for i := 0; i \u0026lt; n; i++ { ch \u0026lt;- i fmt.Printf(\u0026#34;produziu: %d\\n\u0026#34;, i) } close(ch) // sinaliza que não há mais valores } func consumidor(ch \u0026lt;-chan int, done chan\u0026lt;- bool) { // \u0026lt;-chan : channel somente de recebimento for v := range ch { // range em channel: recebe até o channel fechar fmt.Printf(\u0026#34;consumiu: %d\\n\u0026#34;, v) } done \u0026lt;- true } func main() { ch := make(chan int, 5) // buffer de 5 done := make(chan bool) go produtor(ch, 10) go consumidor(ch, done) \u0026lt;-done // espera consumidor terminar fmt.Println(\u0026#34;pronto\u0026#34;) } select select é para channels o que switch é para valores:\n// select espera em múltiplos channels e executa o primeiro que estiver pronto func multiplosChannels(ch1, ch2 \u0026lt;-chan string) { for { select { case msg1 := \u0026lt;-ch1: fmt.Println(\u0026#34;do ch1:\u0026#34;, msg1) case msg2 := \u0026lt;-ch2: fmt.Println(\u0026#34;do ch2:\u0026#34;, msg2) } } } // select com timeout func comTimeout(ch \u0026lt;-chan int) { select { case v := \u0026lt;-ch: fmt.Println(\u0026#34;recebeu:\u0026#34;, v) case \u0026lt;-time.After(5 * time.Second): fmt.Println(\u0026#34;timeout!\u0026#34;) } } // select com default: não bloqueia func naoBloqueia(ch \u0026lt;-chan int) { select { case v := \u0026lt;-ch: fmt.Println(\u0026#34;recebeu:\u0026#34;, v) default: fmt.Println(\u0026#34;channel vazio, continuando...\u0026#34;) } } Deadlocks Um deadlock ocorre quando todas as goroutines estão bloqueadas esperando umas pelas outras:\n// DEADLOCK clássico func main() { ch := make(chan int) ch \u0026lt;- 42 // bloqueia - ninguém está recebendo! // O runtime detecta isso: \u0026#34;all goroutines are asleep - deadlock!\u0026#34; } // DEADLOCK com dois channels func main() { ch1 := make(chan int) ch2 := make(chan int) go func() { v := \u0026lt;-ch1 // espera ch1 ch2 \u0026lt;- v }() go func() { v := \u0026lt;-ch2 // espera ch2 ch1 \u0026lt;- v // ch2 nunca tem valor porque ch1 está esperando ch2 }() select {} // espera para sempre - deadlock } O runtime Go detecta deadlocks quando todas as goroutines estão dormindo. Mas se uma goroutine está em loop infinito ou há goroutines de sistema rodando (como o servidor HTTP), o runtime não detecta.\nRace Conditions Race condition ocorre quando duas goroutines acessam a mesma memória concorrentemente e ao menos uma está escrevendo:\n// RACE CONDITION clássica contador := 0 var wg sync.WaitGroup for i := 0; i \u0026lt; 1000; i++ { wg.Add(1) go func() { defer wg.Done() contador++ // RACE! Leitura + incremento + escrita não são atômicas }() } wg.Wait() fmt.Println(contador) // Resultado imprevisível: pode ser qualquer número abaixo de 1000 Detecte com o race detector:\ngo run -race main.go # ou go test -race ./... O race detector do Go é extraordinariamente bom - detecta races em tempo de execução adicionando instrumentação. O overhead é ~5-10x de CPU e ~5-10x de memória, mas para testes é essencial.\nMutex import \u0026#34;sync\u0026#34; type ContadorSeguro struct { mu sync.Mutex // protege o campo abaixo valor int } func (c *ContadorSeguro) Incrementar() { c.mu.Lock() // adquire o lock defer c.mu.Unlock() // libera quando a função retornar c.valor++ } func (c *ContadorSeguro) Valor() int { c.mu.Lock() defer c.mu.Unlock() return c.valor } // RWMutex: múltiplas leituras, escrita exclusiva type Cache struct { mu sync.RWMutex data map[string]string } func (c *Cache) Get(key string) (string, bool) { c.mu.RLock() // múltiplos leitores podem entrar simultaneamente defer c.mu.RUnlock() v, ok := c.data[key] return v, ok } func (c *Cache) Set(key, value string) { c.mu.Lock() // escritor tem exclusividade total defer c.mu.Unlock() c.data[key] = value } Convenção importante: o mutex deve ser declarado próximo ao dado que protege. Adicione um comentário indicando o que o mutex protege.\nsync.WaitGroup // WaitGroup: espere N goroutines terminarem var wg sync.WaitGroup for i := 0; i \u0026lt; 10; i++ { wg.Add(1) // incrementa o contador go func(id int) { defer wg.Done() // decrementa quando terminar fmt.Printf(\u0026#34;goroutine %d trabalhando\\n\u0026#34;, id) time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) }(i) } wg.Wait() // bloqueia até contador chegar a 0 fmt.Println(\u0026#34;todas as goroutines terminaram\u0026#34;) Worker Pool Pattern fundamental para limitar concorrência:\n// Worker pool: N workers processando uma fila de tarefas func workerPool(numWorkers int, tarefas \u0026lt;-chan int, resultados chan\u0026lt;- int) { var wg sync.WaitGroup for i := 0; i \u0026lt; numWorkers; i++ { wg.Add(1) go func(workerID int) { defer wg.Done() for tarefa := range tarefas { // recebe até o channel fechar // processa a tarefa resultado := tarefa * tarefa // exemplo: calcula quadrado resultados \u0026lt;- resultado } }(i) } // Quando todos os workers terminarem, fecha o channel de resultados go func() { wg.Wait() close(resultados) }() } func main() { tarefas := make(chan int, 100) resultados := make(chan int, 100) // Inicia o pool com 5 workers workerPool(5, tarefas, resultados) // Envia tarefas go func() { for i := 0; i \u0026lt; 20; i++ { tarefas \u0026lt;- i } close(tarefas) // sinaliza que não há mais tarefas }() // Coleta resultados for r := range resultados { fmt.Println(r) } } Pipeline Pattern de encadeamento de goroutines:\n// Cada estágio do pipeline recebe de um channel e envia para outro // Estágio 1: gera números func gerador(nums ...int) \u0026lt;-chan int { out := make(chan int) go func() { for _, n := range nums { out \u0026lt;- n } close(out) }() return out } // Estágio 2: calcula quadrados func quadrados(in \u0026lt;-chan int) \u0026lt;-chan int { out := make(chan int) go func() { for n := range in { out \u0026lt;- n * n } close(out) }() return out } // Estágio 3: filtra números maiores que N func filtrar(in \u0026lt;-chan int, minimo int) \u0026lt;-chan int { out := make(chan int) go func() { for n := range in { if n \u0026gt; minimo { out \u0026lt;- n } } close(out) }() return out } func main() { // Pipeline: gerar → quadrar → filtrar nums := gerador(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) sq := quadrados(nums) filtered := filtrar(sq, 25) for v := range filtered { fmt.Println(v) // 36, 49, 64, 81, 100 } } Concorrência vs Paralelismo Rob Pike tem uma fala famosa sobre isso: \u0026ldquo;Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once.\u0026rdquo;\nEm Go:\nConcorrência é sobre estrutura: você escreve código com goroutines que podem se intercalar Paralelismo é sobre execução: múltiplas goroutines realmente rodando ao mesmo tempo em CPUs diferentes Com GOMAXPROCS=1, seu código Go é concorrente mas não paralelo (apenas um CPU). Com GOMAXPROCS=8, o scheduler pode executar até 8 goroutines verdadeiramente em paralelo.\nContext Package O pacote context resolve um problema real: como cancelar operações encadeadas de forma limpa.\nImagine: uma requisição HTTP chega. Ela inicia uma query no banco de dados, que inicia uma chamada para um serviço externo. Se o cliente desconectar, você quer cancelar tudo isso. O context.Context propaga esse cancelamento.\nimport \u0026#34;context\u0026#34; // Contexto básico - raiz de todos os contextos ctx := context.Background() // nunca é cancelado, raiz ctx2 := context.TODO() // placeholder - não use em produção // Contexto com cancelamento ctx, cancel := context.WithCancel(context.Background()) defer cancel() // sempre faça isso para liberar recursos // Contexto com timeout ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // Contexto com deadline absoluto deadline := time.Now().Add(30 * time.Second) ctx, cancel := context.WithDeadline(context.Background(), deadline) defer cancel() // Contexto com valor (use com moderação) type chaveUsuario string ctx = context.WithValue(ctx, chaveUsuario(\u0026#34;userID\u0026#34;), 42) userID := ctx.Value(chaveUsuario(\u0026#34;userID\u0026#34;)).(int) Uso em servidores HTTP:\nfunc handler(w http.ResponseWriter, r *http.Request) { // r.Context() já contém o contexto da requisição // É cancelado quando o cliente desconecta ctx := r.Context() resultado, err := buscarDados(ctx, \u0026#34;query\u0026#34;) if err != nil { if errors.Is(err, context.Canceled) { // cliente cancelou - sem log de erro return } http.Error(w, err.Error(), 500) return } // ... } func buscarDados(ctx context.Context, query string) (string, error) { // Cria query no banco respeitando o contexto rows, err := db.QueryContext(ctx, \u0026#34;SELECT ...\u0026#34;, query) if err != nil { return \u0026#34;\u0026#34;, fmt.Errorf(\u0026#34;ao buscar dados: %w\u0026#34;, err) } // ... // Verifica se o contexto foi cancelado antes de continuar select { case \u0026lt;-ctx.Done(): return \u0026#34;\u0026#34;, ctx.Err() default: // continua } // ... } Regras do context:\nSempre passe ctx como primeiro argumento de funções Nunca guarde ctx em structs (passe como argumento) Sempre chame cancel() quando criar um contexto cancelável (geralmente com defer) Use context.WithValue com parcimônia - apenas para dados transversais como request IDs, não para parâmetros funcionais Tratamento de Erros O tratamento de erros em Go é o tópico que mais divide opiniões. Vamos entender o design e as melhores práticas.\nErrors são Valores // A interface error tem apenas um método type error interface { Error() string } // errors.New cria um erro simples import \u0026#34;errors\u0026#34; err := errors.New(\u0026#34;algo deu errado\u0026#34;) // fmt.Errorf cria um erro formatado err2 := fmt.Errorf(\u0026#34;falha ao processar id %d: %w\u0026#34;, 42, err) // %w envolve o erro original (wrapping) - disponível desde Go 1.13 Criando Tipos de Erro Customizados // Erro simples como variável (sentinel error) var ErrNaoEncontrado = errors.New(\u0026#34;não encontrado\u0026#34;) // Tipo de erro rico com contexto type ErroValidacao struct { Campo string Motivo string } func (e *ErroValidacao) Error() string { return fmt.Sprintf(\u0026#34;campo %q inválido: %s\u0026#34;, e.Campo, e.Motivo) } // Uso func validarEmail(email string) error { if !strings.Contains(email, \u0026#34;@\u0026#34;) { return \u0026amp;ErroValidacao{ Campo: \u0026#34;email\u0026#34;, Motivo: \u0026#34;deve conter @\u0026#34;, } } return nil } errors.Is e errors.As Desde Go 1.13, há um sistema de unwrapping de erros:\n// errors.Is: verifica se um erro (ou algum na cadeia) é específico err := fmt.Errorf(\u0026#34;operação falhou: %w\u0026#34;, ErrNaoEncontrado) if errors.Is(err, ErrNaoEncontrado) { fmt.Println(\u0026#34;recurso não encontrado\u0026#34;) // imprime isso } // errors.As: extrai um tipo específico da cadeia de erros var errValidacao *ErroValidacao if errors.As(err, \u0026amp;errValidacao) { fmt.Println(\u0026#34;campo com erro:\u0026#34;, errValidacao.Campo) } O padrão de wrapping:\n// Sempre adicione contexto ao propagar erros func buscarUsuario(id int) (*Usuario, error) { u, err := db.QueryOne(\u0026#34;SELECT ...\u0026#34;, id) if err != nil { // %w \u0026#34;envolve\u0026#34; o erro original return nil, fmt.Errorf(\u0026#34;ao buscar usuário %d: %w\u0026#34;, id, err) } return u, nil } func processarRequisicao(userID int) error { usuario, err := buscarUsuario(userID) if err != nil { return fmt.Errorf(\u0026#34;ao processar requisição: %w\u0026#34;, err) } // ... } // No topo da pilha de chamadas, você tem um contexto rico: // \u0026#34;ao processar requisição: ao buscar usuário 42: sql: no rows in result set\u0026#34; panic e recover panic é para situações verdadeiramente excepcionais - não para controle de fluxo normal:\n// Use panic para: // - Erros de programação (índice fora dos limites, nil pointer que não deveria ser nil) // - Invariantes violados que indicam bug, não condição de erro func assertNaoNulo(v interface{}, msg string) { if v == nil { panic(\u0026#34;invariante violada: \u0026#34; + msg) } } // recover captura um panic em andamento // Só funciona chamado diretamente de um defer func seguro(fn func()) (err error) { defer func() { if r := recover(); r != nil { err = fmt.Errorf(\u0026#34;panic capturado: %v\u0026#34;, r) } }() fn() return nil } // Servidores HTTP da stdlib já fazem recover em cada handler // para que um panic num handler não derrube o servidor inteiro Regra prática: se você se encontra usando panic para controle de fluxo, algo está errado no design. Erros previsíveis (usuário não encontrado, conexão falhou, input inválido) devem ser retornados como error. Panics são para condições que nunca deveriam acontecer em produção.\nPadrão de Tratamento Idiomático // Padrão mais comum: tratar erro imediatamente func processarArquivo(caminho string) error { f, err := os.Open(caminho) if err != nil { return fmt.Errorf(\u0026#34;ao abrir arquivo: %w\u0026#34;, err) } defer f.Close() scanner := bufio.NewScanner(f) for scanner.Scan() { linha := scanner.Text() if err := processarLinha(linha); err != nil { return fmt.Errorf(\u0026#34;ao processar linha %q: %w\u0026#34;, linha, err) } } if err := scanner.Err(); err != nil { return fmt.Errorf(\u0026#34;ao ler arquivo: %w\u0026#34;, err) } return nil } Parece verboso comparado ao try/catch de Java. Mas cada tratamento de erro é explícito - você sabe exatamente o que pode falhar em cada ponto. Não há \u0026ldquo;surpresas\u0026rdquo; de exceções pulando várias camadas.\nOrganização de Projetos go mod Go Modules são o sistema de gerenciamento de dependências desde Go 1.11 (estável em Go 1.16):\n# Inicializa um módulo go mod init github.com/seunome/meumodulo # go.mod criado: # module github.com/seunome/meumodulo # # go 1.22 # Adiciona uma dependência go get github.com/gin-gonic/gin@v1.9.0 # Atualiza todas as dependências para versões menores/patches go get -u ./... # Remove dependências não usadas, adiciona faltantes go mod tidy # go.sum: arquivo de verificação de integridade # Não edite manualmente - é gerenciado automaticamente go.mod e go.sum:\n# go.mod - define o módulo e suas dependências module github.com/seunome/servidor go 1.22 require ( github.com/gin-gonic/gin v1.9.1 github.com/jackc/pgx/v5 v5.5.0 ) # go.sum - checksums criptográficos de cada dependência # Garante reprodutibilidade: mesma build em qualquer máquina Estrutura de Projeto Moderna Não existe uma estrutura oficial obrigatória, mas a comunidade convergiu para alguns padrões:\nmeu-projeto/ ├── cmd/ # pontos de entrada (binários) │ ├── api/ │ │ └── main.go # servidor API │ └── worker/ │ └── main.go # worker de background ├── internal/ # código privado - não importável por módulos externos │ ├── domain/ # entidades e regras de negócio │ │ ├── usuario.go │ │ └── pedido.go │ ├── repository/ # acesso a dados │ │ ├── usuario_repo.go │ │ └── pedido_repo.go │ ├── service/ # lógica de aplicação │ │ ├── usuario_service.go │ │ └── pedido_service.go │ └── handler/ # HTTP handlers │ ├── usuario_handler.go │ └── middleware.go ├── pkg/ # código público reutilizável (use com cautela) │ └── validator/ │ └── validator.go ├── migrations/ # migrations de banco de dados ├── scripts/ # scripts de build, deploy ├── configs/ # arquivos de configuração ├── go.mod ├── go.sum ├── Makefile └── README.md Por que internal? O diretório internal tem semântica especial no Go: apenas código no módulo pai pode importar pacotes dentro de internal. Isso cria uma fronteira forte: internal/repository só pode ser usado por código dentro de meu-projeto, nunca por dependentes externos.\ncmd/ é para binários: cada subdiretório de cmd/ tem seu próprio main.go e produz um binário separado. Um projeto pode ter múltiplos binários: a API, um worker, uma ferramenta de CLI.\nJSON e APIs encoding/json O pacote encoding/json da stdlib é poderoso e bem projetado:\nimport \u0026#34;encoding/json\u0026#34; type Usuario struct { ID int `json:\u0026#34;id\u0026#34;` Nome string `json:\u0026#34;nome\u0026#34;` Email string `json:\u0026#34;email\u0026#34;` Senha string `json:\u0026#34;-\u0026#34;` // ignora este campo Ativo bool `json:\u0026#34;ativo,omitempty\u0026#34;` // omite se false (zero value) Dados *Extra `json:\u0026#34;dados,omitempty\u0026#34;` // omite se nil } type Extra struct { Preferencias []string `json:\u0026#34;preferencias\u0026#34;` } // Serialização (struct → JSON) u := Usuario{ID: 1, Nome: \u0026#34;Alice\u0026#34;, Email: \u0026#34;alice@ex.com\u0026#34;, Ativo: true} data, err := json.Marshal(u) // {\u0026#34;id\u0026#34;:1,\u0026#34;nome\u0026#34;:\u0026#34;Alice\u0026#34;,\u0026#34;email\u0026#34;:\u0026#34;alice@ex.com\u0026#34;,\u0026#34;ativo\u0026#34;:true} // Com indentação (útil para debug e APIs) data, err = json.MarshalIndent(u, \u0026#34;\u0026#34;, \u0026#34; \u0026#34;) // Desserialização (JSON → struct) jsonStr := `{\u0026#34;id\u0026#34;:2,\u0026#34;nome\u0026#34;:\u0026#34;Bob\u0026#34;,\u0026#34;email\u0026#34;:\u0026#34;bob@ex.com\u0026#34;}` var u2 Usuario err = json.Unmarshal([]byte(jsonStr), \u0026amp;u2) Usando json.Decoder para streams (HTTP):\n// Melhor para HTTP requests - evita ler tudo na memória func decodificarRequisicao(r *http.Request, destino interface{}) error { decoder := json.NewDecoder(r.Body) decoder.DisallowUnknownFields() // rejeita campos desconhecidos return decoder.Decode(destino) } Servidor HTTP package main import ( \u0026#34;encoding/json\u0026#34; \u0026#34;log\u0026#34; \u0026#34;net/http\u0026#34; ) type Resposta struct { Status string `json:\u0026#34;status\u0026#34;` Mensagem string `json:\u0026#34;mensagem\u0026#34;` } // Handler básico func healthHandler(w http.ResponseWriter, r *http.Request) { // Configura headers antes de escrever o body w.Header().Set(\u0026#34;Content-Type\u0026#34;, \u0026#34;application/json\u0026#34;) w.WriteHeader(http.StatusOK) resp := Resposta{Status: \u0026#34;ok\u0026#34;, Mensagem: \u0026#34;servidor funcionando\u0026#34;} json.NewEncoder(w).Encode(resp) } // Handler com contexto e logging func criarUsuarioHandler(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, \u0026#34;método não permitido\u0026#34;, http.StatusMethodNotAllowed) return } var usuario UsuarioInput if err := json.NewDecoder(r.Body).Decode(\u0026amp;usuario); err != nil { http.Error(w, \u0026#34;body inválido\u0026#34;, http.StatusBadRequest) return } // ... processa ... w.Header().Set(\u0026#34;Content-Type\u0026#34;, \u0026#34;application/json\u0026#34;) w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(usuario) } func main() { mux := http.NewServeMux() mux.HandleFunc(\u0026#34;/health\u0026#34;, healthHandler) mux.HandleFunc(\u0026#34;/usuarios\u0026#34;, criarUsuarioHandler) servidor := \u0026amp;http.Server{ Addr: \u0026#34;:8080\u0026#34;, Handler: mux, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 60 * time.Second, } log.Println(\u0026#34;servidor iniciando em :8080\u0026#34;) if err := servidor.ListenAndServe(); err != nil \u0026amp;\u0026amp; err != http.ErrServerClosed { log.Fatal(err) } } Middleware // Middleware é uma função que envolve um handler type Middleware func(http.Handler) http.Handler // Logger middleware func loggerMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { inicio := time.Now() // Chama o próximo handler next.ServeHTTP(w, r) log.Printf(\u0026#34;%s %s %v\u0026#34;, r.Method, r.URL.Path, time.Since(inicio)) }) } // Auth middleware func authMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { token := r.Header.Get(\u0026#34;Authorization\u0026#34;) if token == \u0026#34;\u0026#34; { http.Error(w, \u0026#34;não autorizado\u0026#34;, http.StatusUnauthorized) return } // valida token... next.ServeHTTP(w, r) }) } // Encadeando middlewares func encadear(handler http.Handler, middlewares ...Middleware) http.Handler { for i := len(middlewares) - 1; i \u0026gt;= 0; i-- { handler = middlewares[i](handler) } return handler } func main() { mux := http.NewServeMux() mux.HandleFunc(\u0026#34;/api/usuarios\u0026#34;, criarUsuarioHandler) // Aplica middlewares: logger → auth → handler handler := encadear(mux, loggerMiddleware, authMiddleware) http.ListenAndServe(\u0026#34;:8080\u0026#34;, handler) } Banco de Dados database/sql A interface database/sql é uma abstração que funciona com qualquer driver:\nimport ( \u0026#34;database/sql\u0026#34; _ \u0026#34;github.com/lib/pq\u0026#34; // driver PostgreSQL - side-effects import ) func conectar() (*sql.DB, error) { dsn := \u0026#34;postgres://user:pass@localhost/meubanco?sslmode=disable\u0026#34; db, err := sql.Open(\u0026#34;postgres\u0026#34;, dsn) if err != nil { return nil, fmt.Errorf(\u0026#34;ao abrir conexão: %w\u0026#34;, err) } // Configurações do pool de conexões db.SetMaxOpenConns(25) // máximo de conexões abertas db.SetMaxIdleConns(10) // máximo de conexões idle db.SetConnMaxLifetime(5 * time.Minute) // tempo máximo de uma conexão // Verifica a conexão if err := db.Ping(); err != nil { return nil, fmt.Errorf(\u0026#34;ao pingar banco: %w\u0026#34;, err) } return db, nil } CRUD básico:\n// INSERT func criarUsuario(db *sql.DB, ctx context.Context, u *Usuario) error { query := `INSERT INTO usuarios (nome, email) VALUES ($1, $2) RETURNING id` return db.QueryRowContext(ctx, query, u.Nome, u.Email).Scan(\u0026amp;u.ID) } // SELECT func buscarUsuario(db *sql.DB, ctx context.Context, id int) (*Usuario, error) { query := `SELECT id, nome, email FROM usuarios WHERE id = $1` u := \u0026amp;Usuario{} err := db.QueryRowContext(ctx, query, id).Scan(\u0026amp;u.ID, \u0026amp;u.Nome, \u0026amp;u.Email) if errors.Is(err, sql.ErrNoRows) { return nil, ErrNaoEncontrado } if err != nil { return nil, fmt.Errorf(\u0026#34;ao buscar usuário: %w\u0026#34;, err) } return u, nil } // SELECT múltiplos func listarUsuarios(db *sql.DB, ctx context.Context) ([]*Usuario, error) { query := `SELECT id, nome, email FROM usuarios ORDER BY nome` rows, err := db.QueryContext(ctx, query) if err != nil { return nil, fmt.Errorf(\u0026#34;ao listar usuários: %w\u0026#34;, err) } defer rows.Close() // SEMPRE feche rows var usuarios []*Usuario for rows.Next() { u := \u0026amp;Usuario{} if err := rows.Scan(\u0026amp;u.ID, \u0026amp;u.Nome, \u0026amp;u.Email); err != nil { return nil, fmt.Errorf(\u0026#34;ao escanear usuário: %w\u0026#34;, err) } usuarios = append(usuarios, u) } // Verifica erros de iteração if err := rows.Err(); err != nil { return nil, fmt.Errorf(\u0026#34;ao iterar usuários: %w\u0026#34;, err) } return usuarios, nil } Transações:\nfunc transferir(db *sql.DB, ctx context.Context, deID, paraID int, valor float64) error { tx, err := db.BeginTx(ctx, nil) if err != nil { return fmt.Errorf(\u0026#34;ao iniciar transação: %w\u0026#34;, err) } defer func() { if err != nil { tx.Rollback() // rollback em erro } }() // Debita _, err = tx.ExecContext(ctx, `UPDATE contas SET saldo = saldo - $1 WHERE id = $2 AND saldo \u0026gt;= $1`, valor, deID) if err != nil { return fmt.Errorf(\u0026#34;ao debitar: %w\u0026#34;, err) } // Credita _, err = tx.ExecContext(ctx, `UPDATE contas SET saldo = saldo + $1 WHERE id = $2`, valor, paraID) if err != nil { return fmt.Errorf(\u0026#34;ao creditar: %w\u0026#34;, err) } // Commit if err = tx.Commit(); err != nil { return fmt.Errorf(\u0026#34;ao commitar transação: %w\u0026#34;, err) } return nil } ORMs vs SQL Puro A comunidade Go é mais dividida nessa questão do que em outras linguagens. Os prós e contras reais:\nSQL puro com database/sql ou sqlx:\nControle total da query Fácil de otimizar Erros claros de banco de dados Nenhuma mágica implícita Mais verboso ORMs como GORM:\nProdutividade inicial maior Queries geradas podem ser ineficientes Migrations automáticas (útil, perigoso em produção) Abstrai detalhes importantes Community love/hate intenso sqlc (abordagem moderna): você escreve SQL, ele gera código Go tipado. O melhor dos dois mundos para muitos casos.\nTesting Unit Tests // usuario_test.go - mesmo pacote para testar internos // ou usuario_test.go com package usuario_test para teste externo package usuario import \u0026#34;testing\u0026#34; func TestValidarEmail(t *testing.T) { err := ValidarEmail(\u0026#34;alice@exemplo.com\u0026#34;) if err != nil { t.Errorf(\u0026#34;esperava nil, obteve %v\u0026#34;, err) } err = ValidarEmail(\u0026#34;invalido\u0026#34;) if err == nil { t.Error(\u0026#34;esperava erro para email inválido\u0026#34;) } } // Rodar: go test ./... // Com verbose: go test -v ./... // Test específico: go test -run TestValidarEmail ./... Table Driven Tests O padrão mais idiomático para testes em Go:\nfunc TestValidarEmail(t *testing.T) { casos := []struct { nome string email string erro bool }{ {\u0026#34;email válido\u0026#34;, \u0026#34;alice@ex.com\u0026#34;, false}, {\u0026#34;sem arroba\u0026#34;, \u0026#34;invalido\u0026#34;, true}, {\u0026#34;sem domínio\u0026#34;, \u0026#34;alice@\u0026#34;, true}, {\u0026#34;vazio\u0026#34;, \u0026#34;\u0026#34;, true}, {\u0026#34;com subdomínio\u0026#34;, \u0026#34;a@sub.ex.com\u0026#34;, false}, } for _, c := range casos { // t.Run cria um sub-teste - é a forma correta t.Run(c.nome, func(t *testing.T) { err := ValidarEmail(c.email) if c.erro \u0026amp;\u0026amp; err == nil { t.Errorf(\u0026#34;esperava erro para %q, obteve nil\u0026#34;, c.email) } if !c.erro \u0026amp;\u0026amp; err != nil { t.Errorf(\u0026#34;não esperava erro para %q, obteve %v\u0026#34;, c.email, err) } }) } } Testando com Interfaces (Mocks) A forma idiomática de mockar em Go é via interfaces, não frameworks de mock complexos:\n// Interface do repositório type RepositorioUsuario interface { Buscar(id int) (*Usuario, error) Criar(u *Usuario) error } // Service que depende da interface type UsuarioService struct { repo RepositorioUsuario } // Mock para testes type mockRepositorio struct { usuarios map[int]*Usuario } func (m *mockRepositorio) Buscar(id int) (*Usuario, error) { if u, ok := m.usuarios[id]; ok { return u, nil } return nil, ErrNaoEncontrado } func (m *mockRepositorio) Criar(u *Usuario) error { m.usuarios[u.ID] = u return nil } // Teste usando o mock func TestBuscarUsuario(t *testing.T) { mock := \u0026amp;mockRepositorio{ usuarios: map[int]*Usuario{ 1: {ID: 1, Nome: \u0026#34;Alice\u0026#34;}, }, } svc := \u0026amp;UsuarioService{repo: mock} usuario, err := svc.Buscar(1) if err != nil { t.Fatal(err) } if usuario.Nome != \u0026#34;Alice\u0026#34; { t.Errorf(\u0026#34;esperava Alice, obteve %s\u0026#34;, usuario.Nome) } } Benchmarks // Benchmark: nome deve começar com Benchmark func BenchmarkValidarEmail(b *testing.B) { // b.N é definido automaticamente para produzir resultados estáveis for i := 0; i \u0026lt; b.N; i++ { ValidarEmail(\u0026#34;alice@exemplo.com\u0026#34;) } } // Rodar: go test -bench=. -benchmem ./... // Output: // BenchmarkValidarEmail-8 5000000 230 ns/op 48 B/op 2 allocs/op // ^número ^tempo ^memória ^alocações por op -benchmem é essencial: mostra quantas alocações de heap acontecem por operação. Reduzir alocações é frequentemente a forma mais eficaz de melhorar performance em Go.\nProfiling com pprof import _ \u0026#34;net/http/pprof\u0026#34; // ativa endpoints de pprof func main() { // Endpoint de profiling disponível em /debug/pprof/ go http.ListenAndServe(\u0026#34;:6060\u0026#34;, nil) // ... resto do servidor ... } # CPU profiling: 30 segundos go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30 # Memory profiling go tool pprof http://localhost:6060/debug/pprof/heap # Goroutine profiling go tool pprof http://localhost:6060/debug/pprof/goroutine # Dentro do pprof interativo: (pprof) top10 # top 10 funções por consumo (pprof) web # abre visualização gráfica no browser (pprof) list NomeDaFuncao # detalha função específica Para visualização interativa, você precisa do Graphviz instalado. O comando web abre um grafo de call stack com cores indicando onde o tempo é gasto.\nPerformance em Go Entendendo Alocações O custo de alocação no heap não é apenas o malloc. É:\nO tempo da alocação em si O trabalho do GC para eventualmente coletar Pressão de cache: objetos no heap são espalhados na memória // Ruim: aloca em todo loop func processar(items []string) []string { var resultados []string // alocação de slice nil for _, item := range items { resultados = append(resultados, transformar(item)) // possível realocação } return resultados } // Melhor: pré-aloca func processar(items []string) []string { resultados := make([]string, 0, len(items)) // tamanho final conhecido for _, item := range items { resultados = append(resultados, transformar(item)) } return resultados } sync.Pool Para objetos frequentemente alocados e descartados (buffers, parsers, etc.):\nvar bufferPool = sync.Pool{ New: func() interface{} { return new(bytes.Buffer) }, } func processarRequisicao(data []byte) []byte { // Pega um buffer do pool (ou cria novo se pool estiver vazio) buf := bufferPool.Get().(*bytes.Buffer) buf.Reset() // limpa o buffer antes de usar defer bufferPool.Put(buf) // devolve ao pool quando terminar // Usa o buffer sem alocar buf.Write(data) // ... return buf.Bytes() } sync.Pool é limpo pelo GC entre cada ciclo, então não é adequado para cache de longa duração - apenas para reduzir pressão de alocação em código de alta frequência.\nStrings e []byte // RUIM: muitas alocações de string por concatenação func construirURL(partes []string) string { resultado := \u0026#34;\u0026#34; for _, p := range partes { resultado += p // nova alocação a cada iteração } return resultado } // MELHOR: strings.Builder não aloca por concatenação func construirURL(partes []string) string { var sb strings.Builder for _, p := range partes { sb.WriteString(p) } return sb.String() // uma única alocação no final } // AINDA MELHOR quando as partes são conhecidas: return strings.Join(partes, \u0026#34;\u0026#34;) Otimizações Idiomáticas // Usar structs em slices, não ponteiros, quando possível // (locality de memória - CPU cache) // Ruim para dados grandes e sparse, bom para dados pequenos e densos: type PontoRuim struct{ X, Y float64 } pontosRuim := []*PontoRuim{...} // ponteiros espalhados no heap type Ponto struct{ X, Y float64 } pontos := []Ponto{...} // dados contíguos - melhor cache locality // Pré-computar comprimentos em loops // (o compilador já faz isso, mas é boa prática) n := len(slice) for i := 0; i \u0026lt; n; i++ { ... } // Usar io.Writer ao invés de acumular strings // (especialmente para HTTP handlers) func renderizar(w io.Writer, dados Dados) error { return template.Execute(w, dados) // escreve diretamente no ResponseWriter } Padrões Idiomáticos Functional Options Pattern para configuração de structs complexas:\ntype Servidor struct { host string porta int timeout time.Duration maxConn int } // Opção é uma função que modifica o servidor type OpcaoServidor func(*Servidor) func ComHost(host string) OpcaoServidor { return func(s *Servidor) { s.host = host } } func ComPorta(porta int) OpcaoServidor { return func(s *Servidor) { s.porta = porta } } func ComTimeout(t time.Duration) OpcaoServidor { return func(s *Servidor) { s.timeout = t } } func NovoServidor(opcoes ...OpcaoServidor) *Servidor { s := \u0026amp;Servidor{ host: \u0026#34;localhost\u0026#34;, // defaults porta: 8080, timeout: 30 * time.Second, maxConn: 100, } for _, opt := range opcoes { opt(s) } return s } // Uso limpo e extensível s := NovoServidor( ComHost(\u0026#34;0.0.0.0\u0026#34;), ComPorta(9090), ComTimeout(60 * time.Second), ) Este padrão é usado amplamente na stdlib do Go e em bibliotecas populares como grpc-go.\nRepository Pattern // Interface define o contrato type RepositorioUsuario interface { Criar(ctx context.Context, u *Usuario) error Buscar(ctx context.Context, id int) (*Usuario, error) Listar(ctx context.Context, filtro Filtro) ([]*Usuario, error) Atualizar(ctx context.Context, u *Usuario) error Deletar(ctx context.Context, id int) error } // Implementação PostgreSQL type postgresUsuarioRepo struct { db *sql.DB } func NovoPostgresUsuarioRepo(db *sql.DB) RepositorioUsuario { return \u0026amp;postgresUsuarioRepo{db: db} } func (r *postgresUsuarioRepo) Buscar(ctx context.Context, id int) (*Usuario, error) { // implementação... } // Service depende da interface, não da implementação type UsuarioService struct { repo RepositorioUsuario log *slog.Logger } func NovoUsuarioService(repo RepositorioUsuario, log *slog.Logger) *UsuarioService { return \u0026amp;UsuarioService{repo: repo, log: log} } Graceful Shutdown Todo servidor de produção precisa de graceful shutdown:\nfunc main() { srv := \u0026amp;http.Server{Addr: \u0026#34;:8080\u0026#34;} // Inicia servidor em goroutine go func() { if err := srv.ListenAndServe(); err != http.ErrServerClosed { log.Fatal(err) } }() // Espera sinal de término (SIGTERM para Kubernetes, SIGINT para Ctrl+C) quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) \u0026lt;-quit log.Println(\u0026#34;desligando servidor...\u0026#34;) // Dá 30 segundos para requests em andamento terminarem ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Fatal(\u0026#34;erro no shutdown:\u0026#34;, err) } log.Println(\u0026#34;servidor parado\u0026#34;) } Projeto Real Completo Vamos construir uma API REST para gerenciamento de tarefas com todos os conceitos aplicados.\nEstrutura todo-api/ ├── cmd/api/main.go ├── internal/ │ ├── domain/tarefa.go │ ├── repository/tarefa_repo.go │ ├── service/tarefa_service.go │ └── handler/tarefa_handler.go ├── go.mod └── Makefile domain/tarefa.go package domain import ( \u0026#34;errors\u0026#34; \u0026#34;time\u0026#34; ) var ( ErrNaoEncontrado = errors.New(\u0026#34;não encontrado\u0026#34;) ErrTituloVazio = errors.New(\u0026#34;título não pode ser vazio\u0026#34;) ) // Status da tarefa - tipo com validação implícita via constantes type Status string const ( StatusPendente Status = \u0026#34;pendente\u0026#34; StatusEmAndamento Status = \u0026#34;em_andamento\u0026#34; StatusConcluida Status = \u0026#34;concluida\u0026#34; ) // Tarefa é a entidade central do domínio type Tarefa struct { ID int `json:\u0026#34;id\u0026#34;` Titulo string `json:\u0026#34;titulo\u0026#34;` Descricao string `json:\u0026#34;descricao\u0026#34;` Status Status `json:\u0026#34;status\u0026#34;` CriadoEm time.Time `json:\u0026#34;criado_em\u0026#34;` } // Validate verifica invariantes de negócio func (t *Tarefa) Validar() error { if t.Titulo == \u0026#34;\u0026#34; { return ErrTituloVazio } return nil } // Nova cria uma tarefa com defaults corretos func Nova(titulo, descricao string) (*Tarefa, error) { t := \u0026amp;Tarefa{ Titulo: titulo, Descricao: descricao, Status: StatusPendente, CriadoEm: time.Now(), } if err := t.Validar(); err != nil { return nil, err } return t, nil } repository/tarefa_repo.go package repository import ( \u0026#34;context\u0026#34; \u0026#34;sync\u0026#34; \u0026#34;sync/atomic\u0026#34; \u0026#34;github.com/seunome/todo/internal/domain\u0026#34; ) // Interface - define o contrato, não a implementação type TarefaRepository interface { Criar(ctx context.Context, t *domain.Tarefa) error Buscar(ctx context.Context, id int) (*domain.Tarefa, error) Listar(ctx context.Context) ([]*domain.Tarefa, error) Atualizar(ctx context.Context, t *domain.Tarefa) error Deletar(ctx context.Context, id int) error } // InMemory: implementação em memória para desenvolvimento e testes type inMemoryRepo struct { mu sync.RWMutex tarefas map[int]*domain.Tarefa nextID atomic.Int64 } func NovoInMemoryRepo() TarefaRepository { return \u0026amp;inMemoryRepo{ tarefas: make(map[int]*domain.Tarefa), } } func (r *inMemoryRepo) Criar(ctx context.Context, t *domain.Tarefa) error { r.mu.Lock() defer r.mu.Unlock() t.ID = int(r.nextID.Add(1)) // Guarda uma cópia para evitar que o chamador modifique depois copia := *t r.tarefas[t.ID] = \u0026amp;copia return nil } func (r *inMemoryRepo) Buscar(ctx context.Context, id int) (*domain.Tarefa, error) { r.mu.RLock() defer r.mu.RUnlock() t, ok := r.tarefas[id] if !ok { return nil, domain.ErrNaoEncontrado } // Retorna cópia - imutabilidade copia := *t return \u0026amp;copia, nil } func (r *inMemoryRepo) Listar(ctx context.Context) ([]*domain.Tarefa, error) { r.mu.RLock() defer r.mu.RUnlock() tarefas := make([]*domain.Tarefa, 0, len(r.tarefas)) for _, t := range r.tarefas { copia := *t tarefas = append(tarefas, \u0026amp;copia) } return tarefas, nil } func (r *inMemoryRepo) Atualizar(ctx context.Context, t *domain.Tarefa) error { r.mu.Lock() defer r.mu.Unlock() if _, ok := r.tarefas[t.ID]; !ok { return domain.ErrNaoEncontrado } copia := *t r.tarefas[t.ID] = \u0026amp;copia return nil } func (r *inMemoryRepo) Deletar(ctx context.Context, id int) error { r.mu.Lock() defer r.mu.Unlock() if _, ok := r.tarefas[id]; !ok { return domain.ErrNaoEncontrado } delete(r.tarefas, id) return nil } service/tarefa_service.go package service import ( \u0026#34;context\u0026#34; \u0026#34;fmt\u0026#34; \u0026#34;log/slog\u0026#34; \u0026#34;github.com/seunome/todo/internal/domain\u0026#34; \u0026#34;github.com/seunome/todo/internal/repository\u0026#34; ) type TarefaService struct { repo repository.TarefaRepository log *slog.Logger } func NovoTarefaService(repo repository.TarefaRepository, log *slog.Logger) *TarefaService { return \u0026amp;TarefaService{repo: repo, log: log} } func (s *TarefaService) Criar(ctx context.Context, titulo, descricao string) (*domain.Tarefa, error) { tarefa, err := domain.Nova(titulo, descricao) if err != nil { return nil, fmt.Errorf(\u0026#34;ao criar tarefa: %w\u0026#34;, err) } if err := s.repo.Criar(ctx, tarefa); err != nil { return nil, fmt.Errorf(\u0026#34;ao salvar tarefa: %w\u0026#34;, err) } s.log.InfoContext(ctx, \u0026#34;tarefa criada\u0026#34;, \u0026#34;id\u0026#34;, tarefa.ID, \u0026#34;titulo\u0026#34;, tarefa.Titulo) return tarefa, nil } func (s *TarefaService) Concluir(ctx context.Context, id int) error { tarefa, err := s.repo.Buscar(ctx, id) if err != nil { return fmt.Errorf(\u0026#34;ao buscar tarefa: %w\u0026#34;, err) } tarefa.Status = domain.StatusConcluida if err := s.repo.Atualizar(ctx, tarefa); err != nil { return fmt.Errorf(\u0026#34;ao atualizar tarefa: %w\u0026#34;, err) } s.log.InfoContext(ctx, \u0026#34;tarefa concluída\u0026#34;, \u0026#34;id\u0026#34;, id) return nil } func (s *TarefaService) Listar(ctx context.Context) ([]*domain.Tarefa, error) { return s.repo.Listar(ctx) } handler/tarefa_handler.go package handler import ( \u0026#34;encoding/json\u0026#34; \u0026#34;errors\u0026#34; \u0026#34;log/slog\u0026#34; \u0026#34;net/http\u0026#34; \u0026#34;strconv\u0026#34; \u0026#34;strings\u0026#34; \u0026#34;github.com/seunome/todo/internal/domain\u0026#34; \u0026#34;github.com/seunome/todo/internal/service\u0026#34; ) type TarefaHandler struct { svc *service.TarefaService log *slog.Logger } func NovoTarefaHandler(svc *service.TarefaService, log *slog.Logger) *TarefaHandler { return \u0026amp;TarefaHandler{svc: svc, log: log} } // Registra todas as rotas func (h *TarefaHandler) Registrar(mux *http.ServeMux) { mux.HandleFunc(\u0026#34;/tarefas\u0026#34;, h.handleTarefas) mux.HandleFunc(\u0026#34;/tarefas/\u0026#34;, h.handleTarefa) // com / } func (h *TarefaHandler) handleTarefas(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: h.listar(w, r) case http.MethodPost: h.criar(w, r) default: http.Error(w, \u0026#34;método não permitido\u0026#34;, http.StatusMethodNotAllowed) } } func (h *TarefaHandler) handleTarefa(w http.ResponseWriter, r *http.Request) { // Extrai ID da URL: /tarefas/42 idStr := strings.TrimPrefix(r.URL.Path, \u0026#34;/tarefas/\u0026#34;) id, err := strconv.Atoi(idStr) if err != nil { http.Error(w, \u0026#34;ID inválido\u0026#34;, http.StatusBadRequest) return } switch r.Method { case http.MethodPut: h.concluir(w, r, id) case http.MethodDelete: h.deletar(w, r, id) default: http.Error(w, \u0026#34;método não permitido\u0026#34;, http.StatusMethodNotAllowed) } } func (h *TarefaHandler) criar(w http.ResponseWriter, r *http.Request) { var input struct { Titulo string `json:\u0026#34;titulo\u0026#34;` Descricao string `json:\u0026#34;descricao\u0026#34;` } if err := json.NewDecoder(r.Body).Decode(\u0026amp;input); err != nil { h.erroJSON(w, \u0026#34;corpo inválido\u0026#34;, http.StatusBadRequest) return } tarefa, err := h.svc.Criar(r.Context(), input.Titulo, input.Descricao) if err != nil { if errors.Is(err, domain.ErrTituloVazio) { h.erroJSON(w, err.Error(), http.StatusBadRequest) return } h.log.ErrorContext(r.Context(), \u0026#34;erro ao criar tarefa\u0026#34;, \u0026#34;erro\u0026#34;, err) h.erroJSON(w, \u0026#34;erro interno\u0026#34;, http.StatusInternalServerError) return } h.respondJSON(w, tarefa, http.StatusCreated) } func (h *TarefaHandler) listar(w http.ResponseWriter, r *http.Request) { tarefas, err := h.svc.Listar(r.Context()) if err != nil { h.log.ErrorContext(r.Context(), \u0026#34;erro ao listar\u0026#34;, \u0026#34;erro\u0026#34;, err) h.erroJSON(w, \u0026#34;erro interno\u0026#34;, http.StatusInternalServerError) return } h.respondJSON(w, tarefas, http.StatusOK) } func (h *TarefaHandler) concluir(w http.ResponseWriter, r *http.Request, id int) { if err := h.svc.Concluir(r.Context(), id); err != nil { if errors.Is(err, domain.ErrNaoEncontrado) { h.erroJSON(w, \u0026#34;tarefa não encontrada\u0026#34;, http.StatusNotFound) return } h.log.ErrorContext(r.Context(), \u0026#34;erro ao concluir\u0026#34;, \u0026#34;erro\u0026#34;, err) h.erroJSON(w, \u0026#34;erro interno\u0026#34;, http.StatusInternalServerError) return } w.WriteHeader(http.StatusNoContent) } func (h *TarefaHandler) deletar(w http.ResponseWriter, r *http.Request, id int) { // ... similar ao concluir ... w.WriteHeader(http.StatusNoContent) } func (h *TarefaHandler) respondJSON(w http.ResponseWriter, data interface{}, status int) { w.Header().Set(\u0026#34;Content-Type\u0026#34;, \u0026#34;application/json\u0026#34;) w.WriteHeader(status) json.NewEncoder(w).Encode(data) } func (h *TarefaHandler) erroJSON(w http.ResponseWriter, mensagem string, status int) { h.respondJSON(w, map[string]string{\u0026#34;erro\u0026#34;: mensagem}, status) } cmd/api/main.go package main import ( \u0026#34;context\u0026#34; \u0026#34;log/slog\u0026#34; \u0026#34;net/http\u0026#34; \u0026#34;os\u0026#34; \u0026#34;os/signal\u0026#34; \u0026#34;syscall\u0026#34; \u0026#34;time\u0026#34; \u0026#34;github.com/seunome/todo/internal/handler\u0026#34; \u0026#34;github.com/seunome/todo/internal/repository\u0026#34; \u0026#34;github.com/seunome/todo/internal/service\u0026#34; ) func main() { // Logger estruturado (Go 1.21+) log := slog.New(slog.NewJSONHandler(os.Stdout, nil)) // Wiring: injeção de dependências manual repo := repository.NovoInMemoryRepo() svc := service.NovoTarefaService(repo, log) h := handler.NovoTarefaHandler(svc, log) mux := http.NewServeMux() h.Registrar(mux) // Middleware de logging handler := loggingMiddleware(log, mux) srv := \u0026amp;http.Server{ Addr: \u0026#34;:8080\u0026#34;, Handler: handler, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, } // Inicia servidor go func() { log.Info(\u0026#34;servidor iniciado\u0026#34;, \u0026#34;addr\u0026#34;, srv.Addr) if err := srv.ListenAndServe(); err != http.ErrServerClosed { log.Error(\u0026#34;erro no servidor\u0026#34;, \u0026#34;erro\u0026#34;, err) os.Exit(1) } }() // Graceful shutdown quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) \u0026lt;-quit log.Info(\u0026#34;desligando servidor...\u0026#34;) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Error(\u0026#34;erro no shutdown\u0026#34;, \u0026#34;erro\u0026#34;, err) } log.Info(\u0026#34;servidor parado\u0026#34;) } func loggingMiddleware(log *slog.Logger, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { inicio := time.Now() next.ServeHTTP(w, r) log.Info(\u0026#34;requisição\u0026#34;, \u0026#34;method\u0026#34;, r.Method, \u0026#34;path\u0026#34;, r.URL.Path, \u0026#34;duracao\u0026#34;, time.Since(inicio), ) }) } Bastidores do Runtime Go Goroutines Internamente Uma goroutine é representada no runtime pela struct g (em runtime/runtime2.go). Os campos relevantes incluem:\nstack: os limites inferior e superior da stack atual stackguard0: ponteiro para detecção de overflow de stack _panic: lista de defers ativos sched: contexto salvo do scheduler (registradores de CPU quando a goroutine é suspensa) atomicstatus: estado atual (rodando, esperando, morta, etc.) Stack growth: quando uma goroutine está prestes a ultrapassar sua stack atual, o runtime:\nAloca uma nova stack maior (geralmente 2x) Copia toda a stack atual para a nova Atualiza todos os ponteiros que apontavam para endereços na stack antiga Retoma a execução na nova stack Isso é transparente para o programador mas tem um custo. O step 3 (atualizar ponteiros) é o \u0026ldquo;stack copying\u0026rdquo; que acontece. Por isso, ponteiros para variáveis de stack são problemáticos entre goroutines - mas o Go evita isso através do escape analysis: se algo pode ser apontado de outra goroutine, vai para o heap.\nGarbage Collector Tri-Color O GC do Go usa o algoritmo \u0026ldquo;tri-color concurrent mark-sweep\u0026rdquo; com a invariante tri-color:\nA invariante: nenhum objeto preto aponta diretamente para um objeto branco. Isso garante que objetos brancos \u0026ldquo;atrás\u0026rdquo; de objetos pretos não sejam coletados prematuramente.\nAlgoritmo simplificado: 1. STW curto: inicializa marcação, adiciona raízes à fila cinza 2. Concurrent marking (corre junto com o programa): - Pega objeto cinza da fila - Marca como preto - Adiciona seus filhos brancos como cinza - Repete até a fila cinza estar vazia 3. STW curto: finaliza (termina goroutines auxiliares de GC) 4. Concurrent sweeping (corre junto com o programa): - Libera objetos brancos (não alcançados) Objetos alocados durante a marcação são marcados como cinza ou preto para manter a invariante. O write barrier garante a invariante: quando o programa escreve um ponteiro em um objeto preto para um objeto branco, o write barrier intervém e marca o objeto branco como cinza.\nScheduler Detalhado O scheduler do Go é implementado em runtime/proc.go e usa um algoritmo chamado \u0026ldquo;work-stealing\u0026rdquo;:\nEstados de uma goroutine: _Gidle → criada mas não inicializada _Grunnable → pronta para rodar, na fila de um P _Grunning → ativamente rodando num M _Gsyscall → bloqueada numa syscall _Gwaiting → esperando por algo (channel, timer, etc.) _Gdead → terminou, pode ser reutilizada Quando uma goroutine faz uma syscall bloqueante:\nO M que rodava a goroutine descola do P O P pode ser pego por outro M para continuar executando outras goroutines Quando a syscall retorna, a goroutine tenta pegar um P; se nenhum estiver disponível, vai para a fila global Isso é por que I/O bound workloads podem usar muito mais goroutines do que CPUs - goroutines esperando I/O não bloqueiam threads do OS.\nQuando Go é Excelente Servidores e microsserviços HTTP/gRPC: a combinação de goroutines baratas, GC com baixa latência e binário estático faz de Go a linguagem ideal. O servidor HTTP da stdlib é production-ready. gRPC tem excelente suporte.\nFerramentas de linha de comando: go build produz um binário estático sem dependências. Docker, Kubernetes, Terraform, GitHub CLI - todos escritos em Go. A razão é exatamente essa: distribua um único arquivo.\nSistemas com alta concorrência de I/O: proxies, API gateways, servidores de WebSocket, brokers. Goroutines lidam com 100.000 conexões simultâneas com naturalidade.\nInfraestrutura e DevOps: a maioria das ferramentas modernas de infraestrutura é Go. O ecossistema é rico.\nData pipelines e workers: pipelines de processamento de dados, workers de fila, ETL. O modelo de concorrência é perfeito para isso.\nQuando Go NÃO é Ideal Machine learning e data science: Python domina de forma avassaladora. O ecossistema (PyTorch, NumPy, Pandas, Jupyter) não tem equivalente em Go. Não tente lutar contra isso.\nScripting e automação rápida: Python, Ruby ou bash são mais práticos para scripts de 50 linhas. Go tem overhead de ter que compilar e a verbosidade não compensa para scripts pequenos.\nSistemas de tempo real extremamente rígido (hard real-time): o GC pode introduzir pauses imprevisíveis. Para controle industrial com microsegundos de deadline, você quer C, Rust ou Ada.\nFront-end web: sim, Go compila para WebAssembly, mas o ecossistema de front-end é JavaScript/TypeScript. GopherJS e WASM existem mas são nicho.\nDomínios altamente matemáticos ou de computação científica: Fortran, C, Julia e MATLAB têm bibliotecas numéricas maduras. Go não tem.\nTradeoffs Reais Verbosidade do Tratamento de Erros // O famoso padrão if err != nil resultado, err := passo1() if err != nil { return err } dados, err := passo2(resultado) if err != nil { return err } saida, err := passo3(dados) if err != nil { return err } Este código é mais longo do que try/catch. Mas é mais explícito: você sabe exatamente o que pode falhar em cada ponto. Em Java, você pode ter exceções pulando de funções que você nem sabia que podiam lançar. Em Go, o fluxo de erro é visível.\nO tradeoff é real: mais código vs mais clareza. A comunidade Go aceita o custo de verbosidade em troca de explicitness.\nAusência de Generics por Longo Tempo Por muitos anos, não ter generics forçou padrões repetitivos (copiar/colar código para tipos diferentes) ou uso excessivo de interface{} com custos de performance. Go 1.18 (2022) trouxe generics, mas a comunidade ainda está aprendendo onde usá-los bem.\nGC no Lugar de Gerenciamento Manual Go não tem o controle de memória de C++ ou Rust. Para sistemas onde você precisa de zero alocações de heap ou controle muito fino de tempo de vida de objetos, Go não é a ferramenta. O Rust resolve este problema de forma muito mais completa.\nFalta de Imutabilidade Nativa Não existe const para structs ou slices. Imutabilidade em Go é por convenção e disciplina, não por enforcement do compilador. Isso pode levar a bugs sutis em código concorrente.\nEcosistema Mais Jovem Comparado a Java, Python ou JavaScript, o ecossistema Go é menor. Para nichos como ML, finanças quantitativas ou processamento de mídia, você frequentemente encontrará bibliotecas mais maduras em outras linguagens.\nConclusão Go não é a linguagem \u0026ldquo;certa\u0026rdquo; para tudo. Nenhuma linguagem é. Mas para um conjunto específico de problemas - servidores, ferramentas, infraestrutura, sistemas concorrentes - ela é extraordinariamente eficaz.\nO que a torna especial não é nenhuma feature individual. É a combinação de simplicidade deliberada + concorrência de primeira classe + compilação rápida + deploy trivial + performance razoável + excelente tooling.\nA filosofia de \u0026ldquo;faça a coisa óbvia, não a esperta\u0026rdquo; resulta em codebases que são mais fáceis de manter conforme crescem e conforme a equipe muda. Isso tem valor imenso em sistemas de produção.\nAprender Go bem significa internalizar essa mentalidade: valorize a clareza acima da brevidade, a explicitness acima da mágica, a simplicidade acima da sofisticação. É uma disciplina, não apenas uma sintaxe.\nO próximo passo depois deste guia é escrever código real. Pegue um projeto pessoal, reescreva uma ferramenta que você usa, construa um servidor para uma API que você consome. A teoria sem prática envelhece rápido.\nGo está esperando. O compilador é rápido.\nEste guia cobre Go até a versão 1.22. Alguns recursos como generics (1.18), slog (1.21) e mudanças de semântica de loop (1.22) são mencionados ao longo do texto.\n","permalink":"https://maggioni.dev/pt-br/posts/dev/from-zero-to-golang/","summary":"Um guia completo, progressivo e profundo sobre Go - do Hello World ao runtime internamente, passando por concorrência, arquitetura, performance e projetos reais","title":"Do zero ao Go! Aprenda Golang em um post!"},{"content":"Quem usa Btrfs com snapshots automáticos do /home — via Snapper, Timeshift ou scripts próprios — cedo ou tarde percebe que cada snapshot carrega junto vários gigabytes da biblioteca do Steam. O resultado são snapshots gigantes, rollbacks demorados e espaço em disco evaporando sem motivo.\nA solução é simples: transformar o diretório ~/.local/share/Steam em um subvolume Btrfs independente. Subvolumes filhos não são incluídos em snapshots do pai, então o Steam fica completamente fora dos seus backups de /home.\nPré-requisitos Partição raiz formatada em Btrfs btrfs-progs instalado Steam instalado (ou você vai instalar depois) Acesso sudo 1. Feche o Steam completamente Antes de mexer no diretório, certifique-se de que o Steam **não está em execução**:\npkill -9 steam || true 2. Faça backup dos dados atuais Se já tiver jogos baixados, mova a pasta para um local temporário. Isso preserva tudo enquanto recriamos a estrutura:\nmv ~/.local/share/Steam ~/.local/share/Steam.bak 3. Crie o subvolume Recrie o diretório como um subvolume Btrfs real:\nsudo btrfs subvolume create ~/.local/share/Steam Ajuste o dono para o seu usuário (o sudo cria com dono root):\nsudo chown -R $USER:$USER ~/.local/share/Steam 4. Restaure os dados Copie o conteúdo do backup de volta para dentro do novo subvolume:\ncp -a ~/.local/share/Steam.bak/. ~/.local/share/Steam/ Quando a cópia terminar, remova o backup temporário:\nrm -rf ~/.local/share/Steam.bak Dica: se quiser economizar espaço e tempo, e o backup ainda estiver na mesma partição Btrfs, você pode usar btrfs send/receive ou simplesmente referenciar os dados com reflinks (cp --reflink=always).\n5. Verifique o resultado Liste todos os subvolumes da raiz para confirmar que o Steam aparece como subvolume independente:\nsudo btrfs subvolume list / A saída deve ser parecida com esta (os IDs e datas variam no seu sistema):\nID 256 gen 444 top level 5 path @_backup_2026-05-24T02:34:45.946Z ID 257 gen 469 top level 5 path @home_backup_2026-05-24T02:34:50.945Z ID 258 gen 711 top level 5 path @root ID 259 gen 25 top level 5 path @srv ID 260 gen 1088 top level 5 path @cache ID 261 gen 1115 top level 5 path @tmp ID 262 gen 1115 top level 5 path @log ID 263 gen 1115 top level 329 path .snapshots ID 264 gen 27 top level 329 path var/lib/portables ID 265 gen 27 top level 329 path var/lib/machines ID 279 gen 61 top level 263 path .snapshots/14/snapshot ID 290 gen 126 top level 263 path .snapshots/25/snapshot ID 291 gen 142 top level 263 path .snapshots/26/snapshot ID 292 gen 1115 top level 330 path @home/gabriel/.local/share/Steam O ponto-chave é a última linha: @home/gabriel/.local/share/Steam aparece como um subvolume com seu próprio ID (292), subordinado ao subvolume @home (top level 330), mas não incluído em seus snapshots.\n6. (Opcional) Configurar o Snapper para ignorar o subvolume Se estiver usando o Snapper, ele já exclui subvolumes aninhados por padrão. Mesmo assim, confira a configuração do seu perfil:\nsudo snapper -c home get-config | grep SUBVOLUME O campo SUBVOLUME deve apontar para o ponto de montagem do @home (normalmente /home). Pronto — o Snapper jamais entrará em ~/.local/share/Steam ao criar um snapshot.\nPor que isso funciona? O Btrfs trata subvolumes como fronteiras de snapshot. Quando você faz um snapshot de @home, o kernel copia o estado da árvore de arquivos daquele subvolume — mas para nos limites de cada subvolume filho. O diretório .local/share/Steam aparece no namespace de arquivos normalmente, mas o conteúdo interno fica em outro subvolume e simplesmente não é incluído.\nResultado final Situação Snapshot de /home inclui Steam? Antes (diretório comum) ✅ Sim — cada snapshot cresce GB Depois (subvolume separado) ❌ Não — snapshots leves e rápidos Seus snapshots de /home voltam a representar apenas **seus arquivos pessoais**: configurações, documentos, projetos — sem arrastar a biblioteca inteira de jogos junto.\n","permalink":"https://maggioni.dev/pt-br/posts/linux/definindo-o-steam-como-um-subvolume-separado-no-btrfs/","summary":"\u003cp\u003eQuem usa \u003cstrong\u003eBtrfs\u003c/strong\u003e com snapshots automáticos do \u003ccode\u003e/home\u003c/code\u003e — via\n\u003ca href=\"https://wiki.archlinux.org/title/Snapper\"\u003eSnapper\u003c/a\u003e,\n\u003ca href=\"https://github.com/linuxmint/timeshift\"\u003eTimeshift\u003c/a\u003e ou scripts próprios —\ncedo ou tarde percebe que cada snapshot carrega junto vários gigabytes da\nbiblioteca do Steam. O resultado são snapshots gigantes, rollbacks demorados e\nespaço em disco evaporando sem motivo.\u003c/p\u003e\n\u003cp\u003eA solução é simples: transformar o diretório \u003ccode\u003e~/.local/share/Steam\u003c/code\u003e em um\n\u003cstrong\u003esubvolume Btrfs independente\u003c/strong\u003e. Subvolumes filhos não são incluídos em\nsnapshots do pai, então o Steam fica completamente fora dos seus backups de\n\u003ccode\u003e/home\u003c/code\u003e.\u003c/p\u003e","title":"Definindo o Steam como um Subvolume  Separado no BTRFS"},{"content":"Introdução Esse post é direcionado à usuários AMD com Arch ou CachyOS. As configurações a seguir vão ajudar seus jogos a extraírem o máximo de desempenho de suas peças.\n1. Atualiza Tudo Primeiro (Sério, Não Pula Essa Etapa) Antes de qualquer coisa, garante que o sistema está completamente atualizado:\nsudo pacman -Syu Depois, instala os pacotes essenciais pra AMD:\n# Drivers e ferramentas da GPU sudo pacman -S mesa lib32-mesa libva-mesa-driver lib32-libva-mesa-driver mesa-utils rocm-smi-lib # Suporte Vulkan (essencial pra jogos modernos e Proton) sudo pacman -S vulkan-radeon lib32-vulkan-radeon mesa lib32-mesa # GameMode (otimizações automáticas durante o jogo) sudo pacman -S gamemode lib32-gamemode # MangoHud (overlay de estatísticas em tempo real) sudo pacman -S mangohud lib32-mangohud O lib32-* é necessário pra jogos 32-bit e alguns títulos via Proton. Não economiza aqui.\nQuer conferir qual versão do Mesa está rodando?\npacman -Q mesa 2. Desbloqueando a GPU: O Parâmetro do GRUB Aqui começa a parte boa. Por padrão, o kernel Linux restringe algumas funcionalidades do driver amdgpu - incluindo o controle total de clocks e voltagens. O amdgpu.ppfeaturemask=0xffffffff desbloqueia todas essas funcionalidades.\nSem isso, o CoreCtrl (que vamos instalar logo mais) não consegue controlar os clocks da GPU corretamente em GPUs RX modernas.\nEditando o GRUB Abre o arquivo de configuração:\nsudo nano /etc/default/grub Procura a linha GRUB_CMDLINE_LINUX_DEFAULT e adiciona o parâmetro dentro das aspas, junto com o que já existir:\npra mim ficou assim, só adicionei amdgpu.ppfeaturemask=0xffffffff no final:\nGRUB_CMDLINE_LINUX_DEFAULT=\u0026#39;nowatchdog nvme_load=YES splash loglevel=3 amdgpu.ppfeaturemask=0xffffffff\u0026#39; ⚠️ Não apaga os outros parâmetros que já estavam lá! Só adiciona o amdgpu.ppfeaturemask=0xffffffff no final.\nSalva o arquivo (Ctrl+O, depois Enter, depois Ctrl+X) e aplica a mudança:\nsudo grub-mkconfig -o /boot/grub/grub.cfg Reinicia o PC. Sem reiniciar, não adianta.\n3. CoreCtrl: O Painel de Controle da Sua GPU O CoreCtrl é uma ferramenta gráfica que permite controlar clocks, voltagens e perfis de desempenho da GPU de forma visual - sem precisar mexer em arquivos do sistema manualmente.\nInstalação sudo pacman -Ss corectrl Se não encontrar, verifique se os repositórios estão atualizados (sudo pacman -Sy) ou procure nos repos do AUR com yay -S corectrl.\nConfigurando o Perfil de Gaming Depois de abrir o CoreCtrl:\nCria um novo perfil chamado Gaming Na aba GPU, muda o modo para Avançado - isso libera os controles de clock e voltagem 🚨 Aviso sério: Modo Avançado te dá acesso a configurações que podem danificar a GPU se você sair mexendo em tudo sem saber o que está fazendo. Foca apenas no que o guia indica.\nAjustando a GPU ( RX 6600 ) A minha GPU é a RX6600, então eu vou fazer as seguintes alterações nela:\nClock mínimo da GPU → 1900 MHz Clock máximo da GPU → 2500 MHz\nPor padrão, a GPU \u0026ldquo;dorme\u0026rdquo; em clocks baixíssimos (tipo 500 MHz) quando percebe que o jogo não está exigindo 100% do tempo - o que acontece constantemente em jogos com hitches, carregamentos ou momentos menos intensos. O problema é que a transição de 500 MHz → 2750 MHz leva tempo, causando stutters perceptíveis.\nFixar o mínimo em 1900 MHz garante que a GPU nunca cai pra clocks baixos demais, eliminando esses solavancos sem aumentar significativamente o consumo médio.\nNa aba CPU, verifica se o governador de frequência está em Performance Ativa o perfil Gaming Verificando se Funcionou Depois de aplicar, testa com:\nwatch -n 0.5 cat /sys/class/drm/card0/device/pp_dpm_sclk (Se não funcionar, tenta com card1)\nA saída vai mostrar os estados de clock disponíveis. O * indica o estado atual. Se o asterisco aparecer em 2100 ou 2750 - e não ficar preso em 500 - então o clock mínimo está funcionando corretamente.\n4. MangoHud: Seu Overlay de Estatísticas O MangoHud é um overlay que aparece no canto da tela durante o jogo mostrando FPS, temperatura, uso de GPU/CPU, VRAM e muito mais - similar ao MSI Afterburner do Windows, mas nativo e sem frescura.\nConfiguração Edita o arquivo de config:\nnano ~/.config/MangoHud/MangoHud.conf Apaga o que tiver e cola isso:\n# ╔══════════════════════════════════════╗ # ║ MangoHud Configuration ║ # ║ Salve em: ~/.config/MangoHud/ ║ # ╚══════════════════════════════════════╝ legacy_layout=false # ── Visual \u0026amp; Posição ────────────────── position=top-left width=220 font_size=14 background_alpha=0.4 alpha=0.5 round_corners=8 table_columns=2 # Cores dos textos (hex RGB) gpu_color=2e9762 cpu_color=2e97cb ram_color=c2a13b fps_color=e06464 text_color=ffffff # ── FPS ─────────────────────────────── fps # fps_metrics: avg = FPS médio | 0.01 = 1% Low fps_metrics=avg,0.01 # ── GPU ─────────────────────────────── gpu_stats # Uso em % gpu_temp # Temperatura gpu_core_clock # Clock do núcleo vram # VRAM utilizada gpu_power # Consumo em Watts # ── CPU ─────────────────────────────── cpu_stats # Uso em % cpu_temp # Temperatura cpu_mhz # Clock (MHz) # ── RAM ─────────────────────────────── ram # ── Atalhos ─────────────────────────── toggle_hud=Shift_R+F12 toggle_logging=Shift_L+F2 Testando Antes de abrir qualquer jogo, testa se o overlay aparece:\n# Teste com OpenGL mangohud glxgears # Teste com Vulkan mangohud vkcube Se aparecer o overlay no canto superior esquerdo com as estatísticas, está funcionando.\n5. Opções de Inicialização na Steam Com tudo configurado, vai nas propriedades do jogo na Steam → Opções de Inicialização e coloca:\ngamemoderun mangohud %command% # gamemoderun RADV_PERFTEST=sam RADV_DEBUG=syncshaders mangohud %command% O Que Cada Coisa Faz gamemoderun - Ativa o GameMode enquanto o jogo está rodando. O GameMode é um daemon do Feral Interactive que faz uma série de otimizações automáticas no sistema: muda o governador de CPU pra performance, reduz processos em background, aplica otimizações de scheduler, e pode interagir com jogos compatíveis via API. Basicamente, diz pro Linux: \u0026ldquo;estou jogando, prioriza isso\u0026rdquo;. mangohud - Injeta o overlay do MangoHud no jogo para mostrar as estatísticas configuradas. %command% - É o placeholder do Steam pro executável do jogo. Tudo que vem antes dele são variáveis de ambiente e wrappers que serão aplicados. Resumo Rápido O Que Por Que mesa atualizado Melhorias de desempenho e correção de bugs no driver amdgpu.ppfeaturemask=0xffffffff Desbloqueia controle total de clocks pra o CoreCtrl CoreCtrl clock min 2100 MHz Elimina stutters por transição de clock CoreCtrl -25 mV offset Menos calor e consumo sem perder desempenho MangoHud Visibilidade total do que está acontecendo na GPU GameMode Otimizações automáticas do sistema durante o jogo Dúvidas? Problemas? Se o CoreCtrl não estiver aplicando os clocks, confirma que:\nO amdgpu.ppfeaturemask=0xffffffff foi adicionado e o grub-mkconfig foi rodado O PC foi reiniciado depois O perfil Gaming está ativo no CoreCtrl Bons jogos! 🎮\n","permalink":"https://maggioni.dev/pt-br/posts/linux/preparing-cachyos-for-gaming/","summary":"Aprenda a como configurar rapidamente o seu CachyOS para jogar tudo!","title":"Preparando Arch/CachyOS para JOGAR com GPUs AMD"},{"content":"Guia direto ao ponto pra usar Docker no dia a dia sem ficar perdido.\nobs: Esse post é um RESUMO desse aqui\n🧠 Docker na prática Docker roda sistemas isolados chamados containers.\nVocê usa pra:\nrodar coisas sem instalar nada subir APIs rápido replicar ambientes iguais em qualquer máquina 📦 INSTALAÇÃO Sistema Comando Arch / CachyOS sudo pacman -S docker Fedora sudo dnf install docker Ubuntu / Debian sudo apt install docker.io Mac / Windows Docker Desktop Importante: Talvez seja necessário reiniciar o pc;\n🔎 Verificação docker --version docker info ▶ INICIAR SERVIÇO sudo systemctl start docker sudo systemctl enable docker 🚀 CONTAINERS (BÁSICO) ▶ Rodar container docker run nginx docker run -d nginx docker run -d -p 8080:80 nginx 📋 Listar containers docker ps docker ps -a ⛔ Parar containers docker stop \u0026lt;id\u0026gt; docker kill \u0026lt;id\u0026gt; 🧹 Remover containers docker rm \u0026lt;id\u0026gt; docker rm -f \u0026lt;id\u0026gt; 🖼 IMAGENS 📥 Baixar imagem docker pull nginx 📋 Listar imagens docker images 🗑 Remover imagem docker rmi nginx 🧼 Limpeza geral docker system prune docker system prune -a 🧩 DOCKER COMPOSE (IMPORTANTE) Docker Compose\n📄 Exemplo real (Postgres + Adminer) version: \u0026#34;3.9\u0026#34; services: db: image: postgres:16 container_name: postgres_db environment: POSTGRES_USER: user POSTGRES_PASSWORD: pass POSTGRES_DB: app ports: - \u0026#34;5432:5432\u0026#34; adminer: image: adminer ports: - \u0026#34;8081:8080\u0026#34; ▶ Rodar stack docker compose up docker compose up -d ⛔ Parar stack docker compose down 🔍 Logs docker compose logs docker compose logs -f 🔄 rebuild docker compose up --build 🧱 DOCKERFILE (CRIAR SUA IMAGEM) 📄 Exemplo Node.js FROM node:20 WORKDIR /app COPY package*.json ./ RUN npm install COPY . . CMD [\u0026#34;node\u0026#34;, \u0026#34;index.js\u0026#34;] 🏗 Build docker build -t minha-app . ▶ Rodar docker run -p 3000:3000 minha-app 🧭 FLUXO REAL DE TRABALHO docker compose up -d docker ps docker logs -f \u0026lt;container\u0026gt; docker compose down 🔥 COMANDOS ESSENCIAIS (RESUMO ABSOLUTO) Containers docker ps docker run nginx docker stop \u0026lt;id\u0026gt; docker rm \u0026lt;id\u0026gt; Imagens docker images docker pull nginx docker rmi nginx Compose docker compose up -d docker compose down docker compose logs -f 🖥 BONUS: LAZYDOCKER LazyDocker\nlazydocker Te dá:\nvisão de containers logs em tempo real controle sem decorar ID ⚡ RESUMO REAL *docker run → roda container rápido *docker ps → vê o que está vivo *docker compose up -d → sobe sistema inteiro *docker build → cria sua imagem *lazydocker → não se perde no caos\n","permalink":"https://maggioni.dev/pt-br/posts/dev/1-minute-docker/","summary":"Comandos básicos : Docker (de forma resumida)","title":"Docker em 1 minuto!"},{"content":" Esse post é resumido. Tenho um bem completo aqui\n🎭 Pacman vs Yay — Qual a diferença?\nPacman Yay O que é gerenciador oficial wrapper do AUR Instala de repositórios oficiais oficial + AUR Precisa sudo sim não (yay pede quando precisa) Uso no dia a dia sistema base tudo que o pacman não tem 💡 AUR = repositório mantido pela comunidade. Tem quase tudo que não está nos repos oficiais.\n📦 Instalar Pacotes\nComando Função sudo pacman -S pacote instalar do repositório oficial yay -S pacote instalar do oficial ou AUR sudo pacman -S p1 p2 p3 instalar vários de uma vez yay -S pacote --noconfirm instalar sem confirmar 🗑️ Remover Pacotes\nComando Função sudo pacman -R pacote remover pacote sudo pacman -Rs pacote remover + dependências órfãs sudo pacman -Rns pacote remover + deps + arquivos de config 💡 Prefira sempre -Rs pra não deixar lixo acumulando.\n🔄 Atualizar o Sistema\nComando Função sudo pacman -Syu atualizar tudo (repos oficiais) yay -Syu atualizar tudo (oficial + AUR) yay atalho — já faz o -Syu 💡 No CachyOS, o hábito é rodar yay todo dia antes de trabalhar.\n🔍 Buscar Pacotes\nComando Função pacman -Ss palavra buscar nos repos oficiais yay -Ss palavra buscar no oficial + AUR pacman -Si pacote ver detalhes do pacote yay -Si pacote ver detalhes (AUR incluso) 📋 Listar Pacotes Instalados\nComando Função pacman -Q listar todos instalados pacman -Qe listar só os que você instalou manualmente pacman -Qm listar pacotes do AUR pacman -Q pacote checar se um pacote está instalado pacman -Ql pacote ver arquivos de um pacote 🧹 Limpeza do Sistema\nComando Função sudo pacman -Sc limpar cache de pacotes antigos sudo pacman -Scc limpar todo o cache sudo pacman -Rns $(pacman -Qdtq) remover órfãos yay -Sc limpar cache do yay/AUR 🔧 Situações do Dia a Dia\nSituação Comando Não sei o nome exato yay -Ss parte-do-nome Pacote quebrado sudo pacman -S pacote --overwrite '*' Forçar refresh das listas sudo pacman -Syy Ver de qual repo veio pacman -Qi pacote Qual pacote tem esse arquivo pacman -F nome-do-arquivo 🧠 Fluxo Básico do Dia a Dia\nyay # atualizar tudo yay -Ss nome # buscar o que quero instalar yay -S pacote # instalar sudo pacman -Rs pacote # remover quando não precisar mais sudo pacman -Rns $(pacman -Qdtq) # limpar órfãos de vez em quando 🎯 Os 10 Que Vale Decorar Primeiro\nyay — atualiza tudo yay -S pacote — instala qualquer coisa yay -Ss palavra — busca sudo pacman -Rs pacote — remove limpo pacman -Q pacote — checa se está instalado pacman -Qe — o que você instalou manualmente pacman -Qm — o que veio do AUR sudo pacman -Sc — limpa cache sudo pacman -Rns $(pacman -Qdtq) — mata órfãos pacman -Qi pacote — info completa do pacote Com isso você gerencia o sistema como um arch user de verdade 📦🔥\n","permalink":"https://maggioni.dev/pt-br/posts/linux/1-minute-pacman-yay/","summary":"Aprenda os comandos básicos pacman + yay!","title":"Pacman e Yay em 1 minuto!"},{"content":"⚡Fish Shell em 1 minuto! Cola prática pra se virar no terminal do CachyOS!\n🐟 O que é o Fish? O CachyOS usa o Fish como shell padrão — ele já vem com autocomplete inteligente, histórico e cores sem precisar configurar nada.\n📁 Navegação Básica\nComando Função cd pasta/ entrar na pasta cd .. voltar uma pasta cd ~ ir para o home ls listar arquivos ls -la listar com detalhes e ocultos pwd mostrar onde você está ✨ Superpoderes do Fish\nRecurso Como funciona Tab autocomplete de comandos e pastas ↑ / ↓ navegar no histórico → aceitar sugestão automática Alt + ← voltar palavra por palavra Ctrl + r buscar no histórico Ctrl + c cancelar comando atual 📦 Pacotes com Pacman e Yay (CachyOS)\nComando Função sudo pacman -S pacote instalar pacote sudo pacman -R pacote remover pacote sudo pacman -Syu atualizar o sistema yay -S pacote instalar do AUR yay -Syu atualizar tudo (incluindo AUR) pacman -Ss palavra buscar pacote pacman -Q listar instalados 📄 Arquivos e Texto\nComando Função cat arquivo.txt ver conteúdo nano arquivo.txt editar no nano cp origem destino copiar arquivo mv origem destino mover / renomear rm arquivo apagar arquivo rm -rf pasta/ apagar pasta inteira mkdir pasta criar pasta touch arquivo.txt criar arquivo vazio 🔍 Busca\nComando Função grep \u0026quot;texto\u0026quot; arquivo buscar texto em arquivo find . -name \u0026quot;*.txt\u0026quot; buscar arquivos por nome which programa saber onde o programa está ⚙️ Sistema\nComando Função htop monitor de processos df -h espaço em disco free -h uso de memória uname -r versão do kernel neofetch info do sistema reboot reiniciar poweroff desligar 🔧 Configurar o Fish\nComando Função fish_config abre config no navegador nano ~/.config/fish/config.fish editar config manualmente alias ll='ls -la' criar atalho temporário funcsave ll salvar o alias pra sempre 🧠 Fluxo Básico do Dia a Dia\nsudo pacman -Syu # atualizar o sistema cd ~/projetos/ # entrar na pasta ls # ver o que tem nano arquivo.txt # editar algo Ctrl + x → Y → Enter # salvar no nano 🎯 Os 10 Que Vale Decorar Primeiro\ncd / ls Tab (autocomplete!) ↑ (histórico) sudo pacman -Syu yay -S pacote cp / mv / rm cat arquivo grep htop fish_config Com isso sozinho você já sobrevive tranquilamente no terminal do CachyOS 🐟🔥\n","permalink":"https://maggioni.dev/pt-br/posts/linux/1-minute-fish-shell/","summary":"Aprenda os comandos básicos do seu terminal fish em 1 minuto!","title":"Fish Shell em 1 minuto!"},{"content":"🚀 Resumão NeoVim 📦 Instalação Comando Arch / CachyOS sudo pacman -S neovim Fedora sudo dnf install neovim Ubuntu / Debian sudo apt install neovim Mac (brew) brew install neovim 💾 Salvar e sair Comando salvar :w sair :q salvar e sair :wq sair sem salvar :q! salvar tudo e sair :wqa ✍️ Inserção Comando antes do cursor i depois do cursor a fim da linha A início da linha I nova linha abaixo o nova linha acima O 🧭 Movimento Comando esquerda h baixo j cima k direita l início da linha 0 fim da linha $ próxima palavra w palavra anterior b início do arquivo gg fim do arquivo G ir para linha :10 descer página Ctrl+d subir página Ctrl+u ✂️ Edição Comando apagar linha dd copiar linha yy colar abaixo p colar acima P desfazer u refazer Ctrl+r apagar caractere x apagar até fim da linha D editar palavra ciw editar linha cc 📋 Copiar e mover Comando copiar palavra yw copiar até fim da linha y$ cortar linha dd colar p colar antes P 🧠 Seleção Comando seleção livre v linha inteira V bloco visual Ctrl+v sair seleção Esc selecionar tudo ggVG copiar tudo ggVG\u0026quot;+y cortar tudo ggVG\u0026quot;+d 🔍 Busca Comando buscar texto /texto próximo resultado n anterior N palavra atual * substituir tudo :%s/velho/novo/g substituir com confirmação :%s/velho/novo/gc 📁 Arquivos Comando abrir arquivo :e nome abrir diretório :Ex salvar como :w nome 🪟 Janelas e buffers Comando split horizontal :split split vertical :vsplit trocar janela Ctrl+w w mover entre janelas Ctrl+w h/j/k/l próximo buffer :bn buffer anterior :bp fechar buffer :bd ⚙️ Configuração básica Arquivo principal:\n~/.config/nvim/init.lua Criar:\nmkdir -p ~/.config/nvim nvim ~/.config/nvim/init.lua Config mínima:\nvim.opt.number = true vim.opt.relativenumber = true vim.opt.tabstop = 2 vim.opt.shiftwidth = 2 vim.opt.expandtab = true vim.opt.ignorecase = true vim.opt.smartcase = true vim.opt.termguicolors = true vim.opt.wrap = false ","permalink":"https://maggioni.dev/pt-br/posts/linux/1-minute-nvim/","summary":"Resumo dos principais comandos e casos de uso do nvim!","title":"NeoVim em 1 minuto!"},{"content":"Introdução: O que é Docker? Docker é uma plataforma de containerização. Em vez de instalar um software diretamente no seu sistema, você o executa dentro de um container - um ambiente isolado, com tudo que aquele software precisa para funcionar (bibliotecas, configs, dependências), sem interferir no resto do sistema.\nPense num container como uma caixinha selada que contém a aplicação e tudo que ela precisa. Você pode criar, destruir, pausar e clonar essas caixinhas livremente.\nContainer vs Máquina Virtual Característica Container Docker Máquina Virtual Inicialização Segundos Minutos Tamanho MBs GBs Isolamento Processo/FS Sistema operacional completo Overhead Mínimo Alto Portabilidade Total Parcial Por que usar Docker? Sem poluir o sistema: Teste softwares, bancos de dados e serviços sem instalar nada diretamente no CachyOS.\n\u0026ldquo;Funciona na minha máquina\u0026rdquo; → funciona em qualquer máquina: O container carrega o ambiente junto. Se funciona aqui, funciona no servidor.\nIsolamento real: Um banco de dados PostgreSQL rodando em container não conflita com outro na porta diferente.\nFácil de destruir e recriar: Errou a configuração? docker rm e começa do zero em segundos.\nDesenvolvimento local limpo: Rode stacks completas (app + banco + cache) com um único comando via Compose.\nInstalação no CachyOS 1. Instalar o Docker sudo pacman -S docker 2. Habilitar e iniciar o serviço sudo systemctl enable --now docker 3. Adicionar seu usuário ao grupo docker Isso evita precisar de sudo em todo comando docker:\nsudo usermod -aG docker $USER ⚠️ Importante: Reinicie o seu PC.\n4. Testar a instalação docker run hello-world Se aparecer uma mensagem de boas-vindas, está funcionando. ✅\n5. Instalar o Docker Compose (plugin) sudo pacman -S docker-compose Conceitos essenciais Conceito O que é Image Template somente-leitura. É o \u0026ldquo;molde\u0026rdquo; do container. Container Uma instância rodando de uma image. Dockerfile Arquivo de instruções para construir uma image. Registry Repositório de images. O padrão é o Docker Hub. Volume Pasta persistente fora do container (dados sobrevivem ao rm). Network Rede virtual entre containers. Compose Ferramenta para orquestrar múltiplos containers via arquivo YAML. Fluxo básico Dockerfile → build → Image → run → Container ↑ Docker Hub (pull) Comandos completos 🖼️ Images # Baixar uma image do Docker Hub docker pull ubuntu docker pull nginx:latest docker pull postgres:16 # Listar images locais docker images docker image ls # Remover uma image docker rmi nome-da-image docker image rm nome-da-image # Remover todas as images não usadas docker image prune # Remover todas as images (inclusive as usadas) docker image prune -a # Construir image a partir de um Dockerfile docker build -t minha-app:1.0 . docker build -t minha-app:latest -f Dockerfile.prod . # Inspecionar uma image docker inspect nome-da-image # Ver histórico de camadas de uma image docker history nome-da-image 📦 Containers # Criar e iniciar container (básico) docker run nginx # Rodar em background (detached) docker run -d nginx # Dar um nome ao container docker run -d --name meu-nginx nginx # Mapear porta (host:container) docker run -d -p 8080:80 nginx # Acesse em: http://localhost:8080 # Rodar e acessar o terminal interativamente docker run -it ubuntu bash # Rodar e remover ao sair (descartável) docker run --rm -it ubuntu bash # Definir variável de ambiente docker run -d -e POSTGRES_PASSWORD=senha123 postgres # Montar volume docker run -d -v /meu/host/pasta:/container/pasta nginx docker run -d -v meu-volume:/data postgres # Limitar recursos docker run -d --memory=\u0026#34;512m\u0026#34; --cpus=\u0026#34;1.0\u0026#34; nginx # Listar containers rodando docker ps # Listar todos os containers (inclusive parados) docker ps -a # Iniciar/parar/reiniciar container docker start nome-ou-id docker stop nome-ou-id docker restart nome-ou-id # Parar todos os containers rodando docker stop $(docker ps -q) # Remover container docker rm nome-ou-id # Remover container forçadamente (mesmo rodando) docker rm -f nome-ou-id # Remover todos os containers parados docker container prune # Ver logs do container docker logs nome-ou-id # Logs em tempo real docker logs -f nome-ou-id # Últimas N linhas de log docker logs --tail 50 nome-ou-id # Entrar no terminal de um container em execução docker exec -it nome-ou-id bash docker exec -it nome-ou-id sh # se não tiver bash # Rodar comando dentro do container docker exec nome-ou-id ls /var/www # Ver uso de recursos em tempo real docker stats # Ver estatísticas de um container específico docker stats nome-ou-id # Inspecionar detalhes do container docker inspect nome-ou-id # Copiar arquivo do host para o container docker cp arquivo.txt nome-ou-id:/destino/ # Copiar arquivo do container para o host docker cp nome-ou-id:/caminho/arquivo.txt ./ 💾 Volumes # Criar volume nomeado docker volume create meu-volume # Listar volumes docker volume ls # Inspecionar volume (ver onde fica no host) docker volume inspect meu-volume # Remover volume docker volume rm meu-volume # Remover volumes não usados docker volume prune 🌐 Redes # Listar redes docker network ls # Criar rede docker network create minha-rede # Conectar container a uma rede docker network connect minha-rede nome-do-container # Rodar container já em uma rede específica docker run -d --network minha-rede nginx # Inspecionar rede docker network inspect minha-rede # Remover redes não usadas docker network prune 🧹 Limpeza geral # Remover tudo que não está sendo usado (containers, images, redes, volumes) docker system prune # Remover TUDO incluindo volumes (⚠️ cuidado com dados) docker system prune --volumes -a # Ver quanto espaço o Docker está ocupando docker system df Docker Compose O Compose permite definir e rodar múltiplos containers com um único arquivo docker-compose.yml.\nExemplo de arquivo docker-compose.yml version: \u0026#34;3.9\u0026#34; services: app: build: . ports: - \u0026#34;3000:3000\u0026#34; environment: - DATABASE_URL=postgres://user:senha@db:5432/meudb depends_on: - db volumes: - .:/app db: image: postgres:16 environment: POSTGRES_USER: user POSTGRES_PASSWORD: senha POSTGRES_DB: meudb volumes: - pgdata:/var/lib/postgresql/data volumes: pgdata: Comandos do Compose # Subir todos os serviços (em background) docker compose up -d # Subir e forçar rebuild das images docker compose up -d --build # Ver logs de todos os serviços docker compose logs -f # Ver logs de um serviço específico docker compose logs -f db # Ver status dos serviços docker compose ps # Parar os serviços (sem remover) docker compose stop # Parar e remover containers e redes docker compose down # Parar, remover containers, redes E volumes docker compose down -v # Rodar comando em um serviço docker compose exec app bash docker compose exec db psql -U user -d meudb # Escalar serviço (ex: 3 instâncias da app) docker compose up -d --scale app=3 # Rebuild de apenas um serviço docker compose up -d --build app Lazydocker - TUI para Docker O Lazydocker é uma interface de terminal (TUI) para gerenciar Docker visualmente, sem precisar digitar comandos toda hora. Pense no lazygit, mas para Docker.\nInstalação no CachyOS # Via AUR com yay yay -S lazydocker-bin Como usar # Abrir o lazydocker lazydocker Navegação básica Tecla Ação ↑ / ↓ Navegar entre itens Tab Alternar entre painel esquerdo e direito Enter Selecionar / expandir [ / ] Mudar aba do painel direito (Logs, Stats, Config\u0026hellip;) x Abrir menu de ações do item selecionado e Editar docker-compose.yml q Sair O que você faz no lazydocker (sem digitar comandos) Ver todos os containers, images e volumes em tempo real Iniciar, parar, reiniciar e remover containers Ver logs com auto-scroll Ver uso de CPU, memória e rede Acessar o shell de um container Gerenciar Compose (subir/derrubar serviços) Limpar imagens e containers não usados Dicas e boas práticas Nunca rodar Docker como root desnecessariamente Adicione seu usuário ao grupo docker (já feito na instalação) e esqueça o sudo.\nSempre nomear seus containers # Ruim docker run -d nginx # Bom docker run -d --name proxy-nginx nginx Usar .dockerignore Crie um .dockerignore na raiz do projeto para não copiar lixo para a image:\nnode_modules .git *.log .env dist Variáveis sensíveis em .env # docker-compose.yml env_file: - .env # .env (nunca suba isso pro git!) POSTGRES_PASSWORD=minha-senha-secreta SECRET_KEY=abc123 Verificar se um container reinicia automaticamente docker run -d --restart unless-stopped --name nginx-prod nginx Opções de --restart:\nno - nunca reinicia (padrão)\nalways - sempre reinicia\non-failure - reinicia se sair com erro\nunless-stopped - reinicia sempre, exceto se parado manualmente\nCheatsheet # IMAGENS docker pull image:tag # Baixar image docker images # Listar images docker rmi image # Remover image docker build -t nome . # Construir image # CONTAINERS docker run -d -p 8080:80 --name nome image # Criar e rodar docker ps # Listar rodando docker ps -a # Listar todos docker stop / start nome # Parar / iniciar docker rm nome # Remover docker logs -f nome # Ver logs ao vivo docker exec -it nome bash # Acessar terminal docker stats # Monitorar recursos # COMPOSE docker compose up -d # Subir stack docker compose down # Derrubar stack docker compose logs -f # Logs ao vivo docker compose ps # Status dos serviços docker compose exec serv bash # Terminal no serviço # LIMPEZA docker system prune # Limpar tudo não usado docker system df # Ver uso de espaço # LAZYDOCKER lazydocker # Abrir TUI 💡 Dica final: Para uso cotidiano no desenvolvimento, o Compose + Lazydocker é a combinação perfeita. Você define sua stack em YAML uma vez e gerencia tudo visualmente pelo lazydocker sem decorar comandos.\n","permalink":"https://maggioni.dev/pt-br/posts/dev/all-about-docker-in-linux/","summary":"Aprenda a instalar e usar Docker no Linux de forma prática e completa. Guia detalhado sobre containers, Docker Compose, volumes, redes, comandos essenciais, Lazydocker e boas práticas para Arch Linux e distribuições baseadas em Arch","title":"Tudo oque você precisa saber sobre Docker no Linux"},{"content":"Introdução: O que é o CachyOS O CachyOS é uma distribuição Linux baseada no Arch Linux, criada com foco em desempenho extremo, baixa latência e uma experiência mais moderna já pronta para uso.\nEnquanto o Arch tradicional entrega um sistema minimalista que exige configuração manual quase do zero, o CachyOS pega essa base poderosa e adiciona uma camada enorme de otimizações. O objetivo é simples: fazer o sistema responder mais rápido, aproveitar melhor o hardware e reduzir várias das dores comuns de configuração do Arch puro.\nUma das características mais conhecidas do CachyOS é o uso de kernels altamente otimizados, compilados com instruções modernas de CPU, schedulers ajustados para responsividade e tweaks agressivos de performance. Em muitos cenários, principalmente em jogos 🎮, compilação de código, multitarefa pesada e uso diário no desktop, a sensação do sistema fica surpreendentemente “leve” e instantânea.\nEle também traz:\ninstalador gráfico amigável suporte facilitado a drivers NVIDIA integração com Btrfs e snapshots gerenciadores de pacotes otimizados várias opções de kernel ferramentas próprias de tuning interface refinada e visual moderno Outro ponto interessante é que o CachyOS mantém a filosofia rolling release do Arch. Isso significa atualizações contínuas, sem precisar reinstalar o sistema a cada nova versão grande. Você recebe kernels novos, drivers recentes e softwares atualizados constantemente.\nNa prática, ele fica meio que entre dois mundos:\nSistema Perfil Arch Linux controle absoluto e minimalismo CachyOS Arch otimizado, pronto e mais confortável EndeavourOS Arch próximo do vanilla Garuda Linux foco visual e automações pesadas O CachyOS acabou ganhando bastante popularidade entre usuários avançados, gamers Linux 🐧 e pessoas que gostam de extrair o máximo possível do hardware sem precisar passar horas configurando tudo manualmente.\nCaracterísticas principais Kernel otimizado: O CachyOS distribui kernels pré-compilados com patches de performance. Repositórios próprios: Pacotes recompilados com otimizações para arquiteturas modernas (x86-64-v3, x86-64-v4 para CPUs com AVX512). Baseado em Arch: Totalmente compatível com o ecossistema Arch, incluindo AUR, pacman e todas as ferramentas. Rolling release: Atualizações contínuas, sem versões fixas. Você sempre tem o software mais recente. GUI amigável: Instalador gráfico (Calamares), Hello App para configuração inicial, e gerenciador de pacotes gráfico opcional. Por que usar o CachyOS? ✅ Prós Performance real e mensurável: Jogos e aplicações respondem melhor por causa do scheduler de kernel otimizado. Pacotes recompilados para sua CPU: Se você tem uma CPU moderna, os binários do repositório CachyOS são compilados especificamente para ela. Acesso ao AUR: Todo o repositório de usuários do Arch Linux está disponível. Controle total: Como qualquer Arch-based, você controla cada pacote instalado no sistema. Comunidade ativa: Fórum, Discord e Wiki próprios, além de herdar toda a base da ArchWiki. ⚠️ Pontos de atenção Rolling release requer atenção: Atualizações constantes significam que, ocasionalmente, algo pode quebrar. Não é para quem quer \u0026ldquo;instalar e esquecer\u0026rdquo;: É preciso manter o sistema, ler os avisos de atualização e ter uma certa intimidade com o terminal. AUR é poderoso, mas não auditado: Pacotes do AUR são mantidos pela comunidade; sempre revise o PKGBUILD antes de instalar. Gerenciadores de Pacotes O CachyOS usa dois sistemas principais:\nFerramenta Repositório Quem mantém pacman Arch oficial + CachyOS Arch / CachyOS Team yay AUR (Arch User Repository) Comunidade (PKGBUILDs) Regra de ouro: Prefira sempre pacman para pacotes dos repositórios oficiais. Use yay somente quando o pacote não está nos repositórios oficiais.\nPacman - Guia Completo O pacman é o gerenciador de pacotes nativo do Arch Linux e por extensão do CachyOS.\nSintaxe geral pacman \u0026lt;operação\u0026gt; [opções] [pacotes] As principais operações são:\n-S → Sincronizar (instalar/atualizar) -R → Remover -Q → Consultar (pacotes locais) -F → Procurar em arquivos -D → Banco de dados (alterar metadados) -U → Atualizar/instalar de arquivo local 📦 Instalar pacotes # Instalar um pacote sudo pacman -S nome-do-pacote # Instalar múltiplos pacotes sudo pacman -S pacote1 pacote2 pacote3 # Instalar sem confirmar (assume yes) sudo pacman -S --noconfirm nome-do-pacote # Reinstalar um pacote já instalado sudo pacman -S nome-do-pacote # Pacman detecta e oferece reinstalar # Instalar de um arquivo .pkg.tar.zst local sudo pacman -U /caminho/para/pacote.pkg.tar.zst # Instalar de URL sudo pacman -U https://exemplo.com/pacote.pkg.tar.zst 🔄 Atualizar o sistema # Sincronizar repositórios e atualizar tudo (USE ISSO REGULARMENTE) sudo pacman -Syu # Forçar re-sincronização dos repositórios antes de atualizar sudo pacman -Syyu # Atualizar apenas um pacote específico sudo pacman -S nome-do-pacote # já atualiza se houver nova versão # Ver o que seria atualizado sem instalar (simulação) sudo pacman -Syu --print # Atualizar ignorando um pacote específico sudo pacman -Syu --ignore nome-do-pacote # Ignorar múltiplos pacotes sudo pacman -Syu --ignore pacote1,pacote2 🗑️ Remover pacotes # Remover um pacote (mantém dependências) sudo pacman -R nome-do-pacote # Remover pacote + dependências não usadas por outros pacotes sudo pacman -Rs nome-do-pacote # Remover pacote + dependências + arquivos de configuração sudo pacman -Rns nome-do-pacote # Remover pacote ignorando dependências (PERIGOSO - use com cuidado) sudo pacman -Rdd nome-do-pacote # Remover orfãos (dependências sem \u0026#34;pai\u0026#34;) - manutenção essencial sudo pacman -Rns $(pacman -Qtdq) 🔍 Buscar e consultar pacotes # Buscar pacote nos repositórios (por nome ou descrição) pacman -Ss nome-ou-termo # Buscar pacote instalado localmente pacman -Qs nome-do-pacote # Ver informações detalhadas de um pacote nos repositórios pacman -Si nome-do-pacote # Ver informações de um pacote instalado pacman -Qi nome-do-pacote # Listar todos os pacotes instalados pacman -Q # Listar apenas pacotes instalados explicitamente (não como dependência) pacman -Qe # Listar pacotes instalados como dependências pacman -Qd # Listar pacotes orfãos (instalados como deps, mas sem \u0026#34;pai\u0026#34;) pacman -Qdt # Ver todos os arquivos de um pacote instalado pacman -Ql nome-do-pacote # Descobrir a qual pacote um arquivo pertence pacman -Qo /caminho/para/arquivo # Descobrir qual pacote fornece um arquivo (repositório) pacman -F nome-do-arquivo # Buscar todos os pacotes do grupo X pacman -Sg nome-do-grupo # Listar pacotes de um repositório específico pacman -Sl cachyos pacman -Sl extra 🧹 Limpeza e manutenção # Limpar cache de pacotes baixados (mantém versões atuais) sudo pacman -Sc # Limpar TODO o cache (versões antigas e atuais) sudo pacman -Scc # Ver tamanho do cache du -sh /var/cache/pacman/pkg/ # Remover entradas de banco de dados sem instalação correspondente sudo pacman -Rns $(pacman -Qtdq) 🔒 Downgrade de pacotes # Instalar versão específica do cache local sudo pacman -U /var/cache/pacman/pkg/nome-do-pacote-versao-x86_64.pkg.tar.zst # Ver versões disponíveis no cache ls /var/cache/pacman/pkg/ | grep nome-do-pacote # Usar downgrade (ferramenta do AUR, mais fácil) sudo downgrade nome-do-pacote ⚙️ Configuração do pacman O arquivo de configuração fica em /etc/pacman.conf:\nsudo nano /etc/pacman.conf Opções úteis para ativar:\n# Habilitar downloads paralelos (muito mais rápido) ParallelDownloads = 5 # Habilitar cores no terminal Color # Mostrar barra de progresso estilo Pacman 🕹️ ILoveCandy # Manter N versões no cache (recomendo 2 ou 3 para downgrades) # (configurado no pacman-contrib com paccache) Mirrorlist - escolhendo os espelhos mais rápidos # Ver mirrors atuais cat /etc/pacman.d/mirrorlist # Atualizar mirrors com reflector (instale se não tiver) sudo pacman -S reflector # Gerar nova mirrorlist com os 10 mirrors mais rápidos do Brasil sudo reflector --country Brazil --latest 10 --sort rate --save /etc/pacman.d/mirrorlist # Gerar com múltiplos países sudo reflector --country Brazil,Germany --latest 15 --sort rate --save /etc/pacman.d/mirrorlist Yay - AUR Helper Completo O yay (Yet Another Yogurt) é um AUR helper escrito em Go que se comporta exatamente como o pacman, mas também resolve pacotes do AUR (Arch User Repository).\n⚠️ Aviso: Nunca use sudo yay. O yay precisa de permissão de usuário para clonar PKGBUILDs e usa sudo internamente apenas quando necessário.\nInstalando o yay (já vem no CachyOS) # Se por algum motivo não estiver instalado: sudo pacman -S --needed git base-devel git clone https://aur.archlinux.org/yay.git cd yay makepkg -si 📦 Instalar pacotes com yay # Instalar do AUR ou dos repositórios (yay busca nos dois) yay -S nome-do-pacote # Instalar sem confirmar nada (cuidado com isso!) yay -S --noconfirm nome-do-pacote # Instalar múltiplos pacotes yay -S pacote1 pacote2 # Forçar rebuild de um pacote AUR yay -S nome-do-pacote --rebuildall # Instalar apenas de repositórios oficiais (ignora AUR) yay -S --aur=false nome-do-pacote 🔄 Atualizar com yay # Atualizar tudo: repositórios oficiais + AUR yay -Syu # Atualizar apenas pacotes do AUR yay -Sua # Atualizar apenas pacotes dos repositórios (equivalente ao pacman -Syu) yay -Syu --aur=false # Ver o que seria atualizado (simulação) yay -Syu --dryrun # Atualizar ignorando um pacote yay -Syu --ignore nome-do-pacote 🔍 Buscar com yay # Buscar nos repositórios e no AUR yay -Ss nome-ou-termo # Buscar apenas no AUR yay -Ss nome --aur # Ver informações de um pacote AUR yay -Si nome-do-pacote # Ver informações de pacote instalado yay -Qi nome-do-pacote 🗑️ Remover com yay O yay usa a mesma sintaxe do pacman para remoção:\n# Remover pacote + dependências não usadas yay -Rns nome-do-pacote # Remover orfãos yay -Yc # Ver orfãos sem remover yay -Qdt 📋 Revisando PKGBUILDs antes de instalar Isso é uma boa prática de segurança:\n# Ao instalar, yay perguntará se deseja revisar o PKGBUILD yay -S nome-do-pacote # → Aparecerá: \u0026#34;View PKGBUILD? [Y/n]\u0026#34; - pressione Y e revise! # Para que yay SEMPRE mostre o diff das mudanças yay --editmenu -S nome-do-pacote # Configurar yay para sempre pedir revisão yay --save --editmenu ⚙️ Configuração do yay # Ver configurações atuais yay --show --config # Configurar editor para revisão de PKGBUILDs yay --save --editor nvim # Desabilitar confirmação do PKGBUILD (não recomendado) yay --save --nocleanmenu --nodiffmenu # Habilitar a limpeza automática depois de builds yay --save --cleanafter # Ver estatísticas de uso do yay yay -Ps 🔐 Verificar pacotes AUR manualmente # Clonar e revisar manualmente antes de instalar git clone https://aur.archlinux.org/nome-do-pacote.git cd nome-do-pacote cat PKGBUILD # Revise este arquivo com atenção makepkg -si # Compila e instala Workflow Diário Rotina semanal recomendada # 1. Sincronizar repositórios e atualizar tudo yay -Syu # 2. Remover orfãos yay -Yc # 3. Limpar cache antigo (mantém 2 versões recentes) sudo paccache -rk2 # 4. Verificar integridade do banco de dados sudo pacman -Dk # Verifica dependências Fluxo completo de instalação responsável # 1. Buscar o pacote yay -Ss firefox # 2. Ver detalhes antes de instalar yay -Si firefox # 3. Instalar (revisando o PKGBUILD se for AUR) yay -S firefox # 4. Verificar instalação yay -Qi firefox # 5. Ver arquivos instalados yay -Ql firefox 🆘 O que fazer quando algo dá errado Erro durante atualização Sintoma: sudo pacman -Syu retorna erro de conflito de arquivos ou dependências\n# Ver o erro completo sudo pacman -Syu 2\u0026gt;\u0026amp;1 | tee /tmp/pacman-update.log # Erro de \u0026#34;file conflict\u0026#34; - checar qual pacote possui o arquivo pacman -Qo /caminho/do/arquivo/em/conflito # Forçar sobrescrever arquivo em conflito (use com cuidado) sudo pacman -Syu --overwrite \u0026#34;/caminho/do/arquivo\u0026#34; # Conflito de dependências - tentar resolver instalando dependência primeiro sudo pacman -S dependencia-faltante Banco de dados corrompido # Sintoma: \u0026#34;could not open file /var/lib/pacman/sync/*.db\u0026#34; # Remover e re-sincronizar sudo rm /var/lib/pacman/sync/*.db sudo pacman -Syyu Lock do pacman (outro processo usando) # Sintoma: \u0026#34;error: could not lock database\u0026#34; # Verificar se pacman ou yay está rodando ps aux | grep -E \u0026#34;pacman|yay\u0026#34; # Se não estiver rodando, remover o lock manualmente sudo rm /var/lib/pacman/db.lck Sistema não inicializa após atualização de kernel # Na tela do GRUB, selecione uma entrada mais antiga # Depois de inicializar: # Ver kernels disponíveis pacman -Q | grep linux # Instalar kernel estável como fallback sudo pacman -S linux linux-headers # Gerar nova configuração do GRUB sudo grub-mkconfig -o /boot/grub/grub.cfg Reverter uma atualização problemática # Ver histórico de operações do pacman less /var/log/pacman.log # Filtrar apenas instalações/upgrades recentes grep -E \u0026#34;\\[ALPM\\] (upgraded|installed)\u0026#34; /var/log/pacman.log | tail -50 # Fazer downgrade de um pacote pelo cache ls /var/cache/pacman/pkg/ | grep nome-do-pacote sudo pacman -U /var/cache/pacman/pkg/nome-do-pacote-versao-anterior.pkg.tar.zst # Usando a ferramenta downgrade (mais prática) sudo pacman -S downgrade # instala do AUR via yay sudo downgrade nome-do-pacote Pacote corrompido ou incompleto # Verificar integridade de todos os pacotes instalados sudo pacman -Qkk 2\u0026gt;\u0026amp;1 | grep -v \u0026#34; 0 altered\u0026#34; # Reinstalar um pacote específico sudo pacman -S nome-do-pacote # Reinstalar todos os pacotes com arquivos alterados sudo pacman -Qkk 2\u0026gt;\u0026amp;1 | grep \u0026#34; altered\u0026#34; | awk \u0026#39;{print $1}\u0026#39; | xargs sudo pacman -S Pacote AUR falhou ao compilar # Ver o erro completo de compilação yay -S nome-do-pacote 2\u0026gt;\u0026amp;1 | tee /tmp/yay-build.log # Tentar recompilar limpando o cache de build yay -S nome-do-pacote --rebuild # Compilar manualmente para ver erros detalhados git clone https://aur.archlinux.org/nome-do-pacote.git cd nome-do-pacote makepkg -si --noconfirm Resolver conflitos de chaves GPG # Erro: \u0026#34;invalid or corrupted package (PGP signature)\u0026#34; # Atualizar chaveiro sudo pacman-key --refresh-keys # Inicializar chaveiro (se nunca foi feito) sudo pacman-key --init # Importar chave específica sudo pacman-key --recv-keys CHAVE_ID sudo pacman-key --lsign-key CHAVE_ID # Reinstalar chaveiro do Arch sudo pacman -S archlinux-keyring 👁️ Ver o que vai mudar ANTES de atualizar Esta é uma das habilidades mais importantes para um usuário de rolling release.\nVer pacotes que serão atualizados # Listar atualizações disponíveis sem instalar checkupdates # Com AUR incluído yay -Qu # Com detalhes de versão (de X para Y) yay -Syu --print # Forma verbosa pacman -Syu --print-format \u0026#34;%n: %v -\u0026gt; %l\u0026#34; Ler os news do Arch ANTES de atualizar Este é o passo mais importante para evitar problemas!\n# Instalar arch-news (exibe news do Arch direto no terminal) yay -S arch-news # Ver notícias do Arch arch-news # Alternativa: ver direto no site # https://archlinux.org/news/ 💡 Dica crítica: O site https://archlinux.org/news/ publica avisos de ações manuais necessárias antes de grandes atualizações. Se você atualizar sem ler, pode quebrar o sistema.\nCachyOS Changelog e anúncios # Ver o repositório do CachyOS no GitHub # https://github.com/CachyOS # Discord do CachyOS (anúncios de updates importantes) # https://discord.gg/cachyos-862292009423470592 # Fórum do CachyOS # https://discuss.cachyos.org/ Simular uma atualização completa # Ver tudo que seria instalado, atualizado ou removido - sem executar sudo pacman -Syu --print # Checar dependências sem instalar sudo pacman -Sp nome-do-pacote # lista URL dos pacotes necessários # Ver conflitos antes de instalar sudo pacman -S nome-do-pacote --print Antes de atualizar - checklist ✅ 1. Ler https://archlinux.org/news/ - avisos de ações manuais ✅ 2. Rodar `checkupdates` - ver o que vai mudar ✅ 3. Ter um snapshot/backup (Timeshift, Btrfs snapshot, etc.) ✅ 4. Não atualizar antes de uma apresentação ou trabalho importante ✅ 5. Ter acesso ao TTY caso a interface gráfica quebre (Ctrl+Alt+F2) 📚 Como ler a documentação ArchWiki - a melhor documentação Linux A ArchWiki é válida para o CachyOS em praticamente tudo que não é específico do CachyOS:\nhttps://wiki.archlinux.org/ Páginas essenciais para marcar:\nPacman - documentação completa do pacman AUR - como funciona o AUR System maintenance - guia de manutenção de sistema rolling Pacman/Rosetta - comparação de comandos com apt, dnf, etc. General recommendations - após instalação Wiki do CachyOS https://wiki.cachyos.org/ Tópicos específicos do CachyOS:\nKernels disponíveis e como trocar Repositórios CachyOS (cachyos, cachyos-extra, cachyos-v3, cachyos-v4) BORE scheduler e como configurar Hardware específico Man pages - documentação offline # Ver manual do pacman man pacman # Ver manual do yay yay --help man yay # se disponível # Buscar na man page man pacman # Dentro do man, use /termo para buscar, n para próxima ocorrência Verificar logs do sistema para diagnóstico # Ver log completo do sistema (systemd journal) journalctl -xe # Ver logs de boot journalctl -b # Ver logs do boot anterior (quando o sistema travou) journalctl -b -1 # Filtrar por serviço específico journalctl -u nome-do-servico # Ver logs em tempo real journalctl -f # Log do pacman (todas as operações já realizadas) cat /var/log/pacman.log less /var/log/pacman.log # Filtrar log do pacman por data grep \u0026#34;2024-05\u0026#34; /var/log/pacman.log 🌟 Extras e Dicas Avançadas Kernels disponíveis no CachyOS O CachyOS é famoso por seus kernels otimizados. Você pode trocar facilmente:\n# Ver kernels disponíveis pacman -Ss linux-cachyos # Instalar kernel com scheduler BORE+EEVDF (padrão recomendado) sudo pacman -S linux-cachyos linux-cachyos-headers # Kernel RT (Real-Time) para áudio profissional sudo pacman -S linux-cachyos-rt linux-cachyos-rt-headers # Kernel com suporte a Hardened (segurança) sudo pacman -S linux-cachyos-hardened # Kernel puro do Arch (fallback estável) sudo pacman -S linux linux-headers # Após instalar novo kernel, atualizar GRUB sudo grub-mkconfig -o /boot/grub/grub.cfg Btrfs + Snapper - Snapshots automáticos Se você instalou com Btrfs (padrão no CachyOS), você pode configurar snapshots automáticos:\n# Instalar snapper e snap-pac (snapshots automáticos no pacman) sudo pacman -S snapper snap-pac # Criar configuração para raiz sudo snapper -c root create-config / # Ver snapshots sudo snapper -c root list # Criar snapshot manual antes de uma atualização arriscada sudo snapper -c root create --description \u0026#34;antes-de-atualizar\u0026#34; # Reverter para snapshot (em caso de desastre) # Inicialize pelo live USB, monte a partição btrfs e: sudo btrfs subvolume list / # Renomeie subvolumes conforme necessário Timeshift - backup e restauração simplificada # Instalar sudo pacman -S timeshift # Criar snapshot agora sudo timeshift --create --comments \u0026#34;estado estável\u0026#34; # Listar snapshots sudo timeshift --list # Restaurar snapshot sudo timeshift --restore paccache - limpeza inteligente de cache # Instalar pacman-contrib (vem com paccache) sudo pacman -S pacman-contrib # Manter 3 versões de cada pacote no cache sudo paccache -rk3 # Manter 1 versão (economiza espaço) sudo paccache -rk1 # Remover apenas versões não instaladas sudo paccache -ruk0 # Habilitar limpeza automática semanal sudo systemctl enable --now paccache.timer Aliases úteis para o .bashrc ou .zshrc Adicione ao seu ~/.bashrc, ~/.zshrc ou /.config/fish/config.fish: (use echo $SHELL caso não souber qual o seu shell);\n# Atualização completa alias update=\u0026#39;yay -Syu\u0026#39; # Limpeza total alias cleanup=\u0026#39;yay -Yc \u0026amp;\u0026amp; sudo paccache -rk2\u0026#39; # Ver atualizações disponíveis alias updates=\u0026#39;checkupdates \u0026amp;\u0026amp; yay -Qua\u0026#39; # Log do pacman resumido alias paclog=\u0026#39;grep -E \u0026#34;\\[ALPM\\] (upgraded|installed|removed)\u0026#34; /var/log/pacman.log | tail -20\u0026#39; # Busca rápida alias search=\u0026#39;yay -Ss\u0026#39; # Informações de pacote alias info=\u0026#39;yay -Si\u0026#39; # Remover orfãos alias orphans=\u0026#39;sudo pacman -Rns $(pacman -Qtdq) 2\u0026gt;/dev/null || echo \u0026#34;Nenhum orfão.\u0026#34;\u0026#39; não esqueça de recarregar as settings do shell com source /.config/fish/config.fish ou equivalente.\nGerenciar serviços com systemctl # Ver status de um serviço systemctl status nome-do-servico # Iniciar serviço sudo systemctl start nome-do-servico # Habilitar na inicialização sudo systemctl enable nome-do-servico # Habilitar e iniciar de uma vez sudo systemctl enable --now nome-do-servico # Reiniciar serviço sudo systemctl restart nome-do-servico # Listar todos os serviços ativos systemctl list-units --type=service --state=active # Ver serviços com falha systemctl --failed Verificar o hardware detectado # Informações de CPU lscpu cat /proc/cpuinfo | grep \u0026#34;model name\u0026#34; | head -1 # Memória free -h # Dispositivos PCI (placas de vídeo, rede, etc.) lspci # Dispositivos USB lsusb # Discos e partições lsblk df -h # Informações de GPU lspci | grep -i vga glxinfo | grep \u0026#34;OpenGL renderer\u0026#34; # Temperatura e sensores sensors # requer lm_sensors: sudo pacman -S lm_sensors Recursos online essenciais Recurso URL Para que serve ArchWiki https://wiki.archlinux.org Documentação principal CachyOS Wiki https://wiki.cachyos.org Específico do CachyOS Arch News https://archlinux.org/news/ Avisos de atualizações AUR https://aur.archlinux.org Buscar pacotes AUR CachyOS GitHub https://github.com/CachyOS Código-fonte e issues CachyOS Forum https://discuss.cachyos.org Comunidade r/cachyos https://reddit.com/r/cachyos Comunidade Reddit 🧠 Resumo rápido - Cheatsheet # ATUALIZAR yay -Syu # Atualizar tudo checkupdates # Ver o que vai atualizar (sem instalar) # INSTALAR yay -S pacote # Instalar (repositórios + AUR) sudo pacman -S pacote # Instalar (apenas repositórios oficiais) # REMOVER sudo pacman -Rns pacote # Remover + deps + configs yay -Yc # Remover orfãos # BUSCAR yay -Ss termo # Buscar em tudo pacman -Si pacote # Informações de pacote # DIAGNÓSTICO journalctl -xe # Logs do sistema cat /var/log/pacman.log # Histórico do pacman pacman -Qkk # Verificar integridade dos pacotes # EMERGÊNCIA sudo rm /var/lib/pacman/db.lck # Remover lock travado sudo pacman -Syyu # Forçar re-sync e atualizar sudo pacman -U /var/cache/... # Downgrade pelo cache Última dica: No mundo do rolling release, o maior aliado não é o Google - é a ArchWiki. Antes de perguntar qualquer coisa em fóruns, procure na wiki. 90% das respostas já estão lá, com exemplos e explicações detalhadas.\n","permalink":"https://maggioni.dev/pt-br/posts/linux/pacman-and-yay-cachyos-guide/","summary":"Aprenda a usar pacman e yay no CachyOS e Arch Linux com um guia completo de instalação, atualização, remoção de pacotes, AUR, manutenção, troubleshooting, snapshots e boas práticas para sistemas rolling release.","title":"Pacman e Yay no CachyOS"},{"content":"O que é Btrfs Sistema de arquivos moderno com Copy-on-Write (CoW): em vez de sobrescrever arquivos, cria uma nova versão antes de alterar a antiga. Isso permite snapshots rápidos e rollback do sistema.\nSubvolumes \u0026ldquo;Mini partições\u0026rdquo; dentro do mesmo disco. No Arch/CachyOS:\n@ → / @home → /home Snapshot de / não inclui /home.\nsudo btrfs subvolume list / findmnt -t btrfs Snapshots # Raiz sudo btrfs subvolume snapshot -r / /.snapshots/meu-snap-$(date +%Y-%m-%d_%H-%M) # Home sudo btrfs subvolume snapshot -r /home /home/.snapshots/home-snap-$(date +%Y-%m-%d_%H-%M) Snapshot ≠ Backup. Se o SSD morrer, os snapshots morrem junto.\nSnapper # Instalar sudo pacman -S snapper snap-pac grub-btrfs # Configurar sudo snapper -c root create-config / sudo snapper -c home create-config /home # Ativar sudo systemctl enable --now snapper-timeline.timer sudo systemctl enable --now snapper-cleanup.timer Cria snapshot PRE + POST automaticamente a cada pacman -Syu.\n# Snapshot manual sudo snapper -c root create --description \u0026#34;antes-de-atualizar\u0026#34; Rollback sudo snapper list sudo snapper rollback N sudo reboot # Recuperar arquivo apagado sudo cp /.snapshots/2/snapshot/caminho/arquivo . # Ver diferenças sudo snapper diff 2..0 Ver uso real do disco df -h não é confiável no Btrfs.\nsudo btrfs filesystem usage / # Espaço por snapshot (coluna \u0026#34;excl\u0026#34; = quanto seria liberado ao deletar) sudo btrfs qgroup show -reF / # Peso dos snapshots sudo du -sh /.snapshots sudo du -sh /home/.snapshots 2\u0026gt;/dev/null Sinal de alerta na saída do filesystem usage:\nData,single: Size:437.01GiB, Used:433.74GiB (99.25%) Apagar snapshots Nunca use rm -rf. Use btrfs subvolume delete ou Snapper.\nsudo snapper list # Apagar um sudo snapper delete 20 # Apagar intervalo (verifique a lista antes — número inexistente falha o comando) sudo snapper delete 14-94 # Home sudo snapper -c home list sudo snapper -c home delete 1-10 Subvolumes de backup do rollback Após um snapper rollback, o CachyOS cria subvolumes no nível raiz do Btrfs que não aparecem no snapper list:\n@_backup_2026-05-31T16:39:04.582Z @home_backup_2026-05-31T16:38:57.703Z # Montar o nível raiz (confirme o dispositivo com findmnt -t btrfs) sudo mkdir -p /mnt/btrfs-top sudo mount -o subvolid=5 /dev/nvme0n1p2 /mnt/btrfs-top ls -lah /mnt/btrfs-top # Apagar os backups sudo btrfs subvolume delete \u0026#34;/mnt/btrfs-top/@_backup_...\u0026#34; sudo btrfs subvolume delete \u0026#34;/mnt/btrfs-top/@home_backup_...\u0026#34; sudo btrfs subvolume sync /mnt/btrfs-top Forçar liberação do espaço Após apagar, o espaço pode não aparecer imediatamente — o Btrfs trabalha com chunks de alocação.\nsudo btrfs filesystem sync / sudo btrfs balance start -dusage=50 / df -h sudo btrfs filesystem usage / Por que os snapshots enchem o disco O snap-pac cria PRE + POST para cada operação do pacman, mesmo pacotes pequenos. Snapshots do /home também preservam arquivos grandes já deletados — se havia snapshot quando um jogo de 50GB estava instalado, ele continua ocupando espaço mesmo após desinstalar.\nLimitar snapshots sudo nano /etc/snapper/configs/root # (repita para /home se necessário) Conservador (recomendado para SSDs menores):\nTIMELINE_LIMIT_HOURLY=\u0026#34;3\u0026#34; TIMELINE_LIMIT_DAILY=\u0026#34;3\u0026#34; TIMELINE_LIMIT_WEEKLY=\u0026#34;1\u0026#34; TIMELINE_LIMIT_MONTHLY=\u0026#34;0\u0026#34; TIMELINE_LIMIT_YEARLY=\u0026#34;0\u0026#34; NUMBER_LIMIT=\u0026#34;10\u0026#34; NUMBER_LIMIT_IMPORTANT=\u0026#34;5\u0026#34; # Forçar limpeza manualmente sudo snapper cleanup number sudo snapper cleanup timeline Desligar snapshots automáticos (opcional) sudo systemctl disable --now snapper-timeline.timer sudo systemctl disable --now snapper-cleanup.timer Ou só parar a criação mantendo o Snapper ativo:\nTIMELINE_CREATE=\u0026#34;no\u0026#34; sudo systemctl list-timers | grep snapper Liberar espaço adicional # Cache do pacman sudo du -sh /var/cache/pacman/pkg sudo paccache -rk2 sudo pacman -Scc # Logs sudo journalctl --vacuum-time=7d # Encontrar o que está pesando sudo du -xh / | sort -h | tail -40 sudo pacman -S ncdu \u0026amp;\u0026amp; sudo ncdu / Manutenção sudo btrfs scrub start -Bd / sudo btrfs device stats / Resumo Btrfs ├── CoW → copia antes de alterar ├── Subvolumes → @ e @home separados ├── Snapshots → rollback rápido ├── Snapper → automação └── grub-btrfs → snapshots no boot Fluxo normal:\npacman -Syu → PRE → update → POST → deu problema? → snapper rollback N → reboot Fluxo de limpeza:\nsnapper list ↓ snapper delete \u0026lt;intervalo\u0026gt; ↓ verificar subvolumes de backup no btrfs-top ↓ btrfs subvolume delete \u0026#34;@_backup_...\u0026#34; ↓ btrfs filesystem sync / \u0026amp;\u0026amp; btrfs balance start -dusage=50 / ↓ df -h ↓ ajustar limites em /etc/snapper/configs/root ","permalink":"https://maggioni.dev/pt-br/posts/linux/btrfs-snapshots-arch-linux/","summary":"Aprenda como funcionam snapshots Btrfs no Arch Linux e CachyOS usando Snapper. Veja como criar snapshots automáticos, rollback, recuperar arquivos, limitar espaço usado e configurar subvolumes corretamente.","title":"Guia Completo de Snapshots Btrfs no Arch Linux com Snapper"},{"content":"Resumo do post Nesse post iremos entender como funciona o sistema de arquivos do linux, como ele usa as pastas e etc. Também tem conteúdos extras no final: lost+found, fstab e trash.\nIntrodução Se você cresceu usando Windows, é bem provável que a ideia de \u0026ldquo;disco C:\u0026rdquo; esteja quase automática no seu cérebro. Programas em um lugar, arquivos pessoais em outro, tudo meio segmentado por letras que organizam o caos de forma bem intuitiva.\nAí você abre o Linux pela primeira vez e… nada de C:, D:, E:. Em vez disso, você encontra uma única árvore de diretórios, começando pela raiz, o famoso \u0026ldquo;/\u0026rdquo;. E isso causa um pequeno curto no início, porque o jeito de pensar muda completamente.\nNo Linux, tudo faz parte do mesmo sistema de arquivos. Discos, pendrives, pastas do sistema, configurações, usuários, tudo vive dentro dessa estrutura hierárquica. Entender isso não é só um detalhe técnico, é praticamente a chave para começar a se sentir confortável dentro do sistema.\nE quando essa virada de mentalidade acontece, o Linux deixa de parecer estranho e começa a fazer sentido de um jeito bem mais profundo do que parece à primeira vista.\nO sistema de arquivos do Linux O linux geralmente é composto por essa estrutura de pastas básicas:\n/ ├── bin ├── boot ├── dev ├── etc ├── home ├── lib ├── media ├── mnt ├── opt ├── proc ├── root ├── run ├── sbin ├── srv ├── sys ├── tmp └── usr └── var vamos entender como cada pasta funciona e suas responsabilidades:\nA pasta ROOT (ou /) No Windows, as coisas costumam ficar geralmente em C:\\. No Linux, a pasta principal do sistema fica em /.\n/ (ou \u0026ldquo;root\u0026rdquo;) é a raiz do sistema, onde todas as pastas vivem. Basicamente, no root você vê todo o sistema aberto, e tudo oque tem nele.\nPerceba que, algumas pastas tem um ícone de \u0026ldquo;link\u0026rdquo;, alguns tem um ícone de \u0026ldquo;cadeado\u0026rdquo; ou de \u0026ldquo;xis\u0026rdquo;.\nAs pastas com o ícone de link\u0026hellip; \u0026hellip; são \u0026ldquo;links simbólicos\u0026rdquo; (symlinks) criados pelo sistema. Isso quer dizer que você pode ver a pasta bin dentro de /, mas ela não está realmente ali. Na prática, ela aponta para outro local do sistema, como se fosse um atalho, só que em nível de filesystem.\nSe você olhar no print, pode ver que o link está em /, mas aponta pra usr/bin.\nAs pastas com o ícone de xis ou cadeado\u0026hellip; \u0026hellip;são pastas cujo seu usuário atual não possui acesso, ou privilégios para acessar (para acessá-las pode ser necessário digitar a senha do admin pra fazer alterações).\nNote que, essas pastas são protegidas por um motivo: assegurar que você não vai estragar o seu sistema; Não é recomendado mecher nelas, a menos que você entenda o que está fazendo. O próprio sistema lhe avisa sobre os riscos:\nEntendo as pastas - BIN O nome bin deriva de \u0026ldquo;binaries\u0026rdquo; (binários).\nEla é a pasta que contém os executáveis dos aplicativos que você usa. Se você passear por esta pasta, verá vários nomes comuns no seu dia:\nComandos como ls, cp, mv, rm, cat, mkdir aparecem por aqui, e são justamente esses pequenos executáveis que você usa o tempo todo sem nem pensar muito nisso.\nVocê pode, inclusive, jogar um executável seu aqui dentro (de alguma cli que você baixou ou criou) e poderá chamá-lo de qualquer lugar, apenas digitando o seu nome.\n- BOOT Como o nome sugere, esta é a pasta responsável pelo boot do seu sistema. Ela armazena todos os arquivos e configurações responsáveis pela inicialização do seu linux.\nAqui você encontra a pasta do GRUB. Ele é o bootloader que entra em ação logo após o firmware da máquina iniciar o processo de boot. É ele quem decide qual sistema será carregado, especialmente em cenários de dual boot, permitindo escolher entre Linux, Windows ou qualquer outro sistema instalado antes de iniciar de fato o sistema operacional.\nAqui você encontra também, curiosamente, o próprio kernel do linux, no meu caso como uso o cachyos, ele usa sua própria versão customizada: \u0026ldquo;vmlinuz-linux-cachyos\u0026rdquo;.\n- DEV A pasta dev me enganou ao pensar ser \u0026ldquo;developer\u0026rdquo;. Na real, ela é abreviação de \u0026ldquo;devices\u0026rdquo; (dispositivos).\nEssa pasta é, muito interessante, e conceitualmente distinta do windows;\nEla abriga arquivos que, incrivelmente, representam o seu hardware. No linux, todo e qualquer dispositivo que você tem no seu pc é, olha que loucura, representado por um arquivo. Ou seja, seu teclado, mouse, hd, ssd, estão todos aqui.\n- ETC Etcétara? Não sei oque significa, e há divergências sobre o real significado da palavra. No entanto isso não é relevante para nós.\nEssa pasta costuma abrigar arquivos de configurações dos softwares do seu sistema. Ou seja, você pode configurar algo pela interface gráfica, e as configurações podem vir parar em algum lugar por aqui.\n- HOME Essa é a pasta que nos interessa!\nÉ aqui que ficam as pastas dos usuários, e seus respectivos arquivos. Essa é a pasta mais semelhante ao que temos no windows:\nAqui é onde criamos os nossos arquivos, e trabalhamos no dia a dia.\n- LIB, LIB64 e etc Sâo pastas utilizadas geralmente por devs.\nEssas pastas armazenam bibliotecas compartilhadas, ou seja, pedaços de código que programas usam para funcionar sem precisar \u0026ldquo;recriar tudo do zero\u0026rdquo; toda vez.\nPensa nelas como uma espécie de base de peças reutilizáveis que o sistema inteiro compartilha.\noutras variações: /usr/lib, /usr/local/lib Aqui começa a parte mais \u0026ldquo;organizada por camadas\u0026rdquo;.\n/usr/lib → bibliotecas de programas instalados pelo sistema ou gerenciador de pacotes /usr/local/lib → bibliotecas de programas instalados manualmente (fora do gerenciador de pacotes) Essa separação ajuda o sistema a não misturar o que é do sistema base com o que você instalou por fora.\n- MEDIA A pasta media funciona como um ponto de montagem, voltada a dispositivos removíveis, como pendrives, cartões de memória, HDs e SSDs externos.\nNo Linux, quando um dispositivo é conectado, o sistema pode montá lo automaticamente em algum ponto do sistema de arquivos. Em algumas distribuições isso acontece dentro de /media, criando subpastas por usuário e nome do dispositivo.\nEssa pasta é dinâmica, então só aparece algo útil quando existe um dispositivo montado. Caso contrário, ela pode estar vazia ou até nem existir no sistema, dependendo da distribuição.\nEm sistemas mais modernos, esse comportamento pode variar. Em muitos casos, especialmente com systemd (meu caso no cachyos), as montagens automáticas acabam indo para caminhos como /run/media/usuario, enquanto o /media fica apenas como um padrão tradicional que nem sempre é utilizado diretamente.\nNa prática, ela continua sendo um ponto de referência importante na estrutura do Linux, mas hoje o uso dela depende bastante de como o sistema está configurado e do ambiente desktop em uso.\n- MNT mnt é uma pasta \u0026ldquo;prima\u0026rdquo; de media. O nome vem de \u0026ldquo;mount\u0026rdquo;, que significa montagem.\nEla funciona como um ponto de montagem mais genérico. A diferença principal é que, enquanto o /media costuma ser usado por sistemas e ambientes desktop para montar dispositivos automaticamente, o /mnt tradicionalmente é reservado para montagens feitas manualmente pelo usuário ou pelo administrador do sistema.\nNa prática, você pode usar o /mnt quando quiser montar qualquer coisa de forma controlada, como um segundo disco, uma partição específica ou até um sistema remoto. Por exemplo, um comando comum seria montar um disco ali temporariamente para manutenção ou transferência de arquivos.\nHoje em dia, muitas distribuições não impõem regras rígidas sobre isso, então tanto /media quanto /mnt podem ser usados de forma flexível.\nUm ponto importante dentro desse assunto é o arquivo /etc/fstab. Ele é basicamente a lista de montagens fixas do sistema. Nele você define quais dispositivos devem ser montados automaticamente no boot, em quais pontos de montagem e com quais opções.\n- OPT OPT deriva de \u0026ldquo;Optional\u0026rdquo; (Opcional).\nEssa pasta é usada para instalação de softwares adicionais que não fazem parte do sistema base nem seguem totalmente a estrutura padrão de pacotes da distribuição. A ideia é manter esses programas isolados, com todos os arquivos deles organizados em um único lugar, sem misturar com o restante do sistema.\nNa prática, ela costuma ser usada por softwares distribuídos \u0026ldquo;prontos\u0026rdquo;, que vêm com tudo embutido. Em vez de espalhar executáveis, bibliotecas e recursos por várias pastas do sistema, tudo fica concentrado dentro de /opt/nome-do-programa.\nO uso dela depende bastante de como o desenvolvedor empacota o software. Algumas aplicações escolhem esse modelo para evitar conflitos com bibliotecas do sistema ou para facilitar atualizações independentes.\nNo meu caso, por exemplo, o Brave aparece aqui isolado.\nJá outros programas podem não seguir esse padrão e acabam sendo instalados pelo gerenciador de pacotes da distro, ficando espalhados pelas pastas tradicionais como /usr/bin, /usr/lib e outras partes do sistema.\n- PROC PROC deriva de \u0026ldquo;processes\u0026rdquo; (processos), e é um diretório especial do Linux conhecido como filesystem virtual.\nNa prática, o /proc funciona como uma janela direta para o kernel. Ele expõe informações sobre processos, uso de memória, CPU, dispositivos e várias configurações internas que normalmente não seriam acessíveis de forma simples. Essas informações não estão gravadas no seu HD, ou no SSD. Elas estão na memória RAM do seu PC, e são apagados e recriados toda vez que você inicia o sistema, quando um processo é criado ou encerrado.\nPor exemplo, cada processo em execução tem uma pasta dentro de /proc, identificada pelo seu PID. Dentro dela você encontra dados como status, uso de recursos e até links para arquivos abertos pelo processo.\nÉ basicamente a mesma idéia da pasta dev, só que aplicado aos processos.\nSim, isso são os processos que estão rodando na sua máquina representados por arquivos:\n- ROOT Assim como a pasta home, o /root é um diretório pessoal, mas do usuário administrador do sistema.\nEle não deve ser confundido com a raiz / do Linux. O /root é apenas a \u0026ldquo;home\u0026rdquo; do superusuário.\nNa prática, é onde ficam arquivos e configurações usadas quando você está operando com permissões administrativas, separado dos usuários comuns que ficam em /home.\nGeralmente está vazia, não usamos ela diretamente.\n- RUN A pasta run, de \u0026ldquo;runtime\u0026rdquo;, é outro diretório virtual, assim como o proc.\nOs arquivos ali não ficam no disco, mas em memória, e representam o estado atual do sistema desde o último boot.\nDiferente do /proc, que expõe informações direto do kernel, o /run guarda dados mais práticos de execução: coisas como sessões de usuários, sockets, arquivos de controle de serviços e pontos de montagem temporários.\nÉ ali, por exemplo, que aparecem caminhos como /run/media/usuario, usados para montar dispositivos automaticamente.\nNo fim, o /run funciona como um espaço temporário onde o sistema e os serviços trocam informações enquanto estão rodando.\n- SBIN Se você entendeu a função da pasta bin, essa aqui segue a mesma ideia.\nA diferença é que o sbin reúne executáveis voltados para administração do sistema. São ferramentas mais \u0026ldquo;sensíveis\u0026rdquo;, usadas para manutenção, configuração de rede, discos, boot e coisas do tipo.\nNem sempre significa que só o root pode executar, mas, na prática, a maioria desses comandos faz sentido apenas com permissões elevadas. Por isso eles ficam separados dos binários comuns.\nEnquanto o /bin tem comandos do dia a dia, o /sbin concentra utilitários mais críticos do sistema.\n- SRV Pouco usada no dia a dia.\nA pasta srv vem de \u0026ldquo;service\u0026rdquo; e foi pensada para armazenar dados servidos por serviços do sistema, como um servidor web ou FTP. Por exemplo, arquivos de um site poderiam ficar em /srv/http.\nNa prática, muitas distribuições e aplicações ignoram esse padrão e usam outros caminhos como /var/www ou diretórios próprios, então ela acaba ficando vazia na maioria dos sistemas desktop.\n- SYS Abreviação de “system”. Assim como proc e run, também é um diretório virtual, criado em tempo real pelo sistema.\nO /sys expõe informações do kernel de forma mais estruturada, principalmente sobre hardware, dispositivos e drivers. Ele faz parte do sysfs, uma interface que permite não só ler informações, mas em alguns casos até alterar o comportamento de componentes do sistema.\nDiferente do que parece, os módulos (drivers) e firmwares não ficam armazenados ali. Eles estão no disco, geralmente em /lib/modules e /lib/firmware. O /sys apenas mostra o estado atual desses componentes já carregados no sistema.\nNa prática, é um ponto de interação direta com o kernel, mais técnico e raramente usado no dia a dia.\n- TMP Abreviação de \u0026ldquo;temporary\u0026rdquo;. Como o próprio nome sugere, arquivos e programas podem usar essa pasta como armazenamento temporário, que vão ser usados pelo usuário ou pelo próprio programa. Todos os dados aqui são apagados na reinicialização do sistema.\n- USR Muitas vezes interpretado como \u0026ldquo;user\u0026rdquo;, mas o significado mais aceito é \u0026ldquo;Unix System Resources\u0026rdquo;.\nO /usr concentra a maior parte dos programas e recursos do sistema que não são críticos para o boot. É ali que ficam executáveis, bibliotecas, documentação e outros arquivos usados no dia a dia.\nNa prática, muita coisa que você instala vai parar dentro de /usr, principalmente em subpastas como /usr/bin, /usr/lib e /usr/share.\nse lembra que o bin, link é um link que vem pra cá?\n- VAR Estou ficando cansado de escrever esse post 🫠\nBom, estamos quase acabando! ~ grub grub grub café;\nO nome var vem de \u0026ldquo;variable\u0026rdquo;. É uma pasta onde ficam arquivos que mudam com o tempo, tanto em conteúdo quanto em tamanho.\nAqui entram coisas como logs do sistema, cache, arquivos temporários mais persistentes e dados gerados por serviços enquanto estão rodando. Por exemplo, logs costumam ficar em /var/log, e alguns serviços armazenam estado ou dados em /var/lib.\nDiferente de outras partes mais \u0026ldquo;estáticas\u0026rdquo; do sistema, o /var está sempre sendo atualizado.\n- extra #1: LOST+FOUND lost+found pode ser traduzida como \u0026ldquo;achados e perdidos\u0026rdquo;.\nEssa pasta aparece principalmente em sistemas de arquivos do tipo ext, como ext4, e ela é criada automaticamente pelo sistema. Em condições normais, você quase nunca interage com ela.\nA função dela é bem específica: armazenar arquivos que foram recuperados após algum tipo de corrupção no sistema de arquivos. Isso pode acontecer depois de um desligamento inesperado, queda de energia ou falhas no disco. Quando o sistema roda uma verificação com ferramentas como fsck, ele tenta restaurar o que for possível e coloca esses dados dentro do lost+found.\nNa prática, o que vai parar ali geralmente são fragmentos de arquivos ou arquivos sem nome original, já que o sistema não conseguiu reconstruir completamente sua estrutura. Por isso ela costuma parecer vazia ou confusa quando acessada.\nEm muitas distribuições ela fica oculta por padrão e aparece apenas com permissões elevadas, justamente porque não é um diretório para uso manual no dia a dia.\n- extra #2: Como funciona a Lixeira A lixeira é virtual.\nQuando você abre a lixeira no gerenciador de arquivos, o endereço exibido é trash:// — um protocolo virtual que unifica as lixeiras de todos os dispositivos conectados em uma interface única. Por baixo dos panos, ela aponta para pastas físicas reais no sistema de arquivos.\nOnde os arquivos ficam? Para o disco principal do sistema, a lixeira fica na pasta oculta dentro da sua home:\n# ~/.local/share/Trash/ ├── files/ ← os arquivos apagados ficam aqui ├── info/ ← metadados: caminho original + data de exclusão └── expunged/ ← limbo antes do kernel liberar o espaço A pasta info/ guarda um arquivo .trashinfo para cada item apagado — é ele que permite restaurar o arquivo para o lugar exato de onde veio.\n.Trash-1000? Quando você apaga um arquivo de um dispositivo externo (HD externo, pendrive), o Linux não manda para a lixeira do sistema. Ele cria uma lixeira dentro do próprio dispositivo, com o número de identificação do usuário no nome.\nNome da pasta : .Trash-1000 O número 1000 é o UID do primeiro usuário criado na instalação\nLocalização : /media/user/DISK/ Fica na raiz do dispositivo externo, oculta (começa com ponto)\nO que acontece ao esvaziar? Ao excluir da lixeira, o sistema operacional não apaga os dados fisicamente — ele apenas marca os inodes e o espaço em disco como disponíveis. Os bits continuam lá até serem sobrescritos por novos dados. É por isso que ferramentas de recuperação funcionam: enquanto o espaço não foi reutilizado, os dados podem ser recuperados.\nVerificar seu UID Para confirmar seu número de usuário (e entender o nome da pasta):\nid -u 1000\nSe o root apagar algo de um pendrive, a lixeira se chamará .Trash-0 — porque o UID do root é sempre 0.\n- extra #3: FSTAB /etc/fstab o mapa de montagem do seu sistema\nO que é? O /etc/fstab (filesystem table) é uma tabela de configuração que o sistema lê durante o boot para saber:\nquais dispositivos montar onde montar com quais opções Tecnicamente, quem executa a montagem hoje em dia costuma ser o systemd (via systemd-mount), não diretamente o kernel, mas a ideia continua a mesma.\nSem o fstab, você teria que rodar mount manualmente toda vez que ligasse o computador. Funciona, mas ninguém quer viver assim.\nComo ele se parece? # \u0026lt;dispositivo\u0026gt; \u0026lt;ponto\u0026gt; \u0026lt;fs\u0026gt; \u0026lt;opções\u0026gt; \u0026lt;dump\u0026gt; \u0026lt;pass\u0026gt; UUID=a1b2-c3d4 / ext4 defaults 0 1 UUID=e5f6-g7h8 /boot/efi vfat umask=0077 0 2 UUID=i9j0-k1l2 /home ext4 defaults 0 2 /dev/sdb1 /dados ntfs uid=1000,gid=1000 0 0 tmpfs /tmp tmpfs size=2G,noexec 0 0 Pequeno detalhe que muita gente ignora: a ordem das linhas não é totalmente irrelevante, especialmente quando há dependências entre mounts.\nOs 6 campos de cada linha Campo 1 — dispositivo Pode ser:\nUUID LABEL /dev/sdX UUID é o mais confiável. /dev/sdb1 pode virar /dev/sdc1 se você plugar outro disco antes.\nCampo 2 — ponto de montagem É onde o sistema “encaixa” o disco na árvore.\nExemplo: se você monta em /dados, tudo daquele disco aparece ali.\nE sim, a pasta precisa existir antes. Se não existir, o mount falha silenciosamente em alguns casos… e aí começa a confusão.\nCampo 3 — tipo de sistema de arquivos\nAlguns comuns:\next4 → padrão Linux btrfs → snapshots, compressão vfat → EFI, pendrives ntfs → Windows tmpfs → memória RAM Campo 4 — opções\nAqui mora o poder… e os bugs.\ndefaults já cobre bastante coisa, mas no mundo real você acaba usando combinações.\nUm exemplo mais “realista” pra NTFS:\nuid=1000,gid=1000,umask=022,nofail Sem isso, você monta o disco e não consegue escrever nele como usuário normal. Clássico.\nCampo 5 — dump\nQuase morto hoje. Deixa 0 e segue a vida.\nCampo 6 — pass (fsck)\nDefine a ordem de verificação no boot:\n1 → raiz (/) 2 → outras partições 0 → não verifica Se você colocar errado aqui, o sistema pode demorar MUITO pra iniciar ou até travar esperando checagem.\nComo usar na prática 1. Descubra o UUID\nlsblk -f # ou blkid /dev/sdb1 Dica meio prática: o lsblk -f é mais legível, o blkid é mais direto.\n2. Crie o ponto de montagem\nsudo mkdir -p /mnt/dados 3. Edite com cuidado\nsudo cp /etc/fstab /etc/fstab.bak #backup! sudo nano /etc/fstab # \u0026lt;= isso vai abrir o arquivo para você mecher Sempre realize backups para evitar quebrar o boot\u0026hellip;\nexemplo do que colar para que monte um disco sozinho:\nUUID=XXXXXXXXX /mnt/dados ext4 defaults,nofail 0 2 4. Teste sem reiniciar\nsudo mount -a Se der erro aqui, você ainda está seguro. Se ignorar isso e reiniciar… aí vira aventura.\nDICAS Use nofail para:\nHD externo SSD secundário qualquer coisa não essencial Sem isso, se o disco não estiver presente, o sistema pode parar no boot esperando algo que nunca vai aparecer.\nAVISO Um fstab mal configurado pode:\ntravar o boot cair em emergency mode ou simplesmente não montar nada e você nem perceber Se acontecer, você pode corrigir via modo recovery ou live USB. Mas é melhor não chegar lá.\nOpções mais usadas defaults → rw, suid, dev, exec, auto, nouser, async noauto → não monta no boot ro → somente leitura nofail → ignora erro se o dispositivo não existir uid=1000 → define dono (útil pra ntfs/vfat) noexec → bloqueia execução (bom pra /tmp) x-systemd.automount → monta só quando acessado ","permalink":"https://maggioni.dev/pt-br/posts/linux/understanding-the-linux-folder-structure/","summary":"Entenda de uma vez por todas como funciona o sistema de pastas e arquivos do linux","title":"Entendendo a estrutura de pastas do Linux"},{"content":"Se você usa Hugo hospedado no GitHub Pages e queria um CMS visual para gerenciar seu conteúdo sem precisar do Netlify, esse post é pra você.\nIntrodução Eu construí este blog usando o Hugo como gerador de sites estáticos e o tema PaperMod, que me dá uma base leve, rápida e bem organizada para conteúdo técnico e pessoal. No começo isso parece suficiente, e de fato funciona muito bem só com Markdown e build estático.\nMas conforme o projeto cresce, começa a ficar claro que editar tudo “na mão” vira um gargalo. Publicar um post novo, gerenciar imagens, ajustar front matter, lidar com estrutura de pastas… tudo isso começa a pesar no fluxo. É aí que a ideia de um CMS entra naturalmente, não como luxo, mas como uma forma de manter o blog vivo sem transformar cada atualização em um pequeno projeto paralelo.\nDentro desse contexto entra o Sveltia CMS. Ele é uma interface moderna para gerenciamento de conteúdo em projetos estáticos, funcionando como uma camada amigável por cima dos arquivos do repositório. Em vez de editar Markdown diretamente, você passa a ter uma experiência mais guiada, quase como um editor de blog tradicional, mas sem abrir mão da simplicidade e do controle total que o Hugo oferece.\nA escolha por ele vem dessa tentativa de equilibrar duas coisas que normalmente brigam entre si: liberdade total do sistema de arquivos e uma experiência de edição mais fluida, quase “sem fricção”.\nPor que não simplesmente usar o Netlify CMS? O Netlify CMS (agora Decap CMS) usa o api.netlify.com como intermediário para autenticação OAuth com o GitHub. Se o seu site não está hospedado no Netlify, isso simplesmente não funciona - e você recebe um Not Found na hora do login.\nO Sveltia CMS é um fork moderno e mais rápido do Netlify CMS, e resolve esse problema permitindo que você plugue seu próprio servidor OAuth.\nO problema com usePKCE: true Você pode ter visto na documentação do Sveltia que existe uma opção usePKCE: true que eliminaria a necessidade de um servidor OAuth. Mas atenção:\nIsso não funciona com GitHub. O suporte a PKCE pelo GitHub ainda não foi lançado. A opção só funciona com GitLab. Mesmo com usePKCE: true no config, o Sveltia cai no fluxo padrão e tenta usar o api.netlify.com - que retorna 404 se seu site não está lá.\nA solução correta é usar o Sveltia CMS Authenticator, um Cloudflare Worker oficial feito pelo time do Sveltia.\nPré-requisitos Site Hugo rodando no GitHub Pages com domínio customizado (veja a minha wiki) Conta e Domínio no Cloudflare (ensinei nesse post) Node.js instalado localmente wrangler CLI do Cloudflare Passo 1: Criar um OAuth App no GitHub Acesse GitHub → Settings → Developer settings → OAuth Apps → New OAuth App e preencha:\nApplication name: Sveltia CMS (ou qualquer nome) Homepage URL: https://seu-dominio.com Authorization callback URL: https://sveltia-cms-auth.SEU_USUARIO.workers.dev A callback URL será atualizada depois que você criar o Worker. Por enquanto, coloque um placeholder.\nApós criar, anote o Client ID e gere um Client Secret - ele só aparece uma vez.\nPasso 2: Instalar o Wrangler e fazer login npm install -g wrangler wrangler login O comando abrirá o browser para autenticar com sua conta Cloudflare.\nPasso 3: Deploy do Sveltia CMS Authenticator Clone o repositório oficial e instale as dependências:\ngit clone https://github.com/sveltia/sveltia-cms-auth cd sveltia-cms-auth npm install Configure as variáveis secretas (o CLI vai pedir que você cole os valores):\nwrangler secret put GITHUB_CLIENT_ID wrangler secret put GITHUB_CLIENT_SECRET Faça o deploy:\nwrangler deploy A URL do Worker será exibida no terminal - algo como:\nhttps://sveltia-cms-auth.SEU_USUARIO.workers.dev Passo 4: Atualizar o callback URL no GitHub Volte no seu OAuth App no GitHub e atualize o Authorization callback URL para a URL do seu Worker:\nhttps://sveltia-cms-auth.SEU_USUARIO.workers.dev/callback Passo 5: Configurar o Sveltia CMS No seu repositório Hugo, crie (ou atualize) o arquivo static/admin/config.yml:\nbackend: name: github repo: SEU_USUARIO/SEU_REPO branch: main base_url: https://sveltia-cms-auth.SEU_USUARIO.workers.dev/callback site_url: https://seu-dominio.com media_folder: static/images public_folder: /images collections: # suas collections aqui E o static/admin/index.html:\n\u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026#34;pt-BR\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026gt; \u0026lt;title\u0026gt;Painel de Administração - Sveltia CMS\u0026lt;/title\u0026gt; \u0026lt;script type=\u0026#34;module\u0026#34; src=\u0026#34;https://unpkg.com/@sveltia/cms@latest/dist/sveltia-cms.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;sveltia-cms config=\u0026#34;config.json\u0026#34;\u0026gt;\u0026lt;/sveltia-cms\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; Passo 6: Commit e push git add static/admin/ git commit -m \u0026#34;feat: adiciona sveltia cms com cloudflare workers oauth\u0026#34; git push Aguarde o GitHub Actions fazer o deploy e acesse https://seu-dominio.com/admin/.\nVerificando se funcionou Ao clicar em Login with GitHub, o fluxo correto é:\nRedireciona para github.com/login/oauth/authorize com o seu client_id Você autoriza o app GitHub redireciona para o seu Worker (workers.dev/?code=...) Worker troca o code pelo token e redireciona de volta para o CMS Você entra autenticado ✅ Se ainda aparecer api.netlify.com na URL, limpe o cache do browser (Ctrl+Shift+R) ou teste em aba anônima - o Sveltia às vezes mantém configuração antiga em cache.\nCom isso, você tem um CMS visual completo, rodando 100% no GitHub Pages, com autenticação segura via Cloudflare Workers - sem precisar migrar para o Netlify ou manter nenhuma infraestrutura adicional.\n","permalink":"https://maggioni.dev/pt-br/posts/dev/sveltia-cms-github-pages-cloudflare/","summary":"Como configurar o Sveltia CMS no GitHub Pages usando Cloudflare Workers para autenticação OAuth - sem depender do Netlify.","title":"Sveltia CMS com GitHub Pages e Cloudflare Workers"},{"content":"O que iremos fazer apagar tudo do disco criar partição nova formatar em ext4 montar automaticamente no sistema 1. Identificar o disco correto Antes de qualquer coisa:\nlsblk Saída típica:\nsda 931.5G └─sda1 nvme0n1 465.8G O sistema geralmente está no NVMe. O HD secundário costuma ser sda.\nConfirma isso com calma. Esse passo evita desastre.\n2. Desmontar o disco Se ele estiver montado automaticamente:\nsudo umount /dev/sda1 Se reclamar que está em uso:\nsudo umount -l /dev/sda1 3. Apagar tudo (tabela de partição) sudo parted /dev/sda mklabel gpt Isso limpa completamente o disco.\n4. Criar nova partição sudo parted -a opt /dev/sda mkpart primary ext4 0% 100% Agora você terá uma partição nova ocupando todo o HD.\n5. Formatar em ext4 sudo mkfs.ext4 -L DADOS /dev/sda1 Aqui você pode definir um nome (label). Não é obrigatório, mas ajuda a identificar depois.\n6. Montar manualmente para teste sudo mkdir /mnt/hd sudo mount /dev/sda1 /mnt/hd Teste rápido:\ntouch /mnt/hd/teste.txt Se der permissão negada:\nsudo chown -R $USER:$USER /mnt/hd 7. Descobrir o UUID lsblk -f Você vai ver algo assim:\nsda1 ext4 UUID=0ad14adb-dd8a-4c93-875b-bde24e4f3892 Guarde esse valor.\n8. Montagem automática no boot Edite o arquivo:\nsudo nano /etc/fstab Adicione no final:\nUUID=SEU_UUID_AQUI /mnt/hd ext4 defaults,nofail 0 2 Exemplo real:\nUUID=0ad14adb-dd8a-4c93-875b-bde24e4f3892 /mnt/hd ext4 defaults,nofail 0 2 9. Testar sem reiniciar sudo mount -a Se não aparecer erro, está funcionando.\nSobre permissões Por padrão, o Linux usa dono e grupo. Se quiser acesso total para seu usuário:\nsudo chown -R $USER:$USER /mnt/hd Se quiser algo compartilhado entre usuários, o ideal é usar grupos ao invés de liberar tudo.\nResultado final Depois disso:\no HD monta sozinho ao ligar o sistema não pede senha funciona como parte nativa do Fedora pronto para Steam, backups ou projetos Se algo não montar no boot, geralmente é erro de digitação no fstab. Vale revisar com calma.\n","permalink":"https://maggioni.dev/pt-br/posts/linux/how-format-hd-fedora/","summary":"Guia prático para formatar um HD e configurar montagem automática no Fedora KDE usando ext4 e fstab","title":"Como formatar e montar automaticamente um HD no Linux"},{"content":" Para quem é este post? Para quem ouviu falar de Linux, curiosos que querem entrar nesse mundo, e para quem já usa mas ainda esbarra em termos desconhecidos. Aqui você encontra um glossário completo, explicado com linguagem simples e exemplos do dia a dia.\nPor que aprender Linux? Linux está em todo lugar: nos servidores que hospedam seus sites favoritos, nos smartphones Android, nas smart TVs, nos supercomputadores e até nas sondas espaciais da NASA. Aprender Linux não é só uma habilidade técnica - é entender como o mundo digital realmente funciona.\nMas o universo Linux tem seu próprio vocabulário. Este dicionário vai te guiar por ele, letra a letra.\n🅐 - A de Abertura (e mais) APT (Advanced Package Tool) O gerenciador de pacotes padrão do Debian e Ubuntu. É como a \u0026ldquo;loja de aplicativos\u0026rdquo; da linha de comando. Com ele você instala, atualiza e remove programas sem precisar procurar no Google.\nsudo apt install nome-do-programa # instala sudo apt update # atualiza a lista de pacotes sudo apt upgrade # atualiza os programas instalados sudo apt remove nome-do-programa # remove Alias Um apelido que você cria para um comando longo. Imagine que toda vez que quer ver seus arquivos com detalhes, você digita ls -lah --color=auto. Com um alias, você simplesmente digita ll.\nalias ll=\u0026#39;ls -lah --color=auto\u0026#39; Ambiente de Desktop (DE - Desktop Environment) É a interface gráfica do Linux: janelas, ícones, barra de tarefas, menus. Os mais famosos são:\nGNOME - moderno e elegante (padrão no Ubuntu) KDE Plasma - altamente customizável XFCE - leve, ideal para computadores mais antigos MATE - clássico e estável Arch Linux Uma distribuição Linux minimalista e voltada para usuários avançados. Famosa pela filosofia \u0026ldquo;faça você mesmo\u0026rdquo; (DIY) e pelo AUR (repositório da comunidade). Quem usa Arch geralmente não perde oportunidade de mencionar isso.\nArquivo (File) No Linux, tudo é arquivo - programas, pastas, dispositivos de hardware, conexões de rede. É um dos princípios fundamentais do sistema. Inclusive o seu pendrive aparece como um arquivo dentro de /dev.\n🅑 - B de Bash Bash (Bourne Again Shell) O interpretador de comandos mais popular do Linux. É ele que \u0026ldquo;entende\u0026rdquo; o que você digita no terminal e executa as ações. Pense nele como o idioma que o Linux fala.\necho \u0026#34;Olá, mundo Linux!\u0026#34; Boot / Bootloader Boot é o processo de inicialização do computador. O bootloader é o programa que roda antes do sistema operacional e permite escolher qual sistema carregar (muito útil em dual boot Linux + Windows). O mais famoso é o GRUB.\nBug Um erro no código de um programa. No Linux, como boa parte do software é open source, qualquer pessoa pode reportar ou até corrigir bugs.\nBuild O processo de compilar o código-fonte de um programa para transformá-lo em um executável. É como \u0026ldquo;cozinhar\u0026rdquo; uma receita: você pega os ingredientes (código) e transforma no prato final (programa).\n🅒 - C de Comandos chmod (Change Mode) Comando que altera as permissões de arquivos e pastas. No Linux, todo arquivo tem três tipos de permissão: leitura (r), escrita (w) e execução (x), para três grupos: dono, grupo e outros.\nchmod +x script.sh # dá permissão de execução chmod 755 arquivo # dono pode tudo, grupo e outros só leem e executam chmod 644 documento.txt # dono lê e escreve, outros só leem chown (Change Owner) Muda o dono de um arquivo ou pasta.\nsudo chown joao:joao arquivo.txt CLI (Command Line Interface) Interface de linha de comando - ou seja, o terminal. Ao contrário de uma GUI (interface gráfica), na CLI você interage com o sistema digitando texto. Parece assustador no começo, mas é incrivelmente poderoso.\nCron / Crontab Sistema de agendamento de tarefas. Quer fazer backup todo dia às 3h da manhã automaticamente? Use o cron.\ncrontab -e # edita as tarefas agendadas Formato: minuto hora dia mês dia-da-semana comando\nCurl Ferramenta de linha de comando para transferir dados pela internet. Muito usada para testar APIs e baixar arquivos.\ncurl https://exemplo.com/arquivo.zip -o arquivo.zip 🅓 - D de Distribuição Distro (Distribuição Linux) Uma \u0026ldquo;versão\u0026rdquo; do Linux empacotada com diferentes programas, gerenciadores de pacotes e interfaces. O kernel (núcleo) é o mesmo, mas cada distro tem sua personalidade. As mais famosas:\nDistro Para quem é? Ubuntu Iniciantes, uso geral Fedora Usuários intermediários, tecnologias modernas Debian Estabilidade máxima, servidores Arch Linux Usuários avançados, personalização total Linux Mint Migrantes do Windows Kali Linux Segurança e hacking ético Pop!_OS Usuários de hardware NVIDIA, desenvolvedores Daemon Um processo que roda em segundo plano, sem interação direta com o usuário. É o equivalente a um \u0026ldquo;serviço\u0026rdquo; no Windows. O nome vem de \u0026ldquo;Disk And Execution MONitor\u0026rdquo;. Exemplos: servidor web (apache2), SSH (sshd), bluetooth (bluetoothd).\ndf e du Dois comandos para verificar o uso de espaço em disco.\ndf -h # mostra o uso de cada partição (human-readable) du -sh pasta/ # mostra o tamanho de uma pasta Dependência Um programa que outro programa precisa para funcionar. Quando você instala algo pelo APT ou DNF, o gerenciador cuida das dependências automaticamente.\n🅔 - E de Execução echo Comando que imprime texto na tela. Simples e muito útil em scripts.\necho \u0026#34;Bem-vindo ao Linux!\u0026#34; echo $HOME # imprime o diretório home do usuário atual Editor de Texto (Terminal) Programas para editar arquivos de texto sem interface gráfica. Os mais conhecidos:\nnano - simples, ideal para iniciantes vim - poderoso, curva de aprendizado íngreme (piada clássica: como sair do vim? :q!) emacs - extensível, quase um sistema operacional dentro do editor Ext4 O sistema de arquivos mais comum no Linux. É a forma como o sistema organiza e armazena dados no disco. Outros exemplos: btrfs, xfs, zfs.\nEnvironment Variables (Variáveis de Ambiente) Variáveis que o sistema usa para guardar configurações importantes.\necho $HOME # /home/seuusuario echo $PATH # onde o sistema procura por executáveis echo $USER # nome do usuário atual 🅕 - F de Filesystem Filesystem Hierarchy Standard (FHS) O padrão que define onde cada tipo de arquivo fica no Linux. Diferente do Windows (C:, D:), o Linux tem uma estrutura em árvore:\n/ → raiz do sistema (como o C:\\ do Windows) ├── /home → pastas dos usuários (seus documentos, downloads, etc.) ├── /etc → arquivos de configuração do sistema ├── /bin → programas essenciais ├── /usr → programas instalados pelo usuário ├── /var → logs, bancos de dados, e-mails ├── /tmp → arquivos temporários (apagados ao reiniciar) ├── /dev → dispositivos (HD, pendrive, placa de som...) ├── /proc → informações sobre processos em execução └── /mnt → ponto de montagem de dispositivos externos find Um dos comandos mais poderosos do Linux. Busca arquivos e pastas com infinitas opções de filtro.\nfind / -name \u0026#34;arquivo.txt\u0026#34; # procura em todo o sistema find . -name \u0026#34;*.log\u0026#34; -mtime -7 # logs modificados nos últimos 7 dias find /home -size +100M # arquivos maiores que 100MB Fork Quando o código de um projeto open source é copiado e desenvolvido de forma independente. Por exemplo, o LibreOffice é um fork do OpenOffice.\n🅖 - G de GNU GNU Projeto criado por Richard Stallman em 1983 com o objetivo de criar um sistema operacional totalmente livre. GNU fornece a maioria das ferramentas que usamos no Linux (compiladores, editores, utilitários). Por isso o nome correto é GNU/Linux.\nGNOME Um dos ambientes de desktop mais populares. Moderno, limpo e focado em produtividade. Padrão no Ubuntu e Fedora.\ngrep Ferramenta poderosa de busca em texto. Procura por padrões dentro de arquivos ou na saída de outros comandos.\ngrep \u0026#34;erro\u0026#34; arquivo.log # busca a palavra \u0026#34;erro\u0026#34; no arquivo grep -r \u0026#34;função\u0026#34; ./projeto/ # busca recursivamente na pasta ps aux | grep firefox # verifica se o Firefox está rodando GRUB (Grand Unified Bootloader) O bootloader mais usado no Linux. É a tela que aparece quando o computador liga e permite escolher entre Linux, Windows ou outras opções.\n🅗 - H de Home /home O diretório pessoal dos usuários. Cada usuário tem sua pasta em /home/nome-do-usuario. É onde ficam seus documentos, downloads, configurações pessoais, etc. O símbolo ~ representa seu home.\ncd ~ # vai para /home/seuusuario cd ~/Downloads História (history) O terminal guarda um histórico de tudo que você digita. Use history para ver e a seta ↑ para navegar.\nhistory # lista os últimos comandos history | grep apt # filtra só os comandos com \u0026#34;apt\u0026#34; !! # repete o último comando !sudo # repete o último comando que começou com \u0026#34;sudo\u0026#34; htop Monitor de processos interativo. Mostra CPU, RAM, processos em tempo real. É a versão melhorada do top.\nhtop 🅘 - I de Init init / systemd O primeiro processo que o Linux executa após o boot (PID 1). O systemd é o sistema de init mais moderno e amplamente usado. Ele gerencia serviços, montagem de discos, logs e muito mais.\nsystemctl status nginx # verifica status de um serviço systemctl start nginx # inicia systemctl stop nginx # para systemctl enable nginx # habilita na inicialização journalctl -xe # lê logs do systemd IP / Rede Comandos para gerenciar conexões de rede:\nip addr show # mostra interfaces e IPs (substituto do ifconfig) ip route # mostra a tabela de rotas ping google.com # testa conectividade ss -tuln # mostra portas abertas 🅙 - J de Jobs Jobs / Background No Linux, você pode rodar processos em segundo plano (background) sem bloquear o terminal.\ncomando \u0026amp; # roda em background jobs # lista processos em background fg # traz o processo para foreground bg # envia para background Ctrl+Z # pausa um processo 🅚 - K de Kernel Kernel O coração do Linux. É o software que faz a ponte entre os programas e o hardware. Gerencia memória, processos, dispositivos e segurança. Quando falamos \u0026ldquo;Linux\u0026rdquo;, tecnicamente falamos do kernel - criado por Linus Torvalds em 1991.\nuname -r # mostra a versão do kernel em uso kill / killall Comandos para encerrar processos.\nkill 1234 # encerra o processo com PID 1234 kill -9 1234 # força o encerramento (SIGKILL) killall firefox # encerra todos os processos chamados \u0026#34;firefox\u0026#34; 🅛 - L de Linux Linus Torvalds O criador do kernel Linux. Estudante finlandês que em 1991, aos 21 anos, publicou o primeiro kernel Linux como projeto pessoal. Hoje é um dos programadores mais influentes da história.\nln (Link) Cria links (atalhos) para arquivos.\nln -s /caminho/original /caminho/atalho # link simbólico (soft link) ln /caminho/original /caminho/hardlink # hard link ls O comando mais básico: lista arquivos e pastas.\nls # lista simples ls -l # lista detalhada ls -a # mostra arquivos ocultos (começam com .) ls -lah # detalhada + ocultos + tamanho legível Log Registros de eventos do sistema e dos programas. Ficam em /var/log/.\ntail -f /var/log/syslog # acompanha o log em tempo real 🅜 - M de Montagem man (Manual) A documentação embutida do Linux. Todo comando tem um manual acessível pelo terminal.\nman ls # manual do comando ls man grep # manual do grep Dica: dentro do man, use /palavra para buscar, e q para sair.\nMount / Umount No Linux, dispositivos externos precisam ser \u0026ldquo;montados\u0026rdquo; (associados a um diretório) antes de serem usados.\nmount /dev/sdb1 /mnt/pendrive # monta pendrive umount /mnt/pendrive # desmonta mkdir Cria diretórios (pastas).\nmkdir nova-pasta mkdir -p projetos/linux/tutorial # cria toda a hierarquia de uma vez 🅝 - N de Nano nano Editor de texto simples para o terminal. Ideal para iniciantes. Os atalhos aparecem na tela (^ = Ctrl).\nnano arquivo.txt # Ctrl+O = salvar | Ctrl+X = sair | Ctrl+W = buscar Network Manager Ferramenta gráfica (e de linha de comando) para gerenciar conexões Wi-Fi, Ethernet, VPN, etc.\nnmcli device wifi list # lista redes Wi-Fi nmcli device wifi connect \u0026#34;MinhaRede\u0026#34; password \u0026#34;senha123\u0026#34; 🅞 - O de Open Source Open Source (Código Aberto) Software cujo código-fonte é público, podendo ser estudado, modificado e redistribuído. O Linux é open source, assim como Firefox, VLC, LibreOffice e milhares de outros programas.\n/opt Diretório onde ficam programas de terceiros instalados manualmente (não pelo gerenciador de pacotes). Exemplo: Google Chrome, Android Studio.\n🅟 - P de Permissões Permissões Todo arquivo Linux tem três tipos de permissão para três grupos:\n-rwxr-xr-- 1 joao joao 1234 abr 26 10:00 script.sh ↑↑↑↑↑↑↑↑↑ │└┤└┤└┤└┤ │ │ │ └── outros: r-- (só leitura) │ │ └───── grupo: r-x (leitura e execução) │ └──────── dono: rwx (tudo) └────────── tipo: - (arquivo), d (diretório), l (link) PID (Process ID) Número único que identifica cada processo em execução.\nps aux # lista todos os processos ps aux | grep nginx # filtra por nome pgrep nginx # retorna apenas o PID PATH Variável de ambiente que diz ao sistema onde procurar por executáveis quando você digita um comando.\necho $PATH # /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin Pipe ( | ) Um dos recursos mais poderosos do Linux: conecta a saída de um comando à entrada de outro.\nls -l | grep \u0026#34;.txt\u0026#34; # lista só arquivos .txt ps aux | grep firefox # verifica se firefox roda cat log.txt | sort | uniq # ordena e remove duplicatas 🅠 - Q de Quota Quota de Disco Recurso que limita o quanto de espaço em disco cada usuário pode usar. Muito usado em servidores compartilhados.\n🅡 - R de Root Root O superusuário do Linux. Tem permissão para fazer qualquer coisa no sistema - apagar arquivos do sistema, instalar drivers, modificar configurações críticas. Com grande poder vem grande responsabilidade.\nsudo su # vira root (cuidado!) whoami # mostra o usuário atual rm (Remove) Remove arquivos e pastas. Cuidado: não tem lixeira no terminal!\nrm arquivo.txt rm -rf pasta/ # remove pasta e todo conteúdo (MUITO CUIDADO!) ⚠️ NUNCA execute rm -rf / como root. Isso apaga o sistema inteiro.\nrsync Ferramenta poderosa para sincronizar e copiar arquivos, localmente ou pela rede.\nrsync -avz origem/ destino/ rsync -avz -e ssh pasta/ usuario@servidor:/backup/ 🅢 - S de Shell Shell O programa que interpreta seus comandos no terminal. O mais comum é o Bash, mas existem outros como Zsh (padrão no macOS), Fish e Dash.\nSSH (Secure Shell) Protocolo para acesso remoto seguro a outro computador pela rede.\nssh usuario@192.168.1.100 # conecta ao servidor ssh -p 2222 usuario@servidor.com # porta diferente scp arquivo.txt usuario@servidor:/home/usuario/ # copia arquivo via SSH sudo Permite executar comandos como superusuário (root) de forma controlada e segura. É preferível ao uso direto do root.\nsudo apt update sudo systemctl restart apache2 sudo nano /etc/hosts Swap Espaço no disco rígido usado como memória RAM extra quando a RAM física acaba. É mais lento, mas evita travamentos.\nfree -h # mostra uso de RAM e swap swapon -s # mostra partições swap ativas Snap / Flatpak / AppImage Formatos modernos de distribuição de aplicativos que funcionam em qualquer distro Linux.\nSnap - criado pela Canonical (Ubuntu) Flatpak - favorito da comunidade Fedora AppImage - arquivo único, roda sem instalar 🅣 - T de Terminal Terminal / Emulador de Terminal O programa que você abre para digitar comandos. Não é o shell - é a \u0026ldquo;janela\u0026rdquo; que exibe o shell. Exemplos: GNOME Terminal, Konsole, Alacritty, Kitty, Tilix.\ntar Comando para compactar e descompactar arquivos.\ntar -czf arquivo.tar.gz pasta/ # compacta tar -xzf arquivo.tar.gz # descompacta tar -tzf arquivo.tar.gz # lista conteúdo sem extrair Macete para memorizar: cria, extrai, zip, file.\ntouch Cria um arquivo vazio ou atualiza a data de modificação de um arquivo existente.\ntouch novo-arquivo.txt 🅤 - U de Ubuntu Ubuntu A distribuição Linux mais popular para iniciantes. Baseada no Debian, mantida pela empresa Canonical. Tem lançamentos semestrais (ex: 24.04, 24.10) e versões LTS (Long Term Support) com suporte de 5 anos.\nuname Exibe informações sobre o sistema.\nuname -a # todas as informações uname -r # versão do kernel uname -m # arquitetura (x86_64, arm64...) Update vs Upgrade Confunde muito os iniciantes:\napt update - atualiza a lista de pacotes disponíveis (não instala nada) apt upgrade - instala as atualizações disponíveis 🅥 - V de Vim Vim Editor de texto de terminal extremamente poderoso. Tem modos diferentes: Normal (navegação), Insert (edição) e Command (salvar/sair).\ni → entra no modo Insert (para digitar) Esc → volta ao modo Normal :w → salva :q → sai :wq → salva e sai :q! → sai sem salvar Virtual Machine (VM) Computador simulado dentro do seu computador. Permite rodar Linux dentro do Windows (ou vice-versa) sem particionar o HD. Programas populares: VirtualBox (gratuito), VMware, GNOME Boxes.\n🅦 - W de wget wget Baixa arquivos da internet via linha de comando.\nwget https://exemplo.com/arquivo.zip wget -c https://exemplo.com/arquivo.iso # retoma download interrompido which / whereis Localiza onde um programa está instalado.\nwhich python3 # /usr/bin/python3 whereis nginx # mostra binário, sources e man pages 🅧 - X de X11 / Xorg X11 / Xorg / Wayland O sistema de janelas do Linux - o que permite exibir interfaces gráficas. X11/Xorg é o tradicional (30+ anos). Wayland é o moderno substituto, mais seguro e eficiente. Muitas distros já migram para Wayland como padrão.\n🅨 - Y de YUM/DNF YUM / DNF Gerenciadores de pacotes do Red Hat, Fedora e CentOS. O DNF é o sucessor moderno do YUM.\nsudo dnf install pacote sudo dnf update sudo dnf remove pacote sudo dnf search palavra-chave 🅩 - Z de Zsh Zsh (Z Shell) Um shell moderno e altamente configurável, alternativa ao Bash. Com o Oh My Zsh (framework de configuração), fica extremamente poderoso e bonito. Padrão no macOS desde 2019.\n# instalar zsh no Ubuntu sudo apt install zsh chsh -s $(which zsh) # define como shell padrão Tabela de Comandos Essenciais Comando O que faz pwd Mostra o diretório atual cd Muda de diretório ls Lista arquivos cp Copia arquivos mv Move ou renomeia arquivos rm Remove arquivos cat Exibe conteúdo de arquivo less Exibe arquivo paginado grep Busca texto find Busca arquivos chmod Altera permissões chown Altera dono sudo Executa como root apt/dnf/pacman Gerencia pacotes ssh Acesso remoto ps Lista processos kill Encerra processo df Uso de disco free Uso de memória top/htop Monitor do sistema tar Compacta/descompacta man Manual de comandos Por onde continuar? Agora que você tem o vocabulário básico, aqui estão os próximos passos sugeridos:\nInstale uma distro - Ubuntu ou Linux Mint são ótimas escolhas para começar Use o terminal todo dia - mesmo para coisas simples como criar pastas Leia o manual - man comando é seu melhor amigo Explore o DistroWatch - distrowatch.com para conhecer as distribuições Participe da comunidade - fóruns, Reddit (r/linux4noobs), grupos no Telegram 💡 Dica final: O Linux recompensa a curiosidade. Não tenha medo de explorar, errar (em uma VM primeiro!) e aprender com os erros. A comunidade é enorme e acolhedora.\nFicou algum termo de fora? Deixa nos comentários e atualizo o dicionário! 🐧\n","permalink":"https://maggioni.dev/pt-br/posts/linux/abc-do-linux/","summary":"\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003ePara quem é este post?\u003c/strong\u003e Para quem ouviu falar de Linux, curiosos que querem entrar nesse mundo, e para quem já usa mas ainda esbarra em termos desconhecidos. Aqui você encontra um glossário completo, explicado com linguagem simples e exemplos do dia a dia.\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"por-que-aprender-linux\"\u003ePor que aprender Linux?\u003c/h2\u003e\n\u003cp\u003eLinux está em todo lugar: nos servidores que hospedam seus sites favoritos, nos smartphones Android, nas smart TVs, nos supercomputadores e até nas sondas espaciais da NASA. Aprender Linux não é só uma habilidade técnica - é entender como o mundo digital realmente funciona.\u003c/p\u003e","title":"O ABC do Linux: Dicionário Completo para Iniciantes"},{"content":" O que você vai aprender neste guia: Criar um pendrive bootável inteligente (que aceita várias ISOs de uma vez), configurar a BIOS/UEFI para dar boot pelo pendrive, instalar o Fedora Linux e dar os primeiros passos no novo sistema. Do zero ao desktop funcional.\nRequisitos Antes de colocar a mão na massa, separe o seguinte:\nPendrive com pelo menos 16 GB Conexão com internet para baixar a ISO do Fedora Computador com Windows, Linux ou macOS para preparar o pendrive Cerca de 30–60 minutos de tempo livre Backup dos seus dados - se for instalar no seu HD principal, faça backup antes! Parte 1 - Baixando a ISO do Fedora O que é uma ISO? Uma ISO é um arquivo de imagem de disco - basicamente, uma cópia exata de um CD/DVD de instalação, comprimida num único arquivo. Você vai gravar essa imagem no seu pendrive para criar a mídia de instalação.\nQual versão do Fedora baixar? O Fedora tem várias \u0026ldquo;edições\u0026rdquo;. Eu vou recomendar que você baixe a versão com KDE Plasma, que está bastante interessante na minha opinião.\nBaixando a ISO Acesse: https://fedoraproject.org/kde/download/ Clique em \u0026ldquo;Download For Intel and AMD x86x64 systems\u0026rdquo; Escolha a arquitetura x86_64 para a maioria dos computadores modernos Aguarde o download - o arquivo tem cerca de 3 GB O arquivo vai se chamar algo parecido com Fedora KDE Plasma Desktop 43.iso.\n💡 Verifique a integridade: Após o download, você pode (opcionalmente, mas recomendado) verificar se o arquivo não foi corrompido durante o download comparando o hash SHA256. Na página de download do Fedora, clique em \u0026ldquo;verify your download\u0026rdquo; para ver as instruções.\n# No Linux/macOS, verificar o hash: sha256sum caminho-do-arquivo/nome-do-arquivo.iso Parte 2 - Criando o Pendrive Bootável com Ventoy Aqui está o diferencial deste guia: em vez de usar ferramentas comuns que apagam o pendrive inteiro para gravar apenas uma ISO, vamos usar o Ventoy - uma solução muito mais inteligente.\nPor Que o Ventoy é Superior? Ferramentas como Rufus, Balena Etcher e dd sobrescrevem todo o pendrive com uma única ISO. Se você quiser testar outra distro, precisa regravá-lo do zero.\nO Ventoy funciona de forma diferente:\nInstala uma vez no pendrive Depois é só copiar e colar arquivos ISO como se fosse um pendrive normal O pendrive continua usável para arquivos comuns na outra partição Na hora do boot, aparece um menu para você escolher qual ISO iniciar Suporta centenas de ISOs - Linux, Windows, ferramentas de recuperação… Instalando o Ventoy no Pendrive No Windows: Acesse ventoy.net e baixe a versão para seu sistema operacional Extraia o arquivo ZIP Execute o Ventoy2Disk como Administrador Em \u0026ldquo;Device\u0026rdquo;, selecione o seu pendrive (cuidado para não selecionar o HD errado!) Clique em \u0026ldquo;Install\u0026rdquo; Confirme o aviso - o pendrive será formatado Aguarde a conclusão ⚠️ ATENÇÃO: Instalar no HD errado vai apagar seus dados! Tenha certeza que está selecionando o pendrive no menu\nCopiando as ISOs para o Pendrive Após instalar o Ventoy, o pendrive vai aparecer com uma partição chamada \u0026ldquo;Ventoy\u0026rdquo;. É simples:\nAbra o pendrive no explorador de arquivos Copie e cole o arquivo .iso do Fedora diretamente para o pendrive Pronto! Você pode copiar quantas ISOs quiser (desde que caibam no espaço disponível! Inclusive isos do windows) 📁 Pendrive (Ventoy) ├── Fedora43.iso ├── ubuntu-24.04.2-desktop-amd64.iso ← pode ter várias! ├── linuxmint-22-cinnamon-64bit.iso └── SystemRescue-11.00-amd64.iso Parte 3 - Configurando a BIOS/UEFI para Dar Boot pelo Pendrive Esta é a etapa que mais assusta os iniciantes, mas é mais simples do que parece.\nO Que é a BIOS e a UEFI? BIOS (Basic Input/Output System) é o firmware do computador - o software gravado diretamente na placa-mãe que roda antes de qualquer sistema operacional. Ele inicializa o hardware e define de onde o computador vai dar boot (HD, pendrive, CD, rede…).\nUEFI (Unified Extensible Firmware Interface) é a evolução moderna da BIOS. A maioria dos computadores fabricados após 2012 usa UEFI. A diferença prática para o usuário é pequena, mas é importante saber que existem os dois.\nComo Entrar na BIOS/UEFI Conecte o pendrive e reinicie o computador. Logo no início, antes do sistema carregar, você precisa pressionar uma tecla específica. A tecla varia conforme o fabricante:\nFabricante / Produto Tecla para BIOS Tecla para Boot Menu Dell F2 F12 HP F10 ou Esc F9 Lenovo F1 ou F2 F12 Asus Del ou F2 F8 Acer Del ou F2 F12 MSI Del F11 Gigabyte Del F12 Samsung F2 Esc Apple (Boot Camp) - Option (Alt) 💡 Dica rápida: Se você não sabe a tecla, preste atenção na primeira tela que aparece ao ligar o computador - geralmente está escrito algo como \u0026ldquo;Press F2 to enter Setup\u0026rdquo; ou \u0026ldquo;Press Del for BIOS\u0026rdquo;. Você tem apenas alguns segundos!\nAtalho no Windows 10/11 (para UEFI) Se o Windows estiver instalado e você não conseguir entrar na BIOS pela tecla (boot muito rápido), faça isso:\nVá em Configurações → Sistema → Recuperação Clique em \u0026ldquo;Reiniciar agora\u0026rdquo; (em \u0026ldquo;Inicialização Avançada\u0026rdquo;) Na tela azul: Solução de Problemas → Opções Avançadas → Configurações de Firmware UEFI Clique em Reiniciar - você vai direto para a UEFI Configurando a Ordem de Boot Uma vez dentro da BIOS/UEFI:\nOpção 1 - Boot Menu (mais fácil): Em vez de entrar na BIOS, use a tecla do Boot Menu (tabela acima). Vai aparecer uma lista de dispositivos. Selecione seu pendrive com as setas do teclado e pressione Enter. Nenhuma configuração permanente é necessária!\nOpção 2 - Configurar na BIOS:\nProcure a aba/seção chamada \u0026ldquo;Boot\u0026rdquo;, \u0026ldquo;Boot Order\u0026rdquo; ou \u0026ldquo;Boot Priority\u0026rdquo; Mova o USB ou USB Flash Drive para o primeiro lugar da lista (geralmente usando F5/F6 ou arrastando) Salve e saia: pressione F10 (na maioria das BIOS) ou vá em \u0026ldquo;Save \u0026amp; Exit\u0026rdquo; Configurações Importantes na UEFI (se disponíveis) Algumas configurações podem impedir o boot pelo pendrive. Verifique:\nSecure Boot:\nLocalização: geralmente em \u0026ldquo;Security\u0026rdquo; ou \u0026ldquo;Boot\u0026rdquo; Para o Fedora, pode deixar ativado - o Fedora suporta Secure Boot nativamente Se tiver problemas, desative temporariamente para instalar Fast Boot / Fast Startup:\nLocalização: \u0026ldquo;Boot\u0026rdquo; ou \u0026ldquo;Advanced\u0026rdquo; Desative durante a instalação - pode interferir na detecção do pendrive CSM (Compatibility Support Module):\nSe aparecer, mantenha desativado para PCs modernos (UEFI puro) Ative apenas se o seu PC for muito antigo e precisar de suporte BIOS legado Parte 4 - Iniciando pelo Pendrive e o Menu do Ventoy Após configurar a BIOS e reiniciar com o pendrive conectado, você verá a tela do Ventoy:\n┌─────────────────────────────────────────────┐ │ VENTOY │ ├─────────────────────────────────────────────┤ │ \u0026gt; Fedora │ │ ubuntu-24.04.2-desktop-amd64 │ │ linuxmint-22-cinnamon-64bit │ ├─────────────────────────────────────────────┤ │ Use ↑↓ to navigate, Enter to boot │ └─────────────────────────────────────────────┘ Use as setas do teclado para selecionar a ISO do Fedora Pressione Enter Se aparecer outra tela perguntando o modo de boot, escolha \u0026ldquo;Boot in normal mode\u0026rdquo; Aguarde alguns segundos enquanto o sistema carrega da ISO…\nParte 5 - Instalando o Fedora A Tela de Boas-vindas (Live Environment) O Fedora vai iniciar em modo Live - ou seja, você está rodando o sistema diretamente do pendrive, sem instalar nada no HD. Isso é ótimo para:\nTestar se o Fedora funciona bem no seu hardware Verificar se Wi-Fi, áudio e vídeo estão funcionando Explorar o sistema antes de decidir instalar Você verá uma janela de boas-vindas com duas opções:\n\u0026ldquo;Try Fedora\u0026rdquo; - usa o sistema sem instalar \u0026ldquo;Install to Hard Drive\u0026rdquo; - inicia a instalação Clique em \u0026ldquo;Install to Hard Drive\u0026rdquo; para começar.\nO Instalador Anaconda O instalador do Fedora se chama Anaconda. É visual, intuitivo e organizado numa tela central chamada \u0026ldquo;Installation Summary\u0026rdquo; (Resumo da Instalação), onde você configura tudo antes de confirmar.\nPasso 1 - Idioma Na primeira tela, selecione seu idioma:\nNa lista da esquerda, escolha \u0026ldquo;Português (Brasil)\u0026rdquo; Na lista da direita, escolha \u0026ldquo;Português (Brasil)\u0026rdquo; Clique em \u0026ldquo;Continuar\u0026rdquo; Passo 2 - Resumo da Instalação Você verá a tela principal com vários itens para configurar. Vamos por partes:\n🌍 Localização - Hora e Data Clique em \u0026ldquo;Hora e Data\u0026rdquo; No mapa, clique em Brasil (ou selecione a região manualmente) Selecione a cidade mais próxima: \u0026ldquo;América/São Paulo\u0026rdquo; para a maioria do Brasil Ative \u0026ldquo;Horário de Rede\u0026rdquo; se estiver conectado - o sistema vai sincronizar automaticamente Clique em \u0026ldquo;Concluído\u0026rdquo; (canto superior esquerdo) ⌨️ Localização - Teclado Clique em \u0026ldquo;Teclado\u0026rdquo; Verifique se \u0026ldquo;Português (Brasil)\u0026rdquo; já está na lista Se não estiver, clique no \u0026quot;+\u0026quot;, busque \u0026ldquo;Português (Brasil)\u0026rdquo; e adicione Use o campo de teste na parte inferior para verificar se as teclas batem (teste o ç, ã, etc.) Clique em \u0026ldquo;Concluído\u0026rdquo; 💾 Sistema - Destino de Instalação (A Parte Mais Importante!) Esta é a etapa mais crítica. Aqui você define onde o Fedora será instalado.\nClique em \u0026ldquo;Destino de Instalação\u0026rdquo; Você verá os discos disponíveis no seu computador. Clique no disco onde quer instalar o Fedora Em \u0026ldquo;Configuração de Armazenamento\u0026rdquo;, escolha: Opção A - Automático (recomendado para iniciantes):\nSelecione \u0026ldquo;Automático\u0026rdquo; O instalador vai criar as partições necessárias sozinho ⚠️ Selecione se você quer manter o sistema antigo ou manter instalado junto com o novo. Se o disco tiver outros sistemas, leia com atenção o que será apagado 💡 Btrfs vs Ext4: O Fedora usa btrfs por padrão. Ele suporta snapshots (como pontos de restauração), compressão automática e é excelente para uso geral. Para quem está começando, deixe o padrão.\nClique em \u0026ldquo;Concluído\u0026rdquo; e confirme as mudanças 🔒 Configuração de Usuário Root (Administrador do Sistema):\nClique em \u0026ldquo;Senha de Root\u0026rdquo; Você pode criar uma senha de root, ou deixar desativado (recomendado - use sudo em vez disso) Clique em \u0026ldquo;Concluído\u0026rdquo; Criar sua conta de usuário:\nClique em \u0026ldquo;Criação de Usuário\u0026rdquo; Preencha: Nome completo: Seu nome Nome de usuário: nome sem espaços e em minúsculas (ex: joao) Senha: Use uma senha forte! Marque a opção \u0026ldquo;Tornar este usuário administrador\u0026rdquo; (permite usar sudo) Clique em \u0026ldquo;Concluído\u0026rdquo; ✅ Iniciando a Instalação Com tudo configurado (sem nenhum ícone de aviso ⚠️ na tela de resumo), clique em:\n\u0026ldquo;Iniciar Instalação\u0026rdquo;\nO processo vai começar. Você verá a barra de progresso realizando várias etapas:\nPreparar partições Instalar o sistema base Instalar pacotes e aplicativos Configurar o bootloader (GRUB) Finalizar configurações Tempo estimado: 10 a 25 minutos (depende da velocidade do pendrive e do HD).\n🔄 Reiniciando Quando a instalação terminar:\nClique em \u0026ldquo;Concluir a Instalação\u0026rdquo; Será exibida uma tela pedindo para reiniciar Clique em \u0026ldquo;Reiniciar o Sistema\u0026rdquo; Retire o pendrive quando o sistema começar a desligar Parte 6 - Primeira Inicialização do Fedora O GRUB - Escolhendo o Sistema Se você tem dual boot (Fedora + Windows), vai aparecer o menu do GRUB com as opções. Use as setas do teclado para selecionar e Enter para confirmar.\nSe só tem o Fedora, o GRUB vai aparecer por alguns segundos e iniciar automaticamente.\nO Assistente de Configuração Inicial Na primeira vez, o Fedora vai te guiar por um assistente de configuração:\nÉ bem básico, basta ler e continuar;\n⚠️ Cuidado! Vai aparecer um botão bem discreto chamado \u0026ldquo;habilitar pacotes de terceiros\u0026rdquo; ou algo parecido! Marque essa opção, se não ficará meio limitado usar o sistema sem isso Se você saiu da interface e não viu ou não habilitou, pode executar isso no terminal (nome Konsole):\nsudo dnf install \\ https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm # e depois sudo dnf install \\ https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm Parte 7 - Primeiras Coisas a Fazer no Fedora Parabéns, você está no seu novo Fedora! Aqui estão os primeiros passos recomendados:\n1. Atualizar o Sistema Antes de qualquer coisa, atualize tudo. Abra o terminal (Super → busque \u0026ldquo;Terminal\u0026rdquo;):\nsudo dnf update -y Isso pode demorar alguns minutos na primeira vez. Reinicie após as atualizações:\nsudo reboot Eu gosto de rodar alguns scripts para deixar meu sistema top, com um único clique, agiliza bastante. Basta copiar o código, e criar um arquivo .sh. Em seguida dê permissão para execução: chmod +x caminho/do/arquivo.sh:\n⚠️ Esse script é para usuários de AMD, se você tem NVIDIA veja a seção abaixo antes de rodar — está tudo separado por comentários\nClique para ver o script (AMD) # 1. Otimizar o DNF (Downloads mais rápidos) echo \u0026#34;⚡ Otimizando o DNF...\u0026#34; if ! grep -q \u0026#34;max_parallel_downloads\u0026#34; /etc/dnf/dnf.conf; then echo \u0026#34;max_parallel_downloads=10\u0026#34; | sudo tee -a /etc/dnf/dnf.conf \u0026gt; /dev/null fi if ! grep -q \u0026#34;fastestmirror\u0026#34; /etc/dnf/dnf.conf; then echo \u0026#34;fastestmirror=True\u0026#34; | sudo tee -a /etc/dnf/dnf.conf \u0026gt; /dev/null fi # 2. Atualizar o sistema echo \u0026#34;🔄 Atualizando o sistema...\u0026#34; sudo dnf upgrade --refresh -y # 3. Habilitar Repositórios RPM Fusion (Free e Non-Free) echo \u0026#34;📦 Habilitando RPM Fusion...\u0026#34; sudo dnf install https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm -y # 4. Instalar Codecs e Aceleração de Hardware para AMD (RX 6600) echo \u0026#34;🎥 Instalando Codecs e Drivers Mesa (VA-API)...\u0026#34; sudo dnf swap ffmpeg-free ffmpeg --allowerasing -y sudo dnf groupupdate multimedia --setop=\u0026#34;install_weak_deps=False\u0026#34; --exclude=PackageKit-gstreamer-plugin -y sudo dnf groupupdate sound-and-video -y sudo dnf install mesa-va-drivers-freeworld mesa-vdpau-drivers-freeworld rocm-opencl -y # 5. Configurar Flatpak e Flathub echo \u0026#34;🌩️ Configurando Flathub...\u0026#34; flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo # 6. Ferramentas Essenciais (Gaming e Dev) echo \u0026#34;🛠️ Instalando ferramentas base (Git, Gamemode)...\u0026#34; sudo dnf install git gamemode jetbrains-mono-fonts-all -y echo \u0026#34;Instalando o Steam\u0026#34; sudo dnf install steam -y # 7. Limpeza Final echo \u0026#34;🧹 Limpando o sistema...\u0026#34; sudo dnf autoremove -y echo \u0026#34;✅ Tudo pronto! Reinicie o PC para aplicar todas as mudanças de Kernel e Drivers.\u0026#34; 2. Usuários de NVIDIA — Drivers Proprietários Se você tem uma placa NVIDIA, essa etapa é essencial. O Fedora vem com o driver nouveau (open source), que funciona para uso básico mas tem desempenho limitado — sem suporte a CUDA, sem aceleração de hardware decente para vídeo, e com possíveis artefatos visuais.\n⚠️ Antes de instalar os drivers NVIDIA, certifique-se que o RPM Fusion Non-Free já está ativado (o assistente inicial ou os comandos da seção anterior cuidam disso).\nInstalando o driver NVIDIA # Instala o driver proprietário + módulo do kernel (akmod compila automaticamente) sudo dnf install akmod-nvidia -y # Suporte a CUDA (necessário para IA, edição de vídeo acelerada, etc.) sudo dnf install xorg-x11-drv-nvidia-cuda -y ⏳ Importante: O akmod-nvidia precisa compilar o módulo do kernel. Isso leva de 3 a 5 minutos após a instalação. Não reinicie imediatamente — espere a compilação terminar. Você pode acompanhar com:\n# Aguarda a conclusão da compilação (rode antes de reiniciar) modinfo -F version nvidia Quando o comando acima retornar um número de versão (ex: 550.144.03), a compilação terminou. Aí sim reinicie.\nCodecs com aceleração de hardware (NVIDIA) Após reiniciar com o driver instalado:\n# Codecs e VA-API para decodificação acelerada por GPU NVIDIA sudo dnf swap ffmpeg-free ffmpeg --allowerasing -y sudo dnf groupupdate multimedia --setop=\u0026#34;install_weak_deps=False\u0026#34; --exclude=PackageKit-gstreamer-plugin -y sudo dnf install nvidia-vaapi-driver -y Script completo para NVIDIA Prefere fazer tudo de uma vez? Mesmo esquema do script AMD — salve como .sh e execute:\nClique para ver o script (NVIDIA) # 1. Otimizar o DNF echo \u0026#34;⚡ Otimizando o DNF...\u0026#34; if ! grep -q \u0026#34;max_parallel_downloads\u0026#34; /etc/dnf/dnf.conf; then echo \u0026#34;max_parallel_downloads=10\u0026#34; | sudo tee -a /etc/dnf/dnf.conf \u0026gt; /dev/null fi if ! grep -q \u0026#34;fastestmirror\u0026#34; /etc/dnf/dnf.conf; then echo \u0026#34;fastestmirror=True\u0026#34; | sudo tee -a /etc/dnf/dnf.conf \u0026gt; /dev/null fi # 2. Atualizar o sistema echo \u0026#34;🔄 Atualizando o sistema...\u0026#34; sudo dnf upgrade --refresh -y # 3. Habilitar RPM Fusion echo \u0026#34;📦 Habilitando RPM Fusion...\u0026#34; sudo dnf install \\ https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm \\ https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm -y # 4. Instalar driver NVIDIA proprietário echo \u0026#34;🟢 Instalando driver NVIDIA...\u0026#34; sudo dnf install akmod-nvidia xorg-x11-drv-nvidia-cuda -y echo \u0026#34;⏳ Aguardando compilação do módulo do kernel NVIDIA (pode levar alguns minutos)...\u0026#34; # Espera o módulo estar disponível antes de continuar until modinfo -F version nvidia \u0026amp;\u0026gt;/dev/null; do sleep 5; done echo \u0026#34;✅ Driver NVIDIA compilado com sucesso!\u0026#34; # 5. Codecs e VA-API para NVIDIA echo \u0026#34;🎥 Instalando codecs e aceleração de vídeo...\u0026#34; sudo dnf swap ffmpeg-free ffmpeg --allowerasing -y sudo dnf groupupdate multimedia --setop=\u0026#34;install_weak_deps=False\u0026#34; --exclude=PackageKit-gstreamer-plugin -y sudo dnf groupupdate sound-and-video -y sudo dnf install nvidia-vaapi-driver -y # 6. Configurar Flatpak e Flathub echo \u0026#34;🌩️ Configurando Flathub...\u0026#34; flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo # 7. Ferramentas Essenciais echo \u0026#34;🛠️ Instalando ferramentas base...\u0026#34; sudo dnf install git gamemode jetbrains-mono-fonts-all -y echo \u0026#34;Instalando o Steam\u0026#34; sudo dnf install steam -y # 8. Limpeza Final echo \u0026#34;🧹 Limpando o sistema...\u0026#34; sudo dnf autoremove -y echo \u0026#34;✅ Tudo pronto! Reinicie o PC para usar o driver NVIDIA.\u0026#34; Verificando se o driver está ativo após o reboot # Deve retornar informações da sua placa com o driver \u0026#34;nvidia\u0026#34; nvidia-smi # Confirma qual driver está em uso lspci -k | grep -A 3 \u0026#34;VGA\u0026#34; Se nvidia-smi mostrar o modelo da sua placa e a versão do driver, está tudo certo. 🎉\nReinicie o sistema para aplicar todas as alterações.\nBasicamente, é isso; O que você precisa fazer agora é personalizar o seu sistema, e instalar seus apps. Isso é algo meio pessoal, cada pessoa tem seu gosto, no entanto planejo fazer um post futuro sobre personalização no Fedora\nResolução de Problemas Comuns O computador não deu boot pelo pendrive Verifique se o pendrive foi identificado na BIOS; Tente outra porta USB (prefira USB 2.0 se disponível para compatibilidade) Desative o Secure Boot temporariamente. Verifique se a ISO foi copiada corretamente para o pendrive Ventoy A tela ficou preta após selecionar a ISO Pode ser problema com driver de vídeo.\nNa tela do Ventoy, pressione e para editar os parâmetros de boot. Adicione nomodeset ao final da linha que começa com linux Pressione F10 para continuar o boot 💡 Isso é especialmente comum em placas NVIDIA — o nomodeset desativa a aceleração de vídeo temporariamente para você conseguir chegar ao instalador. Instale normalmente e depois instale o driver proprietário conforme a seção acima.\nWi-Fi não aparece durante a instalação Conecte via cabo Ethernet para a instalação Após instalar, os drivers podem ser obtidos via RPM Fusion Sem som após a instalação Clique no ícone de som, na barra de tarefas e selecione a saída de áudio. Se não funcionar: # Reinicie o serviço de áudio systemctl --user restart pipewire pipewire-pulse # Verifique se não está mutado alsamixer Tela preta após instalar driver NVIDIA Se o sistema não inicializar corretamente após instalar o driver NVIDIA:\nNa tela do GRUB, pressione e para editar Na linha que começa com linux, adicione nomodeset ao final Pressione F10 para iniciar Dentro do sistema, verifique se o módulo compilou: # Se não retornar versão, o módulo ainda não compilou — aguarde e tente recompilar: sudo akmods --force sudo dracut --force sudo reboot Resumo visual do processo: [1] Baixar ISO do Fedora ↓ [2] Instalar Ventoy no pendrive ↓ [3] Copiar a ISO para o pendrive ↓ [4] Conectar pendrive → reiniciar ↓ [5] Entrar na BIOS → Boot pelo pendrive ↓ [6] Selecionar ISO no menu do Ventoy ↓ [7] Ambiente Live do Fedora carrega ↓ [8] Clicar em \u0026#34;Install to Hard Drive\u0026#34; ↓ [9] Configurar idioma, teclado, partições, usuário ↓ [10] Aguardar instalação (10–25 min) ↓ [11] Retirar pendrive → reiniciar ↓ [12] Configuração inicial do KDE ↓ [13] ✅ Fedora instalado e pronto! ↓ [14] Atualizar sistema + RPM Fusion + drivers (AMD ou NVIDIA) Conteúdos relevantes Deixando o Fedora Bonito! (personalização) Apps essenciais para Linux ","permalink":"https://maggioni.dev/pt-br/posts/linux/how-to-install-fedora/","summary":"Guia para instalar o Fedora Linux: aprenda a criar um pendrive bootável com suporte a múltiplas ISOs usando o Ventoy, configurar a BIOS/UEFI e realizar a instalação passo a passo até a primeira inicialização.","title":"Como instalar a distro Linux Fedora + KDE Plasma"},{"content":"Introdução Se você vinha do Windows, provavelmente conhece aquele comportamento do Google Drive aparecendo como um “disco” no gerenciador de arquivos. Era bem prático: acesso rápido aos arquivos e ainda dava pra usar como backup automático de pastas inteiras do sistema.\nNesse post a ideia é reproduzir isso no Linux, de um jeito simples e funcional usando rclone.\nInstalação 1. Instale o rclone e o fuse3 sudo dnf install rclone fuse3 Se seu sistema é arch:\nsudo pacman -S rclone fuse3 2. Configurar o Google Drive rclone config Depois disso:\nn → new remote nome: gdrive escolha a opção referente ao Google Drive quando pedir autenticação, ele vai abrir um link no navegador você loga e autoriza normalmente volta pro terminal e finaliza a configuração 3. Criar a pasta de montagem Essa pasta vai ser onde o Drive vai “aparecer” no sistema:\nmkdir -p ~/gdrive Configurar para montar automaticamente no login Agora vamos fazer isso iniciar sozinho quando você entrar no sistema.\nCriar o serviço do systemd mkdir -p ~/.config/systemd/user nano ~/.config/systemd/user/rclone-gdrive.service O nano vai abrir um arquivo no terminal para edição. Cole isso:\n[Unit] Description=Google Drive via rclone After=network-online.target [Service] Type=simple ExecStart=/usr/bin/rclone mount gdrive: /home/%u/gdrive \\ --vfs-cache-mode writes \\ --dir-cache-time 72h \\ --poll-interval 1m ExecStop=/bin/fusermount3 -u /home/%u/gdrive Restart=on-failure [Install] WantedBy=default.target Ativar o serviço systemctl --user daemon-reload systemctl --user enable rclone-gdrive systemctl --user start rclone-gdrive Garantir que inicia no login loginctl enable-linger $USER Troubleshooting 1. O Google Drive não apareceu no gerenciador de arquivos Primeiro veja se o serviço realmente iniciou:\nsystemctl --user status rclone-gdrive Se aparecer failed, veja o log completo:\njournalctl --user -u rclone-gdrive -b 2. Testar o mount manualmente Antes de culpar o systemd, teste o comando direto no terminal:\nrclone mount gdrive: ~/gdrive --vfs-cache-mode writes Isso normalmente mostra o erro real imediatamente.\n3. Verificar se o remote existe rclone listremotes Precisa aparecer algo assim:\ngdrive: Se não aparecer, o remote não foi configurado corretamente no rclone config.\n4. Verificar se a pasta de montagem existe mkdir -p ~/gdrive Finalizando Depois disso, reinicie o computador. Pode levar alguns segundos até o Google Drive aparecer no Dolphin como gdrive, já montado e pronto pra uso.\n","permalink":"https://maggioni.dev/pt-br/posts/linux/mounting-google-drive-as-partition-on-fedora/","summary":"Aprenda como usar o rclone para integrar o Google Drive ao Linux como se fosse uma unidade local, direto no sistema de arquivos","title":"Montando o Google Drive como unidade no Linux"},{"content":"Introdução: O Desafio do Wallpaper Animado no Linux Até o momento, não existe uma solução nativa do Wallpaper Engine para Linux. Os desenvolvedores já sinalizaram que não pretendem portar o software devido à fragmentação dos ambientes de desktop (GNOME, KDE, XFCE, etc.).\nEmbora existam projetos não oficiais que tentam integrar o conteúdo do Workshop da Steam, muitos são instáveis ou complexos de configurar. No meu caso, utilizando Fedora 42 (KDE Plasma + Wayland), o popular Hidamari apresentou falhas críticas: o vídeo ficava sobreposto aos ícones, impedindo qualquer interação com a área de trabalho.\nobs: Isso funciona também para o CachyOS, ou qualquer distro com o KDE Plasma;\nA solução definitiva que encontrei - estável e leve - é o plugin Smart Video Wallpaper Reborn.\nPré-requisitos: Configurando os Codecs Antes de instalar o plugin, precisamos garantir que o sistema tenha os codecs necessários para reproduzir vídeos (especialmente H.264) via hardware. O Fedora, por padrão, não os inclui.\n1. Habilitando o RPM Fusion Execute os comandos abaixo para adicionar os repositórios necessários:\nsudo dnf install \\ https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm \\ https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm 2. Trocando para o FFmpeg Completo O Fedora vem com uma versão \u0026ldquo;free\u0026rdquo; do ffmpeg. Vamos substituir pela versão completa do RPM Fusion:\nsudo dnf swap ffmpeg-free ffmpeg --allowerasing 3. Verificando a Instalação Certifique-se de que o suporte ao codec H.264 está ativo:\nffmpeg -codecs | grep h264 Dica: Se o retorno mostrar EV ou D seguido de h264, a aceleração e decodificação estão prontas.\nInstalando e Configurando o Plugin Com os codecs instalados, o processo no KDE Plasma é simples:\nAcesse as Configurações: Clique com o botão direito na área de trabalho e selecione \u0026ldquo;Configurar área de trabalho e papel de parede\u0026hellip;\u0026rdquo;. Baixe o Plugin: Em \u0026ldquo;Tipo de papel de parede\u0026rdquo;, clique no botão Obter novos plugins\u0026hellip; \u0026gt; Baixar novos papéis de parede de área de trabalho. Busque por Reborn: Procure por Smart Video Wallpaper Reborn e clique em instalar. Ative o Plugin: Feche a janela de download e, na lista de tipos de papel de parede, selecione o plugin recém-instalado. Selecione o Vídeo: Clique em \u0026ldquo;Escolher arquivo\u0026rdquo; (Pick a file) e selecione o seu vídeo (recomendo .mp4). Finalize: Clique em Aplicar e pronto! Por que essa é a melhor opção? Diferente de apps externos, esse plugin se integra diretamente ao gerenciador de janelas do KDE, o que garante que ele fique sempre atrás dos seus ícones.\n","permalink":"https://maggioni.dev/pt-br/posts/linux/how-to-have-animated-roles-in-fedora-with-kde-plasma/","summary":"Aprenda a como ter papéis de parede animados no Linux KDE Plasma","title":"Como ter papéis de parede animados no Linux KDE Plasma"},{"content":"O Windows 11 é, definitivamente, um erro. Feio, inchado, cheio de lixo, propaganda, IA. Pelo menos enquanto escrevo esse post. Não sei se irão concertar isso no futuro.\nEu já estou com um pé no Linux, uso a certo tempo, mas o Windows sempre é bem vindo e familiar, e as vezes não queremos complicar muito, apenas usar nosso sistema sem preocupação.\nNão se preocupe, não irei evangelizar a palavra do Linux nesse post (vou deixar pra fazer isso nos próximos).\nEmbora esse tutorial seja focado 100% no Windows, haverão próximos que estarão abordando o Linux.\nSem mais rodeios, Vamos aprender a como formatar seu PC de forma ninja e fazer uma instalação seca seca seca do Windows 11. (Inspiração pra esse post foi o vídeo do ET )\nRequisitos Ter um PC (obrigatório) Ter um pendrive bootável (te ensinei nesse post =\u0026gt; aqui) Capítulo 1: Autounattend O arquivo autounattend.xml é um arquivo XML utilizado para automatizar e personalizar a instalação do Windows (como Windows 10 e 11) sem a necessidade de interação manual do usuário. Ele permite definir configurações específicas, como idioma, partição de disco, scripts de pós-instalação, garantindo uma implantação consistente e rápida de sistemas operacionais.\nIremos usar o autounattend para automatizar nossa instalação do windows; Isso significa que você pode deixar o PC formatando e ir dormir, e acordar com ele já configurado. Fan-tás-ti-co.\nVocê nunca mais vai querer formatar o seu windows sem isso, sério.\nPara gerar um autounattend, você pode usar esse site =\u0026gt; https://schneegans.de/windows/unattend-generator/ ;\nEu não irei abordar todas as configs desse site. São muuuuitas. Seria melhor você mesmo dar uma explorada.\nEu vou disponibilizar o meu autounattend para você baixar, e você pode inclusive personalizar ele a seu gosto, inclusive.\nBaixar autounattend Pra personalizar o autounattend que você acabou de baixar, extraia o arquivo, acesse o site do schneegans, clique em escolher arquivo e em importar. Pronto, já estamos falando a mesma língua;\nVou fazer um resumo de todas as configs que fiz nesse autounattend, se você não gostou de alguma, basta mudar no site. Se tudo está ok para você, pode usar esse mesmo.\n- Idioma: PT-BR - Keyboard: ABNT2 - Arquitetura: 64-bit - Coloquei para bypassar os requerimentos do Windows 11 (TPM, secure boot, etc) - O particionamento de disco deixei manual. Gosto de fazer com atenção essa parte. - partition layout GPT - versão instalada do windows 11: Home - vai ser criada duas contas offlines: Admin e User. As senhas são 0000 - menu de contexto clássico invés do novo - Widgets desabilitados - Não mostrar resultados do Bing no menu Iniciar - Sem apps fixados no menu iniciar - Windows Update sempre pausado - O windows update não inicia sozinho. Eu gosto disso, particulamente. Para atualizar basta ir na configuração e clicar no botão de atualizar. - Desabilitar o Edge de ficar minerando o seu pc em segundo plano - Bitlocker desabilitado (eu particulamente odeio me deu muita dor de cabeça pra recuperar pc bloqueado no bitlocker no passado) - Desabilitar aceleração do mouse (isso aqui é horrivel! Melhor desabilitado) - Apps inúteis são desinstalados automaticamente na primeira instalação. Só vem o básico: edge, ms store, camera, paint, powershell, galeria, calculadora, snipping tool, notepad, etc. Lixo como Copilot, Solitaire, One Drive, etc etc vem desinstalado; Além dessas settings, eu criei alguns scripts que serão executados para deixar ainda mais automatizado:\nscript que coloca wallpaper automaticamente script que muda foto de perfil automaticamente script que instala drivers automaticamente script que instala seus aplicativos favoritos automaticamente. Irei ensinar adiante como usar;\nAgora você precisa clicar em exportar como XML. Isso vai exportar o arquivo xml com suas settings, se você mecheu em algo, claro. Garanta que o arquivo de chame autounattend.xml. Não mude o nome, é exatamente assim;\nVocê precisa colar esse arquivo na pasta raiz do seu pendrive bootável.\nCapítulo 2: Preparação Antes de formatar nosso pc, precisamos nos preparar; Prepare uns 2 pendrive bootáveis. Nunca se sabe né? Melhor pecar pelo excesso. Assim você tem um pendrive backup se fizer algo errado. Mas é bem tranquilo, relaxe.\nPrimeiro, precisamos fazer backup dos nossos drivers. Bom, isso é opcional. Você pode querer instalar os drivers do 0, indo nos sites das marcas, procurando o software, instalado um por um\u0026hellip; Isso não é errado, é até bom. No entanto, eu estou ficando velho e impaciente. Não quero perder meu tempo. Eu costumo usar um script que faz backup de TODOS os meus drivers pra mim;\nVocê pode copiar esse código, colar e salvar como \u0026ldquo;backup-drivers.ps1\u0026rdquo;:\nClique para ver o script # ================================ # CONFIG # ================================ $ErrorActionPreference = \u0026#34;Stop\u0026#34; $scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path $backupFolder = Join-Path $scriptPath \u0026#34;_drivers\u0026#34; $logFile = Join-Path $scriptPath \u0026#34;backup-drivers.log\u0026#34; # inicia log completo (captura TUDO, atÃ© erro bruto) Start-Transcript -Path $logFile -Append function Write-Log { param ($msg) $timestamp = Get-Date -Format \u0026#34;yyyy-MM-dd HH:mm:ss\u0026#34; Write-Host \u0026#34;[$timestamp] $msg\u0026#34; } function Is-Admin { $currentUser = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) return $currentUser.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } try { Write-Log \u0026#34;===== INICIANDO BACKUP =====\u0026#34; # ADMIN if (-not (Is-Admin)) { Write-Log \u0026#34;Não está como admin. Reabrindo com elevação...\u0026#34; Start-Process powershell ` -ArgumentList \u0026#34;-NoProfile -ExecutionPolicy Bypass -File `\u0026#34;$PSCommandPath`\u0026#34;\u0026#34; ` -Verb RunAs exit } # PASTA if (!(Test-Path $backupFolder)) { New-Item -ItemType Directory -Path $backupFolder | Out-Null Write-Log \u0026#34;Pasta criada: $backupFolder\u0026#34; } else { Write-Log \u0026#34;Pasta já existe\u0026#34; } # DISM Write-Log \u0026#34;Executando DISM...\u0026#34; $process = Start-Process dism.exe ` -ArgumentList \u0026#34;/online /export-driver /destination:`\u0026#34;$backupFolder`\u0026#34;\u0026#34; ` -Wait -PassThru -NoNewWindow if ($process.ExitCode -ne 0) { throw \u0026#34;DISM falhou com cÃ³digo $($process.ExitCode)\u0026#34; } Write-Log \u0026#34;Backup concluí­do com sucesso!\u0026#34; } catch { Write-Log \u0026#34;ERRO FATAL:\u0026#34; Write-Log $_ } finally { Write-Log \u0026#34;===== FIM =====\u0026#34; Stop-Transcript Write-Host \u0026#34;\u0026#34; Write-Host \u0026#34;Pressione ENTER para sair...\u0026#34; Read-Host } Ok, após salvar como um arquivo .ps1, você precisa executar esse script no powershell. Ele vai pedir permissão de adm, conceda. Aguarde finalizar. Ele vai criar uma pasta chamada _drivers/, na mesma pasta onde você executou o script;\nPegue essa pasta (vai ser relativamente pesada, talvez 1GB) e faça um backup;\nTambém faça uma cópia dessa pasta pro seu pendrive bootável do windows 11, na raiz mesmo, nada de mudar de nome nem colocar dentro de outras pastas! Ela precisa ficar intacta!\nCerto. Faça backup das outras coisas que você tem n oseu pc, sei lá, fotos, projetos, jogos, qualquer coisa. Pois tudo será apagado.\nMais personalização Lembrando que essa etapa é opcional\nNesse autounattend que eu disponibilizei pra download, ele tem alguns scripts muito úteis que eu criei. Um deles muda a foto de fundo da área de trabalho, e da tela de bloqueio, além da sua foto de perfil;\nIsso é opcional claro, mas é muito legal! Tudo oque você precisa fazer pra funcionar, é criar uma pasta chamada _pics na raiz do seu pendrive bootável. Dentro de _pics, você deve colocar três imagens (as três precisam ser jpg!): homescreen.jpg para ser seu plano de fundo principal, lockscreen.jpg para ser sua foto de bloqueio, e perfil.jpg para ser sua miniatura de perfil.\nMinhas fotos personalizadas\nPodemos personalizar quais apps queremos instalar também; Podemos combinar dois métodos: Ninite e instaladores próprios;\nPara criar seu ninite, acesse https://ninite.com/ , marque todos os apps que você quer instalar no seu pc, e clique no botão em Get Your Ninite;\nIsso vai baixar um instalador do Ninite, que vai instalar tudo oque você marcou; Cole esse instalador na pasta raiz do seu pendrive bootável; Isso vai ser executado automaticamente no primeiro login;\nMas o ninite não instala tudo oque a gente quer. Talvez você tenha sua própria lista de apps favoritos, assim como eu:\nMeus apps que sempre uso\nAqui eu coloco apps obrigatórios, como o amd adrenalin e o ryzen master para que eu não precise os baixar manualmente um por um depois. Muito útil.\nPara isso, crie uma pasta chamada _apps na raiz do seu pendrive; dentro da pasta _apps crie outra pasta chamada instaladores; Ainda na pasta _apps, crie um script auto-install.bat com o seguinte código:\nClique para ver o script @echo off setlocal enabledelayedexpansion echo =================================== echo Iniciando instalacoes sequenciais echo =================================== echo. echo [1/1] Iniciando instalacao dos executaveis locais... set \u0026#34;APP_DIR=%~dp0instaladores\u0026#34; if not exist \u0026#34;%APP_DIR%\\\u0026#34; ( echo ERRO: Pasta \u0026#34;instaladores\u0026#34; nao encontrada em: \u0026#34;%APP_DIR%\u0026#34; goto :fim ) for %%F in (\u0026#34;%APP_DIR%\\*.exe\u0026#34;) do ( echo -------------------------------- echo Instalando: %%~nxF echo Aguarde a conclusao... echo -------------------------------- :: start /wait garante que espera terminar (mais seguro) start \u0026#34;\u0026#34; /wait \u0026#34;%%F\u0026#34; if !errorlevel! neq 0 ( echo ❌ ERRO durante instalacao de %%~nxF ) else ( echo ✅ Sucesso: %%~nxF ) echo. ) echo =================================== echo Todas as instalacoes foram concluidas! echo =================================== :fim pause exit Esse script vai ser responsável por instalar todos os apps que estiverem dentro de instaladores;\nJogue dentro de instaladores todos os apps que você deseja instalar. (Obviamente você vai precisar procurar todos eles no google e ir baixando, e jogando na pasta)\n⚠️ Esse script não vai executar sozinho! Após concluir a formatação, você vai navegar até essa pasta, e clicar com o botão direito no `.bat` para instalar esses apps Você pode alterar o autounattend pra executar esse código automaticamente, fica a seu critério. Se quiser fazer isso, vai precisar dar uma leve alterada, e colar nos scripts de ´firstLogon scripts´ Vale a pena você rodar esse script agora, só pra testar se tá dando tudo certo, só ir fechando as janelas dos instaladores que irem aparecendo.\nEstamos prontos pra formatar! Certifique-se que fez tudo certo!\nSeu pendrive bootável deve se parecer com isso:\nCapítulo 3: Enfim, a formatação! Reinicie o computador e entre na BIOS. Na maioria das placas, é só pressionar uma tecla assim que a tela aparecer: F2 nas placas ASUS, Del, F10 ou Esc em outras marcas. Se não souber qual é a da sua, uma busca rápida no Google resolve.\nDentro da BIOS, o que você precisa fazer é mudar a ordem de boot, ou seja, dizer pro computador que ele deve iniciar pelo pendrive antes de qualquer coisa. Isso geralmente aparece como Boot Priority, Boot Option #1 ou algo parecido, dependendo do firmware.\nColoque o pendrive (normalmente listado como UEFI: nome_do_dispositivo) na primeira posição, acima do seu SSD ou HD. Depois salve com F10 e o computador vai reiniciar automaticamente.\nSe tudo estiver certo, o instalador do Windows vai abrir sozinho.\nAtenção antes de continuar: se o instalador começar pedindo idioma e layout de teclado, o autounattend.xml não foi carregado corretamente. Ele foi configurado pra pular essa parte. Se isso acontecer, aborte a instalação e verifique o arquivo antes de continuar.\nCaso o processo seja automático mesmo, ótimo. Mas em algum momento pode aparecer uma tela perguntando o que você quer fazer. Se aparecer, escolha Personalizada: Instalar apenas o Windows (avançado). É essa opção que te dá controle sobre o disco.\nParticionando o disco Aqui é onde você precisa prestar atenção de verdade. Vai aparecer uma lista com todos os discos e partições do seu computador.\n⚠️ Cuidado pra não apagar o pendrive nem o disco errado! Apague apenas as partições do disco onde o Windows vai ser instalado. Se nunca formatou um PC antes e tá inseguro, vale ver um vídeo rápido sobre como identificar e apagar partições corretamente antes de continuar. Dois cenários possíveis:\nInstalação limpa total — quer zerar o disco completamente? Selecione e exclua todas as partições do disco alvo uma por uma, até restar só Espaço não alocado.\nTem mais de um disco? — identifique qual é o certo pela capacidade e tipo. Não mexa nas partições dos outros discos.\nCom o espaço não alocado selecionado, clique em Avançar. O instalador cria tudo que é necessário automaticamente:\nEFI System Partition (bootloader) MSR (Microsoft Reserved) Partição principal do Windows Partição de recuperação Não precisa criar nada manualmente.\nA partir daqui o autounattend assume o processo. Ele configura idioma, fuso horário, bloqueia coleta de dados da Microsoft e mais um monte de coisa sem você precisar fazer nada.\nSE APARECER, NÃO FECHE NENHUMA JANELA DO TERMINAL OU POWERSHELL! É O AUTOUNATTEND TRABALHANDO!\nSe o Windows começar a fazer perguntas da instalação, o arquivo não foi carregado. Nesse caso, refaça o pendrive, garanta que o autounattend.xml está na raiz e tente de novo.\nSe tudo deu certo\u0026hellip; Se a instalação rolou bem, sem você precisar confirmar nada\u0026hellip; parabéns, esse tutorial foi um sucesso!\nprovalvemente vai aparecer umas janelas de powershell, apenas minimize;\nSe você criou a pasta _apps, não esquece de rodar o .bat para instalar todos eles de forma automática;\nA partir daqui, não tem muito mais o que explicar, o computador é seu, e basta personálizá-lo a seu critério.\n","permalink":"https://maggioni.dev/pt-br/posts/windows/how-to-format-your-pc-with-windows/","summary":"Aprenda a como fazer uma instalação limpa do windows, usando pendrive bootável, e tirando todo o lixo da microsoft","title":"Como formatar seu PC + Deixando seu Windows menos ruim!"},{"content":"Introdução Se você usa o Backblaze B2 pra servir imagens estáticas, provavelmente começou do jeito mais simples possível: bucket público e links diretos.\n(Eu ensinei como configurar isso do zero, nesse post =\u0026gt; configurando um bucket b2 para servir imagens estáticas )\nFunciona. Até não funcionar mais.\nO problema aparece quando alguém começa a acessar esses links direto. Pode ser bot, hotlink em outro site, scraping… e de repente você está pagando download direto do B2 sem nem perceber.\nA solução não é só esconder o bucket. É forçar todo o tráfego a passar por um proxy controlado com cache. Foi exatamente isso que implementei usando Cloudflare Workers.\nO problema real Quando seu bucket é público, qualquer um pode acessar:\nhttps://seu-bucket.s3.us-east-005.backblazeb2.com/imagem.png\nMesmo que você use um CDN na frente, esse endpoint continua aberto.\nIsso significa:\nbypass do cache custo direto no B2 perda total de controle A arquitetura correta:\nDepois da configuração, o fluxo fica assim:\nUsuário → assets.seudominio.com → Cloudflare Worker → Backblaze (privado)\nO usuário nunca fala direto com o B2.\nO que vamos fazer\nCriar um Worker como proxy Assinar requests para um bucket privado Servir tudo via domínio próprio Cachear no edge da Cloudflare Bloquear acesso direto ao B2 Pré requisitos Conta + Bucket configurado no https://www.backblaze.com/ Conta + Domínio na https://www.cloudflare.com/pt-br/ Node.js instalado Git instalado Visual Studio Code ou outra IDE ⚠️ Sente-se perdido? Leia meu post anterior: Hospedagem de Imagens com Backblaze B2 e Cloudflare: CDN Gratuito Aviso importante: Desabilite a função de reescrita de URL na Cloudflare ⚠️ Se você seguiu meu tutorial anterior, provalvelmente habilitou a custum rule de reescrita de URL, na cloudflare. Não precisaremos mais dela, desative! Instalando o Wrangler\nnpm install -g wrangler Login:\nwrangler login Usando o template oficial O Backblaze já fornece um template pronto:\ngit clone https://github.com/backblaze-b2-samples/cloudflare-b2 b2-proxy cd b2-proxy npm i Abra essa pasta com code . ou navegue até ela pelo vscode, vamos precisar editar alguns códigos.\nCriando a Application Key\nNo B2 :\n\u0026ldquo;Add a new application key\u0026rdquo;:\nacesso: Read Only escolha seu bucket sem prefixo (deixe vazio) Anote no seu bloco de notas:\nKey ID Application Key (só aparece uma vez depois some, anote!) Configurando o Worker No vscode, na pasta que você clonou do github, encontre o wrangler.toml. você vai ver que existem algumas variáveis para serem preenchidas. Insira os dados correspondentes à sua conta.\n[vars] B2_APPLICATION_KEY_ID = \u0026#34;SEU_KEY_ID\u0026#34; B2_ENDPOINT = \u0026#34;s3.us-east-005.backblazeb2.com\u0026#34; BUCKET_NAME = \u0026#34;seu-bucket\u0026#34; ALLOW_LIST_BUCKET = \u0026#34;false\u0026#34; Agora, no cmd:\nwrangler secret put B2_APPLICATION_KEY Vai lhe perguntar o valor. Cole a sua Application Key (lembra que eu mandei anotar no bloco de notas?!)\nVamos fazer um teste Antes de mandar isso pra Cloudflare e derrubarmos nosso site (panic) vamos fazer um teste para saber se está tudo nos conformes:\nProvavelmente existe um arquivo .dev.vars. Se não existir, crie-a;\nedite a var:\nB2_APPLICATION_KEY = \u0026#34;sua key aqui\u0026#34; Essa é a mesma application key que você colou no terminal antes. Vamos usar ela um momento aqui apenas para testar localmente.\nRode:\nwrangler dev Isso vai expor algum localhost da sua máquina, não sei qual, mas vai aparecer nos logs, basta clicar segurando ctrl encima do url.\nTeste no browser:\nhttp://localhost:8787/imagem.png (exemplo! use o localhost que foi aberto e apareceu no log do terminal, e claro, substitua \u0026ldquo;imagem.png\u0026rdquo; por alguma imagem que esteja no seu bucket).\nSe funcionar aqui, pode respirar fundo, metade do caminho! Se não funcionou\u0026hellip; provavelmente você configurou algo errado ou pulou etapas.\nDeploy (atenção aqui) wrangler deploy detalhe: vá no cloudflare, em Rotas de Workers \u0026gt; Adicionar rota; Rota: assets.seusite.com Em Worker selecione o worker que você criou;\nAssim sempre que você acessar aquela rota vai ativar o worker;\nCalma calma lá - última configuração ⚠️ Não pule essa etapa, se não todo o nosso trabalho não valerá de nada! Já tá funcionando, mas ainda falta a configuração final:\nVai no seu bucket B2 \u0026gt; Balde de configurações (ou bucket settings): marque arquivos de segmento como privado; Defina \u0026ldquo;Balde de informações\u0026rdquo; ou \u0026ldquo;Bucket infos\u0026rdquo; como {\u0026quot;cache-control\u0026quot;:\u0026quot;public, max-age=31536000\u0026quot;};\nClique em salvar;\nAgora, o teste definitivo; Se tudo foi configurado certo, deve ter o seguinte comportamento:\nColoque na raiz do seu bucket uma imagem de teste, hello-world.png; Copia o link que o B2 vai fornecer dela, abra uma guia anônima e tente acessar;\ndeve aparecer algo como:\n{ \u0026#34;code\u0026#34;: \u0026#34;unauthorized\u0026#34;, \u0026#34;message\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;status\u0026#34;: 401 } ok, isso é definitivamente bom; Agora acesse pelo seu subdomínio:\nassets.seusite.com/hello-world.png;\ndeve aparecer uma linda imagem de hello world;\nResumo Você aprendeu nesse post, a como deixar seu bucket backblaze B2 privado, deixando-o mais seguro contra ataques, e principalmente, preservando sua carteira de gastos desnecessários;\nA partir de agora, seus arquivos só poderão ser acessados com segurança pelo seu próprio subdomínio configurado na cloudflare, com cache ativo, e com custo de banda praticamente 0!\nDe nada!\n","permalink":"https://maggioni.dev/pt-br/posts/dev/securing-a-backblaze-b2-bucket-using-cloudflare-workers/","summary":"Guia prático garantindo que imagens sejam servidas apenas pelo seu domínio com custo controlado.","title":"Como proteger um bucket Backblaze B2 usando Cloudflare Workers (sem custo inesperado)"},{"content":"Se você tem um blog estático no GitHub Pages, em algum momento você vai esbarrar no mesmo problema: onde hospedar as imagens sem pagar caro, sem URLs feias e sem prejudicar o carregamento?\nEssa foi exatamente a pergunta que me fiz quando comecei a montar o maggioni.dev. A resposta que encontrei foi combinar o Backblaze B2 com o Cloudflare. Nesse post vou te mostrar exatamente como configurar isso do zero.\nEu simplesmente faço upload dos meus arquivos no Backblaze, e posso usar o link dos meus arquivos para colocar em meus posts, como por exemplo: https://assets.maggioni.dev/hello-world.png .\nMuito legal, e fica com cara profissional.\n⚠️ Leia esse post até o final! Ao fim desse post lhe darei 2 dicas super importantes, de como manter seu bucket seguro e previnir que acabe gerando custos desnecessários no seu backblaze! O que é o Backblaze B2? O Backblaze B2 é um serviço de armazenamento em nuvem focado em custo baixo e performance. Diferente do armazenamento convencional, ele organiza os dados como \u0026ldquo;objetos\u0026rdquo;, o que permite que cada imagem ou arquivo seja acessado via URL de forma rápida e direta.\nNa prática, pro meu blog, ele funciona como o \u0026ldquo;back-end\u0026rdquo; onde os assets ficam guardados, enquanto o GitHub Pages cuida apenas do código e do texto.\nPor que usar B2 + Cloudflare? Antes de partir pra configuração, vale entender os quatro motivos que tornam essa combinação especialmente boa pra quem mantém um blog estático.\n1. Custo-Benefício Imbatível\nEnquanto o Amazon S3 tem uma estrutura de preços cheia de variáveis e cobranças por requisição, o B2 é direto: os primeiros 10 GB são gratuitos e, depois disso, o custo por GB é uma fração do que os grandes players cobram.\n2. Taxa de Saída Zero\nEssa é a maior vantagem pra quem usa Cloudflare. Normalmente, provedores de nuvem cobram pelo \u0026ldquo;egress\u0026rdquo;, ou seja, pelo dado que sai do servidor toda vez que alguém acessa sua imagem. Graças à Bandwidth Alliance, a transferência entre Backblaze B2 e Cloudflare é totalmente gratuita.\nVocê paga só pelo armazenamento. Não importa quantas pessoas acessem suas fotos, a banda de saída não custa nada.\n3. URLs Profissionais e Limpas\nCom as Transform Rules que vamos configurar, você não vai expor URLs genéricas tipo f005.backblazeb2.com/.... Suas imagens ficam servidas pelo seu próprio subdomínio, como assets.maggioni.dev. Melhor pro SEO, melhor pra confiança do leitor.\n4. Desempenho Global com Edge Caching\nAo colocar o Cloudflare na frente do B2, as imagens ficam cacheadas nos servidores de borda da Cloudflare ao redor do mundo. Um leitor em Portugal baixa a imagem de um servidor em Lisboa, não dos EUA. A diferença no tempo de carregamento (LCP) é considerável.\nRequisitos Possui um domínio Parte 1: Configurando o Cloudflare no seu Domínio Comprei meu domínio na GoDaddy. Gosto de lá por ser rápido de configurar. Mas pra nossa solução funcionar, precisamos tirar as mãos da GoDaddy do DNS e transferir essa responsabilidade pro Cloudflare.\nSe você comprou seu domínio em outro registrador, o processo é parecido. Basta encontrar a opção de \u0026ldquo;nameservers\u0026rdquo; na interface do seu registrador.\nTransferindo os nameservers para o Cloudflare No painel da GoDaddy:\nAcesse sua conta e vá em Foto de perfil → Meus Produtos Escolha o domínio e clique em Gerenciar meu domínio Vá na aba DNS → Servidores de nome Clique em Alterar servidores de nome Marque a opção Usarei meus próprios servidores de nome Deixa essa página aberta, você vai precisar voltar aqui No Cloudflare:\nAcesse https://www.cloudflare.com/pt-br/ e crie uma conta se ainda não tem Clique em Adicionar → Conectar um domínio e informe o seu domínio (ex: meusite.com) Selecione Importar DNS automaticamente e clique em continuar O Cloudflare vai exibir dois nameservers próprios, algo parecido com: sid.ns.cloudflare.com vita.ns.cloudflare.com Copie os dois De volta na GoDaddy:\nCole os nameservers nos campos que você deixou abertos e salve.\nA GoDaddy vai transferir a administração do domínio pro Cloudflare. Isso pode levar alguns minutos. No painel da Cloudflare, fique atualizando até aparecer que o domínio está ativo.\nParte 2: Criando sua Conta e Bucket no Backblaze B2 Criar a conta Acesse https://www.backblaze.com/ , crie uma conta e ative o B2 Cloud Storage nas configurações.\nCriar um bucket público No painel do Backblaze:\nVá em B2 Cloud Storage → Buckets → Create a Bucket Configure assim: Bucket name: nome-bucket-unico-no-mundo (mínimo 6 caracteres, no meu caso vou colocar como \u0026ldquo;maggioni-blog-assets\u0026rdquo;) Privacy: Public ⚠️ Atenção! Nessa etapa ele vai pedir um cartão de crédito! Não se desespere! Apenas use um cartão temporário, ele vai te cobrar 1 dólar. Depois pode remover o cartão ;)\nClique em Create a Bucket Copie o valor do campo Endpoint que aparece depois de criar (algo tipo f000.backblazeb2.com). Você vai precisar desse endereço logo. Parte 3: Conectando Cloudflare ao Backblaze Criar o registro CNAME No painel da Cloudflare, vá em DNS → Registros → Add Novo Registro.\nCampo Valor Type CNAME Name media Target f000.backblazeb2.com (o endpoint que você copiou) Proxy status Proxied (ícone laranja ativado) Salva. Agora assets.seusite.com aponta pro Backblaze, mas ainda precisamos dizer qual bucket ele deve servir.\nCriar a Transform Rule Sem essa regra, alguém poderia usar seu domínio pra acessar o bucket de outra pessoa no Backblaze, já que o endpoint é compartilhado entre clientes. A regra garante que as requisições sempre vão pro seu bucket específico.\nVai em Regras → Visão Geral → Criar regra → Regra de reescrita de URL.\npreencha o filtro:\nNome da regra: \u0026ldquo;Reescrita de URL do Backblaze\u0026rdquo;.\nSe as solicitações recebidas coincidirem…:\nSelecione \u0026ldquo;Personalizar expressão do filtro\u0026rdquo;\nVai abrir um input para você preencher, selecione campo como \u0026ldquo;Nome do host\u0026rdquo;, e Operador como \u0026ldquo;é igual a\u0026rdquo;, e em valor, adicione \u0026ldquo;assets.seusite.com\u0026rdquo;\nDepois… Regravar em\u0026hellip;: Vai abrir outro input para você preencher, selecione \u0026ldquo;dynamic\u0026rdquo; e em valor cole \u0026ldquo;concat(\u0026quot;/file/nome-do-seu-bucket\u0026rdquo;, http.request.uri.path)\u0026quot; (no meu caso ficou \u0026ldquo;concat(\u0026quot;/file/maggioni-blog-assets\u0026rdquo;, http.request.uri.path)\u0026quot;)\nConsulta: Deixe marcado \u0026ldquo;preservar\u0026rdquo;;\nSalve. Clique em Implantar.\nO que isso faz na prática: uma requisição pra https://assets.seusite.com/foto.jpg vira https://f000.backblazeb2.com/file/nome-do-seu-bucket/foto.jpg antes de chegar no Backblaze. Transparente pra quem acessa, seguro pra você.\nConfigurar o SSL/TLS O Backblaze só aceita HTTPS. Precisa garantir que o Cloudflare também vai usar HTTPS pra se comunicar com ele, do contrário as requisições vão falhar.\nVai em SSL/TLS → Visão Geral → Configurar → Custom SSL/TLS, seleciona Full (Strict) e salva.\nTestando tudo ☢️ Pode levar alguns minutos pra funcionar! Apenas aguarde! Limpe o cache e reinicie o navegador!\nAcesse no navegador:\nhttps://assets.seusite.com/nome-da-imagem.jpg exemplo real:\nhttps://assets.maggioni.dev/hello-world.png Se a imagem apareceu, funcionou. Nos seus posts do Hugo, agora você usa esse subdomínio direto:\n![Descrição da imagem](https://assets.seusite.com/nome-da-imagem.jpg) Dica opcional #1: Cache e performance extra Por padrão, o Cloudflare já cacheia arquivos de imagem com base na extensão. Se quiser controle maior, vá em Caching → Cache Rules e crie uma regra específica pro subdomínio assets.seusite.com com um TTL longo, algo como 1 mês.\nImagem estática não muda. Faz sentido cachear bastante.\nNo Cloudflare, encontre as Cache Rules;\nCrie uma nova regra de cache:\nNome da regra: cache-media-images; Se as solicitações recebidas coincidirem…: Personalizar expressão do filtro; no criador de expressão cole: http.host eq \u0026quot;assets.seusite.com\u0026quot;; Então\u0026hellip;Elegibilidade de cache: Qualificado para cache; TTL da borda \u0026gt; Ignore o cabeçalho de controle de cache e use este TTL: coloque 1 mês; Navegador TTL: Substitua a origem e use este TTL: coloque 1 mês clique em salvar/implantar;\nDica opcional #2: Deixar seu bucket privado Tudo oque a gente configurou até agora\u0026hellip; funciona muito bem\u0026hellip; No entanto, existe um problema de segurança nisso tudo:\nquando você envia um arquivo pro seu bucket b2 público, ele vai gerar uma URL semelhante à essa: https://f005.backblazeb2.com/file/maggioni-blog-assets/hello-world.png; Ocorre que, ao deixar seu bucket público, qualquer pessoa pode acessar esse link. Ou usar a sua imagem que está no blackbaze em outro lugar, rede social, outro blog, etc\u0026hellip;\nE é aí que mora o perigo: Se a requição bater direto no b2, invés do nosso CDN que configuramos na cloudflare, isso vai te gerar custos.\nSe lembra que, no ínicio desse post eu mencionei a Bandwidth Alliance? Certo, a Bandwidth Alliance faz com que não importa quantas pessoas acessem aos seus arquivos, você não paga pelo tráfego, apenas pelo armazenamento (10gb gratuitos depois vai cobrando a mais se extrapolar). Isso só é possível se a requição bater no nosso Cloudflare primeiro:\nhttps://assets.maggioni.dev/hello-world.png - ✔️ Tráfego grátis garantido https://f005.backblazeb2.com/file/maggioni-blog-assets/hello-world.png - ❌ Se cair direto na b2, vai gerar custos \u0026ldquo;Mas não é apenas eu divulgar o meu link assets.meusite.com e esconder o link direto da backblaze?\u0026rdquo; - Sim\u0026hellip; e não.\nAté funciona, um usuário comum vai usar o seu subdomínio e não vai nem saber da existência da backblaze. No entanto, um bug em seu site, ou até mesmo um ataque hacker, pode descobrir a backblaze por trás do seu subdomínio (nem é tão difícil assim na verdade, só inspecionar o código da página) e fazer requisições infinitas, o que vai derrubar a sua conexão, e se seu cartão estiver ativo, vai ficar cobrando sem parar\u0026hellip;\n\u0026ldquo;Ok Gabriel, então é só eu ir lá no meu bucket e mudar o botão pra privado?\u0026rdquo; - Não hehehehe; Se você fizer isso, vai simplesmente parar de funcionar;\nSerá necessário uma configuração adicional para resolver essa situação. Caso tenha interesse em seguir o tutorial, sinta-se a vontade para ler meu próximo post: deixando seu backblaze b2 mais seguro - e sem riscos de perder grana\nConclusão No final das contas, você tem um CDN global, custo perto de zero e URLs limpas com seu próprio domínio. O Backblaze cuida do armazenamento, o Cloudflare cuida da entrega, e você não paga nada pela banda de saída graças à Bandwidth Alliance.\nPra um blog estático no GitHub Pages, é difícil achar solução melhor.\n=\u0026gt; crie um blog estático com hugo!\n","permalink":"https://maggioni.dev/pt-br/posts/dev/how-to-use-backblaze-to-host-your-images/","summary":"Descubra como hospedar os assets do seu blog estático com custo quase zero, usando o subdomínio do seu próprio domínio e cache de borda global.","title":"Hospedagem de Imagens com Backblaze B2 e Cloudflare: CDN Gratuito"},{"content":"Bom, esse vai ser um guia prático, rápido e sem enrolação. Você vai precisar de um pendrive de, pelo menos, 16GB; Tenha noção que o pendrive será formatado e você perderá todos os arquivos dele.\n1. Baixe a imagem oficial do windows 11 do site oficial da Microsoft: Download windows 11 (role a página até a seção \u0026ldquo;Baixar imagem de disco (ISO) do Windows 11 para dispositivos x64\u0026rdquo; \u0026gt; Baixar agora \u0026gt; selecionar idioma \u0026gt; confirmar \u0026gt; 64-bits baixar)\n2. Baixe o Rufus O rufus é uma ferramenta que ajuda a formatar e criar drives USB inicializáveis, como chaves/drives USB, cartões de memória e etc.\nBaixar rufus Após baixar o rufus, execute o .exe que você baixou;\n3. Criar o pendrive bootável Selecione essas opções na janela do Rufus, apontando para o seu pendrive: (Cuidado para não selecionar a partição errada! Pois ela será formatada!)\nclique em \u0026ldquo;Iniciar\u0026rdquo; e aguarde o processo terminar.\nE\u0026hellip; pronto! Você já tem um pendrive bootável e pode estar o usando para formatar seu pc! Esse post o foco é criar o pendrive.\nEu abordo de forma completa o processo de formatação aqui\n","permalink":"https://maggioni.dev/pt-br/posts/windows/bootable-pendrive-windows/","summary":"Criando pendrive bootável para instalação limpa do windows","title":"Como criar um pendrive bootável para instalar o windows?"},{"content":"Hugo - Guia Completo para Criar e Gerenciar seu Blog Nesse post, iremos abordar os seguintes temas:\nO que é Hugo e por que usá-lo Instalação Criando seu primeiro site Estrutura de pastas Instalando e configurando temas Criando e organizando conteúdo Comandos essenciais Personalizando o tema Deploy e publicação O que é Hugo e por que usá-lo? Hugo é um gerador de sites estáticos escrito em Go. Ele pega seus arquivos Markdown e transforma em um site HTML completo em milissegundos - sem banco de dados, sem servidor PHP, sem complexidade.\nVantagens:\n⚡ Extremamente rápido (builds em milissegundos) 🔒 Mais seguro (sem backend vulnerável) 💸 Hospedagem gratuita ou barata (Netlify, Vercel, Github Pages) ✍️ Escreva posts em Markdown simples 🎨 Centenas de temas prontos 💡 Sites como o blog da Cloudflare e documentações de grandes projetos open source usam Hugo.\nInstalação Linux (Debian/Ubuntu) sudo apt install hugo Para a versão mais recente (recomendado):\nsudo snap install hugo macOS brew install hugo Windows Pelo Chocolatey:\nchoco install hugo-extended Pelo Winget:\nwinget install Hugo.Hugo.Extended ⚠️ Prefira sempre a versão extended - ela suporta SCSS/SASS, necessário para a maioria dos temas modernos.\nVerificando a instalação hugo version Criando seu primeiro site hugo new site meu-blog cd meu-blog Isso cria a estrutura base do projeto. Em seguida, inicie um repositório Git:\ngit init Estrutura de pastas meu-blog/ ├── archetypes/ # Templates padrão para novos conteúdos ├── assets/ # Arquivos processados (SCSS, JS) ├── content/ # Seus posts e páginas em Markdown ├── data/ # Arquivos de dados (JSON, YAML, TOML) ├── i18n/ # Traduções ├── layouts/ # Templates HTML customizados ├── public/ # Site gerado (não versionar) ├── resources/ # Cache de assets processados ├── static/ # Arquivos estáticos (imagens, fontes, CSS) ├── themes/ # Temas instalados └── hugo.toml # Configuração principal do site Pasta O que você vai mexer content/ Sempre - seus posts ficam aqui static/ Para adicionar imagens e arquivos layouts/ Para customizar o tema hugo.toml Para configurar o site themes/ Para instalar/atualizar temas Instalando e configurando temas Onde encontrar temas themes.gohugo.io - catálogo oficial com centenas de opções Instalando via Git Submodule (recomendado) git submodule add https://github.com/autor/nome-do-tema.git themes/nome-do-tema Ativar o tema no hugo.toml:\ntheme = \u0026#34;nome-do-tema\u0026#34; Atualizando o tema git submodule update --remote --merge Instalando via clone simples (sem submodule) git clone https://github.com/autor/nome-do-tema.git themes/nome-do-tema ⚠️ Com clone simples você não consegue atualizar facilmente. Prefira o submodule.\nExemplo com o tema PaperMod (muito popular) git submodule add https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod hugo.toml:\nbaseURL = \u0026#34;https://seusite.com/\u0026#34; languageCode = \u0026#34;pt-br\u0026#34; title = \u0026#34;Meu Blog\u0026#34; theme = \u0026#34;PaperMod\u0026#34; Configuração principal - hugo.toml O arquivo hugo.toml controla tudo do seu site. Exemplo completo:\nbaseURL = \u0026#34;https://seusite.com/\u0026#34; languageCode = \u0026#34;pt-br\u0026#34; title = \u0026#34;Meu Blog\u0026#34; theme = \u0026#34;PaperMod\u0026#34; paginate = 10 enableRobotsTXT = true enableEmoji = true [params] author = \u0026#34;Seu Nome\u0026#34; description = \u0026#34;Um blog sobre tecnologia e desenvolvimento\u0026#34; ShowReadingTime = true ShowShareButtons = true ShowPostNavLinks = true ShowBreadCrumbs = true ShowCodeCopyButtons = true ShowToc = true [params.homeInfoParams] Title = \u0026#34;Olá! 👋\u0026#34; Content = \u0026#34;Bem-vindo ao meu blog sobre tecnologia\u0026#34; [[params.socialIcons]] name = \u0026#34;github\u0026#34; url = \u0026#34;https://github.com/seu-usuario\u0026#34; [[params.socialIcons]] name = \u0026#34;linkedin\u0026#34; url = \u0026#34;https://linkedin.com/in/seu-usuario\u0026#34; [menu] [[menu.main]] name = \u0026#34;Posts\u0026#34; url = \u0026#34;/posts/\u0026#34; weight = 1 [[menu.main]] name = \u0026#34;Sobre\u0026#34; url = \u0026#34;/about/\u0026#34; weight = 2 [[menu.main]] name = \u0026#34;Tags\u0026#34; url = \u0026#34;/tags/\u0026#34; weight = 3 Criando e organizando conteúdo Criando um novo post hugo new content posts/meu-primeiro-post.md O arquivo será criado em content/posts/ com o front matter padrão:\n+++ title = \u0026#39;Meu Primeiro Post\u0026#39; date = \u0026#39;2026-04-16T00:00:00-03:00\u0026#39; draft = true +++ Campos do front matter +++ title = \u0026#34;Título do Post\u0026#34; description = \u0026#34;Descrição curta para SEO\u0026#34; summary = \u0026#34;Resumo exibido na listagem\u0026#34; author = \u0026#34;Seu Nome\u0026#34; date = \u0026#39;2026-04-16T00:00:00-03:00\u0026#39; lastmod = \u0026#39;2026-04-16T00:00:00-03:00\u0026#39; # Data de última modificação draft = true # true = não publica tags = [\u0026#34;hugo\u0026#34;, \u0026#34;blog\u0026#34;] categories = [\u0026#34;desenvolvimento\u0026#34;] keywords = [\u0026#34;hugo\u0026#34;, \u0026#34;blog\u0026#34;, \u0026#34;tutorial\u0026#34;] cover: image = \u0026#34;posts/meu-post/capa.jpg\u0026#34; # Imagem de capa alt = \u0026#34;Descrição da imagem\u0026#34; showToc = true # Índice no post TocOpen = false # Índice aberto por padrão +++ Organizando com pastas (Page Bundles) Para posts com imagens, use a estrutura de bundle:\ncontent/ └── posts/ └── meu-post/ ├── index.md ← conteúdo do post ├── capa.jpg ← imagem de capa └── diagrama.png ← outras imagens Assim você referencia as imagens diretamente no Markdown:\n![Diagrama](diagrama.png) Criando uma página estática hugo new content about.md +++ title = \u0026#34;Sobre\u0026#34; layout = \u0026#34;page\u0026#34; +++ Olá, sou desenvolvedor e gosto de escrever sobre tecnologia... Rascunhos Posts com draft = true não são publicados. Para visualizá-los localmente:\nhugo server -D Quando estiver pronto para publicar, mude para:\ndraft = false Comandos essenciais Servidor local hugo server # Inicia o servidor em localhost:1313 hugo server -D # Inclui rascunhos (drafts) hugo server -p 8080 # Porta customizada hugo server --bind 0.0.0.0 # Acessível na rede local O servidor tem live reload - qualquer alteração no conteúdo ou tema atualiza o navegador automaticamente.\nBuild do site hugo # Gera o site na pasta /public hugo --minify # Minifica HTML, CSS e JS hugo -e production # Usa configuração de produção Gerenciamento de conteúdo # Criar novo post hugo new content posts/titulo-do-post.md # Criar nova página hugo new content sobre.md # Listar todo o conteúdo hugo list all # Listar apenas drafts hugo list drafts # Listar posts futuros (publishDate no futuro) hugo list future Módulos e temas # Atualizar submódulos (temas via git submodule) git submodule update --remote --merge # Ver versão do Hugo hugo version # Verificar configuração hugo config # Limpar cache hugo --gc Personalizando o tema Hugo segue uma hierarquia de templates: seu layout sobrescreve o do tema. Você nunca precisa editar os arquivos dentro de themes/ diretamente.\nSobrescrevendo um template Copie o arquivo do tema para a pasta layouts/ do seu projeto:\n# Exemplo: sobrescrever o template de post único cp themes/PaperMod/layouts/_default/single.html layouts/_default/single.html Agora edite layouts/_default/single.html à vontade. O tema original não é alterado.\nEstrutura de layouts layouts/ ├── _default/ │ ├── baseof.html # Template base (wrapping) │ ├── list.html # Página de listagem │ └── single.html # Página de post único ├── partials/ │ ├── header.html # Cabeçalho │ └── footer.html # Rodapé ├── index.html # Página inicial └── 404.html # Página de erro Adicionando CSS customizado Crie o arquivo assets/css/extended/custom.css (no PaperMod e temas similares):\n/* Exemplo: mudar a fonte do corpo */ body { font-family: \u0026#39;Inter\u0026#39;, sans-serif; } /* Mudar cor de destaque */ a { color: #ff6b6b; } Ou adicione no static/css/custom.css e referencie no hugo.toml:\n[params] customCSS = [\u0026#34;css/custom.css\u0026#34;] Adicionando JS customizado [params] customJS = [\u0026#34;js/custom.js\u0026#34;] Shortcodes customizados Shortcodes são componentes reutilizáveis dentro dos posts. Crie em layouts/shortcodes/:\nlayouts/shortcodes/aviso.html:\n\u0026lt;div class=\u0026#34;aviso aviso-{{ .Get \u0026#34;tipo\u0026#34; | default \u0026#34;info\u0026#34; }}\u0026#34;\u0026gt; {{ .Inner | markdownify }} \u0026lt;/div\u0026gt; Uso no Markdown:\n{{\u0026lt; aviso tipo=\u0026#34;atenção\u0026#34; \u0026gt;}} Isso é muito importante! {{\u0026lt; /aviso \u0026gt;}} Variáveis úteis nos templates {{ .Title }} \u0026lt;!-- Título do post --\u0026gt; {{ .Date }} \u0026lt;!-- Data --\u0026gt; {{ .Params.author }} \u0026lt;!-- Campo customizado do front matter --\u0026gt; {{ .Content }} \u0026lt;!-- Conteúdo completo do post --\u0026gt; {{ .Summary }} \u0026lt;!-- Resumo --\u0026gt; {{ .ReadingTime }} \u0026lt;!-- Tempo de leitura estimado --\u0026gt; {{ .WordCount }} \u0026lt;!-- Contagem de palavras --\u0026gt; {{ .Permalink }} \u0026lt;!-- URL completa --\u0026gt; {{ .Site.Title }} \u0026lt;!-- Título do site --\u0026gt; Imagens e assets Adicionando imagens estáticas Coloque em static/images/ e referencie assim:\n![Descrição](/images/foto.jpg) Processamento de imagens (Hugo Pipes) Hugo pode redimensionar imagens automaticamente:\n{{ $img := resources.Get \u0026#34;images/foto.jpg\u0026#34; }} {{ $resized := $img.Resize \u0026#34;800x\u0026#34; }} \u0026lt;img src=\u0026#34;{{ $resized.RelPermalink }}\u0026#34; alt=\u0026#34;Foto\u0026#34;\u0026gt; Deploy e publicação Github Pages 1. Crie um repositório no Github chamado seu-usuario.github.io\n2. Adicione o remote e envie:\ngit remote add origin git@github.com:seu-usuario/seu-usuario.github.io.git git push -u origin main 3. Crie o arquivo .github/workflows/hugo.yml:\nname: Deploy Hugo on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: submodules: true - name: Setup Hugo uses: peaceiris/actions-hugo@v3 with: hugo-version: \u0026#39;latest\u0026#39; extended: true - name: Build run: hugo --minify - name: Deploy uses: peaceiris/actions-gh-pages@v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./public 4. No Github, vá em Settings → Pages e selecione a branch gh-pages.\nNetlify (mais simples) 1. Conecte seu repositório Github no netlify.com\n2. Configure o build:\nCampo Valor Build command hugo --minify Publish directory public 3. Adicione a variável de ambiente:\nHUGO_VERSION = 0.145.0 Pronto - a cada git push, o Netlify faz o deploy automaticamente.\nVercel Conecte o repositório no vercel.com e selecione o framework Hugo. O Vercel detecta automaticamente as configurações necessárias.\nResumo dos comandos do dia a dia # Novo post hugo new content posts/meu-post.md # Visualizar com rascunhos hugo server -D # Gerar site para produção hugo --minify # Atualizar tema git submodule update --remote --merge # Ver configuração ativa hugo config Com isso você tem tudo que precisa para criar, personalizar e publicar um blog profissional com Hugo. É uma das ferramentas mais simples e poderosas para quem quer ter um blog sem complexidade de backend. ✍️🚀\n","permalink":"https://maggioni.dev/pt-br/posts/dev/create-a-blog-with-hugo/","summary":"Aprenda a instalar o Hugo, criar seu blog, instalar temas, personalizar e publicar do zero","title":"Tudo que você precisa saber sobre Hugo - Crie e gerencie seu blog"},{"content":"Git e Github — Guia Prático para Iniciantes Nesse post, iremos abordar os seguintes temas:\nComo conectar via SSH no Github Como enviar um repositório local para o remoto Comandos úteis Workflow com Git e Github O que é Git e por que usar? Git é um sistema de controle de versão distribuído criado por Linus Torvalds em 2005. Ele permite que você rastreie as alterações no seu código ao longo do tempo, volte para versões anteriores e colabore com outras pessoas sem sobrescrever o trabalho umas das outras.\nGithub é uma plataforma online que hospeda repositórios Git, facilitando a colaboração, o backup e o compartilhamento de projetos.\n💡 Pense no Git como uma \u0026ldquo;máquina do tempo\u0026rdquo; para o seu código, e no Github como a \u0026ldquo;nuvem\u0026rdquo; onde você guarda essas versões.\nInstalação Linux (Debian/Ubuntu) sudo apt update \u0026amp;\u0026amp; sudo apt install git -y macOS brew install git Windows Baixe o instalador em git-scm.com.\nApós instalar, pode fazer toda a configuração pelo terminal do git bash, comece configurando seu nome e e-mail:\ngit config --global user.name \u0026#34;Seu Nome\u0026#34; git config --global user.email \u0026#34;seu@email.com\u0026#34; Como conectar via SSH no Github A autenticação via SSH é mais segura e prática do que usar usuário e senha. Com ela, você não precisa digitar credenciais a cada push.\n1. Gerar a chave SSH ssh-keygen -t ed25519 -C \u0026#34;seu@email.com\u0026#34; Pressione Enter para aceitar o caminho padrão (~/.ssh/id_ed25519). Opcionalmente, defina uma senha para a chave.\n2. Adicionar a chave ao ssh-agent eval \u0026#34;$(ssh-agent -s)\u0026#34; # ssh-agent -c | source ssh-add ~/.ssh/id_ed25519 3. Copiar a chave pública cat ~/.ssh/id_ed25519.pub Copie o conteúdo exibido no terminal.\n4. Adicionar a chave no Github Acesse Github → Settings → SSH and GPG keys Clique em New SSH key Cole a chave pública e salve 5. Testar a conexão ssh -T git@github.com Se tudo estiver correto, você verá:\nHi seu-usuario! You\u0026#39;ve successfully authenticated, but GitHub does not provide shell access. Como enviar um repositório local para o remoto Partindo do zero (novo projeto) # 1. Crie a pasta e entre nela mkdir meu-projeto \u0026amp;\u0026amp; cd meu-projeto # 2. Inicie o repositório Git git init # 3. Crie um arquivo inicial echo \u0026#34;# Meu Projeto\u0026#34; \u0026gt; README.md # 4. Adicione os arquivos ao stage git add . # 5. Faça o primeiro commit git commit -m \u0026#34;feat: primeiro commit\u0026#34; # 6. Renomeie a branch principal (boa prática) git branch -M main # 7. Conecte ao repositório remoto (crie o repo no Github antes) git remote add origin git@github.com:seu-usuario/meu-projeto.git # se já tem uma origin não ssh, pode substituir com: # git remote set-url origin git@github.com:seu-usuario/meu-projeto.git # 8. Envie para o Github git push -u origin main ⚠️ Lembre-se de criar o repositório vazio no Github antes do passo 7. Não marque a opção de adicionar README para evitar conflitos.\nClonando um repositório existente git clone git@github.com:usuario/repositorio.git cd repositorio Comandos Úteis Informação e status Comando O que faz git status Mostra o estado atual dos arquivos git log Exibe o histórico de commits git log --oneline Histórico resumido em uma linha por commit git diff Mostra as diferenças ainda não staged git diff --staged Mostra as diferenças já no stage Stage e commits git add arquivo.txt # Adiciona um arquivo específico git add . # Adiciona todos os arquivos modificados git commit -m \u0026#34;mensagem\u0026#34; # Cria um commit git commit --amend # Edita o último commit (mensagem ou arquivos) Branches git branch # Lista as branches locais git branch minha-feature # Cria uma nova branch git checkout minha-feature # Muda para a branch git checkout -b minha-feature # Cria e já muda para a branch git switch -c minha-feature # Alternativa moderna ao checkout -b git merge minha-feature # Faz merge da branch na atual git branch -d minha-feature # Deleta a branch local Remoto git push origin main # Envia commits para o remoto git pull # Baixa e integra mudanças do remoto git fetch # Baixa mudanças sem integrar git remote -v # Lista os remotos configurados Desfazendo mudanças git restore arquivo.txt # Descarta mudanças não staged git restore --staged arquivo.txt # Remove do stage sem perder mudanças git revert HEAD # Cria um commit que desfaz o último git reset --soft HEAD~1 # Desfaz o último commit, mantém stage git reset --hard HEAD~1 # ⚠️ Desfaz tudo — use com cuidado! Stash (guardar mudanças temporariamente) git stash # Salva mudanças temporariamente git stash pop # Recupera a última mudança salva git stash list # Lista todos os stashes git stash drop # Remove o stash mais recente Workflow com Git e Github Um bom workflow evita conflitos e mantém o histórico organizado. O mais comum para times é o Feature Branch Workflow:\nPasso a passo main ──────────────────────────────────●───────── / feature/login ──●──●──●──────────────● 1. Sempre parta da main atualizada\ngit checkout main git pull 2. Crie uma branch para sua feature ou correção\ngit checkout -b feature/nome-da-feature 3. Desenvolva e faça commits pequenos e descritivos\ngit add . git commit -m \u0026#34;feat: adiciona tela de login\u0026#34; 4. Envie sua branch para o remoto\ngit push origin feature/nome-da-feature 5. Abra um Pull Request no Github\nNo Github, clique em \u0026ldquo;Compare \u0026amp; pull request\u0026rdquo;, descreva as mudanças e solicite revisão.\n6. Após aprovação, faça o merge e delete a branch\ngit checkout main git merge feature/nome-da-feature git branch -d feature/nome-da-feature git push origin --delete feature/nome-da-feature Boas práticas para mensagens de commit Use o padrão Conventional Commits:\nfeat: adiciona funcionalidade de login fix: corrige bug no formulário de cadastro docs: atualiza README com instruções de instalação style: formata código sem alterar lógica refactor: reorganiza estrutura de pastas test: adiciona testes para o módulo de auth chore: atualiza dependências Resumo rápido # Fluxo básico do dia a dia git pull # Atualiza o repositório local git checkout -b minha-feature # Cria e entra na branch # ... faz as alterações ... git add . # Stage das mudanças git commit -m \u0026#34;feat: minha feature\u0026#34; # Commit git push origin minha-feature # Envia para o Github # Abre Pull Request no Github Com esses conceitos e comandos você já consegue trabalhar de forma profissional com Git e Github no dia a dia. Bons commits! 🚀\n","permalink":"https://maggioni.dev/pt-br/posts/dev/commands-for-git-and-github/","summary":"Aprenda os comandos necessários de git e github","title":"Tudo oque você precisa saber sobre Git e Github"},{"content":" Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Vídeo Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Vídeo Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Ver imagem Vídeo Vídeo × ","permalink":"https://maggioni.dev/pt-br/gallery/","summary":"\u003cdiv class=\"gallery\"\u003e\n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/1i0dtd.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/1i0dtd.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250202_193658.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250202_193658.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250316_152307.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250316_152307.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250316_152310.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250316_152310.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250316_152318.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250316_152318.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250316_152425.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250316_152425.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250614_194537.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250614_194537.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250614_194557.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250614_194557.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item video-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250627_202700-00.00.00.000-00.00.19.399%20%281%29%20%281%29.mp4\" data-type=\"video\"\u003e\n        \u003cvideo muted preload=\"metadata\" tabindex=\"-1\"\u003e\n          \u003csource src=\"https://assets.maggioni.dev/gallery/20250627_202700-00.00.00.000-00.00.19.399%20%281%29%20%281%29.mp4#t=0.1\" /\u003e\n        \u003c/video\u003e\n        \u003cdiv class=\"play-btn\" aria-label=\"Reproduzir vídeo\"\u003e\n          \u003csvg viewBox=\"0 0 24 24\" fill=\"currentColor\"\u003e\n            \u003cpath d=\"M8 5v14l11-7z\"/\u003e\n          \u003c/svg\u003e\n        \u003c/div\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVídeo\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250719_160604.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250719_160604.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250719_160615.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250719_160615.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250719_160636.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250719_160636.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250904_182602.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250904_182602.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250904_182604.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250904_182604.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250906_103602.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250906_103602.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250912_124300.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250912_124300.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250912_124304.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250912_124304.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250912_124308.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250912_124308.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250912_124314.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250912_124314.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250912_124348.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250912_124348.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250912_124514.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250912_124514.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250919_175424.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250919_175424.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250919_175428.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250919_175428.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250919_175436.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250919_175436.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250919_175447.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250919_175447.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20250919_175456.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20250919_175456.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163212.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163212.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163220.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163220.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163231.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163231.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163327.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163327.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163332.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163332.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163337.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163337.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163410.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163410.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163432.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163432.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163736.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163736.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163737.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163737.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163739.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163739.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163744.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163744.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163748.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163748.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163752.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163752.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163756.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163756.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163759.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163759.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163817.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163817.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163828.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163828.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163840.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163840.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163939.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163939.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163940.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163940.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163946.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163946.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251004_163958.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251004_163958.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item video-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251005_072923-00.00.05.078-00.01.02.262%20%281%29%20%281%29.mp4\" data-type=\"video\"\u003e\n        \u003cvideo muted preload=\"metadata\" tabindex=\"-1\"\u003e\n          \u003csource src=\"https://assets.maggioni.dev/gallery/20251005_072923-00.00.05.078-00.01.02.262%20%281%29%20%281%29.mp4#t=0.1\" /\u003e\n        \u003c/video\u003e\n        \u003cdiv class=\"play-btn\" aria-label=\"Reproduzir vídeo\"\u003e\n          \u003csvg viewBox=\"0 0 24 24\" fill=\"currentColor\"\u003e\n            \u003cpath d=\"M8 5v14l11-7z\"/\u003e\n          \u003c/svg\u003e\n        \u003c/div\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVídeo\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251026_111359.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251026_111359.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251026_111403.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251026_111403.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251026_111429.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251026_111429.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251026_111437.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251026_111437.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251109_154953.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251109_154953.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251109_155002.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251109_155002.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251109_155011.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251109_155011.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251221_144551.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251221_144551.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251221_144555.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251221_144555.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20251221_144600.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20251221_144600.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20260221_123011.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20260221_123011.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20260221_123018.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20260221_123018.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20260221_123020.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20260221_123020.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20260221_123029.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20260221_123029.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20260221_123047.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20260221_123047.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20260301_140805.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20260301_140805.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20260316_155611.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20260316_155611.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/20260316_155620.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/20260316_155620.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/IMG-20260105-WA0044.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/IMG-20260105-WA0044.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/IMG-20260214-WA0003.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/IMG-20260214-WA0003.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/Screenshot_20251022_171303_Instagram~2.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/Screenshot_20251022_171303_Instagram~2.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/Screenshot_20260327_085308_Photos%281%29.jpg\" data-type=\"image\"\u003e\n        \u003cimg src=\"https://assets.maggioni.dev/gallery/Screenshot_20260327_085308_Photos%281%29.jpg\" loading=\"lazy\" alt=\"\" /\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVer imagem\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item video-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/VID-20260503-WA0001%20%281%29.mp4\" data-type=\"video\"\u003e\n        \u003cvideo muted preload=\"metadata\" tabindex=\"-1\"\u003e\n          \u003csource src=\"https://assets.maggioni.dev/gallery/VID-20260503-WA0001%20%281%29.mp4#t=0.1\" /\u003e\n        \u003c/video\u003e\n        \u003cdiv class=\"play-btn\" aria-label=\"Reproduzir vídeo\"\u003e\n          \u003csvg viewBox=\"0 0 24 24\" fill=\"currentColor\"\u003e\n            \u003cpath d=\"M8 5v14l11-7z\"/\u003e\n          \u003c/svg\u003e\n        \u003c/div\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVídeo\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n    \n    \n      \u003cdiv class=\"gallery-item video-item\" onclick=\"openLightbox(this)\" data-src=\"https://assets.maggioni.dev/gallery/VID-20260503-WA0002%20%281%29.mp4\" data-type=\"video\"\u003e\n        \u003cvideo muted preload=\"metadata\" tabindex=\"-1\"\u003e\n          \u003csource src=\"https://assets.maggioni.dev/gallery/VID-20260503-WA0002%20%281%29.mp4#t=0.1\" /\u003e\n        \u003c/video\u003e\n        \u003cdiv class=\"play-btn\" aria-label=\"Reproduzir vídeo\"\u003e\n          \u003csvg viewBox=\"0 0 24 24\" fill=\"currentColor\"\u003e\n            \u003cpath d=\"M8 5v14l11-7z\"/\u003e\n          \u003c/svg\u003e\n        \u003c/div\u003e\n        \u003cdiv class=\"gallery-overlay\"\u003e\u003cspan\u003eVídeo\u003c/span\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \n  \n\u003c/div\u003e\n\n\u003cdiv class=\"lightbox\" id=\"lightbox\" onclick=\"closeLightbox(event)\"\u003e\n  \u003cspan class=\"close\" onclick=\"closeLightbox()\"\u003e×\u003c/span\u003e\n  \u003cdiv class=\"lightbox-content\" id=\"lightbox-content\"\u003e\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cscript\u003e\n  function openLightbox(el) {\n  const lb = document.getElementById(\"lightbox\");\n  const content = document.getElementById(\"lightbox-content\");\n  const src = el.dataset.src;\n  const type = el.dataset.type;\n\n  content.innerHTML = \"\";\n\n  if (type === \"video\") {\n    const video = document.createElement(\"video\");\n    video.src = src;\n    video.controls = true;\n    video.autoplay = true;\n    video.style.maxWidth = \"92vw\";\n    video.style.maxHeight = \"92vh\";\n    video.style.borderRadius = \"3px\";\n    content.appendChild(video);\n  } else {\n    const img = document.createElement(\"img\");\n    img.src = src;\n    content.appendChild(img);\n  }\n\n  lb.classList.add(\"active\");\n  document.body.style.overflow = \"hidden\";\n}\n\nfunction closeLightbox(event) {\n  if (event \u0026\u0026 event.target !== event.currentTarget \u0026\u0026 event.type !== \"keydown\") return;\n\n  const lb = document.getElementById(\"lightbox\");\n  const content = document.getElementById(\"lightbox-content\");\n\n  lb.classList.remove(\"active\");\n\n  \n  const video = content.querySelector(\"video\");\n  if (video) video.pause();\n\n  content.innerHTML = \"\";\n  document.body.style.overflow = \"\";\n}\n\ndocument.addEventListener(\"keydown\", function (e) {\n  if (e.key === \"Escape\") closeLightbox();\n});\n\u003c/script\u003e","title":""},{"content":" ⭠ voltar\n🎥 Animações #1 Gato de botas 2 🎬 Animação ⭐ 10 Filmaço da porra! #2 Robô Selvagem 🎬 Animação ⭐ 10 Filme lindo demais! Sem defeitos! Cortaram cebola na minha cara meo ","permalink":"https://maggioni.dev/pt-br/films/animations/","summary":"Filmes de animação!","title":"🎬 Animações"},{"content":" ⭠ voltar\n🎥 Comédia #1 Todo mundo quase morto 🎬 comédia ⭐ 8 Zumbis 🧟‍♂️. Divertido, legal, final surpeendente. #2 Tucker \u0026amp; Dale contra o mal 🎬 comédia ⭐ 7 Cara é uma comédia, bastante engraçada que brinca com os famosos clichês de filmes slasher. Aqui a lógica é completamente invertida: os adolescentes vão se matando sozinhos em acidentes cada vez mais absurdos, enquanto os supostos “assassinos” são só dois caras simples e tranquilos tentando viver a vida deles 😭 kkk ","permalink":"https://maggioni.dev/pt-br/films/comedia/","summary":"Filmes de comédia!","title":"🎬 Comédia"},{"content":" ⭠ voltar\n🎥 Heróis #1 Homem aranha no aranhaverso (2018) 🎬 héroi ⭐ 10 Homem aranha, homem aranha, nunca bate, sempre apanha #2 Homem aranha através do aranhaverso (2023) 🎬 héroi ⭐ 9.5 Mano o filme não tem final! AAAAAAAAAAAAA (mas é bom) #3 Spiderman (2002) 🎬 héroi ⭐ 10 O primeiro miranha! #4 Superman (2025) 🎬 héroi ⭐ 10 Cara\u0026hellip; primeiro filme que eu vi no cinema, na vida. Foi muito legal, apesar de muita gente criticar a falta de aura do superman kkk, esquece isso, é muito bom. ","permalink":"https://maggioni.dev/pt-br/films/herois/","summary":"Filmes de heróis!","title":"🎬 Heróis"},{"content":" ⭠ voltar\n🎥 Sci-fi #1 Devoradores de Estrelas (2026) 🎬 sci-fi, humor ⭐ 10 Gostei demais desse filme. É um sci-fi, mas sem ser super cabeçudo. Aqui tudo é mais leve, divertido e muito carismático. A montagem é muito boa, o ritmo flui fácil e o filme consegue equilibrar ciência, humor e emoção sem ficar forçando profundidade o tempo todo. 😄. E sério… eu nunca imaginei que fosse me apegar tanto a uma pedra :3 #2 O Astronauta 🎬 sci-fi ⭐ 9 O Astronauta é um filme bastante subestimado. Tem uma pegada sci-fi mais melancólica e introspectiva. A solidão do espaço, os diálogos estranhos e o clima meio existencial acabam criando uma experiência bem única. ","permalink":"https://maggioni.dev/pt-br/films/sci-fi/","summary":"Filmes cabeçudos!","title":"🎬 Sci-fi"}]