vibe coding 12 min read 954 views

O que é Vibe Coding?

Admin Prompt Engineer & AI Agent Developer
O que é Vibe Coding?

Vibe Coding: O Manifesto da Nova Era da Programação

Por Jacques Belmont | Engenheiro de Prompt & Arquiteto de Soluções

Do Código à Intenção

Você ainda programa pensando em ponto e vírgula? O jogo mudou.

Vibe Coding é uma metodologia de desenvolvimento onde a sintaxe rígida dá lugar ao fluxo criativo.
A IA (LLMs) atua como nosso “compilador”, transformando linguagem natural em sistemas robustos.
Não é no-code; é code-at-speed-of-thought.

Diferente de plataformas que escondem o código, o Vibe Coding gera código real, limpo e escalável (React, TypeScript, Python), mas a interface principal é a visão do arquiteto — não a digitação manual de caracteres.

A Filosofia do “One-Person Unicorn”

Eu defendo que o desenvolvedor moderno não é um operário de código, mas um orquestrador de inteligência. No Vibe Coding, a barreira entre a ideia e o software funcional é dissolvida.

O mercado não paga pelo código que você digita — paga pelo problema que você resolve. Essa metodologia permite que um único desenvolvedor construa ecossistemas inteiros.

Foi assim que desenvolvi produtos como o Roulette Analytica e estruturas do meu ecossistema sozinho, em uma fração do tempo de um time tradicional.

O Stack do Vibe Coder

  • IDEs com IA nativa: Cursor & Windsurf para manter o contexto total do projeto.
  • Cérebros digitais: Claude 3.5 Sonnet e GPT-4o para raciocínio lógico complexo.
  • Foco: sai a “depuração de sintaxe”, entra a “depuração de lógica de negócio”.
  • Disciplina: prompts com constraints, critérios de aceite, segurança e testes.

Engenharia de Prompt: O que separa “prompt aleatório” de “prompt de produção”

Um prompt profissional não é “faça X”. É um contrato de entrega: define papel, escopo, restrições, critérios de aceite e checklist de segurança.

Template (o prompt que eu realmente uso)

Você é [PAPEL: ex. Senior Fullstack Engineer].
Contexto: [o que já existe no repo].
Objetivo: [o que precisa ser implementado].

Restrições:
- Linguagem: [TS/React/Python]
- Sem quebrar APIs existentes
- Sem comentários novos
- Tipagem estrita
- Sem secrets hardcoded
- Validar inputs e tratar erros

Critérios de aceite:
- [lista objetiva, testável]
- [ex.: retorna 200/400 corretamente, não vaza stacktrace, etc.]

Entregáveis:
- Diff minimalista
- Trechos de código finais
- Lista do que foi validado e como testar

Vibe Coding na Prática: Exemplos Reais (com código do meu repo)

O “código-fonte” do Vibe Coder é a intenção clara. Abaixo estão exemplos onde um prompt bem estruturado vira código de produção — com segurança, padrões e deploy em mente.

Exemplo 1: Paywall de Produção (React + Tailwind + UX)

A Intenção (Prompt de UI/UX com constraints):

Você é um Senior Frontend Engineer especialista em produtos pagos.

Crie um componente React + TypeScript para paywall:
- Estado: método ('PIX' | 'CREDIT_CARD') e plano ('MONTHLY_100' | 'FULL')
- Gerar URL de referral usando window.location.origin e user.referralCode
- Ter ações "Copiar link" e "Compartilhar" (usar navigator.share se disponível, fallback para clipboard)
- Design em Tailwind: modal central, foco em conversão, CTA com loading
- Não use libs extras
- Tipagem estrita e props claras

Critérios de aceite:
- Copiar/compartilhar funciona com fallback
- Botão de pagar só habilita após escolher método
- Texto reforça "checkout seguro" sem prometer coisas falsas

Resultado (trecho real do projeto: Roullete-PRO/components/PaywallScreen.tsx):

const PaywallScreen: React.FC<Props> = ({ user, onUpgrade }) => {
  const [method, setMethod] = useState<'PIX' | 'CREDIT_CARD' | null>(null);
  const [plan, setPlan] = useState<'MONTHLY_100' | 'FULL'>('FULL');
  const [processing, setProcessing] = useState(false);

  const referralUrl = `${window.location.origin}/?ref=${user.referralCode}`;

  const handleCopyReferral = async () => {
    try {
      await navigator.clipboard.writeText(referralUrl);
      alert('Link copiado! Envie para seu amigo.');
    } catch {
      alert('Não foi possível copiar automaticamente. Copie manualmente: ' + referralUrl);
    }
  };

  const handleShareReferral = async () => {
    try {
      // @ts-ignore
      if (navigator.share) {
        // @ts-ignore
        await navigator.share({
          title: 'Roulette Analytica Pro',
          text: 'Use meu link para se cadastrar. Quando você ativar qualquer plano, eu ganho 15 rodadas.',
          url: referralUrl,
        });
        return;
      }
      await handleCopyReferral();
    } catch {
      await handleCopyReferral();
    }
  };

  const handlePay = () => {
    if (!method) return;
    setProcessing(true);
    onUpgrade(method, plan);
  };

  return (
    <div className="fixed inset-0 z-50 bg-slate-950 flex items-center justify-center p-4">
      {/* ... UI do paywall ... */}
    </div>
  );
};

