Files
ranking/RESUMO_PROJETO.md
Frederico Castro d1379b4f5c docs: Adiciona resumo completo do projeto de ranking
Documenta:
- Arquitetura implementada (4 componentes)
- Estrutura de código (Clean Architecture)
- Problema atual (Componente B = 0 por rede)
- Soluções propostas (script standalone)
- Comandos úteis e validações
- Status: 95% completo, falta resolver acesso rede CAPES
2025-12-10 05:28:34 -03:00

12 KiB

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)

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)

# 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)

# 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:

# 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:

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

# 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

nslookup oracledhtsrv02.hom.capes.gov.br

SOLUÇÃO 3: Network Mode Host

# 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
    • 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:

# 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:

    cd /home/fred/projetos/ranking/backend
    python3 scripts/popular_componente_b.py
    
  2. Ou configurar extra_hosts no docker-compose.yml:

    # 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:

    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:

-- 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

echo "SELECT COUNT(*), AVG(COMPONENTE_B) FROM TB_RANKING_CONSULTOR;" | \
  sqlplus -S local123/local123@127.0.0.1:1521/XEPDB1

Rodar job manualmente

curl -X POST -H "Content-Type: application/json" \
  -d '{"limpar_antes": true}' \
  http://localhost:8000/api/v1/ranking/processar

Ver status

curl -s http://localhost:8000/api/v1/ranking/status | python3 -m json.tool

Ver estatísticas

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