| Severidade | Problema | Localização | Observações |
|---|---|---|---|
| CRITICAL | SQL Injection | models.py:28 | |
| CRITICAL | SQL Injection | models.py:48 | |
| CRITICAL | SQL Injection | models.py:110 | |
| CRITICAL | SQL Injection | models.py:291 | |
| CRITICAL | Exposição de dados sensíveis | models.py:83 | |
| CRITICAL | Exposição de dados sensíveis | models.py:99 | |
| CRITICAL | Exposição de Credenciais | database.py:76 | |
| CRITICAL | Exposição de Credenciais | app.py:7 | |
| CRITICAL | Exposição de Credenciais | app.py:7 | |
| CRITICAL | Exposição de Credenciais | controllers.py:289 | |
| CRITICAL | Ausência de Autenticação | app.py:47, app.py:59 | Nenhum endpoint tem mas ações administrativas são um risco pois podem apagar o banco ou executar scripts maliciosos |
| HIGH | Baixa coesão | models.py | Varios dominios no mesmo arquivo de model |
| MEDIUM | Violação do SRP | models.py, controllers.py:208 | model executando regras de negocio, ausência de camadas de serviços, alto acoplamento |
| MEDIUM | Queries N+1 | models.py:171-233 | |
| LOW | Magic numbers | models.py:257 | |
| LOW | Ausência de Logs estruturados | controllers.py:* |
| Severidade | Problema | Localização | Observações |
|---|---|---|---|
| CRITICAL | Exposição de Credenciais | utils.js:2-4 | |
| CRITICAL | Exposição de dados sensíveis | AppManager.js:45 | número do cartão e a chave do gateway impressos em log |
| CRITICAL | Senha default fraca | AppManager.js:68 | |
| CRITICAL | Ausência de Autenticação | AppManager.js:80, AppManager.js:131 | delete de usuário públicos; |
| HIGH | God Object/Violação do SRP | AppManager.js | uma classe faz conexão, DDL, seed, rotas, validação, pagamento, persistência e auditoria |
| MEDIUM | Queries N+1 | AppManager.js:92-106 | |
| MEDIUM | Ausência de Try/catch | AppManager.js | |
| LOW | Nomenclatura pouco descritiva | AppManager.js:29-33 | variáveis u, e, p, cid, cc |
| LOW | Magic number | AppManager.js:46 |
| Severidade | Problema | Localização | Observações |
|---|---|---|---|
| CRITICAL | Exposição de dados sensíveis | models/user.py:21 | to_dict() inclui password e vaza até na resposta do /login |
| CRITICAL | Exposição de Credenciais | services/notification_service.py:7-10 | |
| CRITICAL | Exposição de Credenciais | app.py:13 | |
| CRITICAL | Ausência de Autenticação | routes/* | token nunca é verificado; qualquer um pode fazer PUT /users/<id> e virar admin |
| HIGH | Código duplicado | models/task.py:50-60 | is_overdue() existe e nunca é chamado — a mesma lógica está repetida em 5 rotas |
| MEDIUM | Queries N+1 | routes/task_routes.py:41-57, routes/report_routes.py:53-68 | |
| MEDIUM | Validação duplicada | utils/helpers.py:57, models/task.py:38-48, routes/task_routes.py:110-114 | mesmas regras em 3 camadas, mas só a inline nas rotas é executada |
| MEDIUM | Baixa coesão | routes/report_routes.py:157-223 | CRUD de categorias dentro de relatórios |
| LOW | Tratamento de exceção genérico | routes/task_routes.py:62, :137, :204 | |
| LOW | Ausência de Logs estruturados | routes/* |
A skill refactor-arch vive em .claude/skills/refactor-arch/, copiada dentro
de cada um dos 3 projetos. SKILL.md define 3 fases sequenciais (Análise →
Auditoria → Refatoração) e 5 arquivos de referência em Markdown:
| Arquivo | Área de conhecimento |
|---|---|
references/analise-projeto.md |
Heurísticas para detectar linguagem, framework, banco e mapear arquitetura |
references/catalogo-antipatterns.md |
12 anti-patterns, cada um com sinais de detecção e severidade |
references/template-relatorio.md |
Formato padronizado do relatório de auditoria |
references/diretrizes-arquitetura.md |
Regras do padrão MVC alvo (camadas e responsabilidades) |
references/playbook-refatoracao.md |
12 padrões de transformação com exemplos de código antes/depois |
Decisões de design
- Catálogo derivado da análise manual, não do zero. Os 12 anti-patterns do catálogo mapeiam diretamente para os problemas documentados na Seção 1 — SQL Injection, exposição de credenciais/dados sensíveis, ausência de autenticação, ausência de transação, N+1, lógica de negócio fora do domínio, duplicação/abstração não usada, tratamento de erro genérico, APIs deprecated, God Object, e CORS/superfície pública. Isso garante que a skill resolve exatamente os problemas que motivaram sua criação, não uma lista genérica de boas práticas.
- Severidade decisiva, não hedgeada. Cada anti-pattern tem uma severidade padrão única (nunca "MEDIUM/HIGH"), com uma frase explícita de quando ela sobe ou desce — por exemplo, ausência de autenticação é CRITICAL por padrão, mas cai para HIGH quando o dado exposto não é sensível.
- Fase 2 é um portão, não uma sugestão. O SKILL.md declara como regra inviolável que nenhum arquivo é modificado antes da confirmação explícita do usuário, e o template de relatório termina com a pergunta de confirmação formatada (todos / só CRITICAL+HIGH / itens específicos / nenhum agora).
- Agnosticismo testado, não assumido. Todo sinal de detecção no catálogo
tem uma variante por stack (ex.: SQLi é "
execute(+ concatenação" em Python e "template string emquery()" em Node.js). Isso foi validado na prática rodando a skill nos 3 projetos (Seção 3). - Escopo de correção rastreável ao relatório aprovado. Nenhuma correção da Fase 3 foi aplicada sem corresponder a um item numerado do relatório — evitando "melhorias de carona" que tornariam a skill imprevisível.
Desafios encontrados
- A primeira versão do catálogo tinha várias severidades duplas (
MEDIUM / HIGH) e uma tabela-resumo redundante no fim — sintomas de texto gerado sem uma posição definida. Foi revisado para severidade única por item com justificativa de quando ela escala. - No
ecommerce-api-legacy(Node.js), o schema init original dependia dedb.serialize()para garantir a ordem de execução das queries; ao reescrever para repositórios com Promises, a primeira versão semserialize()quebrou o boot (no such table: users) porque o driversqlite3não garante ordem entre chamadas não encadeadas — corrigido reintroduzindodb.serialize()só na inicialização do schema. - Habilitar
PRAGMA foreign_keys = ONno mesmo projeto mudou o comportamento deDELETE /api/users/:id: em vez de sempre responder 200 e deixar matrículas/pagamentos órfãos, agora falha com 409 quando há vínculos — uma mudança de contrato deliberada e aprovada, documentada no relatório. - No
task-manager-api, a auditoria revelou que a estrutura de pastas já existia (routes/,models/,services/,utils/) mas as abstrações (is_overdue(),NotificationService,process_task_data) não eram usadas. Isso confirmou que o catálogo precisa detectar "abstração pronta e não usada" como categoria própria, não só duplicação literal de código. Na primeira passada da Fase 3, o esforço foi só em passar a chamar o que já existia sem tocar na estrutura de pastas — mas isso deixou a rota fazendo a mesma orquestração de sempre, sem um controller fino entre rota e domínio, contradizendo a própria proposta de reestruturação MVC do relatório (reports/audit-project-3.md). Corrigido extraindo uma camadacontrollers/(mesmo padrão dos outros 2 projetos), com as rotas virando apenas registro deBlueprint.add_url_rule+ guarda de autenticação. - Durante a validação, um processo de teste anterior (
code-smells-project) ficou rodando em background e ocupou a porta 5000 ao validar o projeto seguinte — lembrete de que cadaBashdo agente é um shell novo ekill %1não sobrevive entre chamadas; a solução foi localizar o PID vialsof/pse encerrá-lo explicitamente.
| Projeto | Stack | Findings (Fase 2) | Severidade | Fase 3 |
|---|---|---|---|---|
code-smells-project |
Python/Flask | 10 | 4 CRITICAL, 1 HIGH, 3 MEDIUM, 2 LOW | ✅ todos os 10 corrigidos |
ecommerce-api-legacy |
Node.js/Express | 11 | 4 CRITICAL, 2 HIGH, 2 MEDIUM, 3 LOW | ✅ todos os 11 corrigidos |
task-manager-api |
Python/Flask | 10 | 4 CRITICAL, 1 HIGH, 3 MEDIUM, 2 LOW | ✅ todos os 10 corrigidos |
Relatórios completos em reports/audit-project-1.md,
reports/audit-project-2.md e
reports/audit-project-3.md.
Comparação antes/depois (destaques)
| Problema | Antes | Depois |
|---|---|---|
Login (code-smells-project) |
email = "' OR '1'='1' --" autentica como qualquer usuário |
queries parametrizadas — bypass testado e bloqueado |
| Rotas admin (3 projetos) | /admin/*, /api/admin/* públicas |
exigem token/JWT; código-smells e ecommerce guardam por header, task-manager por JWT real |
Privilégio no cadastro (task-manager-api) |
POST /users aceitava role enviado pelo cliente |
cadastro público força role=user; alteração de papel fica restrita a usuário admin |
Acesso entre contas (task-manager-api) |
usuário autenticado podia ler/alterar dados e tasks de outro usuário | controllers validam proprietário do recurso ou admin; listagens globais filtram usuário comum |
Senha (code-smells-project) |
texto plano, devolvida em GET /usuarios |
removida da serialização |
Senha (ecommerce-api-legacy) |
badCrypto reversível (base64 concatenado) |
bcryptjs com salt |
Senha (task-manager-api) |
MD5 sem salt, devolvida até no /login |
werkzeug.security + removida da serialização |
Checkout (ecommerce-api-legacy) |
3 inserts encadeados sem transação | BEGIN/COMMIT/ROLLBACK explícito |
Pedido (code-smells-project) |
sem transação, sem rollback | rollback em qualquer falha no meio do fluxo |
Relatório financeiro (ecommerce-api-legacy) |
5 níveis de callback aninhado, N+1, err ignorado |
1 query com JOIN |
is_overdue() (task-manager-api) |
existia, nunca chamado; lógica copiada em 5 rotas | usado nos 5 pontos |
Delete de usuário (ecommerce-api-legacy) |
sempre 200, deixava órfãos | FK + PRAGMA foreign_keys=ON, 409 se houver vínculo |
Checklist de validação (preenchido nos 3 projetos)
Fase 1 — Análise
- Linguagem detectada corretamente (Python/Flask ×2, Node.js/Express ×1)
- Framework detectado corretamente (versões lidas do manifesto)
- Domínio da aplicação descrito corretamente
- Número de arquivos analisados condiz com a realidade
Fase 2 — Auditoria
- Relatório segue o template definido nos arquivos de referência
- Cada finding tem arquivo e linhas exatos
- Findings ordenados por severidade (CRITICAL → LOW)
- Mínimo de 5 findings identificados (10, 11 e 10 respectivamente)
- Detecção de APIs deprecated incluída no catálogo (MD5/
utcnow()acionados nos 3 projetos) - Skill pausou e pediu confirmação antes da Fase 3 (nos 3 projetos)
- Validação negativa de autenticação executada: rotas sensíveis sem token retornam 401/403 e cadastro público não permite
role=admin - Validação negativa de autorização executada: usuário comum não acessa nem modifica recursos de outro usuário
Fase 3 — Refatoração
- Estrutura de diretórios segue padrão MVC (nos 2 projetos que não tinham; mantida e reforçada no 3º)
- Configuração extraída para módulo/variável de ambiente (sem hardcoded)
- Models/repositórios criados ou corrigidos para abstrair dados
- Rotas separadas do roteamento de negócio
- Error handling centralizado (
logging, exceções específicas) - Entry point claro (
app.py/src/app.jscomo composition root) - Aplicação inicia sem erros (validado com boot real, não só leitura de código)
- Endpoints originais respondem corretamente (validado com
curlem todos os 3 projetos)
Evidência de execução (excerto real do code-smells-project após a Fase 3):
$ curl -X POST http://localhost:5000/login -d '{"email":"admin@loja.com","senha":"admin123"}'
{"dados":{"email":"admin@loja.com","id":1,"nome":"Admin","tipo":"admin"},"mensagem":"Login OK","sucesso":true}
$ curl -X POST http://localhost:5000/login -d '{"email":"'"'"' OR '"'"'1'"'"'='"'"'1","senha":"x"}'
{"erro":"Email ou senha inválidos","sucesso":false} # bypass de SQLi bloqueado
$ curl -X POST http://localhost:5000/admin/reset-db
{"erro":"Não autorizado"} # 401 sem token
$ curl -X POST http://localhost:5000/admin/reset-db -H "X-Admin-Token: ..."
{"mensagem":"Banco de dados resetado","sucesso":true} # 200 com token
Pré-requisitos
- Python 3.11+ (para
code-smells-projectetask-manager-api) - Node.js 18+ (para
ecommerce-api-legacy) - Claude Code (a skill usa
.claude/skills/refactor-arch/)
Rodar a skill em cada projeto
# Projeto 1 — code-smells-project
cd code-smells-project
claude "/refactor-arch"
# Projeto 2 — ecommerce-api-legacy
cd ../ecommerce-api-legacy
claude "/refactor-arch"
# Projeto 3 — task-manager-api
cd ../task-manager-api
claude "/refactor-arch"A Fase 2 sempre pausa e pergunta quais correções aplicar antes de tocar em qualquer arquivo — responda a pergunta de confirmação para prosseguir à Fase 3.
Subir cada API refatorada e validar manualmente
code-smells-project (Python/Flask):
cd code-smells-project
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # preencha SECRET_KEY e ADMIN_TOKEN
export $(cat .env | xargs)
python app.py
# em outro terminal:
curl http://localhost:5000/produtos
curl -X POST http://localhost:5000/admin/reset-db -H "X-Admin-Token: <seu-token>"ecommerce-api-legacy (Node.js/Express):
cd ecommerce-api-legacy
npm install
cp .env.example .env # preencha DB_PASS, PAYMENT_GATEWAY_KEY, ADMIN_TOKEN
export $(cat .env | xargs)
npm start
# em outro terminal:
curl -X POST http://localhost:3000/api/checkout -H "Content-Type: application/json" \
-d '{"usr":"Teste","eml":"teste@x.com","pwd":"123456","c_id":1,"card":"4111111111111111"}'
curl http://localhost:3000/api/admin/financial-report -H "X-Admin-Token: <seu-token>"task-manager-api (Python/Flask):
cd task-manager-api
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # preencha SECRET_KEY
export $(cat .env | xargs)
python seed.py
python app.py
# em outro terminal:
TOKEN=$(curl -s -X POST http://localhost:5000/login -H "Content-Type: application/json" \
-d '{"email":"joao@email.com","password":"1234"}' | python3 -c "import json,sys;print(json.load(sys.stdin)['token'])")
curl http://localhost:5000/users -H "Authorization: Bearer $TOKEN"Como validar que a refatoração funcionou
- O servidor deve subir sem traceback.
- Os endpoints listados no "Resumo da Análise" da Fase 1 de cada projeto devem responder com o mesmo formato de antes (exceto as mudanças de contrato aprovadas e documentadas em cada relatório: remoção do campo de senha e guarda de autenticação nas rotas administrativas/sensíveis).
- Os relatórios em
reports/audit-project-*.mddocumentam, para cada achado, a correção aplicada — qualquer revisor pode conferir achado por achado contra o código final.