Workflow Sistemático de Revisão de Código com IA: Planejar, Gerar, Validar
Guia prática para manter a qualidade do código na velocidade da IA
Introdução: O Custo Oculto do Código que “Funciona”
O código a seguir gera um endpoint de registro de usuários. Compila corretamente, passa nos testes básicos e funciona em staging:
app.post('/api/register', async (req, res) => {
const { email, password, username } = req.body;
const user = await db.query(
`INSERT INTO users (email, password, username)
VALUES ('${email}', '${password}', '${username}') RETURNING *`
);
res.json({ success: true, user });
});
Problemas críticos:
- Vulnerabilidade de injeção SQL
- Senha armazenada em texto plano
- Sem validação de entrada
- Sem tratamento de erros
- Sem proteção contra duplicatas
Este é o resultado típico quando se gera código com IA sem um processo de validação. A IA otimiza para código que funciona, não para código correto.
A solução é implementar um workflow sistemático que separe a geração da validação.
O Workflow de Três Fases

Princípio fundamental: Cada fase tem um propósito específico e utiliza ferramentas diferentes. A IA de geração (Cursor, Copilot, Claude) otimiza velocidade. A IA de revisão (Claude Code, CodeRabbit) otimiza segurança e qualidade.
Fase 1: Planejamento Estruturado
Um planejamento claro produz melhores resultados da IA generativa. Antes de escrever código, complete o seguinte template:
Template de Planejamento
Feature: [Nome do feature]
Propósito: [Uma sentença descrevendo o objetivo]
Entradas:
- campo: tipo, regras de validação
- campo: tipo, regras de validação
Saídas:
Sucesso:
- código HTTP, estrutura de resposta
Erro:
- código HTTP, estrutura de erro
Casos Edge:
- O que acontece se...?
- O que acontece se...?
Segurança:
- Consideração 1
- Consideração 2
Dependências:
- Biblioteca/serviço requerido
Exemplo Aplicado: Registro de Usuário
Feature: User Registration Endpoint
Propósito: Criar novos usuários com validação completa e armazenamento seguro
Entradas:
- email: string, formato RFC 5322, único em BD
- password: string, mínimo 8 caracteres, pelo menos 1 número e 1 maiúscula
- username: string, 3-20 caracteres alfanuméricos
Saídas:
Sucesso:
- 201 Created, { user: { id, email, username, createdAt } }
Erro:
- 400 Bad Request, { errors: [{ field, message }] }
- 409 Conflict, { error: "O email já está registrado" }
- 500 Internal Error, { error: "Erro interno do servidor" }
Casos Edge:
- Email com formato válido mas domínio inexistente
- Senha que atende requisitos mínimos mas é comum (123456Aa)
- Username com caracteres Unicode que parecem alfanuméricos
- Solicitações duplicadas simultâneas (race condition)
Segurança:
- Hash de senha com bcrypt (cost factor 12)
- Queries parametrizadas (prevenir injeção SQL)
- Rate limiting no endpoint
- Não revelar se email existe em mensagem de erro genérica
- Sanitização de inputs antes de logging
Dependências:
- bcrypt para hashing
- zod para validação
- express-rate-limit para throttling
Fase 2: Geração com Contexto
Com o template completo, constrói-se um prompt estruturado que inclui todos os requisitos.
Melhores Práticas de Geração
| Prática | Descrição |
|---|---|
| Uma tarefa por prompt | Gerar um endpoint, componente ou função por vez |
| Contexto limpo | Novo chat para cada tarefa, evitar contextos contaminados |
| Stack explícito | Especificar versões, convenções e estrutura do projeto |
| Iteração deliberada | 2-3 iterações refinando, não esperar perfeição inicial |
Prompt Estruturado
Criar um endpoint Express + TypeScript para registro de usuários.
REQUISITOS TÉCNICOS:
- POST /api/v1/auth/register
- Validação com Zod
- Hash com bcrypt (12 rounds)
- Queries parametrizadas com pg (node-postgres)
- TypeScript strict mode
VALIDAÇÕES:
- email: formato RFC 5322
- password: mínimo 8 chars, 1 número, 1 maiúscula
- username: 3-20 chars alfanuméricos
RESPOSTAS:
- 201: { user: { id, email, username, createdAt } }
- 400: { errors: [{ field: string, message: string }] }
- 409: { error: string } para email duplicado
- 500: { error: string } genérico
SEGURANÇA:
- Não incluir senha em nenhuma resposta
- Mensagem genérica para email duplicado
- Logging sem dados sensíveis
ESTRUTURA DO PROJETO:
src/
controllers/
middleware/
validators/
types/
Fase 3: Validação Automatizada
O código gerado requer validação com uma segunda perspectiva especializada em segurança.
Arquitetura de Validação

