O sistema consome dados de quatro fontes externas, cada uma com um motor (classe) e uma forma de acesso diferente. Nenhuma delas roda "magicamente" — cada uma tem um gatilho específico, documentado abaixo.
Os quatro motores
| Motor | Classe | Acesso | O que traz | Quando roda |
|---|---|---|---|---|
| Lattes (CNPq) | LattesImporter + LattesParser |
Upload manual de XML | Pesquisador, produções, projetos, orientações | Admin faz upload, ou em lote via bin/indexer.php |
| OpenAlex | OpenAlexFetcher |
REST público (sem chave, e-mail por cortesia) | Citações, DOI, conceitos — enriquece a produção já indexada | Automático após indexação em lote, com cache local por DOI |
| ORCID | OrcidFetcher |
REST (Consórcio CAPES-ORCID) | Perfil, obras, formação, vínculos empregatícios | Sob demanda — não roda em lote automaticamente |
| BrCris | BrCrisIntegration |
REST institucional | Sincronização de dados de programa com a plataforma nacional | ⚠️ Implementada, mas ainda não conectada a nenhum endpoint/rota |
Gap conhecido:
BrCrisIntegration existe e funciona isoladamente (tem syncInstitutionData(), validateRecord(), etc.), mas nenhuma página ou endpoint a instancia hoje. Antes de expor essa integração, alguém precisa decidir o gatilho (manual? agendado?) e criar a rota.
Upload de Lattes — passo a passo
flowchart TD
ADM["Admin: upload de XML (.xml)"] --> UP["upload_and_index.php"]
UP --> LI["LattesImporter::importFromXML()"]
LI --> VAL["Validação anti-XXE: bloqueia DOCTYPE, LIBXML_NONET"]
VAL --> EXT["extractPesquisadorData / extractProducoes / extractProjetos"]
EXT --> IDX["indexPesquisador / indexProducoes / indexProjetos"]
IDX --> ES["Elasticsearch"]
Enriquecimento em lote — OpenAlex
flowchart TD
BATCH["bin/indexer.php (lote)"] --> LP["LattesParser::parse()"]
LP --> OA["OpenAlexFetcher::enrichProduction()"]
OA --> CACHE{"Já existe cache local do DOI?"}
CACHE -- sim --> ENR["Produção enriquecida"]
CACHE -- não --> REQ["Chamada à API OpenAlex"] --> SAVE["Salva no cache local"] --> ENR
ENR --> ES2["Elasticsearch"]
Perfil ORCID — sob demanda
flowchart LR
REQ2["Requisição sob demanda"] --> OF["OrcidFetcher::getCompleteProfile()"]
OF --> P["getProfile()"]
OF --> W["getWorks()"]
OF --> E["getEducation()"]
OF --> EMP["getEmployments()"]
P --> N["normalizeProfileData()"] --> OUT["Perfil normalizado"]
W --> OUT
E --> OUT
EMP --> OUT