feat(home): prova no topo, contato sem atrito e conversão medida
Home mais curta (hero, vitrine de clientes, sobre, serviços, IA resumida, depoimentos e contato), faixa de clientes e telas reais no hero, sem números do GitHub. Barra de cookies fina, WhatsApp fixo no celular, formulário com e-mail opcional e alternativa por e-mail, página /ia, eventos de e-mail, redes e currículo e conversão do Ads opcional por variável. Rodapé em 3 colunas. Remove componentes órfãos (LighthouseMetrics, Skills, Experience, contagem do GitHub).
This commit is contained in:
1 parent
6e1022b58c
commit
8d07b8c6bb
60 files changed
+4392
-2124
No files matched your search
@@ -0,0 +1,17 @@
|
||||
import { ImageResponse } from "next/og";
|
||||
import { OG_CONTENT_TYPE, OG_SIZE, OgCard } from "@/lib/og-card";
|
||||
|
||||
export const alt = "Começou um sistema com IA? Revisão e continuidade";
|
||||
export const size = OG_SIZE;
|
||||
export const contentType = OG_CONTENT_TYPE;
|
||||
|
||||
export default function Image() {
|
||||
return new ImageResponse(
|
||||
<OgCard
|
||||
eyebrow="IA no desenvolvimento"
|
||||
title="Começou um sistema com IA? Dá para partir daí."
|
||||
description="Revisão do que foi gerado, correção dos riscos e continuidade até a produção."
|
||||
/>,
|
||||
OG_SIZE,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import { render, screen, within } from "@testing-library/react";
|
||||
import AiPage, { metadata } from "./page";
|
||||
|
||||
it("uses its own title without the site suffix being added twice", () => {
|
||||
expect(metadata.title).toEqual({
|
||||
absolute:
|
||||
"Começou um sistema com IA? Revisão e continuidade | Evandro Fonseca Junior",
|
||||
});
|
||||
expect(metadata).toMatchObject({
|
||||
description: expect.any(String),
|
||||
alternates: { canonical: "https://evandro.dev.br/ia" },
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps the full AI content, with the cited incidents summarized only here", () => {
|
||||
render(<AiPage />);
|
||||
|
||||
expect(screen.getByRole("heading", { level: 1 })).toHaveTextContent(
|
||||
"Começou um sistema com IA? Dá para partir daí.",
|
||||
);
|
||||
for (const heading of [
|
||||
"Se a IA cria um sistema, por que contratar um desenvolvedor?",
|
||||
"O que casos documentados ensinam",
|
||||
"E a LGPD?",
|
||||
]) {
|
||||
expect(screen.getByRole("heading", { name: heading })).toBeInTheDocument();
|
||||
}
|
||||
for (const incident of [/Lovable/, /Replit/, /Base44/]) {
|
||||
expect(screen.getByRole("heading", { name: incident })).toBeInTheDocument();
|
||||
}
|
||||
expect(
|
||||
screen.getByRole("link", { name: "Reportagem da Semafor (em inglês)" }),
|
||||
).toHaveAttribute("rel", "noopener noreferrer");
|
||||
});
|
||||
|
||||
it("offers WhatsApp conversations about reviewing an AI-built system", () => {
|
||||
render(<AiPage />);
|
||||
|
||||
const links = screen
|
||||
.getAllByRole("link")
|
||||
.filter((link) => link.getAttribute("href")?.startsWith("https://wa.me/"));
|
||||
expect(links.map((link) => link.textContent)).toEqual([
|
||||
"Falar sobre meu sistema",
|
||||
"Avaliar meu projeto",
|
||||
]);
|
||||
for (const link of links) {
|
||||
const text = new URL(link.getAttribute("href") ?? "").searchParams.get(
|
||||
"text",
|
||||
);
|
||||
// a mensagem tem de formar uma frase: "Quero conversar sobre a revisão de um sistema feito com IA."
|
||||
expect(text).toContain(
|
||||
"Quero conversar sobre a revisão de um sistema feito com IA.",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("has breadcrumb navigation back to the home", () => {
|
||||
render(<AiPage />);
|
||||
|
||||
const breadcrumb = screen.getByRole("navigation", { name: "Breadcrumb" });
|
||||
expect(
|
||||
within(breadcrumb).getByRole("link", { name: "Início" }),
|
||||
).toHaveAttribute("href", "/");
|
||||
expect(within(breadcrumb).getByText("IA no desenvolvimento")).toHaveAttribute(
|
||||
"aria-current",
|
||||
"page",
|
||||
);
|
||||
});
|
||||
+269
@@ -0,0 +1,269 @@
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { Breadcrumb } from "@/app/components/Breadcrumb";
|
||||
import {
|
||||
pageTop,
|
||||
primaryButton,
|
||||
textLinkDark,
|
||||
} from "@/app/components/button-styles";
|
||||
import WhatsAppLink from "@/app/components/WhatsAppLink";
|
||||
import { safeJsonLd } from "@/lib/jsonld";
|
||||
import { buildBreadcrumbList, buildPageSocialMetadata } from "@/lib/seo";
|
||||
import { siteUrl } from "@/lib/site-content";
|
||||
|
||||
const pageUrl = `${siteUrl}/ia`;
|
||||
const pageTitle =
|
||||
"Começou um sistema com IA? Revisão e continuidade | Evandro Fonseca Junior";
|
||||
const pageDescription =
|
||||
"Protótipo ou sistema criado com IA? Avalio o que pode ser aproveitado, corrijo permissões, dados e publicação e levo o projeto até a produção.";
|
||||
/** Entra na frase "Quero conversar sobre {assunto}." da mensagem do WhatsApp. */
|
||||
const WHATSAPP_SERVICE = "a revisão de um sistema feito com IA";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: { absolute: pageTitle },
|
||||
description: pageDescription,
|
||||
...buildPageSocialMetadata({
|
||||
url: pageUrl,
|
||||
title: pageTitle,
|
||||
description: pageDescription,
|
||||
type: "website",
|
||||
}),
|
||||
};
|
||||
|
||||
const RESPONSIBILITIES = [
|
||||
{
|
||||
title: "Quem pode acessar cada dado?",
|
||||
description:
|
||||
"Login não basta. Permissões precisam ser verificadas no servidor e testadas entre usuários, empresas e perfis diferentes.",
|
||||
},
|
||||
{
|
||||
title: "Como recuperar a operação?",
|
||||
description:
|
||||
"Ambientes separados, acesso restrito à produção e backups com restauração testada reduzem o impacto de uma alteração errada.",
|
||||
},
|
||||
{
|
||||
title: "Quem valida antes de publicar?",
|
||||
description:
|
||||
"Código gerado também passa por revisão, testes e avaliação de dependências. O escopo inclui manutenção, custos e riscos de operação.",
|
||||
},
|
||||
];
|
||||
|
||||
/** Três episódios de 2025, resumidos. Cada um traz o que foi relatado, o que não foi provado e o cuidado técnico. */
|
||||
const INCIDENTS = [
|
||||
{
|
||||
title: "Lovable: dados expostos em aplicações criadas na plataforma",
|
||||
summary:
|
||||
"Em maio de 2025, a Semafor noticiou uma análise que encontrou 170 de 1.645 aplicações com acesso indevido a informações, incluindo dados de usuários e chaves de API, ligado à configuração de acesso dos bancos conectados. O fornecedor contesta que a falha seja da plataforma e lembra que os clientes respondem por seus dados. O relato não comprova roubo em todas essas aplicações.",
|
||||
care: "testar se uma pessoa consegue ler ou alterar dados de outra, em vez de tratar a tela de login como prova de segurança.",
|
||||
links: [
|
||||
{
|
||||
href: "https://www.semafor.com/article/05/29/2025/the-hottest-new-vibe-coding-startup-lovable-is-a-sitting-duck-for-hackers",
|
||||
label: "Reportagem da Semafor (em inglês)",
|
||||
},
|
||||
{
|
||||
href: "https://nvd.nist.gov/vuln/detail/CVE-2025-48757",
|
||||
label: "Registro e contestação no NVD",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Replit: um agente apagou dados de uma aplicação",
|
||||
summary:
|
||||
"Em julho de 2025, o cofundador da SaaStr relatou que um agente apagou dados durante a construção de uma aplicação, e as alterações de desenvolvimento podiam afetar a produção. A Replit reconheceu o episódio, informou que o banco foi recuperado por rollback e anunciou a separação entre bancos de desenvolvimento e produção por padrão. Houve exclusão e recuperação, não roubo de informações.",
|
||||
care: "limitar permissões de agentes, separar ambientes e testar a recuperação antes de depender dela.",
|
||||
links: [
|
||||
{
|
||||
href: "https://replit.com/blog/doubling-down-on-our-commitment-to-secure-vibe-coding",
|
||||
label: "Relato e medidas da Replit (29/07/2025)",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Base44: aplicações privadas com falha de acesso",
|
||||
summary:
|
||||
"Em julho de 2025, pesquisadores da Wiz demonstraram uma falha que permitia acesso não autorizado a aplicações privadas do Base44. Ela estava na camada compartilhada de autenticação da plataforma, não em erro de um usuário iniciante. A Wix corrigiu em menos de 24 horas e informou não ter encontrado exploração maliciosa.",
|
||||
care: "avaliar também o fornecedor e as permissões efetivas das integrações, além do código da aplicação.",
|
||||
links: [
|
||||
{
|
||||
href: "https://www.wiz.io/blog/critical-vulnerability-base44",
|
||||
label: "Pesquisa da Wiz e resposta da Wix (29/07/2025)",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default function AiPage() {
|
||||
const jsonLd = {
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
buildBreadcrumbList(pageUrl, [
|
||||
["Início", siteUrl],
|
||||
["IA no desenvolvimento", pageUrl],
|
||||
] as const),
|
||||
],
|
||||
};
|
||||
|
||||
return (
|
||||
<main>
|
||||
<script type="application/ld+json">{safeJsonLd(jsonLd)}</script>
|
||||
|
||||
<section className={`ds-section ds-section-dark ${pageTop}`}>
|
||||
<div className="ds-section-shell">
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ label: "Início", href: "/" },
|
||||
{ label: "IA no desenvolvimento", href: "/ia" },
|
||||
]}
|
||||
/>
|
||||
<p className="ds-eyebrow">IA no desenvolvimento</p>
|
||||
<h1 className="ds-section-title max-w-[22ch] text-balance">
|
||||
Começou um sistema com IA? Dá para partir daí.
|
||||
</h1>
|
||||
<p className="ds-copy max-w-[62ch]">
|
||||
A IA permite testar ideias e construir protótipos mesmo sem
|
||||
experiência em programação. Quando o sistema passa a cuidar de
|
||||
clientes, dinheiro ou dados pessoais, alguém precisa avaliar o que
|
||||
foi gerado e validar como ele se comporta fora da demonstração.
|
||||
</p>
|
||||
<div className="mt-sp-6 flex flex-wrap items-center gap-x-sp-6 gap-y-sp-3">
|
||||
<WhatsAppLink
|
||||
className={primaryButton}
|
||||
service={WHATSAPP_SERVICE}
|
||||
placement="ia_hero"
|
||||
>
|
||||
Falar sobre meu sistema
|
||||
</WhatsAppLink>
|
||||
<Link href="/cases" className={textLinkDark}>
|
||||
Ver projetos entregues
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="ds-section" aria-labelledby="ia-contratar-title">
|
||||
<div className="ds-section-shell">
|
||||
<h2 id="ia-contratar-title" className="ds-section-title max-w-[26ch]">
|
||||
Se a IA cria um sistema, por que contratar um desenvolvedor?
|
||||
</h2>
|
||||
<div className="mt-sp-6 border-l-2 border-[var(--slash)] pl-sp-5">
|
||||
<p className="max-w-[75ch] text-lg leading-8 text-[var(--ink)]">
|
||||
Você contrata engenharia para transformar as regras do seu negócio
|
||||
em um sistema que possa ser testado, operado e mantido. A IA pode
|
||||
fazer parte desse trabalho. Ela não dispensa decisões sobre
|
||||
arquitetura, segurança e responsabilidade pelos dados.
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-sp-8 grid gap-sp-6 md:grid-cols-3">
|
||||
{RESPONSIBILITIES.map((item) => (
|
||||
<article
|
||||
key={item.title}
|
||||
className="border-t border-[var(--border)] pt-sp-5"
|
||||
>
|
||||
<h3 className="text-lg font-semibold leading-snug">
|
||||
{item.title}
|
||||
</h3>
|
||||
<p className="ds-copy">{item.description}</p>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="ds-section" aria-labelledby="ia-casos-title">
|
||||
<div className="ds-section-shell">
|
||||
<h2 id="ia-casos-title" className="ds-section-title max-w-[26ch]">
|
||||
O que casos documentados ensinam
|
||||
</h2>
|
||||
<p className="ds-copy max-w-[75ch]">
|
||||
São episódios de 2025, não avaliações atuais das plataformas. Eles
|
||||
mostram riscos de configuração, permissões e operação; não provam
|
||||
que todo sistema feito com IA seja inseguro ou que um profissional
|
||||
elimine qualquer risco.
|
||||
</p>
|
||||
<div className="mt-sp-6 grid gap-sp-6 lg:grid-cols-3">
|
||||
{INCIDENTS.map((incident) => (
|
||||
<article key={incident.title} className="ds-card">
|
||||
<h3 className="ds-card-title !mt-0">{incident.title}</h3>
|
||||
<p className="ds-copy">{incident.summary}</p>
|
||||
<p className="ds-copy">
|
||||
<strong>O cuidado técnico:</strong> {incident.care}
|
||||
</p>
|
||||
<ul className="mt-sp-4 flex flex-col gap-sp-1">
|
||||
{incident.links.map((link) => (
|
||||
<li key={link.href}>
|
||||
<a
|
||||
className="inline-flex min-h-11 items-center text-sm underline underline-offset-4"
|
||||
href={link.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="ds-section" aria-labelledby="ia-lgpd-title">
|
||||
<div className="ds-section-shell grid gap-sp-6 lg:grid-cols-2">
|
||||
<article className="ds-card">
|
||||
<h2 id="ia-lgpd-title" className="ds-card-title !mt-0">
|
||||
E a LGPD?
|
||||
</h2>
|
||||
<p className="ds-copy">
|
||||
Usar IA não afasta as obrigações de proteção de dados. A ANPD
|
||||
exige medidas técnicas e administrativas também de agentes de
|
||||
pequeno porte e esclarece que as flexibilizações não os isentam
|
||||
das demais obrigações da LGPD, como bases legais e direitos dos
|
||||
titulares.
|
||||
</p>
|
||||
<p className="ds-copy">
|
||||
O trabalho técnico inclui controles de acesso, coleta limitada ao
|
||||
necessário e rotinas de retenção e exclusão. Conformidade depende
|
||||
também dos processos da empresa e de orientação jurídica;
|
||||
contratar desenvolvimento não equivale a uma certificação de
|
||||
adequação.
|
||||
</p>
|
||||
<a
|
||||
className="mt-sp-4 inline-flex min-h-11 items-center text-sm underline underline-offset-4"
|
||||
href="https://www.gov.br/anpd/pt-br/acesso-a-informacao/institucional/atos-normativos/regulamentacoes_anpd/resolucao-cd-anpd-no-2-de-27-de-janeiro-de-2022"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
ANPD: Resolução nº 2/2022, arts. 6º, 12 e 13
|
||||
</a>
|
||||
</article>
|
||||
<article className="ds-card">
|
||||
<h2 className="ds-card-title !mt-0">
|
||||
Já começou com IA? Podemos partir daí.
|
||||
</h2>
|
||||
<p className="ds-copy">
|
||||
Seu protótipo ajuda a explicar a ideia. Antes de propor uma
|
||||
reconstrução, avalio o que pode ser aproveitado, quais riscos
|
||||
precisam de correção e o que falta para atender usuários em
|
||||
produção.
|
||||
</p>
|
||||
<p className="ds-copy">
|
||||
Você não precisa saber programar para conduzir o negócio. Precisa
|
||||
entender o que está contratando, acompanhar a entrega e ter
|
||||
clareza sobre quem cuida de cada parte do sistema.
|
||||
</p>
|
||||
<div className="mt-sp-6">
|
||||
<WhatsAppLink
|
||||
className={primaryButton}
|
||||
service={WHATSAPP_SERVICE}
|
||||
placement="ia_closing"
|
||||
>
|
||||
Avaliar meu projeto
|
||||
</WhatsAppLink>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user