Portfólio pessoal e cases
Portfólio Astro estático: cases bilíngues tipados, UI editorial paper-first, quase zero JS por padrão, mais superfícies agent-readable (llms.txt, JSON Resume, MCP). O www em produção mantém analytics adiados e Bot Fight da Cloudflare.
Caminho rejeitado: Usar Next.js App Router em todas as páginas
Visão geral
Precisava de um lugar para mostrar como trabalho, não uma galeria de miniaturas. Este site é Astro estático com cases em MDX (EN como fonte, overlays pt-BR), rail tipográfico de trabalhos selecionados na home, prateleira de produtos, folios anuais de Comunidade, Playwright nos fluxos críticos e endpoints máquina para agentes e ferramentas consultarem os mesmos fatos sem scrapar HTML.
Problema
A maioria dos portfólios parece intercambiável: tema escuro, cargo no hero, grades de cards e pouca prova de julgamento. Também deixam crawlers de IA e tooling de agentes adivinharem a partir de HTML bagunçado.
Restrições
- Zero JavaScript por padrão em páginas de conteúdo; React só se uma interação justificar.
- Lighthouse Accessibility e SEO fortes na home ao vivo; documentar trocas de Perf com honestidade.
- Coleções de conteúdo tipadas para cases, palestras e apps.
- Interface clara com tipografia de jornal e contraste legível; o tema escuro permanece opcional.
- Medir tráfego real (gtag adiado + Vercel Analytics); não apagar analytics para perseguir nota de fachada.
- Manter proteções de edge da Cloudflare utilizáveis; não bloquear o challenge no CSP só para subir Best Practices.
- Um perfil canônico para humanos e agentes (PDF + JSON Resume + MCP).
- Ferramentas de IA permitidas para velocidade, não para arquitetura sem supervisão.
Arquitetura
Astro para o shell e a lista de trabalhos selecionados na homepage. MDX + overlays i18n para cases e produtos. Tokens CSS vanilla (IBM Plex) para um sistema editorial discreto. Folios por ano e grades de duas colunas em vez de dashboards de cards. Playwright contra o site buildado. Camada de agentes: profile.ts alimenta llms.txt, resume.json, Person JSON-LD e um servidor MCP (stdio + Streamable HTTP na Vercel). Em produção, analytics sobe após idle e o CSP permanece compatível com scripts de challenge da Cloudflare.
Decisões principais
Astro em vez de Next.js
Site de conteúdo não precisa de runtime React em toda página.
- Usar Next.js App Router em todas as páginas (rejeitado: custo de JS sem benefício)
Lista tipográfica estática de trabalhos selecionados em vez de carrossel hero React
O carrossel precisava de ilha para fade e paginação. Uma lista tipográfica prova o mesmo trabalho com zero client JS na homepage.
- Manter HeroCarousel como ilha React (rejeitado: interatividade sem valor suficiente)
Analytics adiados em vez de nenhum analytics
Portfólio que afirma julgamento técnico ainda deve medir visitas. Analytics sobe após idle com IP anonimizado. Aceitar custo modesto no Lighthouse em vez de site mudo.
- Omitir todo analytics por Performance 100 limpo (rejeitado: produto imensurável, nota de fachada)
- Analytics síncrono no <head> (rejeitado: bloqueia LCP/TBT sem necessidade)
CSP compatível com Cloudflare em vez de scripts travados por hash
script-src só com hash bloqueou bootstrap de challenge Cloudflare e forçou desligar Bot Fight por paridade de score. O CSP de produção permite o caminho de challenge para a proteção de edge permanecer ligada.
- CSP com hash que bloqueia challenge CF para forçar Best Practices 100 (rejeitado: recurso de segurança desligado por nota de fachada)
Tema claro com tipografia de jornal como padrão, em vez de dark-first
Portfólios tech escuros estão saturados. Papel claro com tipografia de contraste mais forte lê melhor na primeira passagem.
- Manter dark como padrão (rejeitado: parece todo portfólio de tech)
Uma prateleira Produtos para toda ferramenta entregue
StackBrief e Dieta e Treino são produtos disponíveis que as pessoas podem abrir. Separar em Lab fazia o segundo parecer inacabado.
- Separar Produtos e Lab (rejeitado: diluiu Dieta e Treino)
Perfil agent-readable (llms.txt + resume.json + MCP) a partir de uma fonte
Recrutadores e agentes de IDE já buscam llms.txt e MCP. Um profile.ts alinha Person schema, JSON Resume e tools sem duplicar o corpo dos MDX.
- Só HTML e esperar scrapers acertarem (rejeitado)
- JSON Resume paralelo à mão (rejeitado: drift)
Playwright em vez de testes unitários de componente
Testes de browser pegam os fluxos que importam num build estático.
CSS vanilla em vez de Tailwind
Estilos escopados e variáveis bastaram aqui.
Stack
- Astro 5
- TypeScript
- MDX + Zod collections
- Vanilla CSS (IBM Plex)
- Playwright (E2E)
- Vercel + Cloudflare
- Google Analytics (deferred gtag)
- Vercel Web Analytics
- MCP (Streamable HTTP + stdio)
Impacto
Auditado em 9 ago 2026 com Lighthouse 12.8.2 em https://www.erbsu.com/en/ (Cloudflare + analytics adiados). Desktop fica quase perfeito; Perf mobile é o principal custo do www. Suite Playwright a11y/nav: 8/8. Endpoints agent-readable saem da mesma fonte do PDF.
Aprendizados
- Tratar JavaScript como custo significa remover ilhas quando uma lista estática basta, não apagar analytics ou segurança de edge para imprimir um placar perfeito.
- Um 100 conquistado tirando medição e Bot Fight soa como nota de fachada; documente a troca.
- A primeira impressão falha em copy defensiva e enfeite de template antes de falhar em escolha de stack.
- Acessibilidade e contraste desde o início superam passada de polimento tardio.
- Arquivos agent-readable não substituem descoberta orgânica. Tornam citações precisas quando alguém (ou um agente) já chega no domínio.