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.
git clone https://github.com/majiayu000/claude-skill-registry
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"
skills/data/code-inspector/SKILL.mdCode 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)
| # | Vulnerabilidade | Regex/Busca | Severidade | Mitigação |
|---|---|---|---|---|
| A01 | Broken Access Control | Rotas sem middleware auth | 🔴 CRÍTICO | verificarAdmin, verificarParticipante |
| A02 | Cryptographic Failures | md5, sha1 para senhas | 🔴 CRÍTICO | bcrypt com salt rounds >= 10 |
| A03 | Injection | $where, eval(), new Function | 🔴 CRÍTICO | Sanitização, prepared statements |
| A04 | Insecure Design | Sem rate limiting em auth | 🟡 ALTO | express-rate-limit |
| A05 | Security Misconfiguration | origin: '*', debug em prod | 🟡 ALTO | Helmet, CORS restrito |
| A06 | Vulnerable Components | npm audit --json | 🟡 ALTO | Dependabot, audits regulares |
| A07 | Auth Failures | Sessão sem httpOnly/secure | 🔴 CRÍTICO | Cookie flags corretas |
| A08 | Data Integrity | Sem validação de schema | 🟡 MÉDIO | Joi, Zod, express-validator |
| A09 | Logging Failures | Dados sensíveis em logs | 🟡 MÉDIO | Sanitizar PII |
| A10 | SSRF | fetch com URL user-controlled | 🔴 CRÍTICO | Whitelist 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
| Item | Status | Arquivo de Referência | Script Validação |
|---|---|---|---|
| Rate limiting em login | ✓ | routes/admin-auth-routes.js | |
| CSRF protection | ✓ | index.js (csurf) | |
| Helmet headers | ✓ | index.js | |
| Session segura | ✓ | config/replit-auth.js | |
| Sanitização de inputs | ? | Controllers | |
| Multi-tenant isolation | 🔴 | Todas queries com liga_id | |
| Google OAuth tokens | ✓ | config/google-auth.js | |
| Admin vs Participante | ✓ | middleware/auth.js | |
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-Pattern | Impacto | Solução | Script Detecção |
|---|---|---|---|
| N+1 Queries | 100x mais lento | $in, $lookup, bulk | |
| Sem .lean() | 5x mais memória | Adicionar .lean() em reads | |
| Sem índices | Scan completo | createIndex em campos filtrados | |
| Select * | I/O desnecessário | .select('campo1 campo2') | |
| Sort sem índice | In-memory sort | Índice composto incluindo sort | Ver explain plan |
| Skip grande | Lento em paginação | Cursor-based pagination | |
| $where | Execução JS | Operadores nativos | |
| Regex sem âncora | Full scan | /^prefixo/ com índice | |
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étrica | Target | Como Medir | Arquivo Referência |
|---|---|---|---|
| FCP (First Contentful Paint) | < 1.8s | Lighthouse | participante-navigation.js |
| LCP (Largest Contentful Paint) | < 2.5s | Lighthouse | index.html (splash screen) |
| CLS (Cumulative Layout Shift) | < 0.1 | Lighthouse | Evitar height/width dinâmicos |
| TTI (Time to Interactive) | < 3.8s | Lighthouse | Lazy load modules |
| IndexedDB Read | < 50ms | Performance API | cache-manager.js |
| API Response | < 200ms | Network tab | Todas 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ípio | Violação Comum | Como Detectar | Threshold |
|---|---|---|---|
| Single Responsibility | Controller com lógica de negócio | Arquivo > 300 linhas | 300 LOC |
| Open/Closed | Switch/case crescendo | switch.*case em múltiplos lugares | 3+ ocorrências |
| Liskov Substitution | Herança quebrada | Override que muda comportamento | Manual review |
| Interface Segregation | Models muito grandes | Schema > 50 campos | 50 fields |
| Dependency Inversion | Import direto de implementação | Sem camada de abstração | Manual 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/
| Camada | Responsabilidade | Validação | Arquivo |
|---|---|---|---|
| Route | Extrair ligaId dos params | req.params.ligaId | routes/*.js |
| Middleware | Injetar liga_id no req | tenantFilter.js | middleware/tenant.js |
| Controller | Sempre passar para Service | Não assumir default | controllers/*.js |
| Model | Índice composto com liga_id | Schema index | models/*.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
| Level | Quando Usar | Exemplo | Arquivo |
|---|---|---|---|
| error | Falhas que precisam ação | DB connection failed | Toda operação crítica |
| warn | Situações anômalas | Rate limit approaching | Features degradadas |
| info | Eventos de negócio | Participante inscrito | Transações importantes |
| debug | Troubleshooting | Query params recebidos | Desenvolvimento |
// 🔴 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
| Smell | Severidade | Threshold | Ação | Script Detecção |
|---|---|---|---|---|
| Função > 50 linhas | 🟡 Médio | 50 LOC | Extrair funções | |
| Arquivo > 500 linhas | 🟡 Médio | 500 LOC | Dividir módulo | |
| Cyclomatic complexity > 10 | 🔴 Alto | 10 | Simplificar lógica | |
| Duplicação > 10 linhas | 🟡 Médio | 10 LOC | Extrair função | |
| Nesting > 4 níveis | 🟡 Médio | 4 | Early return | Grep com regex |
| Parâmetros > 5 | 🟡 Médio | 5 | Object parameter | |
| TODO/FIXME antigo | 🟢 Baixo | 30 dias | Resolver ou remover | |
| Console.log em produção | 🟡 Médio | 0 | Remover | |
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
| Tipo | Cobertura Ideal | Foco | Ferramentas |
|---|---|---|---|
| Unit | 80%+ | Services, Utils, Core logic | Jest, Mocha |
| Integration | 60%+ | Controllers, Routes, DB | Supertest |
| E2E | Fluxos críticos | Login, Pagamentos, Inscrição | Playwright, Cypress |
| Contract | APIs externas | Cartola API | Pact, MSW |
| Performance | Endpoints críticos | Ranking, Tesouraria | Artillery, 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
| Smell | Problema | Solução | Como Detectar |
|---|---|---|---|
| Teste > 50 linhas | Difícil manutenção | Dividir em cenários | |
| Muitos mocks | Acoplamento | Refatorar código | |
| Teste flaky | Dependência externa | Isolar com mocks | Executar 10x e ver falhas |
| Sleep em teste | Lento e frágil | Usar eventos/promises | |
| Sem assertions | Teste inútil | Verificar retorno | |
| Setup duplicado | Manutenção difícil | beforeEach | |
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
em queries read-only.lean() - 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
| Feature | Status | Prioridade | Débito Técnico |
|---|---|---|---|
| Multi-tenant isolation | 🟡 70% | P1 | TD-001 |
| Cache unificado | 🔴 30% | P1 | TD-001 |
| API resilience | 🔴 20% | P2 | TD-002 |
| Testes automatizados | 🔴 15% | P2 | TD-004 |
🎯 Próximos Passos
- Semana 1: Resolver CRIT-001 e CRIT-002
- Semana 2: Implementar TD-001 (cache strategy)
- Semana 3: Adicionar testes para módulos críticos
- 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)
- Adicionar circuit breaker pattern para falhas persistentes
- Implementar cache de fallback para quando API estiver down
- 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
- Fazer as mudanças obrigatórias
- Adicionar testes unitários
- Re-submeter para review
- 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ção | Ação | Responsável |
|---|---|---|
| P0 descoberto | Deploy emergencial dentro de 2h | Tech Lead |
| Exploit ativo | Notificar usuários + autoridades | CEO/CTO |
| Data breach | Seguir LGPD/GDPR compliance | Legal + Tech |
| DDoS | Ativar CloudFlare/WAF | DevOps |
13. 📚 Recursos e Ferramentas
Ferramentas Recomendadas
| Categoria | Ferramenta | Uso |
|---|---|---|
| SAST | SonarQube, ESLint Security | Análise estática |
| DAST | OWASP ZAP, Burp Suite | Testes dinâmicos |
| Dependency Scan | npm audit, Snyk | Vulnerabilidades em deps |
| Performance | Lighthouse, k6 | Benchmarks |
| Monitoring | New Relic, Datadog | APM |
| Logging | Winston, Pino | Logs 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