Claude-skill-registry code-inspector

Senior Full-Stack Code Auditor - Especialista em Arquitetura, Segurança, Performance, Observabilidade e Qualidade de Software. Focado em Node.js/Express/MongoDB com expertise em sistemas multi-tenant SaaS. Use para auditorias profundas, análise de débito técnico, code review, troubleshooting avançado, refatoração estratégica ou otimização de sistemas.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/code-inspector" ~/.claude/skills/majiayu000-claude-skill-registry-code-inspector && rm -rf "$T"
manifest: skills/data/code-inspector/SKILL.md
source content

Code Inspector Skill (Senior Full-Stack Edition)

🎯 Missão

Garantir excelência técnica através de auditorias sistemáticas com visão holística: segurança, performance, manutenibilidade, observabilidade e resiliência.


1. 🔬 Framework de Auditoria (SPARC)

S - Security (Segurança)

P - Performance (Desempenho)

A - Architecture (Arquitetura)

R - Reliability (Confiabilidade)

C - Code Quality (Qualidade)

Toda auditoria deve cobrir essas 5 dimensões com scores de 1-5.


2. 🛡️ Security Deep Dive

2.1 OWASP Top 10 Checklist (Node.js/Express)

#VulnerabilidadeRegex/BuscaSeveridadeMitigação
A01Broken Access ControlRotas sem middleware auth🔴 CRÍTICOverificarAdmin, verificarParticipante
A02Cryptographic Failuresmd5, sha1 para senhas🔴 CRÍTICObcrypt com salt rounds >= 10
A03Injection$where, eval(), new Function🔴 CRÍTICOSanitização, prepared statements
A04Insecure DesignSem rate limiting em auth🟡 ALTOexpress-rate-limit
A05Security Misconfigurationorigin: '*', debug em prod🟡 ALTOHelmet, CORS restrito
A06Vulnerable Componentsnpm audit --json🟡 ALTODependabot, audits regulares
A07Auth FailuresSessão sem httpOnly/secure🔴 CRÍTICOCookie flags corretas
A08Data IntegritySem validação de schema🟡 MÉDIOJoi, Zod, express-validator
A09Logging FailuresDados sensíveis em logs🟡 MÉDIOSanitizar PII
A10SSRFfetch com URL user-controlled🔴 CRÍTICOWhitelist de URLs

2.2 Análise de Autenticação/Autorização

# Rotas POST/PUT/DELETE sem middleware de auth
grep -rn "router\.\(post\|put\|delete\|patch\)" routes/ | grep -v "verificar"

# Sessões sem flags de segurança
grep -rn "cookie:" config/ | grep -v "httpOnly\|secure\|sameSite"

# Secrets expostos
grep -rn "password\s*[:=]\s*['\"][^'\"]*['\"]" --include="*.js" | grep -v "process\.env\|\.example"

# JWT sem expiração
grep -rn "jwt\.sign" --include="*.js" | grep -v "expiresIn"

2.3 MongoDB Injection Patterns

// 🔴 VULNERÁVEL: Query operator injection
const user = await User.findOne({ email: req.body.email }); // Se email = {"$gt": ""}

// 🟢 SEGURO: Sanitização
const email = String(req.body.email).toLowerCase().trim();
const user = await User.findOne({ email });

// 🔴 VULNERÁVEL: $where (executa JS no servidor)
db.collection.find({ $where: "this.name == '" + userInput + "'" });

// 🟢 SEGURO: Usar operadores nativos
db.collection.find({ name: sanitizedInput });

// 🔴 VULNERÁVEL: RegEx injection
const regex = new RegExp(req.query.search); // Se search = ".*"

// 🟢 SEGURO: Escape especial characters
const escaped = req.query.search.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const regex = new RegExp(escaped, 'i');

2.4 Checklist de Segurança - Super Cartola

