6297d135ec145bad0c7660606ea97860a700adf9
Corrige bug onde consultores ativos com vínculos sobrepostos tinham anos_consecutivos zerados incorretamente. Problema: Ao mesclar períodos sobrepostos (ex: UP encerrado + UTFPR ativo), o período mesclado era marcado como encerrado, resultando em anos_consecutivos = 0 mesmo para consultores ativos. Solução: Período mesclado é ativo se QUALQUER um dos períodos originais for ativo (lógica OR em vez de considerar apenas o primeiro período). Impacto: - Consultores ativos com múltiplos vínculos agora recebem corretamente bônus de continuidade (até +20 pontos) - Exemplo: Valdir Fernandes (#1) tinha 0 anos consecutivos, agora tem 10 Otimizações adicionais: - Aumenta batch_size de 5.000 para 10.000 consultores - Reduz tempo de processamento de ~60min para ~25min (58% mais rápido) - Reduz requisições ao Elasticsearch pela metade Arquivos alterados: - backend/src/domain/value_objects/periodo.py: lógica de mesclagem corrigida - backend/src/application/jobs/processar_ranking.py: batch_size otimizado Testado com 350.222 consultores em 25min 35s
Sistema de Ranking de Consultores CAPES
Sistema completo de ranking de consultores CAPES baseado na Minuta Técnica, desenvolvido com arquitetura DDD (Domain-Driven Design).
Arquitetura
Backend (Python + FastAPI + DDD)
- Domain Layer: Entities, Value Objects, Domain Services
- Application Layer: Use Cases, DTOs
- Infrastructure Layer: Repositories, Elasticsearch Client, Oracle Client
- Interface Layer: FastAPI Routes, Schemas, Dependencies
Frontend (React + Vite)
- Interface moderna baseada no layout do HTML de referência
- Componentes reutilizáveis
- Integração com API via Axios
- Design responsivo
Estrutura do Projeto
ranking/
├── backend/
│ ├── src/
│ │ ├── domain/
│ │ │ ├── entities/
│ │ │ │ └── consultor.py
│ │ │ ├── value_objects/
│ │ │ │ ├── periodo.py
│ │ │ │ └── pontuacao.py
│ │ │ ├── repositories/
│ │ │ │ └── consultor_repository.py
│ │ │ └── services/
│ │ │ └── calculador_pontuacao.py
│ │ ├── application/
│ │ │ ├── dtos/
│ │ │ │ └── consultor_dto.py
│ │ │ └── use_cases/
│ │ │ ├── obter_ranking.py
│ │ │ └── obter_consultor.py
│ │ ├── infrastructure/
│ │ │ ├── elasticsearch/
│ │ │ │ └── client.py
│ │ │ ├── oracle/
│ │ │ │ └── client.py
│ │ │ └── repositories/
│ │ │ └── consultor_repository_impl.py
│ │ └── interface/
│ │ ├── api/
│ │ │ ├── app.py
│ │ │ ├── routes.py
│ │ │ ├── config.py
│ │ │ └── dependencies.py
│ │ └── schemas/
│ │ └── consultor_schema.py
│ ├── pyproject.toml
│ ├── Dockerfile
│ └── .env.example
│
├── frontend/
│ ├── src/
│ │ ├── components/
│ │ │ ├── Header.jsx
│ │ │ ├── Header.css
│ │ │ ├── ConsultorCard.jsx
│ │ │ └── ConsultorCard.css
│ │ ├── services/
│ │ │ └── api.js
│ │ ├── App.jsx
│ │ ├── App.css
│ │ ├── main.jsx
│ │ └── index.css
│ ├── package.json
│ ├── vite.config.js
│ ├── Dockerfile
│ └── nginx.conf
│
├── docker-compose.yml
├── .env.example
├── .gitignore
└── README.md
Critérios de Pontuação V2
Baseado na Minuta Técnica - Ranking AtuaCAPES v2.0
Bloco A: Coordenação CAPES
| Código | Função | Base | Tempo | Teto Tempo | Bônus Atualidade | Bônus Retorno | Teto |
|---|---|---|---|---|---|---|---|
| CA | Coordenador de Área | 200 | 10 pts/ano | 100 | +30 | +20 | 450 |
| CAJ | Coordenador Adjunto | 150 | 8 pts/ano | 80 | +20 | +15 | 370 |
| CAJ_MP | Coord. Adjunto MP | 120 | 6 pts/ano | 60 | +15 | +10 | 315 |
| CAM | Câmara Temática | 100 | 5 pts/ano | 50 | +20 | +10 | 280 |
Regras:
- Tempo = anos completos × multiplicador (respeitando teto)
- Bônus Atualidade: apenas se mandato vigente
- Bônus Retorno: se houve retorno após período de inatividade
Bloco B: Coordenação de Programa PPG (máx 180 pts)
| Critério | Pontuação |
|---|---|
| Base | 70 pts |
| Tempo | 5 pts/ano (máx 50) |
| Programas extras | 20 pts/programa (máx 40) |
| Bônus por nota PPG | até 20 pts |
Nota: Bloco B = 0 no V1 (dados incompletos no AtuaCAPES)
Bloco C: Consultoria (máx 230 pts)
| Código | Situação | Base | Tempo | Teto Tempo | Continuidade 8a+ | Retorno | Teto |
|---|---|---|---|---|---|---|---|
| CONS_ATIVO | Ativo | 150 | 5 pts/ano | 50 | +20 | +15 | 230 |
| CONS_HIST | Histórico | 100 | 5 pts/ano | 50 | +20 | - | 230 |
| CONS_FALECIDO | Falecido | 100 | - | - | +20 | - | 230 |
Regras:
- Bônus Continuidade: aplicado se >= 8 anos consecutivos
- Bônus Retorno: apenas para CONS_ATIVO com reativação
- CONS_FALECIDO não pontua por tempo
Bloco D: Premiações, Avaliações e Participações
Inscrições
| Código | Descrição | Base | Teto |
|---|---|---|---|
| INSC_AUTOR | Autoinscrição | 10 | 20 |
| INSC_INST | Inscrição Institucional | 30 | 60 |
Avaliação de Comissão
| Código | Descrição | Base | Teto |
|---|---|---|---|
| AVAL_COMIS_PREMIO | Avaliador Prêmio | 30 | 60 |
| AVAL_COMIS_GP | Avaliador Grande Prêmio | 50 | 80 |
Coordenação de Comissão
| Código | Descrição | Base | Teto |
|---|---|---|---|
| COORD_COMIS_PREMIO | Coord. Comissão Prêmio | 50 | 100 |
| COORD_COMIS_GP | Coord. Comissão GP | 60 | 120 |
Premiações Recebidas
| Código | Descrição | Base | Teto |
|---|---|---|---|
| PREMIACAO | Grande Prêmio CAPES | 100 | 180 |
| PREMIACAO_GP | Prêmio CAPES de Tese | 50 | 60 |
| MENCAO | Menção Honrosa | 30 | 30 |
Bolsas CNPq
| Código | Descrição | Base | Teto |
|---|---|---|---|
| BOL_BPQ_SUPERIOR | Bolsa PQ nível 1A/1B/1C | 30 | 60 |
| BOL_BPQ_INTERMEDIARIO | Bolsa PQ nível 1D/2 | 50 | 100 |
Participações
| Código | Descrição | Base | Teto |
|---|---|---|---|
| EVENTO | Participação em Evento | 1 | 5 |
| PROJ | Participação em Projeto | 10 | 40 |
Orientações
| Código | Descrição | Base | Teto |
|---|---|---|---|
| ORIENT_POS_DOC | Orientação Pós-Doc | 15 | 100 |
| ORIENT_TESE | Orientação Tese | 10 | 50 |
| ORIENT_DISS | Orientação Dissertação | 5 | 25 |
| CO_ORIENT_POS_DOC | Co-Orientação Pós-Doc | 7 | 35 |
| CO_ORIENT_TESE | Co-Orientação Tese | 5 | 25 |
| CO_ORIENT_DISS | Co-Orientação Dissertação | 3 | 15 |
Bancas
| Código | Descrição | Base | Teto |
|---|---|---|---|
| MB_BANCA_POS_DOC | Banca Pós-Doc | 3 | 15 |
| MB_BANCA_TESE | Banca Tese | 3 | 15 |
| MB_BANCA_DISS | Banca Dissertação | 2 | 10 |
Selos Visuais (sem pontuação)
Indicadores visuais que aparecem no card do consultor:
| Selo | Descrição | Ícone |
|---|---|---|
| Coord. PPG | Coordenador de Programa | 🎓 |
| Presid. Câmara | Presidente de Câmara Temática | 🏛️ |
| Bolsista PQ | Bolsista de Produtividade CNPq | 🔬 |
| Grande Prêmio | Vencedor do Grande Prêmio | 🏆 |
| Prêmio | Vencedor de Prêmio | 🥇 |
| Menção Honrosa | Menção Honrosa | 🎖️ |
| Orientações | Orient. Pós-Doc/Tese/Diss | 📚📖📝 |
| Co-Orientações | Co-Orient. Pós-Doc/Tese/Diss | 📚📖📝 |
Fórmula de Cálculo
Score_Atuação = min(Base + Tempo + Bônus, Teto)
Score_Total = Bloco_A + Bloco_B + Bloco_C + Bloco_D
Requisitos
- Python 3.11+
- Node.js 18+
- Docker e Docker Compose (opcional)
- Acesso ao Elasticsearch (ATUACAPES)
- Acesso ao Oracle
Setup Local
Backend
- Entre no diretório do backend:
cd backend
- Crie ambiente virtual e instale dependências:
poetry install
- Configure as variáveis de ambiente:
cp .env.example .env
- Edite
.envcom suas credenciais:
ES_URL=http://seu-elasticsearch:9200
ES_INDEX=atuacapes
ES_USER=seu_usuario_elastic
ES_PASSWORD=sua_senha_elastic
ORACLE_USER=seu_usuario
ORACLE_PASSWORD=sua_senha
ORACLE_DSN=host:1521/service_name
- Execute o backend:
poetry run python src/main.py
A API estará disponível em http://localhost:8010
Frontend
- Entre no diretório do frontend:
cd frontend
- Instale dependências:
npm install
- Execute em modo desenvolvimento:
npm run dev
O frontend estará disponível em http://localhost:5173
Setup com Docker
- Configure as variáveis de ambiente:
cp .env.example .env
-
Edite
.envcom suas credenciais -
Execute com Docker Compose:
docker-compose up -d
- Backend:
http://localhost:8010 - Frontend:
http://localhost
Endpoints da API
GET /api/v1/ranking
Retorna o ranking resumido de consultores.
Query Parameters:
limite(int, default=100): Limite de consultoresoffset(int, default=0): Offset para paginaçãocomponente(str, optional): Filtrar por componente (a, b, c, d)
GET /api/v1/ranking/detalhado
Retorna o ranking completo com todos os detalhes.
Query Parameters:
limite(int, default=100): Limite de consultorescomponente(str, optional): Filtrar por componente (a, b, c, d)
GET /api/v1/consultor/{id_pessoa}
Retorna detalhes completos de um consultor específico.
GET /api/v1/health
Health check da API.
Fontes de Dados
Elasticsearch (ATUACAPES)
- Índice:
atuacapes__1763197236 - Campos:
id,dadosPessoais,atuacoes - Tipos de atuação:
- Coordenação de Área de Avaliação
- Consultor
- Premiação Prêmio
- Avaliação Prêmio
- Inscrição Prêmio
Oracle (SUCUPIRA_PAINEL)
- Tabela:
VM_COORDENADOR - JOIN com:
VM_PROGRAMA_SUCUPIRA,VM_AREA_CONHECIMENTO,VM_AREA_AVALIACAO - 29.546 registros (4.150 ativos, 25.396 históricos)
Documentação da API
Após iniciar o backend, acesse:
- Swagger UI:
http://localhost:8010/docs - ReDoc:
http://localhost:8010/redoc
Desenvolvimento
Testes
cd backend
poetry run pytest
Linting
poetry run black src/
poetry run ruff check src/
Build para Produção
Backend:
docker build -t ranking-capes-backend ./backend
Frontend:
cd frontend
npm run build
Referências
- Documentação dos critérios:
.claude/rules/ranking-consultores-capes.md - Queries e mapeamentos:
.claude/rules/ranking-queries-elasticsearch.md
Description
Languages
Python
54%
JavaScript
25.8%
CSS
12.9%
HTML
6.2%
Shell
1%