Exemplo 2: Upgrade com Stripe (Frontend chamando API serverless)

A Intenção (Prompt de integração segura):

Você é um Senior Fullstack Engineer.
Implemente um fluxo de upgrade:
- Se método for cartão: chamar POST /api/create-checkout-session com { userId, email, plan }
- Validar response.ok, garantir que existe data.url, senão erro
- Redirecionar para Stripe Checkout via window.location.href
- PIX deve ficar desabilitado por segurança (evitar ativação simulada em produção)
- Erros devem exibir mensagem amigável

Critérios de aceite:
- Não redireciona sem URL
- Não "ativa" PIX fake
- Não quebra se localStorage falhar

Resultado (trecho real: Roullete-PRO/App.tsx):

const handleUpgrade = async (method: 'PIX' | 'CREDIT_CARD', plan: 'MONTHLY_100' | 'FULL') => {
  if (!user) return;

  try {
    if (user.subscriptionStatus === 'FREE' && user.credits <= 0) {
      try {
        localStorage.setItem('rp_resume_needed', '1');
      } catch {
        // ignore
      }
    }

    // Stripe Checkout (redirect)
    if (method === 'CREDIT_CARD') {
      const response = await fetch('/api/create-checkout-session', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ userId: user.id, email: user.email, plan }),
      });

      const data = await response.json();
      if (!response.ok) throw new Error(data?.message ?? 'Falha ao iniciar pagamento');
      if (!data?.url) throw new Error('Stripe URL ausente');

      window.location.href = data.url;
      return;
    }

    // PIX disabled for now (avoid simulated activation in production)
    alert('PIX em breve. Por enquanto, use Cartão de Crédito.');
    return;
  } catch (e: any) {
    alert(e?.message ?? 'Falha ao processar upgrade');
    throw e;
  }
};

Exemplo 3: Segurança de Produção (API Stripe com bloqueio de chave de teste)

Aqui é onde Vibe Coding vira engenharia de verdade: o prompt pede segurança, e o código devolve proteções que evitam incidentes reais.

A Intenção (Prompt de hardening):

Você é um Backend Engineer focado em segurança.
Crie uma serverless function (Vercel) para Stripe checkout:
- Ler STRIPE_SECRET_KEY de env e falhar rápido se ausente
- Se VERCEL_ENV=production, bloquear sk_test_
- Criar sessão de assinatura com metadata { userId, plan }
- Construir baseUrl usando headers x-forwarded-proto e host
- Validar method POST e retornar 405 para outros métodos
- Retornar 200 com { url } ou 400 com { message } sem stacktrace

Critérios de aceite:
- Nunca usa chave de teste em produção
- Nunca expõe segredo no response
- Validação de body (userId/email)

Resultado (trecho real: Roullete-PRO/api/create-checkout-session.ts):

const stripeSecretKey = process.env.STRIPE_SECRET_KEY;
if (!stripeSecretKey) {
  throw new Error('Missing STRIPE_SECRET_KEY');
}

if (process.env.VERCEL_ENV === 'production' && stripeSecretKey.startsWith('sk_test_')) {
  throw new Error('Pagamento em produção não configurado (chave Stripe de teste).');
}

const stripe = new Stripe(stripeSecretKey, {
  apiVersion: '2025-02-24.acacia',
});

function getBaseUrl(req: VercelRequest) {
  const proto = (req.headers['x-forwarded-proto'] as string | undefined) ?? 'https';
  const host = req.headers.host;
  if (!host) throw new Error('Missing host header');
  return `${proto}://${host}`;
}

export default async function handler(req: VercelRequest, res: VercelResponse) {
  if (req.method !== 'POST') {
    return res.status(405).json({ message: 'Method Not Allowed' });
  }

  try {
    const { userId, email, plan } = req.body as {
      userId?: string;
      email?: string;
      plan?: 'MONTHLY_100' | 'FULL';
    };

    if (!userId || !email) {
      return res.status(400).json({ message: 'Missing userId/email' });
    }

    // ... cria sessão do Stripe e retorna session.url ...
    return res.status(200).json({ url: session.url });
  } catch (error: any) {
    return res.status(400).json({ message: error?.message ?? 'Unknown error' });
  }
}

Exemplo 4: “Créditos” como regra de negócio (Prisma + Serverless)

A Intenção (Prompt de regra de negócio com proteção):

Você é um Backend Engineer.
Crie endpoint POST /api/deduct-credit:
- Recebe userId
- Busca usuário no Prisma
- Se subscriptionStatus='FREE', decrementa créditos em 1
- Retorna userProfile com subscriptionExpiry em timestamp (number|null)
- Retornar 405 para métodos inválidos
- Tratar erros sem vazar detalhes internos