ItemStatusArquivo de ReferênciaScript Validação
Rate limiting em loginroutes/admin-auth-routes.js
grep -rn "rateLimit" routes/*auth*
CSRF protectionindex.js (csurf)
grep -rn "csurf|csrf" index.js
Helmet headersindex.js
grep -rn "helmet" index.js
Session seguraconfig/replit-auth.js
grep -rn "httpOnly.*secure" config/
Sanitização de inputs?Controllers
./scripts/audit_input_sanitization.sh
Multi-tenant isolation🔴Todas queries com liga_id
./scripts/audit_multitenant.sh
Google OAuth tokensconfig/google-auth.js
grep -rn "GOOGLE_CLIENT" config/
Admin vs Participantemiddleware/auth.js
grep -rn "verificarAdmin|verificarParticipante" middleware/

2.5 Scripts de Auditoria Automática

Crie

/scripts/audit_security.sh
:

#!/bin/bash
echo "🔐 AUDITORIA DE SEGURANÇA - Super Cartola"
echo "=========================================="
echo ""

# Rotas desprotegidas
echo "🔴 ROTAS POST/PUT/DELETE SEM AUTH:"
find routes/ -name "*.js" -exec grep -l "router\.\(post\|put\|delete\)" {} \; | while read file; do
  if ! grep -q "verificar" "$file"; then
    echo "  ⚠️  $file"
  fi
done
echo ""

# Queries sem liga_id
echo "🔴 QUERIES SEM MULTI-TENANT ISOLATION:"
grep -rn "\.find({" controllers/ routes/ | grep -v "liga_id\|ligaId" | head -10
echo ""

# Console.logs em produção
echo "🟡 CONSOLE.LOGS (remover em produção):"
find controllers/ routes/ services/ -name "*.js" -exec grep -Hn "console\.log" {} \; | wc -l
echo ""

# Secrets hardcoded
echo "🔴 SECRETS HARDCODED:"
grep -rn "password\s*[:=]\s*['\"][^'\"]*['\"]" --include="*.js" | grep -v "process\.env\|\.example\|\.sample" | wc -l
echo ""

# npm audit
echo "🟡 VULNERABILIDADES NPM:"
npm audit --json 2>/dev/null | jq '.metadata | {vulnerabilities, totalDependencies}'

3. ⚡ Performance Engineering

3.1 Database Performance

N+1 Query Detection

# Encontrar loops com queries
grep -rn "for.*await\|forEach.*await\|\.map.*await" controllers/ --include="*.js"

# Queries sem .lean()
grep -rn "find\|findOne" controllers/ | grep -v "\.lean()"

# Agregações complexas sem índices
grep -rn "\.aggregate\|\.pipeline" controllers/ services/

Otimizações MongoDB

Anti-PatternImpactoSoluçãoScript Detecção
N+1 Queries100x mais lento$in, $lookup, bulk
grep -rn "for.*await.*find"
Sem .lean()5x mais memóriaAdicionar .lean() em reads
grep "find.*{" | grep -v "lean"
Sem índicesScan completocreateIndex em campos filtrados
mongo --eval "db.collection.getIndexes()"
Select *I/O desnecessário.select('campo1 campo2')
grep "find.*{" | grep -v "select"
Sort sem índiceIn-memory sortÍndice composto incluindo sortVer explain plan
Skip grandeLento em paginaçãoCursor-based pagination
grep "skip.*[0-9]{3,}"
$whereExecução JSOperadores nativos
grep "\$where"
Regex sem âncoraFull scan/^prefixo/ com índice
grep "RegExp.*\$" | grep -v "\\^"

Query Analysis (Super Cartola Specific)

// Habilitar profiling temporário
db.setProfilingLevel(1, { slowms: 100 });

// Ver queries lentas
db.system.profile.find({ ns: /^super_cartola\./ }).sort({ ts: -1 }).limit(10);

// Explain de query suspeita
db.participantes.find({ liga_id: "684cb1c8af923da7c7df51de" })
  .sort({ pontos_acumulados: -1 })
  .explain("executionStats");

// Verificar uso de índices
db.participantes.getIndexes();
db.rodadas.getIndexes();
db.financeiro.getIndexes();

3.2 Node.js Performance

Event Loop Blocking

# Operações síncronas que bloqueiam
grep -rn "readFileSync\|writeFileSync\|execSync" --include="*.js" | grep -v "node_modules"

# JSON.parse em payloads grandes sem stream
grep -rn "JSON\.parse" controllers/ services/

# Loops síncronos pesados
grep -rn "for.*length\|while.*true" --include="*.js" | grep -v "node_modules"

Memory Leaks Patterns

// 🔴 LEAK: Listeners acumulando
emitter.on('event', handler); // Sem removeListener

// 🔴 LEAK: Closures retendo referências
const cache = {};
function process(data) {
  cache[data.id] = data; // Cresce infinitamente
}

// 🔴 LEAK: Timers não limpos
setInterval(() => {}, 1000); // Sem clearInterval

// 🔴 LEAK: Arrays crescendo indefinidamente
global.requestLog = [];
app.use((req, res, next) => {
  global.requestLog.push({ url: req.url, time: Date.now() });
  next();
});

// 🟢 SOLUÇÃO: WeakMap para cache
const cache = new WeakMap();

// 🟢 SOLUÇÃO: LRU Cache com limite
const LRU = require('lru-cache');
const cache = new LRU({ max: 500 });

// 🟢 SOLUÇÃO: Circular buffer
const requestLog = new CircularBuffer(1000);

3.3 Frontend Performance (Super Cartola Mobile)

MétricaTargetComo MedirArquivo Referência
FCP (First Contentful Paint)< 1.8sLighthouseparticipante-navigation.js
LCP (Largest Contentful Paint)< 2.5sLighthouseindex.html (splash screen)
CLS (Cumulative Layout Shift)< 0.1LighthouseEvitar height/width dinâmicos
TTI (Time to Interactive)< 3.8sLighthouseLazy load modules
IndexedDB Read< 50msPerformance APIcache-manager.js
API Response< 200msNetwork tabTodas routes

Checklist Frontend

# Bundles grandes (>100KB)
find public/js -name "*.js" -size +100k -exec ls -lh {} \;

# Imagens não otimizadas (>200KB)
find public/img -type f \( -name "*.png" -o -name "*.jpg" \) -size +200k

# Scripts sem defer/async
grep -rn "<script" public/ views/ | grep -v "defer\|async\|type=\"module\""

# CSS inline excessivo (>1KB)
find public/ -name "*.html" -exec grep -l "style>" {} \; | while read f; do
  size=$(sed -n '/<style>/,/<\/style>/p' "$f" | wc -c)
  if [ $size -gt 1024 ]; then echo "$f: ${size}B"; fi
done

# Requests sem cache headers
grep -rn "res\.json\|res\.send" routes/ | grep -v "Cache-Control"

3.4 Cache Strategy (Super Cartola)

Frontend - IndexedDB

// Pattern Cache-First (correto)
async function loadParticipante() {
  // 1. Tentar cache primeiro (instantâneo)
  const cached = await db.participante.get(userId);
  if (cached && !isStale(cached)) {
    renderUI(cached);
  }
  
  // 2. Atualizar em background
  const fresh = await fetch('/api/participante').then(r => r.json());
  await db.participante.put(fresh);
  
  // 3. Re-render se mudou
  if (JSON.stringify(cached) !== JSON.stringify(fresh)) {
    renderUI(fresh);
  }
}

// TTL por módulo
const TTL = {
  participante: 24 * 60 * 60 * 1000, // 24h
  ranking: 60 * 60 * 1000,           // 1h
  extrato: 30 * 60 * 1000,           // 30min
  liga: 24 * 60 * 60 * 1000          // 24h
};

Backend - MongoDB + Memory

// Pattern para dados calculados (NÃO persistir)
class FluxoFinanceiroService {
  async calcularSaldo(participanteId, ligaId, temporada) {
    // NUNCA salvar em DB - sempre calcular fresh
    const rodadas = await Rodada.find({ participante_id, liga_id, temporada });
    const acertos = await AcertoFinanceiro.find({ participante_id, liga_id, temporada });
    
    return this.somarTudo(rodadas, acertos); // Cálculo em tempo real
  }
}

// Pattern para dados estáticos (persistir com cache)
class RankingService {
  async getRankingRodada(ligaId, rodadaNum) {
    const cacheKey = `ranking:${ligaId}:${rodadaNum}`;
    
    // Memory cache (Node)
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey);
    }
    
    // DB cache
    const cached = await RankingCache.findOne({ liga_id: ligaId, rodada: rodadaNum });
    if (cached) {
      this.cache.set(cacheKey, cached.data);
      return cached.data;
    }
    
    // Calcular e cachear
    const ranking = await this.calcular(ligaId, rodadaNum);
    await RankingCache.create({ liga_id: ligaId, rodada: rodadaNum, data: ranking });
    this.cache.set(cacheKey, ranking);
    
    return ranking;
  }
}

4. 🏗️ Architecture Analysis

4.1 SOLID Principles Check

PrincípioViolação ComumComo DetectarThreshold
Single ResponsibilityController com lógica de negócioArquivo > 300 linhas300 LOC
Open/ClosedSwitch/case crescendoswitch.*case em múltiplos lugares3+ ocorrências
Liskov SubstitutionHerança quebradaOverride que muda comportamentoManual review
Interface SegregationModels muito grandesSchema > 50 campos50 fields
Dependency InversionImport direto de implementaçãoSem camada de abstraçãoManual review

4.2 Layer Violations

✅ CORRETO:
Route → Controller → Service → Model → Database

❌ VIOLAÇÃO:
Route → Database (skip controller/service)
Controller → Database (skip model)
Frontend → Database (exposição direta)
# Routes acessando Model diretamente (pular controller)
grep -rn "import.*from.*models" routes/

# Controllers com lógica que deveria estar em Service
grep -rn "\.aggregate\|\.bulkWrite" controllers/

# Frontend com lógica de negócio
grep -rn "function.*calcular\|function.*processar" public/js/ | grep -v "UI\|render\|format"

4.3 Arquitetura Multi-Tenant (Crítico - Super Cartola)

# TODAS as queries devem filtrar por liga_id
# Buscar queries sem filtro de tenant
grep -rn "\.find({" controllers/ routes/ | grep -v "liga_id\|ligaId" | head -20

# Verificar rotas que recebem ligaId
grep -rn "req\.params\.ligaId\|req\.body\.liga_id" routes/

# Validar middleware de tenant
grep -rn "tenantFilter\|verificarAcesso" middleware/
CamadaResponsabilidadeValidaçãoArquivo
RouteExtrair ligaId dos paramsreq.params.ligaIdroutes/*.js
MiddlewareInjetar liga_id no reqtenantFilter.jsmiddleware/tenant.js
ControllerSempre passar para ServiceNão assumir defaultcontrollers/*.js
ModelÍndice composto com liga_idSchema indexmodels/*.js

Script de Auditoria Multi-Tenant

#!/bin/bash
# /scripts/audit_multitenant.sh

echo "🔍 AUDITORIA MULTI-TENANT"
echo "========================="
echo ""

# Queries perigosas (sem liga_id)
echo "🔴 QUERIES SEM LIGA_ID:"
grep -rn "\.find({}\|\.findOne({})" controllers/ routes/ services/
grep -rn "\.find({" controllers/ routes/ services/ | grep -v "liga_id\|ligaId" | grep -v "system_config\|users" | head -20
echo ""

# Rotas sem validação de tenant
echo "🟡 ROTAS SEM VALIDAÇÃO DE TENANT:"
find routes/ -name "*.js" | while read file; do
  if grep -q "router\.\(post\|put\|delete\)" "$file"; then
    if ! grep -q "ligaId\|liga_id" "$file"; then
      echo "  ⚠️  $file"
    fi
  fi
done
echo ""

# Modelos sem índice de liga_id
echo "🟡 MODELS SEM ÍNDICE DE LIGA_ID:"
find models/ -name "*.js" | while read file; do
  if ! grep -q "liga_id.*index\|index.*liga_id" "$file"; then
    echo "  ⚠️  $file"
  fi
done

4.4 Modular Architecture (Super Cartola)

public/
├── js/
│   ├── fluxo-financeiro/          # Módulo isolado
│   │   ├── config.js               # Configurações
│   │   ├── core.js                 # Lógica de negócio
│   │   ├── ui.js                   # Renderização
│   │   └── orchestrator.js         # Orquestração
│   ├── participante/
│   │   ├── fronts/                 # Templates SPA
│   │   ├── modules/                # Módulos isolados
│   │   └── core/                   # Shared utilities
│   └── admin/
│       └── modules/                # Módulos admin

Validação de Modularidade:

# Módulos que violam isolamento (importam de outros módulos)
grep -rn "import.*from.*\.\./\.\." public/js/*/

