Portfólio profissional multilíngue em Next.js 16 e React 19. A aplicação combina conteúdo pré-renderizado, uma experiência editorial imersiva e efeitos progressivos com limites explícitos de acessibilidade, segurança e performance.
Este README é a porta de entrada operacional. O desenho completo, os fluxos, contratos, decisões e procedimentos de manutenção estão em docs/TECHNICAL_CONTEXT.md.
- Home e artigo localizados e pré-renderizados para português, inglês e espanhol.
- Prefixo de idioma somente quando necessário:
/,/ene/es. - Metadata localizada com canonical,
hreflang, Open Graph, Twitter Cards, sitemap e JSON-LD. - Server Components por padrão e ilhas client-side somente para interação.
- Vitrine de sites publicados com screenshots locais, links externos seguros e conteúdo integralmente localizado.
- Artigo legível sem JavaScript, com experiência de scroll aprimorada quando o navegador e as preferências do usuário permitem.
- WebGL, GSAP e formulário carregados sob demanda, com fallbacks estáticos ou nativos.
- API de contato com validação estrita, proteção de origem, limites de corpo, rate limiting, honeypot, timeout e idempotência.
- Build standalone e imagem de produção distroless, não-root e com filesystem somente leitura via Compose.
- Gates automatizados para testes, lint, tipos, build, bundle, navegadores, dependências e imagem Docker.
| Área | Implementação atual |
|---|---|
| Aplicação | Next.js 16.2.10, React 19.2.4, TypeScript 5 |
| Interface | Tailwind CSS 4, CSS Modules, CSS nativo e Web Animations API |
| Motion opcional | GSAP 3.15.0 e OGL 1.0.11 |
| Formulário | React Hook Form 7.74.0, Zod 4.4.1 e Resend 6.17.2 |
| Internacionalização | next-intl 4.12 |
| Qualidade | ESLint 9, Vitest 4.1, Playwright 1.61 e axe-core |
| Entrega | GitHub Actions, Docker e Docker Compose |
- Node.js
>=24.0.0, sem teto de major. - npm 11.16.0 como versão de referência reproduzível.
- Docker 24+ somente para os fluxos em container.
O projeto usa Node.js 24.18.0 em .nvmrc, CI e Docker. Essa versão é referência, não limite: engines, devEngines e engine-strict=true rejeitam Node anterior à versão 24, mas aceitam versões posteriores. O campo packageManager declara npm 11.16.0 como referência reproduzível, sem impor uma faixa adicional de compatibilidade.
Scripts de lifecycle de dependências ficam desabilitados por .npmrc. Os scripts do próprio projeto, executados explicitamente com npm run, continuam habilitados.
Use nvm use para a toolchain de referência ou qualquer Node.js 24+:
nvm use
node --version
npm --version
npm ci
cp .env.example .env.development.local
npm run devA aplicação fica em http://localhost:3000.
Use especificamente .env.development.local para o desenvolvimento. O template contém apenas placeholders locais e nunca deve ser promovido para produção. As credenciais do Resend só são necessárias para validar um envio real; os demais conteúdos e links funcionam sem elas.
O fluxo padrão usa explicitamente Webpack, limita o old space do V8 a 1.536 MiB e, no macOS e Linux, monitora o RSS de toda a árvore do servidor. Se ela ultrapassar 2.048 MiB, o processo é encerrado com uma mensagem explícita em vez de pressionar a memória da máquina. Os limites podem ser ajustados por NEXT_DEV_OLD_SPACE_MB e NEXT_DEV_MEMORY_LIMIT_MB; ambos aceitam de 512 a 4.096 MiB e o old space deve deixar ao menos 256 MiB para o restante do heap, memória nativa e processos filhos. No Windows, o old space continua limitado, mas o teto rígido de memória exige o fluxo Docker. O wrapper lê os dois valores com a mesma precedência de arquivos .env do Next.js sem repassar o estado do loader ao processo filho.
Se o Node 24 do Homebrew estiver keg-only:
export PATH="$(brew --prefix node@24)/bin:$PATH"O Compose de desenvolvimento monta o repositório, preserva node_modules e .next em volumes nomeados e usa eventos nativos para o hot reload. Além do watchdog da aplicação, o container tem limite rígido padrão de 2.560 MiB e reserva de 1.024 MiB:
cp .env.example .env.development.local
docker compose --env-file .env.development.local -f docker-compose.dev.yml up --buildO parâmetro --env-file também alimenta a interpolação do Compose; assim, valores server-side definidos no arquivo chegam ao container em vez de serem substituídos pelos defaults do YAML.
O template deriva NEXT_PUBLIC_SITE_URL e CONTACT_ALLOWED_ORIGINS de PORT. Portanto, alterar PORT no arquivo muda em conjunto a porta publicada e as duas origens browser-facing.
Os volumes de dependências e cache são reconciliados por um fingerprint de package-lock.json, package.json, .npmrc, Node.js, plataforma e arquitetura. Ao detectar uma runtime incompatível, o container executa uma instalação limpa com verificação de assinaturas e descarta apenas o cache Next obsoleto; um volume antigo nunca é reutilizado silenciosamente.
Para encerrar e remover os containers:
docker compose --env-file .env.development.local -f docker-compose.dev.yml down --remove-orphansAs configurações públicas são incorporadas ao bundle. Segredos permanecem exclusivamente no runtime do servidor.
| Variável | Fase | Obrigatoriedade |
|---|---|---|
NEXT_PUBLIC_SITE_URL |
build e runtime | Origem pública; em produção deve ser HTTPS e pública |
NEXT_PUBLIC_WEB_VITALS_ENDPOINT |
build | Caminho first-party opcional para telemetria |
RESEND_API_KEY |
runtime | Obrigatória no bootstrap de produção |
CONTACT_FROM_EMAIL |
runtime | Remetente com domínio público; deve estar verificado para envio real |
CONTACT_TO_EMAIL |
runtime | Destino das mensagens |
CONTACT_IDEMPOTENCY_SECRET |
runtime | Segredo de alta entropia com pelo menos 32 caracteres |
CONTACT_ALLOWED_ORIGINS |
runtime | Lista de origens HTTPS; deve conter a origem pública |
CONTACT_TRUST_PROXY |
runtime | Decisão explícita: true ou false |
Limites de request, timeout, rate limiting e proxy estão documentados e exemplificados em .env.example. O contrato completo, incluindo faixas aceitas e defaults, está no contexto técnico.
Regras importantes:
- Nunca exponha segredos com prefixo
NEXT_PUBLIC_. - Alterar uma variável pública exige novo build.
- Habilite
CONTACT_TRUST_PROXYsomente se o proxy confiável sobrescrever o header configurado. - O endpoint de Web Vitals deve ser um caminho relativo à origem. Este repositório não implementa o coletor; ele precisa existir na mesma origem antes de a variável ser habilitada.
| Comando | Finalidade |
|---|---|
npm run dev |
Servidor de desenvolvimento com Webpack e limites de memória |
npm run dev:turbo |
Turbopack opt-in, protegido pelos mesmos limites |
npm test |
Vitest e regressão do quality hook |
npm run test:watch |
Vitest em modo interativo |
npm run lint |
ESLint com regras Next.js, Core Web Vitals e TypeScript |
npm run typecheck |
Gera tipos de rotas e executa TypeScript sem emitir arquivos |
npm run build |
Build standalone e cópia validada dos assets |
npm run check:bundle |
Gate de transferência inicial e chunks diferidos |
npm run test:e2e:install |
Instala Chromium, Firefox e WebKit |
npm run test:e2e |
Playwright em todos os projetos configurados |
npm run analyze |
Analyzer oficial do Turbopack |
npm run start |
Executa .next/standalone/server.js |
As validações de ambiente não dependem de um comando manual separado: os gates reais são executados pelo next build para variáveis públicas e pelo bootstrap Node.js ao iniciar em produção.
Instale os browsers uma vez:
npm run test:e2e:installEm uma instalação Linux mínima, instale também as bibliotecas do sistema com npx playwright install --with-deps chromium firefox webkit. A CI já usa essa variante.
Depois execute, nesta ordem:
npm test
npm run lint
npm run typecheck
npm run build
npm run check:bundle
npm run test:e2eO Playwright inicia o standalone em http://localhost:3100 por padrão, portanto o build é pré-requisito. O projeto principal faz a regressão detalhada em Chromium; há um cenário dedicado sem WebGL e smokes adicionais em Firefox e WebKit. Falhas preservam trace, screenshot e vídeo conforme a configuração.
Para testar uma instância já iniciada:
PLAYWRIGHT_TEST_BASE_URL=http://localhost:3000 npm run test:e2eUse essa opção apenas contra um ambiente descartável ou autorizado: os testes exercitam rotas, navegação e a API de contato.
npm run check:bundle mede HTML, JS e CSS com gzip nível 9; WOFF2 é medido pelo tamanho bruto, pois já é comprimido. Preloads de fonte e inventário alcançável pelo CSS são gates separados.
| Superfície | Limite padrão |
|---|---|
| Home JS | 260 KiB |
| Artigo JS | 250 KiB |
| Home CSS / artigo CSS | 25 KiB cada |
| Home HTML | 60 KiB |
| Artigo HTML | 35 KiB |
| Fontes preloadadas da home / artigo | 120 KiB cada |
| Inventário WOFF2 da home / artigo | 210 KiB cada |
| Cada entry lazy | 100 KiB |
| Maior chunk diferido | 90 KiB |
| Total diferido único | 165 KiB |
Os nomes das variáveis de override e o fallback que captura pelo standalone qualquer rota medida sem HTML pré-renderizado estão detalhados no contexto técnico. Manifestos vazios, rotas sem assets iniciais e ausência de chunks diferidos são tratados como erro.
O analyzer grava uma interface estática em .next/diagnostics/analyze:
npm run analyzeO build copia public quando existente e .next/static para o artefato standalone. Injete um ambiente de produção válido antes de iniciar:
set -a
. ./.env.production
set +a
npm run build
npm run start.env.production é ignorado pelo Git. Use valores reais para validar o formulário; fixtures apenas sintaticamente válidas servem para smoke de páginas, mas não para entrega de email.
Ao carregar o arquivo com o shell, mantenha-o compatível com POSIX e coloque entre aspas valores que contenham espaços. O Compose também aceita esses valores entre aspas.
Crie um .env.production exclusivo para o ambiente. Não copie .env.example: seus valores sensíveis são deliberadamente inválidos em produção.
docker compose --env-file .env.production config --quiet
docker compose --env-file .env.production up --build --detach
docker compose --env-file .env.production ps
curl --fail http://127.0.0.1:3000/robots.txtA porta é publicada somente em loopback por padrão. Um proxy reverso deve terminar HTTPS e encaminhar o tráfego público. Se PORT for alterada no arquivo de ambiente, ajuste o URL do smoke.
Para acompanhar logs e encerrar:
docker compose --env-file .env.production logs --follow portfolio
docker compose --env-file .env.production down --remove-orphansO runner usa Node.js 24.18.0 em uma imagem distroless Debian 13, sem shell, package manager ou toolchain. Ele executa como UID/GID 65532:65532; o Compose remove capabilities, proíbe privilege escalation, aplica limites de processo/CPU/memória e disponibiliza somente dois tmpfs graváveis.
- A CSP e os headers defensivos são centralizados em
next.config.ts. - A API não retorna segredos nem inclui dados pessoais nos logs de erro.
- Instalações bloqueiam lifecycle scripts e a CI verifica assinaturas e vulnerabilidades.
- Actions e imagens-base são fixadas por commit ou digest; o Trivy rejeita vulnerabilidades High e Critical da imagem final.
- A política estática ainda usa
unsafe-inlinepara scripts e estilos exigidos pelo bootstrap atual do App Router. Migrar para nonce por request tornaria as superfícies hoje estáticas dinâmicas; a decisão deve ser reavaliada se surgir autenticação ou requisito formal de compliance. - O rate limiter é local ao processo e reinicia com a instância. Múltiplas réplicas exigem Redis/Upstash, WAF ou mecanismo distribuído equivalente.
- Com
CONTACT_TRUST_PROXY=false, nenhum header de IP é confiado e os clientes compartilham o bucket por cliente. Isso é seguro contra spoofing, mas pode gerar contenção sob tráfego real.
Veja o modelo de segurança completo, inclusive a ordem dos controles da API e os gaps operacionais conhecidos.
src/
├── app/ rotas, layouts, metadata, imagens sociais e API
├── components/ layout, seções, componentes compartilhados e artigo
├── content/ modelos editoriais localizados
├── data/ projetos, sites publicados, experiência, métricas e links
├── hooks/ observação de viewport e navegação
├── lib/ constantes, validações, WebGL e gates de produção
├── messages/ catálogos pt, en e es
└── types/ contratos compartilhados
e2e/ regressão Playwright
scripts/ bundle gate, standalone e quality hook
docs/ contexto técnico versionado
public/images/sites/ thumbnails locais dos sites publicados
docs/portifolio/ permanece intencionalmente ignorado e não faz parte da documentação versionada.
Casos, métricas e experiências publicados devem ser verificáveis e autorizados. Logos, screenshots, depoimentos e informações confidenciais de terceiros não devem entrar no portfólio sem aprovação explícita.
Ao alterar conteúdo localizado, arquitetura, ambiente, budgets ou comandos, atualize o README e docs/TECHNICAL_CONTEXT.md no mesmo conjunto de mudanças.