API de busca do OpenAudit Brasil. Responsável por receber uma consulta textual, normalizar o termo e retornar uma lista de possíveis entidades (ex.: políticos) a partir de um catálogo canônico, com confidence e explanation para desambiguação humana.
Importante: esta API não executa cruzamento de fontes, não calcula indicadores e não produz conclusões.
Ela apenas resolve "quem o usuário quis dizer" e devolve candidatos para seleção.
- Objetivo
- Escopo
- Princípios e segurança
- Arquitetura (alto nível)
- Endpoints
- Contrato de resposta (exemplo)
- Cache
- Observabilidade
- Configuração
- Execução local
- Execução com Docker
- Testes
- Boas práticas para contribuição
- Licença
- Fornecer uma API rápida e previsível para busca por nome/termo e retorno de candidatos (
entity_id) com desambiguação. - Garantir que a fase de "resolver entidade" seja:
- auditável (versão do catálogo e explicação do match)
- conservadora (sem auto-seleção)
- segura (sem PII desnecessária; sem logs sensíveis)
- Normalização de query (
q) e geração dequery_hash. - Consulta ao Entity Catalog (local/embutido ou via storage/index).
- Ranking de candidatos por score de match.
- Retorno de:
entity_idcanônico- metadados públicos mínimos (UF, cargo, período)
match.confidenceematch.explanationcatalog_sourceecatalog_version
- Consultar múltiplas fontes públicas (conectores).
- Transformar dados de outras bases.
- Cruzar dados e identificar padrões/anomalias.
- Qualquer linguagem acusatória, classificação moral ou "suspeição".
- Neutralidade: a API só retorna candidatos. Não interpreta condutas.
- Minimização: não persiste nem loga termos sensíveis por padrão.
- PII: busca por CPF não é objetivo do MVP. Se existir no futuro, deve ser local-only e sem persistência.
- Anti-enumeração: aplicar rate limit e limites de paginação.
- Auditabilidade: toda resposta deve informar
catalog_version(e idealmentecatalog_snapshot_id).
-
Fundamentos
-
Contribuição
- Como contribuir (se existir)
- Licença (se existir)
- Roadmap
-
Fontes de Dados
Fluxo:
- Recebe
q - Normaliza
q(casefold, remoção de acentos, tokenização) - Gera
query_hash(não reversível) - Consulta índice/catálogo
- Calcula score e
confidence - Retorna lista de candidatos com
explanation
Componentes:
SearchController— HTTPQueryNormalizer— normalizaçãoCatalogClient— acesso ao catálogo (Parquet/DuckDB/SQLite/FTS)Matcher— scoring e explicaçãoCache— opcional (curto TTL)Observability— logs estruturados sem PII
Retorna status simples para readiness/liveness.
200
{ "status": "ok" }Retorna lista de candidatos para desambiguação humana.
Query params
q(string) — obrigatóriolimit(number) — opcional (default: 10, max: 25)offset(number) — opcional (default: 0)
Resposta
query.normalized(string)query.hash(string)catalog.version(string)candidates[](array)
{
"query": {
"raw": "João Silva",
"normalized": "joao silva",
"hash": "sha256:6f3c... (hash do normalized)"
},
"catalog": {
"name": "entity-catalog",
"version": "2026-02-28",
"snapshot_id": "cat:2026-02-28T03:00:00Z",
"source": "TSE"
},
"candidates": [
{
"entity_id": "tse:SQ_CANDIDATO:123",
"display_name": "JOÃO DA SILVA",
"context": {
"uf": "SP",
"cargo": "DEPUTADO FEDERAL",
"ano": 2022
},
"match": {
"confidence": 0.82,
"explanation": [
"nome_normalizado ~= 'joao silva'",
"UF = SP",
"cargo = DEPUTADO FEDERAL",
"ano = 2022"
]
}
}
]
}Regras
confidencedeve ser numérico e interpretável (0–1 ou 0–100).explanationdeve listar sinais usados no match (sem "mágica").- A API nunca deve "auto-selecionar" a entidade.
Cache recomendado apenas para acelerar buscas repetidas em curto período.
- Cache key:
sha256(normalized_q + catalog_version + limit + offset) - TTL: 60–300s (curto)
- O cache não deve armazenar PII nem logar
qbruto.
Se houver cache, o header deve indicar:
X-Cache: HIT|MISSX-Catalog-Version: ...
Logs devem ser estruturados e sem PII por padrão.
Campos recomendados por request:
request_idquery_hashnormalized_lenlimit,offsetcatalog_versionlatency_msresult_countcache_hit
OpenTelemetry é opcional no MVP, mas o request_id deve existir desde o início.
Exemplo de variáveis:
PORT=3001
# catálogo
CATALOG_PATH=./data/catalog.duckdb
CATALOG_VERSION=2026-02-28
# cache
CACHE_ENABLED=true
CACHE_TTL_SECONDS=120
# rate limit
RATE_LIMIT_ENABLED=true
RATE_LIMIT_WINDOW_SECONDS=60
RATE_LIMIT_MAX_REQUESTS=60
# logs
LOG_LEVEL=info
LOG_REDACT_PII=trueStack do projeto NodeJS.
# instalar
npm install
# dev
npm run dev
# build
npm run build
# start
npm run startCrie a pasta data/ na raiz do projeto e adicione os arquivos de catálogo:
data/
├── catalog.sqlite # ou catalog.duckdb
└── catalog_meta.json
⚠️ Os arquivos de catálogo não são incluídos na imagem Docker.
O container não iniciará se o diretóriodata/estiver vazio.
docker compose upA API estará disponível em: http://localhost:3001
curl http://localhost:3001/health
# Esperado: { "status": "ok" }Edite a variável CATALOG_PATH no docker-compose.yml conforme o formato do seu catálogo:
environment:
CATALOG_PATH: /app/data/catalog.duckdb # ou catalog.sqlitedocker build -t openaudit-search-api .
docker run -p 3001:3001 \
-v ./data:/app/data:ro \
openaudit-search-apiCenários Cobertos:
- unit tests para
QueryNormalizereMatcher - fixtures sintéticas (não usar pessoas reais)
- testes de performance (latência do /search)
npm test- Propostas relevantes devem abrir issue primeiro.
- Não adicionar dados pessoais em exemplos, fixtures ou logs.
- Qualquer mudança que altere o comportamento de match precisa:
- atualizar explicação
- adicionar testes de regressão
- registrar decisão (quando aplicável)
Consulte LICENSE na organização.