# Código duplicado entre módulos
find public/js -name "*.js" -exec grep -l "function calcularSaldo" {} \;

# Módulos sem orchestrator
find public/js -type d -name "*-*" | while read dir; do
  if [ ! -f "$dir/orchestrator.js" ]; then
    echo "Sem orchestrator: $dir"
  fi
done

4.5 Dependency Graph Analysis

Crie

/scripts/analyze_dependencies.js
:

const fs = require('fs');
const path = require('path');

function analyzeFile(filePath) {
  const content = fs.readFileSync(filePath, 'utf8');
  const imports = content.match(/require\(['"]([^'"]+)['"]\)/g) || [];
  const exports = content.match(/module\.exports\s*=|exports\./g) || [];
  
  return {
    file: filePath,
    imports: imports.map(i => i.match(/['"]([^'"]+)['"]/)[1]),
    hasExports: exports.length > 0
  };
}

function findCircularDeps(graph) {
  const visited = new Set();
  const stack = new Set();
  const cycles = [];
  
  function dfs(node, path = []) {
    if (stack.has(node)) {
      cycles.push([...path, node]);
      return;
    }
    if (visited.has(node)) return;
    
    visited.add(node);
    stack.add(node);
    path.push(node);
    
    (graph[node] || []).forEach(dep => dfs(dep, [...path]));
    
    stack.delete(node);
  }
  
  Object.keys(graph).forEach(node => dfs(node));
  return cycles;
}

// Executar
const files = require('glob').sync('**/*.js', { ignore: 'node_modules/**' });
const graph = {};

files.forEach(file => {
  const analysis = analyzeFile(file);
  graph[file] = analysis.imports;
});

const cycles = findCircularDeps(graph);
if (cycles.length > 0) {
  console.log('🔴 DEPENDÊNCIAS CIRCULARES ENCONTRADAS:');
  cycles.forEach(cycle => console.log('  ->', cycle.join(' → ')));
} else {
  console.log('✅ Sem dependências circulares');
}

5. 🔄 Reliability & Resilience

5.1 Error Handling Patterns

// 🔴 RUIM: Engolir erros
try { await operation(); } catch (e) { }

// 🔴 RUIM: Throw genérico
throw new Error('Erro');

// 🔴 RUIM: Não propagar contexto
catch (error) {
  console.error(error);
  res.status(500).json({ error: 'Erro interno' });
}

// 🟢 BOM: Error handling completo
try {
  const result = await operation();
  return result;
} catch (error) {
  // 1. Log estruturado
  console.error('[FLUXO-FINANCEIRO] Operation failed', { 
    error: error.message,
    stack: error.stack,
    context: { userId, ligaId, temporada }
  });
  
  // 2. Error classification
  if (error instanceof ValidationError) {
    throw new AppError('Dados inválidos', 400, 'VALIDATION_ERROR');
  }
  if (error instanceof NotFoundError) {
    throw new AppError('Recurso não encontrado', 404, 'NOT_FOUND');
  }
  
  // 3. Fallback e retry
  if (error.code === 'ECONNREFUSED') {
    return await this.retryWithBackoff(operation, 3);
  }
  
  // 4. Throw com contexto
  throw new AppError('Erro interno', 500, 'INTERNAL_ERROR', { originalError: error.message });
}

5.2 Graceful Degradation

# Operações sem timeout
grep -rn "await.*fetch\|await.*axios" --include="*.js" | grep -v "timeout"

# Sem circuit breaker em integrações externas
grep -rn "cartolaApi\|fetch.*cartola" services/

# Sem fallback em features não-críticas
grep -rn "await.*Service\." controllers/ | grep -v "catch\|try"
// Pattern de graceful degradation
async function loadRanking(ligaId, rodada) {
  try {
    // Tentar fonte primária (API Cartola)
    const data = await cartolaService.getRanking(ligaId, rodada);
    return data;
  } catch (error) {
    console.warn('[RANKING] API Cartola falhou, usando cache', error.message);
    
    // Fallback 1: Cache MongoDB
    const cached = await RankingCache.findOne({ liga_id: ligaId, rodada });
    if (cached) return cached.data;
    
    // Fallback 2: Dados parciais
    console.warn('[RANKING] Sem cache, retornando dados parciais');
    return { status: 'degraded', data: await this.getPartialData(ligaId) };
  }
}

5.3 Idempotency Check (Super Cartola Financial)

// ✅ Operações financeiras DEVEM ser idempotentes
class AcertoFinanceiroService {
  async registrarPagamento(participanteId, ligaId, valor, descricao) {
    // Gerar ID idempotente baseado em dados únicos
    const idempotencyKey = crypto
      .createHash('sha256')
      .update(`${participanteId}-${ligaId}-${valor}-${descricao}-${Date.now()}`)
      .digest('hex');
    
    // Verificar se já foi processado
    const existing = await AcertoFinanceiro.findOne({ 
      idempotency_key: idempotencyKey
    });
    
    if (existing) {
      console.log('[ACERTO] Operação já processada (idempotente)', idempotencyKey);
      return { success: true, message: 'Já processado', idempotent: true, data: existing };
    }
    
    // Processar apenas uma vez
    const acerto = await AcertoFinanceiro.create({
      idempotency_key: idempotencyKey,
      participante_id: participanteId,
      liga_id: ligaId,
      tipo: 'pagamento',
      valor,
      descricao,
      data: new Date()
    });
    
    return { success: true, data: acerto, idempotent: false };
  }
}

Script de validação de idempotência:

# Verificar operações financeiras sem idempotency_key
grep -rn "AcertoFinanceiro\.create\|\.insertOne" controllers/ services/ | grep -v "idempotency"

5.4 Retry & Backoff (External APIs)

// Para integrações externas (Cartola API)
async function fetchWithRetry(url, options = {}, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, { 
        ...options, 
        timeout: 5000,
        signal: AbortSignal.timeout(5000)
      });
      
      if (response.ok) return response;
      
      // Retry em erros 5xx
      if (response.status >= 500 && attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
        console.warn(`[RETRY] Tentativa ${attempt}/${maxRetries} falhou, retry em ${delay}ms`);
        await sleep(delay);
        continue;
      }
      
      // Erro 4xx não faz retry
      throw new Error(`HTTP ${response.status}: ${await response.text()}`);
    } catch (error) {
      if (attempt === maxRetries) {
        console.error(`[RETRY] Todas ${maxRetries} tentativas falharam`, error);
        throw error;
      }
      
      const delay = Math.pow(2, attempt) * 1000;
      console.warn(`[RETRY] Erro na tentativa ${attempt}, retry em ${delay}ms`, error.message);
      await sleep(delay);
    }
  }
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

6. 📊 Observability (Logs, Metrics, Tracing)

6.1 Logging Best Practices

LevelQuando UsarExemploArquivo
errorFalhas que precisam açãoDB connection failedToda operação crítica
warnSituações anômalasRate limit approachingFeatures degradadas
infoEventos de negócioParticipante inscritoTransações importantes
debugTroubleshootingQuery params recebidosDesenvolvimento
// 🔴 RUIM
console.log('erro', error);
console.log(participante);

// 🟢 BOM - Structured logging
console.error('[FLUXO-FINANCEIRO] Falha ao calcular saldo', {
  ligaId,
  timeId,
  temporada,
  error: error.message,
  stack: error.stack
});

console.info('[INSCRICAO] Participante inscrito com sucesso', {
  participanteId: participante._id,
  ligaId: liga._id,
  temporada: '2026',
  timestamp: new Date().toISOString()
});

// 🟢 MELHOR - Logger com níveis
const logger = require('./config/logger');
logger.error('Falha ao calcular saldo', { ligaId, timeId, error });
logger.info('Participante inscrito', { participanteId, ligaId });

6.2 Audit Trail (Operações Sensíveis)

// Toda operação financeira deve ser logada
class AuditLogService {
  async log(action, actor, target, payload, req) {
    await AuditLog.create({
      action,                              // 'ACERTO_FINANCEIRO', 'DELETE_PARTICIPANTE'
      actor: actor || 'system',            // Email do admin ou 'system'
      target,                              // { ligaId, timeId, participanteId }
      payload,                             // { valor, tipo, descricao }
      ip: req?.ip,
      userAgent: req?.headers['user-agent'],
      timestamp: new Date()
    });
  }
}

