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
This commit is contained in:
473
RESUMO_PROJETO.md
Normal file
473
RESUMO_PROJETO.md
Normal file
@@ -0,0 +1,473 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user