wip: foto da pasta principal antes de trocar de branch
CI / verify (push) Failing after 5m29s

Estado do disco em 14/10/2026, sem filtrar. Inclui as copias .sync-conflict-* do Syncthing de 07/10 e os 15 arquivos que o Syncthing apagou; todo esse conteudo ja existia em outros commits. So havia fora do Git: AGENTS.md, CLAUDE.md e a alteracao em data/project-health.json.
This commit is contained in:
Evandro Fonseca Junior committed 2026-10-14 00:42:49 -03:00
1 parent b2f3899dc2
commit dfcadc71fa
77 files changed
+6944 -2419

No files matched your search

-16
View File
@@ -1,10 +1,3 @@
import { readFileSync } from "node:fs";
import { join } from "node:path";
const brandMark = `data:image/png;base64,${readFileSync(
join(process.cwd(), "public/brand/mark-dark.png"),
).toString("base64")}`;
export const OG_SIZE = { width: 1200, height: 630 } as const;
export const OG_CONTENT_TYPE = "image/png";
@@ -23,7 +16,6 @@ export function OgCard({
width: "100%",
height: "100%",
display: "flex",
position: "relative",
flexDirection: "column",
justifyContent: "space-between",
background: "#050505",
@@ -32,17 +24,9 @@ export function OgCard({
fontFamily: "Arial, sans-serif",
}}
>
<img
src={brandMark}
alt="Evandro.dev.br"
width={80}
height={80}
style={{ position: "absolute", top: 48, right: 72 }}
/>
<div
style={{
display: "flex",
paddingRight: 112,
color: "#ccff00",
fontSize: 24,
letterSpacing: "0.16em",
-21
View File
@@ -86,27 +86,6 @@ describe("factual portfolio records", () => {
/produç|clientes?|leads?|ranking|performance|resultado comercial|anime\.js|shadcn/i,
);
});
it("keeps Reddit Posts Explorer and MinGW GCC Installer within what their public repositories support", () => {
const reddit = serializeProject("reddit-explorer");
const gcc = serializeProject("gcc-installer");
expect(reddit).toContain("MongoDB");
expect(reddit).not.toMatch(
/SSG|rate limit|cache|tempo real|real-time|busca em|otimiza|responsiv/i,
);
expect(gcc).toContain("mingw64");
expect(gcc).not.toMatch(
/assíncron|monitoramento|drastic|Watchdog|dependências|intuitiv/i,
);
});
it("does not claim measured performance for SC Plus without a stored measurement", () => {
// Lighthouse mobile local: LCP 3,7 s em 2026-10-05; a alegação anterior (LCP < 2,5 s) não se sustentava
expect(serializeProject("sc-plus")).not.toMatch(
/LCP|Core Web Vitals|otimizad|velocidade|rápid|Performance/i,
);
});
it("does not publish the unavailable Twins Lab demo", () => {
expect(
portfolio.projects.find((item) => item.id === "twins-lab")?.demoUrl,
+1 -12
View File
@@ -37,17 +37,7 @@ it("keeps the root graph limited to verified website and person fields", () => {
["@id", "@type", "inLanguage", "name", "publisher", "url"].sort(),
);
expect(Object.keys(person).sort()).toEqual(
[
"@id",
"@type",
"homeLocation",
"image",
"jobTitle",
"knowsAbout",
"name",
"sameAs",
"url",
].sort(),
["@id", "@type", "homeLocation", "image", "name", "sameAs", "url"].sort(),
);
expect(website).toMatchObject({
"@type": "WebSite",
@@ -59,7 +49,6 @@ it("keeps the root graph limited to verified website and person fields", () => {
"@type": "Person",
"@id": SEO_IDS.person,
image: `${siteUrl}/edev.jpg`,
jobTitle: "Engenheiro da Computação e Desenvolvedor de Software",
homeLocation: { "@type": "Place", name: "Garuva, Santa Catarina, Brasil" },
sameAs: [
"https://github.com/evandrodevbr",
-12
View File
@@ -24,18 +24,6 @@ export function buildPersonJsonLd() {
name: "Evandro Fonseca Junior",
url: siteUrl,
image: `${siteUrl}/edev.jpg`,
// cargo e áreas vêm de public/portfolio-data.json e estão visíveis em /curriculo e na seção de skills
jobTitle: "Engenheiro da Computação e Desenvolvedor de Software",
knowsAbout: [
"Next.js",
"React",
"TypeScript",
"Node.js",
"Python",
"IoT",
"Computação em nuvem",
"Inteligência artificial",
],
homeLocation: {
"@type": "Place",
name: "Garuva, Santa Catarina, Brasil",
+2 -28
View File
@@ -1,12 +1,6 @@
import { caseStudies, getRelatedServices, servicePages } from "./site-content";
const detailedIds = [
"as-servicos",
"gcc-installer",
"nutriscan",
"reddit-explorer",
"twins-lab",
] as const;
const detailedIds = ["as-servicos", "nutriscan", "twins-lab"] as const;
const immutableGitHubBlobUrl =
/^https:\/\/github\.com\/[^/]+\/[^/]+\/blob\/[0-9a-f]{40}\/.+$/;
@@ -17,7 +11,7 @@ function getDetail(id: (typeof detailedIds)[number]) {
return detail;
}
it("limits detailed content to the evidenced cases (public repositories pinned to a commit)", () => {
it("limits detailed content to the three evidenced cases", () => {
expect(
caseStudies
.filter(({ detail }) => detail !== undefined)
@@ -70,15 +64,6 @@ it("requires sources for factual statements and resolves every source ID", () =>
expect(getDetail("nutriscan").boundaries[0]?.sourceIds).toContain(
"nutri-readme",
);
// reddit-explorer e gcc-installer: o 1º limite vem da documentação do repositório; o 2º é o escopo editorial (sem fonte)
for (const id of ["reddit-explorer", "gcc-installer"] as const) {
const { boundaries } = getDetail(id);
expect(boundaries[0]?.sourceIds.length).toBeGreaterThan(0);
expect(
boundaries.slice(1).every(({ sourceIds }) => sourceIds.length === 0),
).toBe(true);
}
});
it("derives the exact related service set from the existing relationship", () => {
@@ -111,14 +96,3 @@ it("does not publish the unavailable Twins Lab demo", () => {
caseStudies.find((item) => item.id === "twins-lab")?.demoUrl,
).toBeUndefined();
});
it("keeps AS Serviços as a project (code only) and states the author's participation", () => {
const asServicos = caseStudies.find(({ id }) => id === "as-servicos");
expect(asServicos?.demoUrl).toBeNull();
expect(asServicos?.githubUrl).toBe(
"https://github.com/evandrodevbr/as-servicos",
);
expect(asServicos?.role).toMatch(/primeira landing page/i);
expect(asServicos?.role).toMatch(/animações 3D/i);
expect(asServicos?.role).toMatch(/painel para controle de projetos/i);
});
+22 -136
View File
@@ -2,13 +2,13 @@ export const siteUrl = "https://evandro.dev.br";
export const siteName = "Evandro.dev.br";
export const intentCtas = {
project: {
label: "Conversar sobre meu projeto",
href: "/#contact",
hiring: {
label: "Avaliar perfil para contratação",
href: "/curriculo",
},
consulting: {
label: "Conhecer as soluções",
href: "/servicos",
label: "Solicitar consultoria técnica",
href: "/#contact",
},
} as const;
@@ -75,8 +75,6 @@ export interface CaseStudyContent {
stack: string[];
demoUrl?: string | null;
githubUrl?: string | null;
/** Papel do autor quando o projeto não é só dele (texto editorial, sem fonte pública). */
role?: string;
detail?: CaseStudyDetail;
}
@@ -146,7 +144,7 @@ export const servicePages: ServicePageContent[] = [
slug: "engenharia-de-software",
navLabel: "Sistemas web e aplicativos mobile",
eyebrow: "Engenharia de software",
seoTitle: "Sistemas Web e Aplicativos Mobile sob Medida",
seoTitle: "Desenvolvimento de Sistemas Web e Aplicativos Mobile",
metaDescription:
"Sistemas web e aplicativos mobile sob medida, integração entre ferramentas e evolução de software existente. Escopo, plataformas e entregas definidos por projeto.",
headline: "Sistemas e apps para o seu trabalho.",
@@ -268,7 +266,7 @@ export const servicePages: ServicePageContent[] = [
slug: "tauri-rust",
navLabel: "Aplicativos desktop para Windows e Linux",
eyebrow: "Aplicativos desktop",
seoTitle: "Aplicativos Desktop com Tauri e Rust",
seoTitle: "Aplicativos Desktop para Windows e Linux com Tauri e Rust",
metaDescription:
"Desenvolvimento de aplicativos desktop para Windows e Linux com Tauri e Rust. Ferramentas locais, arquivos e integrações com compatibilidade definida por projeto.",
headline: "Aplicativos para Windows e Linux.",
@@ -620,83 +618,22 @@ export const caseStudies: CaseStudyContent[] = [
{
id: "reddit-explorer",
title: "Reddit Posts Explorer",
subtitle: "Posts do r/artificial em MongoDB, filtrados por período",
subtitle: "Aplicação orientada a dados com API, cache e busca",
summary:
"Aplicação Astro SSR que coleta os posts em alta do r/artificial, grava no MongoDB sem duplicar e filtra por período, upvotes ou comentários.",
"Projeto em Astro e MongoDB para explorar conteúdo com filtros, ordenação e cache, mantendo boa experiência em consultas frequentes.",
impact:
"Atualizar a coleta sem duplicar posts e consultar o histórico por intervalo de datas e ordenação.",
stack: ["Astro", "MongoDB", "Mongoose", "TypeScript", "Reddit API"],
"Mostra capacidade de desenhar consumo de API, camada de persistência e experiência de busca sem sobrecarregar a aplicação.",
stack: ["Astro.js", "MongoDB", "Mongoose", "TypeScript", "Reddit API"],
githubUrl: "https://github.com/evandrodevbr/reddit-search",
detail: {
answer: {
text: "Aplicação Astro em modo SSR que coleta os posts em alta do r/artificial pela API pública do Reddit, grava no MongoDB com upsert por id e permite filtrar por período e ordenar por upvotes ou comentários.",
sourceIds: ["rd-readme", "rd-service", "rd-astro"],
},
challenge: {
text: "Atualizar a coleta sem duplicar posts e consultar o histórico por intervalo de datas e ordenação.",
sourceIds: ["rd-service", "rd-filter"],
},
implementation: [
{
text: "O serviço consulta r/artificial/hot.json com User-Agent identificado e limite de 15 segundos, e grava os posts em lote com upsert pelo id; rodar a coleta de novo atualiza os existentes.",
sourceIds: ["rd-service"],
},
{
text: "O endpoint de filtro valida as datas e o campo de ordenação (ups ou num_comments) e responde 400 quando faltam parâmetros ou eles são inválidos.",
sourceIds: ["rd-filter"],
},
{
text: "O Astro roda com output server e o adapter Node em modo standalone.",
sourceIds: ["rd-astro", "rd-package"],
},
],
boundaries: [
{
text: "O subreddit é fixo, e o projeto não tem paginação, busca textual, autenticação, testes automatizados nem CI.",
sourceIds: ["rd-readme"],
},
{
text: "O case demonstra implementação e decisões técnicas; não atribui ganho de performance, volume de dados ou resultado comercial.",
sourceIds: [],
},
],
sources: [
{
id: "rd-readme",
label: "README do projeto",
url: "https://github.com/evandrodevbr/reddit-search/blob/ff76e08379a51fc02c3b8e4d6c415d627d8c90de/README.md",
},
{
id: "rd-service",
label: "Serviço de coleta e consulta",
url: "https://github.com/evandrodevbr/reddit-search/blob/ff76e08379a51fc02c3b8e4d6c415d627d8c90de/src/lib/services/redditService.ts",
},
{
id: "rd-filter",
label: "Endpoint de filtro",
url: "https://github.com/evandrodevbr/reddit-search/blob/ff76e08379a51fc02c3b8e4d6c415d627d8c90de/src/pages/api/posts/filter.ts",
},
{
id: "rd-astro",
label: "Configuração do Astro",
url: "https://github.com/evandrodevbr/reddit-search/blob/ff76e08379a51fc02c3b8e4d6c415d627d8c90de/astro.config.mjs",
},
{
id: "rd-package",
label: "Manifesto do projeto",
url: "https://github.com/evandrodevbr/reddit-search/blob/ff76e08379a51fc02c3b8e4d6c415d627d8c90de/package.json",
},
],
},
},
{
id: "sc-plus",
title: "SC Plus Aquicultura",
subtitle: "Landing page institucional em Next.js 15",
subtitle: "Site institucional em Next.js com foco em performance e SEO",
summary:
"Landing page institucional em Next.js 15, React 19 e Tailwind CSS 4, com metadados e dados estruturados para indexação.",
"Landing page em Next.js 15 otimizada para Core Web Vitals, metadata e estrutura técnica de indexação.",
impact:
"Dar à instituição uma página própria, com base técnica para ser encontrada em buscadores.",
"Exemplo de projeto em que clareza de mensagem, velocidade e SEO técnico trabalham juntos.",
stack: ["Next.js 15", "React 19", "Tailwind CSS 4", "TypeScript"],
demoUrl: "https://scplus.evandro.dev.br",
githubUrl: "https://github.com/evandrodevbr/scplus",
@@ -704,80 +641,29 @@ export const caseStudies: CaseStudyContent[] = [
{
id: "gcc-installer",
title: "MinGW GCC Installer",
subtitle: "Instalador gráfico de MinGW-w64/GCC para Windows",
subtitle:
"Ferramenta desktop para automação de ambiente de desenvolvimento",
summary:
"Aplicativo Python com interface tkinter que lista as builds do MinGW-w64, baixa a escolhida, instala em C:\\mingw64 e adiciona o GCC ao PATH do usuário.",
"Aplicação em Python para simplificar setup local no Windows, com download assíncrono, checagem de compatibilidade e integração com PATH.",
impact:
"Reduzir a configuração manual do GCC no Windows (escolher a build, baixar, extrair e ajustar o PATH) a uma única janela.",
stack: ["Python", "Tkinter", "Win32 API", "GitHub API", "7-Zip"],
"Mostra familiaridade com software desktop, integração com sistema operacional e automação de setup técnico.",
stack: ["Python", "Tkinter", "Win32 API", "Threading", "7-Zip"],
githubUrl: "https://github.com/evandrodevbr/gcc-installer",
detail: {
answer: {
text: "Aplicativo Python com interface tkinter que lê as builds publicadas do MinGW-w64, baixa o pacote .7z escolhido, instala em C:\\mingw64 e adiciona o toolchain ao PATH do usuário no registro do Windows.",
sourceIds: ["gcc-readme", "gcc-main"],
},
challenge: {
text: "Reduzir a configuração manual do GCC no Windows (escolher a build, baixar, extrair e ajustar o PATH) a uma única janela.",
sourceIds: ["gcc-readme"],
},
implementation: [
{
text: "A lista de versões vem da API de releases do repositório niXman/mingw-builds-binaries, e as builds com ucrt e thread model posix são destacadas na tabela.",
sourceIds: ["gcc-main"],
},
{
text: "A instalação extrai o pacote com o 7-Zip (caminho padrão fixo) em uma pasta temporária, move o resultado para C:\\mingw64 e renomeia mingw32-make.exe para make.exe.",
sourceIds: ["gcc-main"],
},
{
text: "Adicionar ao PATH grava em HKCU\\Environment e avisa o Windows com WM_SETTINGCHANGE; fora do Windows o programa encerra com um aviso.",
sourceIds: ["gcc-main"],
},
],
boundaries: [
{
text: "Funciona só no Windows, o caminho do 7-Zip é fixo e o fluxo da interface não foi exercitado de ponta a ponta no Windows nesta revisão; os 23 testes cobrem a lógica independente de plataforma, e não há CI.",
sourceIds: ["gcc-readme", "gcc-tests"],
},
{
text: "O case demonstra implementação e decisões técnicas; não atribui ganho de performance, número de usuários ou resultado comercial.",
sourceIds: [],
},
],
sources: [
{
id: "gcc-readme",
label: "README do projeto",
url: "https://github.com/evandrodevbr/gcc-installer/blob/bab64fc5b5c20128e7b06e1afc448c5efe71b747/README.md",
},
{
id: "gcc-main",
label: "Aplicativo (main.py)",
url: "https://github.com/evandrodevbr/gcc-installer/blob/bab64fc5b5c20128e7b06e1afc448c5efe71b747/main.py",
},
{
id: "gcc-tests",
label: "Testes do núcleo",
url: "https://github.com/evandrodevbr/gcc-installer/blob/bab64fc5b5c20128e7b06e1afc448c5efe71b747/tests/test_core.py",
},
],
},
},
{
id: "as-servicos",
title: "AS Serviços",
subtitle: "Site institucional com cena 3D procedural",
summary:
"Site institucional em Next.js 16 com cena Three.js gerada em código: uma casa wireframe e uma placa-mãe ligadas ao progresso da rolagem.",
"Site institucional em Next.js 16 que representa quatro frentes de engenharia com uma cena Three.js gerada em código: uma casa wireframe e uma placa-mãe ligadas ao progresso da rolagem.",
impact:
"Representar engenharia física e software na mesma narrativa visual sem depender de um modelo 3D pronto.",
stack: ["Next.js 16", "Three.js", "TypeScript"],
demoUrl: null,
demoUrl: "https://asservicos.com",
githubUrl: "https://github.com/evandrodevbr/as-servicos",
role: "Desenvolvimento da primeira landing page do site, com animações 3D, e de um painel para controle de projetos.",
detail: {
answer: {
text: "Site institucional em Next.js 16 com cena Three.js gerada em código: uma casa wireframe e uma placa-mãe ligadas ao progresso da rolagem.",
text: "Site institucional em Next.js 16 que representa quatro frentes de engenharia com uma cena Three.js gerada em código: uma casa wireframe e uma placa-mãe ligadas ao progresso da rolagem.",
sourceIds: ["as-readme", "as-package", "as-engine"],
},
challenge: {
+5 -4
View File
@@ -2,9 +2,10 @@ export const CV_URL = "/Profile.pdf";
export const CV_DOWNLOAD_NAME = "Evandro_Fonseca_Junior_CV.pdf";
export const NAVIGATION_ITEMS = [
{ href: "/#modalities", label: "Soluções" },
{ href: "/cases", label: "Projetos" },
{ href: "/#process", label: "Como trabalho" },
{ href: "/#home", label: "Home" },
{ href: "/cases", label: "Casos" },
{ href: "/servicos", label: "Serviços" },
{ href: "/curriculo", label: "Currículo" },
{ href: "/#about", label: "Sobre" },
{ href: "/#experience", label: "Experiência" },
{ href: "/#contact", label: "Contato" },
] as const;