Opção 1: Claude Code como Revisor de Segurança
Claude Code permite executar análises de segurança diretamente do terminal. Configuração recomendada:
Instalação e Setup
# Instalar Claude Code
npm install -g @anthropic-ai/claude-code
# Instalar ferramentas de análise
npm install -D eslint @eslint/js eslint-plugin-security
npm install -D @typescript-eslint/parser @typescript-eslint/eslint-plugin
Configuração ESLint para Segurança
// eslint.config.js
import security from 'eslint-plugin-security';
import tseslint from '@typescript-eslint/eslint-plugin';
export default [
{
plugins: {
security,
'@typescript-eslint': tseslint
},
rules: {
'security/detect-object-injection': 'error',
'security/detect-non-literal-regexp': 'error',
'security/detect-unsafe-regex': 'error',
'security/detect-buffer-noassert': 'error',
'security/detect-child-process': 'warn',
'security/detect-disable-mustache-escape': 'error',
'security/detect-eval-with-expression': 'error',
'security/detect-no-csrf-before-method-override': 'error',
'security/detect-non-literal-fs-filename': 'warn',
'security/detect-non-literal-require': 'warn',
'security/detect-possible-timing-attacks': 'error',
'security/detect-pseudoRandomBytes': 'error',
'security/detect-sql-injection': 'error'
}
}
];
Prompt de Revisão para Claude Code
Criar um arquivo CLAUDE.md na raiz do projeto com instruções de revisão:
# Instruções de Revisão de Segurança
Ao revisar código, analisar sistematicamente:
## 1. Injeção
- [ ] SQL Injection: Se usam queries parametrizadas?
- [ ] NoSQL Injection: Se validam operadores do MongoDB?
- [ ] Command Injection: Se sanitizam inputs para exec/spawn?
- [ ] XSS: Se escapam outputs em templates?
## 2. Autenticação
- [ ] Senhas hasheadas com bcrypt/argon2 (cost >= 10)?
- [ ] Tokens com expiração apropriada?
- [ ] Rate limiting em endpoints de auth?
## 3. Autorização
- [ ] Verificação de ownership em recursos?
- [ ] RBAC/ABAC implementado corretamente?
## 4. Dados Sensíveis
- [ ] Secrets em variáveis de ambiente (não hardcoded)?
- [ ] Logging sem dados sensíveis?
- [ ] Respostas sem informação interna?
## 5. Dependências
- [ ] Executar: npm audit
- [ ] Verificar: nenhuma dependência deprecated
## Comandos de Análise
npx eslint --ext .ts,.js src/
npm audit --audit-level=moderate
Executar Revisão com Claude Code
# Navegar ao projeto
cd meu-projeto
# Iniciar revisão de segurança
claude-code
# Dentro de Claude Code, executar:
> Revise o arquivo src/controllers/auth.controller.ts
> seguindo as instruções de CLAUDE.md.
> Execute os comandos de análise e reporte vulnerabilidades.
```### Opção 2: CodeRabbit (Integração CI/CD)
CodeRabbit se integra diretamente com GitHub/GitLab para revisão automática em cada PR.
```yaml
# .github/workflows/code-review.yml
name: Automated Code Review
on:
pull_request:
types: [opened, synchronize]
jobs:
security-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Dependencies
run: npm ci
- name: Security Audit
run: npm audit --audit-level=moderate
- name: ESLint Security
run: npx eslint --ext .ts,.js src/
# CodeRabbit se ativa automaticamente em PRs
# após instalá-lo no repositório
Fluxo de Decisão de Segurança

