Sobre o portfólio

SEO

100 palavras

  • Unity
  • Multiplayer
  • LiveOps
  • C#

Leonardo Lycan é Lead Game Developer e especialista em desenvolvimento de jogos Unity, arquitetura multiplayer, sistemas de gameplay, LiveOps e produção técnica. Este portfólio reúne projetos publicados, protótipos jogáveis, estudos de produto e artigos sobre engenharia de jogos, IA aplicada, Web3, onboarding e experiências digitais. O trabalho combina liderança de equipes, programação C#, integração de serviços, otimização de performance e comunicação clara entre design, arte e negócio. Para projetos, consultoria ou colaboração, Leonardo oferece uma abordagem prática: entender o problema, construir uma solução robusta e transformar requisitos complexos em experiências memoráveis para jogadores e produtos digitais com impacto mensurável hoje.

Voltar

Engenharia · 26 de agosto de 2026

Da main ao domínio: Astro, GitHub Actions e Cloudflare Pages

Como organizei um único fluxo de publicação para um portfólio Astro: build validada no GitHub Actions, deploy na Cloudflare Pages, domínio próprio e seleção de idioma sem redirecionamento visível.

Da main ao domínio: Astro, GitHub Actions e Cloudflare Pages

Publicar um portfólio parece simples até a tarefa envolver tudo ao mesmo tempo: código local, repositório remoto, build reproduzível, credenciais, domínio próprio, DNS, HTTPS e dois idiomas. O risco não estava em executar um comando de deploy. Estava em criar um sistema no qual a próxima publicação fosse previsível e não exigisse refazer decisões manualmente.

Este artigo registra a arquitetura que usei no meu próprio portfólio. O objetivo foi chegar a uma regra simples:

toda alteração aprovada entra na main; a automação valida o projeto e publica uma única versão; os domínios e idiomas são formas diferentes de chegar a essa mesma publicação.

Não é uma receita universal. É um case de implementação com limites explícitos, incluindo o que ainda permanece como próximo passo.

O desenho final

push na main
  → GitHub Actions
  → npm ci
  → build + validação de release
  → Wrangler envia dist/ para Cloudflare Pages
  → Cloudflare atende o domínio próprio

O projeto continua sendo um site Astro estático. Não foi necessário transformar toda a aplicação em SSR para obter deploy contínuo ou executar uma pequena decisão no edge. O build gera dist/, e o Wrangler publica esse diretório no projeto existente da Cloudflare Pages. Esse caminho também é documentado nos guias oficiais de deploy do Astro na Cloudflare e de Direct Upload com Wrangler.

Uma única fonte de produção

O primeiro princípio foi evitar dois processos concorrentes. O GitHub não hospeda uma cópia e a Cloudflare outra. O GitHub mantém o código e executa a automação; a Cloudflare Pages recebe o artefato de produção.

O workflow é disparado somente por push na main ou manualmente por workflow_dispatch:

on:
  push:
    branches: [main]
  workflow_dispatch:

concurrency:
  group: cloudflare-pages-production
  cancel-in-progress: true

O filtro de branch torna a main o contrato de publicação. A configuração de concorrência impede que dois deploys de produção disputem o mesmo destino. O GitHub documenta tanto os filtros de branch para eventos de push quanto o uso de environments e concurrency em deploys.

Validar antes de enviar

A automação não começa pelo upload. Ela reproduz a instalação e valida o que será publicado:

- name: Install dependencies
  run: npm ci

- name: Build and validate release
  run: npm run release:check

- name: Deploy to Cloudflare Pages
  uses: cloudflare/wrangler-action@v4
  with:
    apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
    accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
    command: pages deploy dist --project-name=portfolio

No projeto, release:check combina o build do Astro com uma validação do resultado. Essa segunda etapa verifica inventário bilíngue, metadados, links internos, assets e ausência das rotas editoriais no artefato público. O deploy só começa se o comando terminar com sucesso.

O token e o identificador da conta não ficam no YAML. Eles são lidos de GitHub Actions Secrets. Além de evitar credenciais versionadas, essa separação permite limitar a permissão do token ao que o deploy realmente precisa. A documentação do GitHub cobre a criação e o uso de secrets em workflows, e suas recomendações de segurança reforçam o princípio de menor privilégio.

Domínio próprio é uma mudança de DNS, não de build

Depois que a URL pages.dev estava respondendo, o domínio principal foi conectado ao mesmo projeto Pages. Essa ordem foi útil porque separou dois diagnósticos:

  1. o artefato está correto e acessível na Cloudflare?
  2. o domínio está delegado e associado corretamente?

