# Resumo do Projeto - Ranking de 350k Consultores CAPES ## O QUE FOI FEITO ### ✅ Sistema de Ranking Completo Implementado **Objetivo:** Classificar TODOS os 300k+ consultores CAPES (governo federal, vai para auditoria) **Arquitetura implementada:** ``` Elasticsearch (ATUACAPES) → Busca 350k consultores com atuações ↓ Oracle REMOTO (CAPES) → Busca coordenações PPG (SUCUPIRA_PAINEL) ↓ Backend Python → Calcula pontuação A+B+C+D ↓ Oracle LOCAL (Docker) → Salva em TB_RANKING_CONSULTOR (cache) ↓ Frontend → Lê tabela paginada (50 por página) ``` --- ## COMPONENTES DE PONTUAÇÃO (Documento Oficial CAPES) ### Componente A - Coordenação CAPES (máx 450 pts) - CA, CAJ, CAJ-MP, CAM - Base + tempo + áreas extras + bônus ativo + retorno - **✅ IMPLEMENTADO E FUNCIONANDO** ### Componente B - Coordenação de Programa PPG (máx 180 pts) - Base: 70 pts - Tempo: 5 pts/ano (máx 50) - Programas extras: 20 pts/programa (máx 40) - Nota PPG: 7=20, 6=15, 5=10, 4=5, 3=0 (máx 20) - **✅ CÓDIGO IMPLEMENTADO MAS NÃO FUNCIONA** (problema de rede) ### Componente C - Consultoria (máx 230 pts) - Consultor ativo/histórico + tempo + eventos + áreas - **✅ IMPLEMENTADO E FUNCIONANDO** ### Componente D - Premiações (máx 180 pts) - Premiações recebidas + avaliações + inscrições - **✅ IMPLEMENTADO E FUNCIONANDO** --- ## ARQUITETURA DO CÓDIGO ### Camadas (Clean Architecture) ``` backend/ ├── src/ │ ├── domain/ # Entidades e regras de negócio │ │ ├── entities/ │ │ │ └── consultor.py # Consultor, Coordenação, Consultoria, etc │ │ ├── services/ │ │ │ └── calculador_pontuacao.py # CÁLCULO DOS 4 COMPONENTES │ │ └── value_objects/ │ │ └── pontuacao.py # ComponentePontuacao, PontuacaoCompleta │ │ │ ├── application/ # Casos de uso e jobs │ │ ├── use_cases/ │ │ │ └── obter_ranking.py │ │ └── jobs/ │ │ ├── processar_ranking.py # JOB PRINCIPAL (350k) │ │ ├── job_status.py # Status em tempo real │ │ └── scheduler.py # Loop asyncio (sem cron) │ │ │ ├── infrastructure/ # Acesso a dados │ │ ├── elasticsearch/ │ │ │ └── client.py # Scroll API para 350k │ │ ├── oracle/ │ │ │ ├── client.py # OracleClient genérico │ │ │ └── ranking_repository.py # CRUD da TB_RANKING_CONSULTOR │ │ └── repositories/ │ │ └── consultor_repository_impl.py # Constrói consultores │ │ │ └── interface/ # API REST │ └── api/ │ ├── app.py # FastAPI + lifespan (conecta Oracles) │ ├── routes.py # Endpoints │ ├── dependencies.py # DUAS CONEXÕES ORACLE │ └── config.py # Settings (lê .env) │ ├── sql/ │ ├── schema_ranking.sql # TB_RANKING_CONSULTOR + SP_ATUALIZAR_POSICOES │ └── schema_ppg.sql # TB_COORDENACAO_PROGRAMA (não usado) │ └── scripts/ └── popular_componente_b.py # Script emergencial (roda no host) ``` --- ## BANCO DE DADOS ### TB_RANKING_CONSULTOR (Oracle LOCAL) ```sql CREATE TABLE TB_RANKING_CONSULTOR ( ID_PESSOA NUMBER(10) PRIMARY KEY, NOME VARCHAR2(200), POSICAO NUMBER(10), PONTUACAO_TOTAL NUMBER(10,2), COMPONENTE_A NUMBER(10,2), COMPONENTE_B NUMBER(10,2), ← PROBLEMA: Está zerado COMPONENTE_C NUMBER(10,2), COMPONENTE_D NUMBER(10,2), ATIVO CHAR(1), ANOS_ATUACAO NUMBER(5,1), DT_CALCULO TIMESTAMP, JSON_DETALHES CLOB ); ``` **Status atual:** 350.215 registros com A, C, D calculados, mas B=0 --- ## CONFIGURAÇÃO (.env) ### Desenvolvimento (atual) ```bash # Elasticsearch ES_URL=http://elastic-atuacapes.hom.capes.gov.br:9200 ES_INDEX=atuacapes ES_USER=admin-atuacapes ES_PASSWORD=O}!S0bj%FhJ: # Oracle LOCAL (Docker) - Para salvar ranking ORACLE_LOCAL_USER=local123 ORACLE_LOCAL_PASSWORD=local123 ORACLE_LOCAL_DSN=oracle18c:1521/XEPDB1 # Oracle REMOTO (CAPES) - Para ler SUCUPIRA_PAINEL ORACLE_REMOTE_USER=FREDERICOAC ORACLE_REMOTE_PASSWORD=FREDEricoac ORACLE_REMOTE_DSN=oracledhtsrv02.hom.capes.gov.br:1521/hom_dr ``` ### Produção (futuro) ```bash # Mesmo Oracle para tudo ORACLE_LOCAL_DSN=oracle-prod.capes:1521/PROD ORACLE_REMOTE_DSN=oracle-prod.capes:1521/PROD # Mesmo! ``` --- ## COMMITS IMPORTANTES ``` f69bcd9 - feat: Implementa job de ranking para 300k consultores c6aaf66 - refactor: Substitui APScheduler por asyncio nativo para OCP e11cdcd - feat: Implementa duas conexões Oracle simultâneas 57ef5a7 - fix: Corrige cálculo de pontuação da nota do PPG no Componente B 178fc2a - docs: Adiciona documentação completa do Componente B (PPG) ``` --- ## O PROBLEMA ATUAL ### Componente B = 0 para todos os 350k consultores **Causa raiz:** Container Docker **não consegue acessar** `oracledhtsrv02.hom.capes.gov.br` porque: - VPN CAPES está no HOST - Container está em rede isolada - DNS não resolve hostname interno da CAPES **Evidências:** ```bash # Dentro do container: oracle_remote_client.is_connected = False # Log do erro: AVISO Oracle: ORA-12154: TNS:could not resolve the connect identifier specified ``` **Resultado:** - Job processa 350k consultores ✅ - Componente A, C, D calculados ✅ - Componente B = 0 (não consulta Oracle REMOTO) ❌ --- ## SOLUÇÕES POSSÍVEIS ### ⭐ SOLUÇÃO 1: Script Standalone (RECOMENDADA - RÁPIDA) **Arquivo criado:** `backend/scripts/popular_componente_b.py` **Como funciona:** - Roda DIRETO NO HOST (não no Docker) - Usa VPN do host para acessar Oracle CAPES - Lê 350k IDs da tabela - Busca PPG do SUCUPIRA_PAINEL - Atualiza COMPONENTE_B em batch de 1000 - Atualiza posições **Executar:** ```bash cd /home/fred/projetos/ranking/backend pip3 install cx-Oracle # Se não tiver python3 scripts/popular_componente_b.py ``` **Tempo estimado:** 20-40 minutos para 350k consultores **Vantagens:** - ✅ Resolve AGORA sem mexer em Docker - ✅ Usa VPN que já está funcionando - ✅ Roda 1x para corrigir os dados - ✅ Depois o job normal funciona (quando tiver em produção) --- ### SOLUÇÃO 2: Extra Hosts no Docker ```yaml # docker-compose.yml backend: extra_hosts: - "oracledhtsrv02.hom.capes.gov.br:IP_DO_SERVIDOR" ``` **Precisa:** Descobrir o IP real de `oracledhtsrv02.hom.capes.gov.br` ```bash nslookup oracledhtsrv02.hom.capes.gov.br ``` --- ### SOLUÇÃO 3: Network Mode Host ```yaml # docker-compose.yml backend: network_mode: "host" # Usa rede do host ``` **Problema:** Perde isolamento, pode conflitar portas --- ## FRONTEND ### Funcionalidades Implementadas **2 Modos de visualização:** 1. **Top N (Rápido)** - Endpoint: `/api/v1/ranking/detalhado?limite=100` - Busca do Elasticsearch + calcula na hora - Bom para top 10/50/100/500 2. **Ranking Completo (300k)** - Endpoint: `/api/v1/ranking/paginado?page=1&size=50` - Lê `TB_RANKING_CONSULTOR` direto - Paginação: 350k consultores, 70k páginas **Componentes:** - ✅ `RankingPaginado.jsx` - Tabela com paginação - ✅ `App.jsx` - Seletor de modo - ✅ Barra de progresso do job em tempo real - ✅ Estatísticas (total, ativos, média, distribuição) - ✅ Botão reprocessar **Acesso:** http://localhost:5173 --- ## JOB DE PROCESSAMENTO ### Scheduler (asyncio nativo - sem cron) **Arquivo:** `backend/src/application/jobs/scheduler.py` **Como funciona:** ```python # Calcula tempo até 3h da manhã proxima_execucao = datetime.now().replace(hour=3, minute=0) await asyncio.sleep(segundos_ate_proxima) await job.executar(limpar_antes=True) # Loop infinito ``` **Execução:** - Automática: Diariamente às 3h - Manual: `POST /api/v1/ranking/processar` **Compatível com OCP/Kubernetes** (não usa cron do sistema) --- ## PERFORMANCE **Máquina atual:** - CPU: 5.8GHz boost - RAM: 64GB DDR5 - Processamento: ~350k consultores em 25-30 minutos **Batch:** - 1.000 consultores por batch - ~350 batches total - MERGE (upsert) em batch --- ## O QUE PRECISA SER FEITO PARA CONCLUIR ### 🎯 ÚNICO PROBLEMA: Componente B zerado **Situação:** - ✅ Código do Componente B está correto e implementado - ✅ Duas conexões Oracle configuradas - ✅ Query SUCUPIRA_PAINEL pronta - ❌ Container Docker não acessa rede CAPES **Solução mais rápida:** 1. **Rodar script standalone:** ```bash cd /home/fred/projetos/ranking/backend python3 scripts/popular_componente_b.py ``` 2. **Ou configurar extra_hosts no docker-compose.yml:** ```bash # Descobrir IP: nslookup oracledhtsrv02.hom.capes.gov.br # Adicionar ao docker-compose.yml: backend: extra_hosts: - "oracledhtsrv02.hom.capes.gov.br:IP_AQUI" ``` 3. **Depois rodar job completo:** ```bash curl -X POST -H "Content-Type: application/json" \ -d '{"limpar_antes": true}' \ http://localhost:8000/api/v1/ranking/processar ``` --- ## VALIDAÇÃO FINAL Quando o Componente B funcionar, verificar: ```sql -- Deve ter consultores com B > 0 SELECT COUNT(*) AS TOTAL, SUM(CASE WHEN COMPONENTE_B > 0 THEN 1 ELSE 0 END) AS COM_PPG, MAX(COMPONENTE_B) AS MAX_B, AVG(COMPONENTE_B) AS MEDIA_B FROM TB_RANKING_CONSULTOR; -- Ver top 5 com PPG SELECT ID_PESSOA, NOME, COMPONENTE_A, COMPONENTE_B, COMPONENTE_C, COMPONENTE_D, PONTUACAO_TOTAL FROM TB_RANKING_CONSULTOR WHERE POSICAO <= 5 ORDER BY POSICAO; ``` **Esperado:** Alguns consultores com B entre 70-180 pts --- ## DOCUMENTAÇÃO GERADA - `COMPONENTE_B_STATUS.md` - Implementação completa do Componente B - `SCHEDULER.md` - Como funciona o scheduler sem cron (OCP) - `backend/sql/schema_ranking.sql` - DDL da tabela principal - `.claude/rules/ranking-*.md` - Regras oficiais e queries --- ## COMANDOS ÚTEIS ### Verificar tabela ```bash echo "SELECT COUNT(*), AVG(COMPONENTE_B) FROM TB_RANKING_CONSULTOR;" | \ sqlplus -S local123/local123@127.0.0.1:1521/XEPDB1 ``` ### Rodar job manualmente ```bash curl -X POST -H "Content-Type: application/json" \ -d '{"limpar_antes": true}' \ http://localhost:8000/api/v1/ranking/processar ``` ### Ver status ```bash curl -s http://localhost:8000/api/v1/ranking/status | python3 -m json.tool ``` ### Ver estatísticas ```bash curl -s http://localhost:8000/api/v1/ranking/estatisticas | python3 -m json.tool ``` --- ## BRANCH E COMMITS **Branch:** `develop` **Últimos commits:** ``` 178fc2a - docs: Adiciona documentação completa do Componente B (PPG) 57ef5a7 - fix: Corrige cálculo de pontuação da nota do PPG no Componente B e11cdcd - feat: Implementa duas conexões Oracle simultâneas f69bcd9 - feat: Implementa job de ranking para 300k consultores c6aaf66 - refactor: Substitui APScheduler por asyncio nativo para OCP ``` --- ## RESUMO EXECUTIVO **Status Geral:** 95% completo **Funciona:** - ✅ 350.215 consultores processados - ✅ Componentes A, C, D calculados corretamente - ✅ Paginação de 350k consultores - ✅ Frontend com 2 modos (Top N + Completo) - ✅ Scheduler asyncio para OCP - ✅ Duas conexões Oracle configuradas - ✅ Performance excelente (~30min para 350k) **Não funciona (1 problema):** - ❌ Componente B = 0 (Container não acessa rede CAPES) **Para resolver:** - Rodar `scripts/popular_componente_b.py` no host (20-40min) - OU configurar DNS/extra_hosts no docker-compose.yml - OU deploy em servidor dentro da rede CAPES **Depois disso:** Sistema 100% funcional e pronto para produção. --- ## CONTEXTO IMPORTANTE - Sistema para GOVERNO FEDERAL - Vai passar por AUDITORIA - Dados REAIS obrigatórios (zero mocks/fakes) - Recursos CAPES intocáveis - Documento técnico oficial deve ser seguido à risca - Ambiente: OCP (sem cron disponível nos PODs) --- ## PRÓXIMA SESSÃO - O QUE FAZER 1. **Verificar VPN CAPES ativa** 2. **Rodar script:** `python3 backend/scripts/popular_componente_b.py` 3. **Validar:** Componente B > 0 em alguns consultores 4. **Testar frontend:** http://localhost:5173 5. **Commit final e push** **Tempo estimado:** 30-60 minutos total