// Usar em controllers críticos
router.post('/acerto-financeiro', verificarAdmin, async (req, res) => {
  const { participanteId, valor, tipo } = req.body;
  
  // Executar operação
  const result = await acertoService.registrar(participanteId, valor, tipo);
  
  // Auditar SEMPRE
  await auditLog.log(
    'ACERTO_FINANCEIRO',
    req.session.admin.email,
    { participanteId, ligaId: req.params.ligaId },
    { valor, tipo },
    req
  );
  
  res.json(result);
});

Script de análise de audit logs:

# Encontrar operações financeiras sem audit
grep -rn "AcertoFinanceiro\|\.updateMany\|\.deleteMany" controllers/ | grep -v "auditLog"

6.3 Health Checks

// Endpoint de health para monitoramento
router.get('/health', async (req, res) => {
  const checks = {
    database: await checkMongoDB(),
    cartolaApi: await checkCartolaAPI(),
    memory: {
      used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
      total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024),
      unit: 'MB'
    },
    uptime: Math.floor(process.uptime()),
    env: process.env.NODE_ENV
  };
  
  const healthy = checks.database.status === 'ok' && checks.cartolaApi.status === 'ok';
  
  res.status(healthy ? 200 : 503).json({
    status: healthy ? 'healthy' : 'degraded',
    checks,
    timestamp: new Date().toISOString()
  });
});

async function checkMongoDB() {
  try {
    await mongoose.connection.db.admin().ping();
    return { status: 'ok', latency: '< 50ms' };
  } catch (error) {
    return { status: 'error', error: error.message };
  }
}

async function checkCartolaAPI() {
  try {
    const start = Date.now();
    await fetch('https://api.cartolafc.globo.com/auth/time/info', { timeout: 3000 });
    const latency = Date.now() - start;
    return { status: 'ok', latency: `${latency}ms` };
  } catch (error) {
    return { status: 'error', error: error.message };
  }
}

6.4 Métricas de Negócio (Super Cartola)

// Métricas importantes para monitorar
class MetricsCollector {
  async collect() {
    return {
      // Métricas de uso
      totalLigas: await Liga.countDocuments(),
      totalParticipantes: await Participante.countDocuments(),
      participantesAtivos: await Participante.countDocuments({ 
        active_seasons: { $in: ['2026'] } 
      }),
      
      // Métricas financeiras
      saldoTotalPositivo: await this.getSaldoTotal('positivo'),
      saldoTotalNegativo: await this.getSaldoTotal('negativo'),
      
      // Métricas de performance
      avgQueryTime: await this.getAvgQueryTime(),
      cacheHitRate: await this.getCacheHitRate(),
      
      // Métricas de API externa
      cartolaApiCalls: this.cartolaApiCallsCount,
      cartolaApiErrors: this.cartolaApiErrorsCount,
      
      timestamp: new Date()
    };
  }
}

// Endpoint de métricas (protegido)
router.get('/metrics', verificarAdmin, async (req, res) => {
  const metrics = await metricsCollector.collect();
  res.json(metrics);
});

7. 🧹 Code Quality & Technical Debt

7.1 Code Smells Severity Matrix

SmellSeveridadeThresholdAçãoScript Detecção
Função > 50 linhas🟡 Médio50 LOCExtrair funções
./scripts/check_function_length.sh
Arquivo > 500 linhas🟡 Médio500 LOCDividir módulo
find . -name "*.js" -exec wc -l {} \; | sort -n
Cyclomatic complexity > 10🔴 Alto10Simplificar lógica
npx complexity-report
Duplicação > 10 linhas🟡 Médio10 LOCExtrair função
npx jscpd
Nesting > 4 níveis🟡 Médio4Early returnGrep com regex
Parâmetros > 5🟡 Médio5Object parameter
grep "function.*(.*, .*, .*, .*, .*, .*)"
TODO/FIXME antigo🟢 Baixo30 diasResolver ou remover
./scripts/check_todos.sh
Console.log em produção🟡 Médio0Remover
grep -rn "console\.log" --exclude-dir=node_modules

7.2 Dead Code Detection

#!/bin/bash
# /scripts/detect_dead_code.sh

echo "🧹 DETECÇÃO DE CÓDIGO MORTO"
echo "==========================="
echo ""

# Código comentado (> 5 linhas)
echo "📝 CÓDIGO COMENTADO:"
find . -name "*.js" ! -path "./node_modules/*" -exec grep -Pzo '(?s)\/\*.*?\*\/' {} \; | grep -c "function\|const\|let"
echo ""

# Console.logs esquecidos
echo "🖨️  CONSOLE.LOGS (remover antes de deploy):"
grep -rn "console\.log" controllers/ routes/ services/ public/js/ --include="*.js" | wc -l
grep -rn "console\.log" controllers/ routes/ services/ public/js/ --include="*.js" | head -10
echo ""

# TODOs e FIXMEs
echo "📌 TODOs/FIXMEs:"
grep -rn "TODO\|FIXME\|HACK\|XXX" --include="*.js" ! -path "./node_modules/*" | wc -l
grep -rn "TODO\|FIXME\|HACK\|XXX" --include="*.js" ! -path "./node_modules/*" | head -10
echo ""

# Funções não exportadas e não usadas
echo "🔇 FUNÇÕES POTENCIALMENTE NÃO USADAS:"
find . -name "*.js" ! -path "./node_modules/*" -exec grep -H "^function\|^const.*= function\|^const.*=>" {} \; | while read line; do
  func=$(echo "$line" | sed 's/.*function \([^(]*\).*/\1/' | sed 's/.*const \([^ =]*\).*/\1/')
  file=$(echo "$line" | cut -d: -f1)
  if ! grep -rq "$func" --exclude="$file" --exclude-dir=node_modules .; then
    echo "  ⚠️  $func em $file"
  fi
done | head -10
echo ""

# Imports não utilizados
echo "📦 IMPORTS NÃO UTILIZADOS:"
find . -name "*.js" ! -path "./node_modules/*" -exec grep -H "^const.*require\|^import" {} \; | while read line; do
  var=$(echo "$line" | sed "s/.*const \([^ =]*\).*/\1/" | sed "s/.*import \([^ ]*\).*/\1/")
  file=$(echo "$line" | cut -d: -f1)
  content=$(cat "$file")
  # Contar ocorrências (deve ter mais de 1 - a própria declaração)
  count=$(echo "$content" | grep -o "$var" | wc -l)
  if [ "$count" -le 1 ]; then
    echo "  ⚠️  $var em $file"
  fi
done | head -10

7.3 Dependency Health

#!/bin/bash
# /scripts/check_dependencies.sh

echo "📦 ANÁLISE DE DEPENDÊNCIAS"
echo "========================="
echo ""

# Pacotes desatualizados
echo "🔄 PACOTES DESATUALIZADOS:"
npm outdated 2>/dev/null || echo "Nenhum"
echo ""

# Vulnerabilidades
echo "🔒 VULNERABILIDADES:"
npm audit --json 2>/dev/null | jq '.metadata.vulnerabilities'
echo ""

# Dependências não utilizadas
echo "🗑️  DEPENDÊNCIAS NÃO UTILIZADAS:"
npx depcheck --json 2>/dev/null | jq '.dependencies'
echo ""

# Dependências duplicadas
echo "🔀 DEPENDÊNCIAS DUPLICADAS:"
npm ls 2>&1 | grep -E "├─|└─" | sort | uniq -d
echo ""

# Tamanho do node_modules
echo "📊 TAMANHO NODE_MODULES:"
du -sh node_modules 2>/dev/null || echo "N/A"

7.4 Complexity Analysis

Crie

/scripts/complexity_report.js
:

const fs = require('fs');
const path = require('path');
const glob = require('glob');