Critérios de aceite:
- Só decrementa se for FREE
- Retorna JSON consistente
- Erros retornam 400 com message

Resultado (trecho real: Roullete-PRO/api/deduct-credit.ts):

const prisma = new PrismaClient();

export default async function handler(req: VercelRequest, res: VercelResponse) {
  if (req.method !== 'POST') {
    return res.status(405).json({ message: 'Method Not Allowed' });
  }

  const { userId } = req.body;

  try {
    const user = await prisma.user.findUnique({ where: { id: userId } });
    if (!user) throw new Error("User not found");

    let updatedUser = user;
    if (user.subscriptionStatus === 'FREE') {
      updatedUser = await prisma.user.update({
        where: { id: userId },
        data: { credits: { decrement: 1 } },
      });
    }

    const userProfile = {
      ...updatedUser,
      subscriptionExpiry: updatedUser.subscriptionExpiry ? updatedUser.subscriptionExpiry.getTime() : null,
    };

    res.status(200).json(userProfile);
  } catch (error: any) {
    res.status(400).json({ message: error.message });
  }
}

Exemplo 5: Prompt para criação de site (Astro) com SEO e config central

Em site institucional, prompt bom não fala só de UI. Fala de SEO, config central, metadados e disciplina de conteúdo.

A Intenção (Prompt de arquitetura para site):

Você é um Web Architect especializado em Astro.
Crie uma configuração central (SITE_CONFIG):
- name, title, description, url, image
- seo.keywords, author, robots, verificações
- social links (linkedin, github, youtube, twitter)
- schema.org Person com sameAs e knowsAbout

Restrições:
- Tudo centralizado em src/config/site.ts
- O layout deve consumir essa config (sem duplicar strings)

Critérios de aceite:
- Fácil trocar metadados em um único lugar
- SEO pronto (keywords, author, robots)
- Schema.org consistente

Resultado (trecho real: site/src/config/site.ts):

export const SITE_CONFIG = {
  name: 'Jacques Belmont',
  title: 'Jacques Belmont - Senior Prompt Engineer & AI Agent Developer',
  description:
    'Specialist in AI Automation, Vibe Coding, and Reverse Prompt Engineering. Architecting autonomous workforces and robust AI systems using Python & LLMs.',
  url: '[https://www.jacquesbelmont.com](https://www.jacquesbelmont.com)',
  image: '/og-image.jpg',

  contact: {
    email: '[email protected]',
    phone: '+55 (83) 9 9999-9999',
    location: 'João Pessoa, Paraíba, Brazil',
    linkedin: '[https://linkedin.com/in/jacquesbelmont'](https://linkedin.com/in/jacquesbelmont'),
    youtube: '[https://youtube.com/@jacquesbelmont'](https://youtube.com/@jacquesbelmont'),
    github: '[https://github.com/jacquesbelmont'](https://github.com/jacquesbelmont'),
    twitter: 'https://x.com/belmont_jacques',
  },

  seo: {
    keywords: [
      'Prompt Engineer',
      'AI Agent Developer',
      'Vibe Coding',
      'AI Automation',
      'Reverse Engineering',
      'n8n Specialist',
      'LLM Optimization',
      'Python Automation',
      'Agentes Autônomos',
    ],
    author: 'Jacques Belmont',
    robots: 'index, follow',
    googleSiteVerification: 'your-google-verification-code',
    bingSiteVerification: '4SEU-CODIGO-B44C1E113E12F01E60096',
  },

  // ... schema.org Person ...
};

Segurança no Vibe Coding: o prompt como firewall

Se você não pede segurança no prompt, você recebe “código que funciona” — até o dia em que não funciona mais. Aqui vai um conjunto de prompts que eu uso para garantir que a IA produza código pronto para produção.

Prompt 1: Anti-vazamento de segredos

Checklist de segurança obrigatório:
- Nunca hardcode API keys, tokens, secrets
- Ler tudo via env (process.env)
- Em caso de erro, retornar mensagem genérica (sem stacktrace, sem config)
- Bloquear execução em produção com credenciais de teste (ex.: Stripe sk_test_)
- Validar method e payload (400/405)

Entregue: implementação + pontos onde posso testar.

Prompt 2: Validação e contratos de API

Implemente validação defensiva:
- Campos obrigatórios
- Tipagem explícita
- Mensagens de erro consistentes
- Sem comportamento implícito perigoso
Critério: nenhuma request malformada causa crash.

Prompt 3: “Produção não aceita gambiarra”

Se existir funcionalidade simulada (ex.: PIX fake), deve ficar desabilitada por default.
Produção = comportamento determinístico e auditável.
Critério: não existe caminho que “ativa” acesso sem pagamento confirmado.

Conclusão

Vibe Coding não é “deixar a IA codar por você”.
É arquitetar intenção, traduzir isso em prompts com critérios de produção e usar o modelo como motor de implementação.

A diferença entre “prompt bonito” e “produto no ar” é: contexto, restrições, segurança e validação. Quando você domina isso, você vira um verdadeiro One-Person Unicorn.