Para um domínio apex, como example.com, a Cloudflare exige que a zona esteja na mesma conta do projeto Pages e que os nameservers apontem para a Cloudflare. O fluxo correto também inclui adicionar o domínio em Custom domains; criar apenas um CNAME manual não substitui essa associação. A sequência está descrita na documentação de custom domains da Cloudflare Pages.

Havia ainda um cuidado operacional: migrar o site sem apagar os registros que atendem outros serviços. Antes de trocar a autoridade DNS, revisei e preservei os registros de e-mail e de verificação existentes. Um site funcionar enquanto o e-mail deixa de funcionar não é um deploy bem-sucedido.

Uma publicação, vários domínios

Domínios adicionais não precisam criar novos builds. A arquitetura pretendida é:

  • um domínio canônico para indexação e compartilhamento;
  • domínios secundários como portas de entrada;
  • redirecionamento permanente dos secundários para o canônico;
  • uma única origem, um único certificado operacional e um único pipeline de conteúdo.

No momento deste registro, o domínio principal já está ativo. O domínio .com.br ainda é um próximo passo porque continua sob outra autoridade DNS. Ele não é apresentado aqui como concluído. Publicá-lo exige adicionar a zona, preservar seus registros, trocar os nameservers no registrador e somente então ativar o redirecionamento para o domínio canônico.

O loading escondido no primeiro acesso

O problema mais visível apareceu depois do domínio entrar no ar. A rota / era um redirect estático do Astro para /en-us/. Em conexões rápidas, isso poderia parecer aceitável. Em uma verificação real no Safari, porém, o navegador mostrou a página intermediária “Redirecting from / to /en-us/” antes de carregar o site.

O requisito mudou: detectar a preferência de idioma sem trocar a URL inicial e sem obrigar o navegador a fazer uma segunda navegação.

A solução foi manter as páginas localizadas já geradas e adicionar somente uma Pages Function na raiz:

GET /
  → ler Accept-Language
  → pt: servir internamente /pt-br/artigos/
  → en ou fallback: servir internamente /en-us/insights/
  → responder 200 mantendo a URL /

Na Cloudflare Pages, functions/index.js corresponde à rota raiz. A função pode pedir um asset estático do próprio projeto por meio de env.ASSETS.fetch(). Assim, não há Location nem uma nova navegação no browser. A resposta também informa Content-Language e Vary: Accept-Language.

Essa abordagem usa capacidades descritas diretamente na documentação de roteamento de Pages Functions, na referência de env.ASSETS.fetch() e no guia de localização por Accept-Language.

As rotas explícitas /pt-br/... e /en-us/... continuam existindo. Elas permanecem úteis para links, compartilhamento, alternates e seleção manual. O que desaparece é o salto obrigatório no primeiro acesso ao domínio.

Custo e escala

Para este tipo de site, requisições puramente estáticas na Pages não consomem cota de Functions. A rota /, por usar uma Function, conta na cota do Workers. A documentação atual informa que o plano gratuito compartilha uma franquia diária entre Workers e Pages Functions; por isso, o custo deve ser reavaliado se o tráfego crescer ou se mais rotas dinâmicas forem adicionadas. Os detalhes vigentes estão na página de pricing de Pages Functions.

No GitHub, o custo depende da visibilidade do repositório, do runner e do plano. Não tratei “CI gratuito” como garantia permanente; a referência correta é a página atual de billing do GitHub Actions.

Checklist que encerra o deploy

O trabalho só pode ser considerado concluído quando cada camada responde:

  • npm ci reproduz a instalação;
  • o build usa a versão de Node declarada pelo projeto;
  • release:check termina sem erro;
  • o workflow da main conclui com sucesso;
  • a URL pages.dev responde;
  • o domínio canônico responde com HTTPS;
  • os registros de e-mail e verificação continuam presentes;
  • / responde 200 sem cabeçalho Location;
  • Accept-Language: pt-BR entrega português;
  • Accept-Language: en-US entrega inglês;
  • nenhuma credencial aparece no repositório ou nos logs.

O aprendizado principal

Automação de deploy não é apenas “publicar ao dar merge”. É tornar explícitos os contratos entre código, build, credencial, infraestrutura e experiência de entrada.

O desenho ficou mais simples quando cada sistema recebeu uma responsabilidade:

  • Git guarda o histórico;
  • main define o que pode ir para produção;
  • GitHub Actions reproduz e valida;
  • Wrangler transporta o artefato;
  • Cloudflare Pages serve o site;
  • DNS conecta nomes sem duplicar aplicações;
  • a Function da raiz resolve apenas a escolha inicial de idioma.

Essa separação evita que cada novo domínio, idioma ou publicação vire um projeto paralelo. O resultado desejado continua sendo um só: alterar, validar e publicar com evidência.