function calculateComplexity(code) {
  // Contar estruturas de decisão
  const ifCount = (code.match(/\bif\s*\(/g) || []).length;
  const forCount = (code.match(/\bfor\s*\(/g) || []).length;
  const whileCount = (code.match(/\bwhile\s*\(/g) || []).length;
  const switchCount = (code.match(/\bswitch\s*\(/g) || []).length;
  const caseCount = (code.match(/\bcase\s+/g) || []).length;
  const ternaryCount = (code.match(/\?[^:]+:/g) || []).length;
  const logicalCount = (code.match(/&&|\|\|/g) || []).length;
  
  return 1 + ifCount + forCount + whileCount + switchCount + caseCount + ternaryCount + logicalCount;
}

function analyzeFunctions(filePath) {
  const content = fs.readFileSync(filePath, 'utf8');
  const functions = content.match(/function\s+(\w+)|(\w+)\s*=\s*function|(\w+)\s*=\s*\([^)]*\)\s*=>/g) || [];
  
  return functions.map(func => {
    const name = func.match(/function\s+(\w+)|(\w+)\s*=/)[1] || func.match(/(\w+)\s*=/)[1];
    // Encontrar corpo da função
    const funcStart = content.indexOf(func);
    const funcBody = content.substring(funcStart, content.indexOf('}', funcStart) + 1);
    
    return {
      name,
      complexity: calculateComplexity(funcBody),
      lines: funcBody.split('\n').length
    };
  });
}

// Executar
const files = glob.sync('**/*.js', { 
  ignore: ['node_modules/**', 'test/**', '*.test.js'] 
});

const report = {};
files.forEach(file => {
  const functions = analyzeFunctions(file);
  const highComplexity = functions.filter(f => f.complexity > 10);
  
  if (highComplexity.length > 0) {
    report[file] = highComplexity;
  }
});

console.log('🔴 FUNÇÕES COM ALTA COMPLEXIDADE (>10):');
Object.entries(report).forEach(([file, functions]) => {
  console.log(`\n📄 ${file}`);
  functions.forEach(f => {
    console.log(`  ⚠️  ${f.name}: complexity=${f.complexity}, lines=${f.lines}`);
  });
});

7.5 Refactoring Priorities (Quadrant)

                    IMPACTO ALTO
                         │
    ┌────────────────────┼────────────────────┐
    │                    │                    │
    │   QUICK WINS       │    MAJOR PROJECTS  │
    │   (Fazer agora)    │    (Planejar)      │
    │   - Console.logs   │    - Multi-tenant  │
    │   - TODOs antigos  │    - Cache strategy│
    │   - Duplicação     │    - Refactor APIs │
────┼────────────────────┼────────────────────┼──── ESFORÇO
    │                    │                    │
    │   FILL-INS         │    THANKLESS       │
    │   (Tempo livre)    │    (Evitar)        │
    │   - Renomear vars  │    - Over-engineer │
    │   - Comentários    │    - Micro-optim.  │
    └────────────────────┼────────────────────┘
                         │
                    IMPACTO BAIXO

Script de priorização:

#!/bin/bash
# /scripts/refactor_priorities.sh

echo "📊 PRIORIDADES DE REFATORAÇÃO"
echo "=============================="
echo ""

# QUICK WINS (Alto impacto, Baixo esforço)
echo "🟢 QUICK WINS:"
echo "  1. Remover console.logs: $(grep -rn 'console\.log' controllers/ routes/ | wc -l) ocorrências"
echo "  2. Resolver TODOs: $(grep -rn 'TODO\|FIXME' --include='*.js' | wc -l) itens"
echo "  3. Adicionar .lean() em queries: $(grep -rn '\.find\|\.findOne' controllers/ | grep -v 'lean' | wc -l) queries"
echo ""

# MAJOR PROJECTS (Alto impacto, Alto esforço)
echo "🔴 MAJOR PROJECTS:"
echo "  1. Auditoria multi-tenant completa"
echo "  2. Implementar cache strategy unificada"
echo "  3. Refatorar serviços externos (retry + circuit breaker)"
echo ""

# FILL-INS (Baixo impacto, Baixo esforço)
echo "🟡 FILL-INS:"
echo "  1. Padronizar nomes de variáveis"
echo "  2. Adicionar JSDoc em funções públicas"
echo "  3. Organizar imports"

8. 🧪 Testing Coverage

8.1 Test Strategy Matrix

TipoCobertura IdealFocoFerramentas
Unit80%+Services, Utils, Core logicJest, Mocha
Integration60%+Controllers, Routes, DBSupertest
E2EFluxos críticosLogin, Pagamentos, InscriçãoPlaywright, Cypress
ContractAPIs externasCartola APIPact, MSW
PerformanceEndpoints críticosRanking, TesourariaArtillery, k6

8.2 Verificar Cobertura de Testes

#!/bin/bash
# /scripts/check_test_coverage.sh

echo "🧪 COBERTURA DE TESTES"
echo "====================="
echo ""

# Rodar testes com coverage
npm test -- --coverage 2>/dev/null || echo "Sem testes configurados"
echo ""

# Verificar arquivos sem testes
echo "📝 ARQUIVOS SEM TESTES:"
find controllers services -name "*.js" ! -name "*.test.js" | while read f; do
  basename=$(basename "$f" .js)
  testfile="tests/${basename}.test.js"
  if [ ! -f "$testfile" ]; then
    echo "  ⚠️  $f"
  fi
done
echo ""

# Contar testes por módulo
echo "📊 TESTES POR MÓDULO:"
find tests/ -name "*.test.js" 2>/dev/null | while read f; do
  count=$(grep -c "describe\|it\|test" "$f")
  echo "  $f: $count testes"
done

8.3 Test Smells

SmellProblemaSoluçãoComo Detectar
Teste > 50 linhasDifícil manutençãoDividir em cenários
grep -A50 "it('"
Muitos mocksAcoplamentoRefatorar código
grep -c "jest.mock|sinon.stub"
Teste flakyDependência externaIsolar com mocksExecutar 10x e ver falhas
Sleep em testeLento e frágilUsar eventos/promises
grep "sleep|setTimeout" tests/
Sem assertionsTeste inútilVerificar retorno
grep -L "expect|assert" tests/*.test.js
Setup duplicadoManutenção difícilbeforeEach
grep -c "const.*new" tests/*.test.js

8.4 Test Templates (Super Cartola)

// Template para testes de Controller
describe('FluxoFinanceiroController', () => {
  let req, res, controller;
  
  beforeEach(() => {
    req = {
      params: { ligaId: '684cb1c8af923da7c7df51de' },
      session: { participante: { _id: 'participante123' } }
    };
    res = {
      json: jest.fn(),
      status: jest.fn().mockReturnThis()
    };
    controller = new FluxoFinanceiroController();
  });
  
  describe('getSaldo', () => {
    it('deve retornar saldo calculado corretamente', async () => {
      // Arrange
      const expectedSaldo = 105.40;
      jest.spyOn(controller.service, 'calcularSaldo').mockResolvedValue(expectedSaldo);
      
      // Act
      await controller.getSaldo(req, res);
      
      // Assert
      expect(res.json).toHaveBeenCalledWith({ saldo: expectedSaldo });
    });
    
    it('deve retornar erro 500 em falha', async () => {
      // Arrange
      jest.spyOn(controller.service, 'calcularSaldo').mockRejectedValue(new Error('DB error'));
      
      // Act
      await controller.getSaldo(req, res);
      
      // Assert
      expect(res.status).toHaveBeenCalledWith(500);
      expect(res.json).toHaveBeenCalledWith({ error: expect.any(String) });
    });
  });
});

// Template para testes de Service
describe('FluxoFinanceiroService', () => {
  let service, mockDB;
  
  beforeEach(() => {
    mockDB = {
      Rodada: { find: jest.fn() },
      AcertoFinanceiro: { find: jest.fn() }
    };
    service = new FluxoFinanceiroService(mockDB);
  });
  
  describe('calcularSaldo', () => {
    it('deve somar rodadas e acertos corretamente', async () => {
      // Arrange
      mockDB.Rodada.find.mockResolvedValue([
        { ganho_rodada: 20.00 },
        { ganho_rodada: -10.00 }
      ]);
      mockDB.AcertoFinanceiro.find.mockResolvedValue([
        { tipo: 'pagamento', valor: 100.00 }
      ]);
      
      // Act
      const saldo = await service.calcularSaldo('participante123', 'liga123', '2026');
      
      // Assert
      expect(saldo).toBe(110.00); // 20 - 10 + 100
    });
  });
});

9. 🛠️ Comandos de Diagnóstico Avançado

9.1 Análise Completa (Master Script)

Crie

/scripts/audit_full.sh
:

#!/bin/bash
echo "╔══════════════════════════════════════════════╗"
echo "║   AUDITORIA COMPLETA - SUPER CARTOLA         ║"
echo "╚══════════════════════════════════════════════╝"
echo ""
echo "📅 Data: $(date)"
echo "🔍 Escopo: $(pwd)"
echo ""

# ========== MÉTRICAS GERAIS ==========
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📊 MÉTRICAS GERAIS"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
total_js=$(find . -name '*.js' ! -path './node_modules/*' | wc -l)
total_lines=$(find . -name '*.js' ! -path './node_modules/*' -exec cat {} \; | wc -l)
echo "  📄 Arquivos JS: $total_js"
echo "  📝 Linhas totais: $total_lines"
echo "  📦 Dependencies: $(cat package.json | jq '.dependencies | length')"
echo "  🛠️  DevDependencies: $(cat package.json | jq '.devDependencies | length')"
echo ""

# ========== SEGURANÇA ==========
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🔐 SEGURANÇA"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
rotas_desprotegidas=$(grep -rn "router\.\(post\|put\|delete\)" routes/ 2>/dev/null | grep -v "verificar" | wc -l)
console_logs=$(grep -rn "console\.log" controllers/ routes/ services/ 2>/dev/null | wc -l)
secrets=$(grep -rn "password\s*[:=]\s*['\"]" --include="*.js" 2>/dev/null | grep -v "process\.env\|\.example" | wc -l)

echo "  🔴 Rotas sem auth: $rotas_desprotegidas"
echo "  🟡 Console.logs: $console_logs"
echo "  🔴 Secrets hardcoded: $secrets"
echo "  🔒 Vulnerabilidades NPM:"
npm audit --json 2>/dev/null | jq -r '.metadata.vulnerabilities | to_entries[] | "    \(.key): \(.value)"'
echo ""

# ========== MULTI-TENANT ==========
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🏢 MULTI-TENANT ISOLATION"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
queries_sem_tenant=$(grep -rn "\.find({" controllers/ routes/ 2>/dev/null | grep -v "liga_id\|ligaId\|system_config\|users" | wc -l)
echo "  🔴 Queries sem liga_id: $queries_sem_tenant"
if [ $queries_sem_tenant -gt 0 ]; then
  echo "  📋 Exemplos:"
  grep -rn "\.find({" controllers/ routes/ 2>/dev/null | grep -v "liga_id\|ligaId\|system_config\|users" | head -5 | sed 's/^/    /'
fi
echo ""

# ========== PERFORMANCE ==========
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "⚡ PERFORMANCE"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
queries_sem_lean=$(grep -rn "\.find\|\.findOne" controllers/ 2>/dev/null | grep -v "\.lean()" | wc -l)
n_plus_one=$(grep -rn "for.*await.*find\|forEach.*await" controllers/ 2>/dev/null | wc -l)
echo "  🟡 Queries sem .lean(): $queries_sem_lean"
echo "  🔴 Possíveis N+1: $n_plus_one"
echo "  📦 Bundles grandes (>100KB):"
find public/js -name "*.js" -size +100k -exec ls -lh {} \; 2>/dev/null | awk '{print "    " $9 " - " $5}'
echo ""

# ========== QUALIDADE DE CÓDIGO ==========
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🧹 QUALIDADE DE CÓDIGO"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
todos=$(grep -rn "TODO\|FIXME\|HACK\|XXX" --include="*.js" 2>/dev/null | wc -l)
arquivos_grandes=$(find . -name "*.js" ! -path "./node_modules/*" -exec wc -l {} \; | awk '$1 > 500 {print $0}' | wc -l)
echo "  📌 TODOs/FIXMEs: $todos"
echo "  📄 Arquivos >500 linhas: $arquivos_grandes"
if [ $arquivos_grandes -gt 0 ]; then
    echo "  📋 Arquivos grandes:"
    find . -name "*.js" ! -path "./node_modules/*" -exec wc -l {} \; | awk '$1 > 500 {print "    " $2 " - " $1 " linhas"}' | sort -t'-' -k2 -nr | head -5
fi
echo ""

# ========== TESTES ==========
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🧪 COBERTURA DE TESTES"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
total_tests=$(find tests/ -name "*.test.js" 2>/dev/null | wc -l)
total_controllers=$(find controllers/ -name "*.js" 2>/dev/null | wc -l)
echo "  📊 Arquivos de teste: $total_tests"
echo "  📊 Controllers: $total_controllers"
if [ $total_controllers -gt 0 ]; then
  coverage=$((total_tests * 100 / total_controllers))
  echo "  📈 Cobertura estimada: ${coverage}%"
fi
echo ""

# ========== SCORE FINAL ==========
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🎯 SCORE SPARC"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

# Cálculo de scores (1-5)
security_score=5
[ $rotas_desprotegidas -gt 5 ] && security_score=3
[ $secrets -gt 0 ] && security_score=2
[ $queries_sem_tenant -gt 10 ] && security_score=1

performance_score=5
[ $queries_sem_lean -gt 20 ] && performance_score=3
[ $n_plus_one -gt 5 ] && performance_score=2

architecture_score=5
[ $queries_sem_tenant -gt 5 ] && architecture_score=3
[ $arquivos_grandes -gt 10 ] && architecture_score=2

reliability_score=4 # Placeholder

quality_score=5
[ $console_logs -gt 50 ] && quality_score=3
[ $todos -gt 100 ] && quality_score=2

total_score=$((security_score + performance_score + architecture_score + reliability_score + quality_score))

echo "  🛡️  Security:     $security_score/5"
echo "  ⚡ Performance:  $performance_score/5"
echo "  🏗️  Architecture: $architecture_score/5"
echo "  🔄 Reliability:  $reliability_score/5"
echo "  🧹 Code Quality: $quality_score/5"
echo "  ═══════════════════════"
echo "  📊 TOTAL:        $total_score/25"
echo ""

# Status final
if [ $total_score -ge 20 ]; then
  echo "✅ STATUS: EXCELENTE"
elif [ $total_score -ge 15 ]; then
  echo "🟡 STATUS: BOM (melhorias recomendadas)"
elif [ $total_score -ge 10 ]; then
  echo "🟠 STATUS: REGULAR (ação necessária)"
else
  echo "🔴 STATUS: CRÍTICO (refatoração urgente)"
fi

echo ""
echo "═══════════════════════════════════════════════"
echo "📝 Relatório completo salvo em: audit_$(date +%Y%m%d).log"

Executar:

bash scripts/audit_full.sh | tee audit_$(date +%Y%m%d).log

9.2 Busca por Padrões Específicos (Super Cartola)

#!/bin/bash
# /scripts/audit_super_cartola_patterns.sh

echo "🔍 PADRÕES ESPECÍFICOS - SUPER CARTOLA"
echo "======================================"
echo ""

# Inconsistência de tipos (liga_id String vs ObjectId)
echo "🔴 INCONSISTÊNCIA DE TIPOS:"
grep -rn "liga_id.*String\|String.*liga_id" controllers/ routes/ models/
echo ""

# Queries multi-tenant sem filtro
echo "🔴 QUERIES SEM MULTI-TENANT:"
grep -rn "\.find({" controllers/ | grep -v "liga_id\|ligaId" | grep -v "system_config\|users" | head -10
echo ""

# Cache sem invalidação
echo "🟡 CACHE SEM INVALIDAÇÃO:"
grep -rn "\.findOneAndUpdate\|\.updateMany" controllers/ | grep -v "invalidar\|limpar.*cache\|clearCache"
echo ""

# Temporada hardcoded
echo "🟡 TEMPORADA HARDCODED:"
grep -rn "temporada.*2025\|temporada.*2026\|'2025'\|'2026'" controllers/ routes/ | grep -v "CURRENT_SEASON\|seasons\.js"
echo ""

# Acertos financeiros sem idempotência
echo "🔴 OPERAÇÕES FINANCEIRAS SEM IDEMPOTÊNCIA:"
grep -rn "AcertoFinanceiro\.create" controllers/ services/ | grep -v "idempotency"
echo ""

# Exports sem padrão Mobile Dark HD
echo "🟡 EXPORTS SEM PADRÃO:"
grep -rn "html2canvas\|exportar" public/js/ controllers/ | grep -v "mobileDarkHD\|exportConfig"
echo ""

# IndexedDB sem TTL
echo "🟡 INDEXEDDB SEM TTL:"
grep -rn "db\..*\.put\|db\..*\.add" public/js/ | grep -v "timestamp\|ttl\|expiresAt"

10. 📋 Templates de Relatório

10.1 Relatório Executivo (SPARC)

# 📊 Auditoria de Código - Super Cartola Manager

**Data:** 2026-01-16
**Auditor:** Code Inspector (Senior)
**Escopo:** Sistema completo (Backend + Frontend)
**Versão:** 2026.1

---

## Scores SPARC

| Dimensão | Score | Status | Prioridade |
|----------|-------|--------|------------|
| 🛡️ Security | 3/5 | 🟡 ATENÇÃO | P1 |
| ⚡ Performance | 4/5 | 🟢 BOM | P2 |
| 🏗️ Architecture | 3/5 | 🟡 ATENÇÃO | P1 |
| 🔄 Reliability | 4/5 | 🟢 BOM | P3 |
| 🧹 Code Quality | 3/5 | 🟡 ATENÇÃO | P2 |
| **TOTAL** | **17/25** | 🟡 **BOM** | - |

**Tendência:** ⬆️ Melhorando (vs mês anterior: 15/25)

---

## 🔴 Achados Críticos (Bloqueia Deploy)

### CRIT-001: Queries sem Multi-Tenant Isolation
- **Severidade:** 🔴 CRÍTICO
- **Impacto:** Data leakage entre ligas
- **Localização:** 
  - `controllers/rankingController.js:42`
  - `routes/participante-routes.js:78`
- **Ação:** Adicionar filtro `liga_id` em TODAS as queries
- **Prazo:** Imediato

### CRIT-002: Operações Financeiras sem Idempotência
- **Severidade:** 🔴 CRÍTICO
- **Impacto:** Duplicação de pagamentos
- **Localização:** `controllers/acertoFinanceiroController.js`
- **Ação:** Implementar `idempotency_key` pattern
- **Prazo:** 24h

---

## 🟡 Achados Importantes (Resolver em 48h)

### IMPT-001: Queries sem .lean() (Performance)
- **Severidade:** 🟡 ALTO
- **Impacto:** 5x mais memória em reads
- **Quantidade:** 47 ocorrências
- **Ação:** Adicionar `.lean()` em queries read-only
- **Esforço:** Médio (2h)

### IMPT-002: Console.logs em Produção
- **Severidade:** 🟡 MÉDIO
- **Impacto:** Poluição de logs, possível leak de dados
- **Quantidade:** 84 ocorrências
- **Ação:** Remover ou substituir por logger estruturado
- **Esforço:** Baixo (1h)

---

## 📊 Débito Técnico Identificado

| ID | Item | Esforço | Impacto | Prioridade | Módulo |
|----|------|---------|---------|------------|--------|
| TD-001 | Unificar cache strategy | L (3 dias) | Alto | P1 | Cache |
| TD-002 | Implementar retry em Cartola API | M (1 dia) | Médio | P2 | Services |
| TD-003 | Padronizar exports Mobile HD | M (1 dia) | Baixo | P3 | Frontend |
| TD-004 | Adicionar testes unitários | L (1 semana) | Alto | P2 | Global |
| TD-005 | Refatorar fluxo-financeiro.js (800 LOC) | L (2 dias) | Médio | P2 | Frontend |

**Legenda:** S (Small: <1 dia) | M (Medium: 1-3 dias) | L (Large: >3 dias)

---

## ✅ Recomendações Prioritárias

### 1. Segurança (Imediato)
```bash
# Executar auditoria multi-tenant
bash scripts/audit_multitenant.sh

# Adicionar middleware global de tenant
# Implementar em: middleware/tenant-enforcer.js

2. Performance (Curto prazo)

  • Adicionar
    .lean()
    em queries read-only
  • Implementar índices compostos em MongoDB
  • Otimizar bundles frontend (code splitting)

3. Arquitetura (Médio prazo)

  • Criar camada de Service para lógica de negócio
  • Refatorar controllers grandes (>500 LOC)
  • Implementar padrão Repository para acesso a dados

4. Observabilidade (Curto prazo)

  • Implementar logger estruturado (Winston/Pino)
  • Criar dashboard de métricas (/admin/metrics)
  • Adicionar health checks (/health, /ready)

📈 Progresso vs Roadmap 2026

FeatureStatusPrioridadeDébito Técnico
Multi-tenant isolation🟡 70%P1TD-001
Cache unificado🔴 30%P1TD-001
API resilience🔴 20%P2TD-002
Testes automatizados🔴 15%P2TD-004

🎯 Próximos Passos

  1. Semana 1: Resolver CRIT-001 e CRIT-002
  2. Semana 2: Implementar TD-001 (cache strategy)
  3. Semana 3: Adicionar testes para módulos críticos
  4. Semana 4: Refatoração de controllers grandes

Assinatura: Code Inspector v2.0 Próxima auditoria: 2026-02-16


### 10.2 Pull Request Review Template

```markdown
## Code Review: PR #123 - Implementar Retry em Cartola API

### Decisão: ✅ Aprovado com Mudanças | 🔄 Mudanças Necessárias | ❌ Rejeitado

### Score Geral: 7/10

---

### Checklist SPARC

- [x] 🛡️ Sem vulnerabilidades de segurança
- [x] ⚡ Performance adequada
- [ ] 🏗️ Arquitetura mantida (violação em services/cartolaService.js)
- [x] 🔄 Error handling completo
- [ ] 🧹 Code quality (console.log não removido)
- [ ] 🧪 Testes incluídos

---

### 🟢 Pontos Positivos

1. ✅ Implementação correta de exponential backoff
2. ✅ Timeout configurável por request
3. ✅ Logging estruturado de retries

---

### 🔴 Mudanças Obrigatórias

#### 1. services/cartolaService.js:42
```javascript
// ❌ ANTES
console.log('Retry attempt:', attempt);

// ✅ DEPOIS
logger.warn('[CARTOLA-API] Retry attempt', { 
  attempt, 
  maxRetries, 
  url, 
  error: error.message 
});

2. services/cartolaService.js:78

// ❌ ANTES - Lógica de retry no controller
async function getRanking() {
  const result = await this.fetchWithRetry('/api/ranking');
  return result.data;
}

// ✅ DEPOIS - Extrair para service layer
class CartolaService {
  async getRanking(ligaId) {
    const result = await this.fetchWithRetry('/api/ranking', {
      params: { liga_id: ligaId }
    });
    return result.data;
  }
}

🟡 Sugestões (Não-bloqueantes)

  1. Adicionar circuit breaker pattern para falhas persistentes
  2. Implementar cache de fallback para quando API estiver down
  3. Adicionar métrica de taxa de retry (/metrics)

📝 Comentários por Arquivo

services/cartolaService.js

  • L42: Remover console.log
  • L78: Adicionar validação de ligaId
  • L105: Considerar usar AbortController para timeout

tests/cartolaService.test.js

  • ⚠️ Arquivo não incluído - Adicionar testes unitários

🎯 Próximos Passos

  1. Fazer as mudanças obrigatórias
  2. Adicionar testes unitários
  3. Re-submeter para review
  4. Após merge: Monitorar logs de retry em produção

Reviewer: Code Inspector
Data: 2026-01-16
Próximo review: Após mudanças


---

## 11. 🔧 Workflow de Correção (Senior)

### Antes de Corrigir
1. **Entender impacto** - Quem consome esse código?
2. **Verificar testes** - Existem? Vão quebrar?
3. **Avaliar rollback** - Como reverter se der errado?
4. **Criar branch** - `git checkout -b fix/issue-description`

### Durante a Correção
1. **Branch específica** - `fix/security-auth-middleware`
2. **Commits atômicos** - Um commit por mudança lógica
3. **Manter backward compat** - Não quebrar contratos
4. **Seguir S.D.A.** - Mapear dependências antes de modificar

### Após Corrigir
1. **Testar localmente** - `npm test && npm run dev`
2. **Validar em staging** - Se disponível
3. **Monitorar após deploy** - Logs, métricas, errors
4. **Documentar** - Atualizar CHANGELOG.md

### Commit Message Convention

<type>(<scope>): <description>

[optional body]

[optional footer]


**Tipos:**
- `fix`: Correção de bug
- `feat`: Nova funcionalidade
- `refactor`: Refatoração sem mudar comportamento
- `perf`: Melhoria de performance
- `security`: Correção de segurança
- `docs`: Documentação
- `test`: Adicionar/corrigir testes
- `chore`: Manutenção (deps, build, etc)

**Escopos:** auth, financeiro, participante, liga, cache, api, frontend, etc.

**Exemplo:**

fix(security): adicionar verificarAdmin em rotas de escrita

  • Adiciona middleware verificarAdmin em POST/PUT/DELETE
  • Previne acesso não autorizado a operações sensíveis
  • Ref: CRIT-001 da auditoria 2026-01-16

Closes #123


---

## 12. 🚨 Incident Response

### Quando Encontrar Vulnerabilidade Crítica

#### Classificação de Severidade

| Nível | Critério | Tempo de Resposta | Ação |
|-------|----------|-------------------|------|
| 🔴 P0 - CRÍTICO | Exposição de dados, RCE, SQL Injection | Imediato (0-2h) | Deploy emergencial |
| 🟡 P1 - ALTO | Bypass de auth, XSS, CSRF | 4-8h | Hotfix prioritário |
| 🟢 P2 - MÉDIO | Info disclosure, DoS | 24-48h | Fix no próximo sprint |
| ⚪ P3 - BAIXO | Configuração sub-ótima | 1 semana | Backlog normal |

#### Protocolo de Resposta

**1. Conter (Imediato)**
```bash
# Exemplo: Se encontrou SQL injection em /api/search
# Opção A: Desabilitar feature temporariamente
# - Comentar rota no código
# - Deploy imediato

# Opção B: Rate limit agressivo
# - Adicionar rate-limit específico
# - Monitorar tentativas

2. Avaliar (0-30min)

  • ✅ A vulnerabilidade já foi explorada? (checar logs)
  • ✅ Quantos usuários/dados estão expostos?
  • ✅ Existe POC público?

3. Fix (Depende do P-level)

// Exemplo: Fix de SQL Injection
// ❌ ANTES (vulnerável)
const query = `SELECT * FROM users WHERE email = '${req.body.email}'`;

// ✅ DEPOIS (seguro)
const query = 'SELECT * FROM users WHERE email = ?';
db.execute(query, [req.body.email]);

4. Comunicar

  • Interno: Notificar equipe técnica imediatamente
  • Externo: Se houve exposição, notificar usuários afetados
  • Log: Documentar incidente no
    docs/incidents/YYYY-MM-DD-description.md

5. Post-Mortem

# Incident: SQL Injection em /api/search

**Data:** 2026-01-16
**Severidade:** P0 - CRÍTICO
**Tempo de resolução:** 2h 15min

## Timeline
- 14:00 - Vulnerabilidade descoberta por auditoria
- 14:10 - Rota desabilitada (contenção)
- 15:30 - Fix desenvolvido e testado
- 16:15 - Deploy em produção
- 16:20 - Validação e rollback plan

## Root Cause
Falta de sanitização de input em query dinâmica.

## Impact
- Nenhum exploit confirmado
- 0 usuários afetados

## Fix
- Implementado prepared statements
- Adicionado input validation com Joi
- Adicionado teste específico

## Prevention
- [ ] Adicionar SAST no CI/CD
- [ ] Code review obrigatório para queries SQL
- [ ] Treinamento da equipe em secure coding

6. Prevenir Recorrência

  • ✅ Adicionar teste específico
  • ✅ Atualizar checklist de code review
  • ✅ Documentar pattern correto
  • ✅ Executar auditoria similar em código relacionado

Escalation Matrix

SituaçãoAçãoResponsável
P0 descobertoDeploy emergencial dentro de 2hTech Lead
Exploit ativoNotificar usuários + autoridadesCEO/CTO
Data breachSeguir LGPD/GDPR complianceLegal + Tech
DDoSAtivar CloudFlare/WAFDevOps

13. 📚 Recursos e Ferramentas

Ferramentas Recomendadas

CategoriaFerramentaUso
SASTSonarQube, ESLint SecurityAnálise estática
DASTOWASP ZAP, Burp SuiteTestes dinâmicos
Dependency Scannpm audit, SnykVulnerabilidades em deps
PerformanceLighthouse, k6Benchmarks
MonitoringNew Relic, DatadogAPM
LoggingWinston, PinoLogs estruturados

Scripts Úteis (Resumo)

# Auditoria completa
bash scripts/audit_full.sh

# Segurança
bash scripts/audit_security.sh

# Multi-tenant
bash scripts/audit_multitenant.sh

# Performance
bash scripts/audit_performance.sh

# Qualidade
bash scripts/detect_dead_code.sh

# Dependencies
bash scripts/check_dependencies.sh

# Complexidade
node scripts/complexity_report.js

# Análise de dependências
node scripts/analyze_dependencies.js

14. 🎓 Knowledge Base

Padrões Comuns - Super Cartola

1. Multi-Tenant Query Pattern

// ✅ SEMPRE incluir liga_id
async function getParticipantes(ligaId) {
  return await Participante.find({ liga_id: ligaId }).lean();
}

// ❌ NUNCA fazer queries globais
async function getAllParticipantes() {
  return await Participante.find({}); // ERRADO!
}

2. Financial Calculation Pattern

// ✅ SEMPRE calcular, NUNCA persistir saldo
async function getSaldo(participanteId, ligaId, temporada) {
  const rodadas = await Rodada.find({ participante_id, liga_id, temporada });
  const acertos = await AcertoFinanceiro.find({ participante_id, liga_id, temporada });
  
  return calcularSaldoFromRaw(rodadas, acertos); // Cálculo fresh
}

// ❌ NUNCA salvar saldo calculado
async function saveSaldo(participanteId, saldo) {
  // ERRADO - Vai ficar desatualizado
  await Participante.updateOne({ _id: participanteId }, { saldo });
}

3. Cache Pattern (IndexedDB Frontend)

// ✅ Cache-First com Background Refresh
async function loadData() {
  // 1. Render cache imediatamente
  const cached = await db.table.get(key);
  if (cached && !isStale(cached, TTL)) {
    renderUI(cached);
  }
  
  // 2. Fetch fresh em background
  const fresh = await fetch('/api/data').then(r => r.json());
  await db.table.put({ ...fresh, timestamp: Date.now() });
  
  // 3. Re-render se mudou
  if (JSON.stringify(cached) !== JSON.stringify(fresh)) {
    renderUI(fresh);
  }
}

4. Export Pattern (Mobile Dark HD)

// ✅ Padrão unificado de export
const exportConfig = {
  backgroundColor: '#000',
  scale: 2,
  useCORS: true,
  logging: false,
  width: 1080,
  height: 1920
};

async function exportarModulo(elementId) {
  const element = document.getElementById(elementId);
  const canvas = await html2canvas(element, exportConfig);
  
  // Download
  const link = document.createElement('a');
  link.download = `${elementId}-${Date.now()}.png`;
  link.href = canvas.toDataURL('image/png');
  link.click();
}

15. 🔄 Continuous Improvement

Monthly Audit Checklist

## Auditoria Mensal - Super Cartola

**Mês:** Janeiro/2026
**Auditor:** [Nome]

### SPARC Scores
- [ ] Security: __/5
- [ ] Performance: __/5
- [ ] Architecture: __/5
- [ ] Reliability: __/5
- [ ] Code Quality: __/5

### Tarefas
- [ ] Executar `bash scripts/audit_full.sh`
- [ ] Verificar npm audit (vulnerabilidades)
- [ ] Revisar TODO/FIXME antigos (>30 dias)
- [ ] Analisar logs de erro (ultimas 4 semanas)
- [ ] Revisar métricas de performance
- [ ] Atualizar documentação técnica
- [ ] Code review de PRs pendentes

### Findings
| ID | Descrição | Severidade | Status |
|----|-----------|------------|--------|
| | | | |

### Action Items
1. [ ] ...
2. [ ] ...

**Próxima auditoria:** [Data]

STATUS: 🔐 Code Inspector - ARMED & READY

Versão: 2.0 (Super Cartola Edition)

Última atualização: 2026-01-16