Exemplo Completo: De Vulnerável a Seguro
Código Vulnerável (Geração sem validação)
// ⚠️ NÃO USAR EM PRODUÇÃO - Apenas para demonstração
import express from 'express';
import { Pool } from 'pg';
const app = express();
const pool = new Pool();
app.post('/api/register', async (req, res) => {
const { email, password, username } = req.body;
// 🔴 SQL Injection
const result = await pool.query(
`INSERT INTO users (email, password, username)
VALUES ('${email}', '${password}', '${username}')
RETURNING *`
);
// 🔴 Senha na resposta
res.json({ success: true, user: result.rows[0] });
});
Vulnerabilidades detectadas:
- Injeção SQL por concatenação de strings
- Senha armazenada em texto plano
- Senha retornada na resposta
- Sem validação de entrada
- Sem tratamento de erros
- Sem rate limiting
Código Seguro (Pós-validação)
// src/controllers/auth.controller.ts
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import bcrypt from 'bcrypt';
import { pool } from '../config/database';
import { AppError } from '../middleware/errorHandler';
// Esquema de validação
const registerSchema = z.object({
email: z
.string()
.email('Formato de email inválido')
.max(255, 'Email muito longo'),
password: z
.string()
.min(8, 'Mínimo 8 caracteres')
.regex(/[0-9]/, 'Deve conter pelo menos um número')
.regex(/[A-Z]/, 'Deve conter pelo menos uma letra maiúscula'),
username: z
.string()
.min(3, 'Mínimo 3 caracteres')
.max(20, 'Máximo 20 caracteres')
.regex(/^[a-zA-Z0-9]+$/, 'Apenas caracteres alfanuméricos')
});
// Tipos
interface UserResponse {
id: string;
email: string;
username: string;
createdAt: Date;
}
interface RegisterBody {
email: string;
password: string;
username: string;
}
export const register = async (
req: Request<{}, {}, RegisterBody>,
res: Response,
next: NextFunction
): Promise<void> => {
try {
// 1. Validar entrada
const validation = registerSchema.safeParse(req.body);
if (!validation.success) {
const errors = validation.error.errors.map(err => ({
field: err.path.join('.'),
message: err.message
}));
res.status(400).json({ errors });
return;
}
const { email, password, username } = validation.data;
// 2. Hash da senha (fator de custo 12)
const hashedPassword = await bcrypt.hash(password, 12);
// 3. Query parametrizada (previne injeção SQL)
const query = `
INSERT INTO users (email, password_hash, username, created_at)
VALUES ($1, $2, $3, NOW())
RETURNING id, email, username, created_at as "createdAt"
`;
const result = await pool.query<UserResponse>(query, [
email.toLowerCase(),
hashedPassword,
username
]);
// 4. Resposta sem senha
res.status(201).json({
user: result.rows[0]
});
} catch (error: unknown) {
// 5. Tratamento de erros específicos
if (error instanceof Error && 'code' in error) {
const pgError = error as { code: string };
// Violação de restrição única (email duplicado)
if (pgError.code === '23505') {
// Mensagem genérica (não revelar se email existe)
res.status(409).json({
error: 'Não foi possível completar o registro'
});
return;
}
}
// Log sem dados sensíveis
console.error('Erro de registro:', {
timestamp: new Date().toISOString(),
path: req.path,
// NÃO incluir: email, password, username
});
next(new AppError('Erro interno do servidor', 500));
}
};
// src/routes/auth.routes.ts
import { Router } from 'express';
import rateLimit from 'express-rate-limit';
import { register } from '../controllers/auth.controller';
const router = Router();
// Rate limiting: 5 tentativas por IP a cada 15 minutos
const registerLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5,
message: { error: 'Muitas tentativas, tente novamente mais tarde' },
standardHeaders: true,
legacyHeaders: false
});
router.post('/register', registerLimiter, register);
export default router;
Checklist de Implementação
Utilize esta lista de verificação antes de cada deploy:
Pré-Geração
- Template de planejamento preenchido
- Casos extremos identificados
- Requisitos de segurança documentados
Pós-Geração
- Revisão manual da estrutura
- Convenções do projeto respeitadas
- Tipos TypeScript corretos
Validação Automatizada
-
npm auditsem vulnerabilidades críticas - ESLint security sem erros
- Claude Code / CodeRabbit sem problemas de segurança
Segurança Específica
- Queries parametrizadas (sem concatenação)
- Senhas com hash (bcrypt >= 10 rounds)
- Entradas validadas com esquema (Zod, Joi)
- Erros sem informações sensíveis
- Rate limiting em endpoints críticos
- CORS configurado corretamente
Conclusão
O fluxo de trabalho de três fases transforma a geração de código com IA de um risco potencial em uma vantagem competitiva:
- Planejar antes de gerar reduz iterações e melhora a qualidade do output
- Gerar com contexto completo produz código mais próximo da produção
- Validar com ferramentas especializadas captura o que a geração omite
A chave está em reconhecer que a IA de geração e a IA de validação têm objetivos diferentes e complementares. Integrar ambas em um fluxo sistemático permite manter a velocidade de desenvolvimento sem sacrificar a segurança.
Recursos Adicionais
- OWASP Top 10 - Vulnerabilidades web mais críticas
- Claude Code Documentation - Guia oficial
- ESLint Plugin Security - Regras de segurança
- Zod Documentation - Validação de esquemas TypeScript
Publicado em yoDEV.dev - A comunidade de desenvolvedores da América Latina