GovHub Data Lakehouse
Data Lakehouse format-agnostic e infra-agnostic: a mesma camada de orquestração funciona independente de object storage, catálogo de metadados, engine de query e formato de tabela por baixo (Iceberg, Delta Lake, Hudi).
docs/REQUIREMENTS.md— visão, requisitos e arquiteturadocs/USER_STORIES.md— histórias de usuário e ordem de execução
Stack
- Core: Python, gerenciado com
uv - Infra como código: Terraform (módulos por ambiente:
local,aws, ...) - Versões de ferramentas:
mise(.mise.toml)
Subindo o ambiente local
mise trust
mise install
cp .env.example .env # ajuste se necessário — os defaults já batem com a infra local
cd infra/environments/local
terraform init
terraform apply
terraform apply só retorna quando todos os serviços respondem como
saudáveis (ver null_resource.wait_for_services em
infra/environments/local/main.tf) — não só quando os containers existem.
Evita testes/comandos rodando contra um serviço (ex: Trino) que ainda não
terminou de subir.
Sobe, via Docker:
| Serviço | Endpoint | Login |
|---|---|---|
| MinIO API (S3) | http://localhost:9003 | lakehouse / lakehouse-dev |
| MinIO Console | http://localhost:9002 | lakehouse / lakehouse-dev |
| Iceberg REST Catalog | http://localhost:8181 | — |
| Airflow (standalone) | http://localhost:8082 | admin / ver comando abaixo |
| Trino | http://localhost:8083 | — |
Senha do Airflow (gerada na primeira subida, persiste no volume):
docker exec govhub-lakehouse-airflow cat /opt/airflow/simple_auth_manager_passwords.json.generated
Bucket warehouse é criado automaticamente no MinIO. Catálogo Iceberg
persiste metadados em Postgres (porta 5434).
Para derrubar: terraform destroy dentro de infra/environments/local.
Configuração (.env)
.env.example documenta todas as variáveis GOVHUB_* (storage, catálogo,
extractors) com os defaults que já batem com a infra local, mais
GOVHUB_ENV (dev | homolog | prod — qual ambiente este checkout
está apontando agora; aparece no log de auditoria da CLI). Copie pra .env
(gitignorado) e ajuste — mise carrega automaticamente em todo comando
rodado via mise exec (.mise.toml), sem depender de nenhuma lib Python.
Rodando o core Python
uv sync
uv run pytest tests/
Testes contra backends reais (s3 em tests/storage/, iceberg_rest em
tests/catalog/ e tests/table/, DuckDB + Trino em tests/engines/)
precisam do ambiente local do Terraform no ar — caso contrário são
pulados automaticamente.
Storage backend
Backend escolhido via GOVHUB_STORAGE_BACKEND (local ou s3). Os demais
nomes são genéricos de propósito — os mesmos valerão para os próximos
backends (Azure, GCS):
| Variável | Uso |
|---|---|
GOVHUB_STORAGE_BACKEND |
local | s3 |
GOVHUB_STORAGE_LOCAL_ROOT |
raiz no filesystem (backend local) |
GOVHUB_STORAGE_CONTAINER |
bucket/container |
GOVHUB_STORAGE_ENDPOINT |
endpoint do serviço |
GOVHUB_STORAGE_ACCESS_KEY |
credencial de acesso |
GOVHUB_STORAGE_SECRET_KEY |
credencial secreta |
GOVHUB_STORAGE_REGION |
região (quando aplicável) |
Catalog backend
Backend escolhido via GOVHUB_CATALOG_BACKEND (iceberg_rest por
enquanto):
| Variável | Uso |
|---|---|
GOVHUB_CATALOG_BACKEND |
iceberg_rest |
GOVHUB_CATALOG_URI |
endpoint do catálogo REST |
GOVHUB_CATALOG_WAREHOUSE |
localização do warehouse (s3://...) |
GOVHUB_CATALOG_ENDPOINT |
endpoint do object storage (S3 FileIO) |
GOVHUB_CATALOG_ACCESS_KEY |
credencial de acesso |
GOVHUB_CATALOG_SECRET_KEY |
credencial secreta |
GOVHUB_CATALOG_REGION |
região (quando aplicável) |
Table format backend
Sem variáveis próprias — reaproveita a config do catálogo (GOVHUB_CATALOG_*
acima), já que a camada de formato sempre opera sobre uma conexão de
catálogo existente. Seleção do formato é por código (TableBackendFactory),
iceberg por enquanto.
Extractors e transformers
src/govhub_lakehouse/extractors/ (Strategy + Factory, mesmo padrão de
core/) — ApiExtractor, PostgresExtractor, S3Extractor, registrados
em ExtractorFactory. src/govhub_lakehouse/transformers/ (Template
Method) — IcebergTransformer cuida do passo específico de formato
(ajustar o schema solto do extractor para exatamente o que o Iceberg
espera) dentro de um algoritmo fixo (transform) compartilhado por
qualquer formato futuro.
DAGs (dags/)
Ingestão organizada por domínio de dados (estilo data mesh, mesma lógica
do govhub-cidades) — cada domínio tem sua própria pasta/DAG(s) sob
dags/<domínio>/, montada em /opt/airflow/dags. Exemplo real:
dags/ibge/estados_dag.py — domínio ibge, extract >> transform via
TaskFlow API, puxando a lista de estados da API pública do IBGE e
carregando em ibge.estados (Iceberg).
docker exec govhub-lakehouse-airflow airflow dags unpause ibge_estados
docker exec govhub-lakehouse-airflow airflow dags trigger ibge_estados
docker exec govhub-lakehouse-airflow airflow dags list-runs ibge_estados
A imagem do Airflow é buildada com o próprio pacote instalado
(infra/modules/orchestration/local/docker/airflow/Dockerfile), então
qualquer DAG pode importar govhub_lakehouse.extractors/.transformers/
.core.* normalmente.
Lint
uv run black --check src tests dags
uv run isort --check src tests dags
CLI (glh)
uv run glh init
uv run glh create-table --namespace ns --table people --column id:long:required --column name:string
uv run glh ingest --namespace ns --table people --file dados.parquet [--mode append|overwrite]
uv run glh list-tables --namespace ns
uv run glh describe-table --namespace ns --table people
Cada comando lê a config de GOVHUB_STORAGE_*/GOVHUB_CATALOG_* (acima) e
emite um log estruturado em JSON por operação em stderr — quem rodou
(usuário do SO), quando, quais argumentos, sucesso/erro e duração. O
resultado da operação vai pro stdout, também em JSON.
Build e deploy
Pra implantar o glh na infra de um órgão, sem precisar de Python/uv
instalado lá:
uv build # wheel + sdist em dist/
docker build -t govhub-lakehouse-cli . # imagem standalone do CLI
docker run --rm govhub-lakehouse-cli init # roda contra GOVHUB_STORAGE_*/GOVHUB_CATALOG_* passadas via -e
A imagem não inclui nossa infra local de dev — só o glh e suas
dependências. O órgão aponta as variáveis de ambiente pro storage/catálogo
deles.
Também publicamos duas imagens no GHCR a cada push na main (CD, ver
abaixo):
docker pull ghcr.io/bottinolucas/govhub-lakehouse-cli:latest
docker pull ghcr.io/bottinolucas/govhub-lakehouse-airflow:latest
A -airflow já vem com govhub_lakehouse instalado — é a mesma imagem
que infra/modules/orchestration/local builda localmente, só que pronta
pra puxar em vez de buildar.
CI/CD
.github/workflows/ci.yml roda em todo push/PR na main:
-
lint:
black+isort(src,tests,dags) -
terraform:
fmt -check+validate -
test: sobe a infra local via Terraform (só retorna com tudo saudável — ver
null_resource.wait_for_services), rodapytest, derruba a infra no final, mesmo se os testes falharem -
build:
uv build+ build das duas imagens Docker (CLI e Airflow) -
publish (CD — só em push na
main, nunca em PR, só depois que os outros quatro jobs passarem): publica as duas imagens no GHCR (ghcr.io/bottinolucas/govhub-lakehouse-{cli,airflow}), usando oGITHUB_TOKENnativo — nenhum secret extra a configurar. -
publish-pypi (CD — só em tag
v*, ex:v0.1.0, nunca em push simples): publica o wheel/sdist no PyPI via Trusted Publishing (OIDC — sem token pra guardar). Precisa de um passo manual único, feito uma vez no site do PyPI, antes do primeiro release:- Acesse https://pypi.org/manage/account/publishing/ (logado na conta que vai ser dona do pacote)
- Em "Add a new pending publisher", preencha:
- PyPI project name:
govhub-lakehouse(ou o nome que preferir — precisa bater com onameempyproject.toml) - Owner:
bottinolucas - Repository name:
govhub-data-lakehouse - Workflow name:
ci.yml - Environment name:
pypi
- PyPI project name:
- Pra liberar:
git tag v0.1.0 && git push origin v0.1.0(a versão da tag deve bater comversionempyproject.toml— PyPI rejeita reenviar uma versão já publicada).
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file govhub_lakehouse-0.1.0.tar.gz.
File metadata
- Download URL: govhub_lakehouse-0.1.0.tar.gz
- Upload date:
- Size: 18.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f69242caecab50b576451f066da292fcee587ad5708bc74fbc75e0d361c1159e
|
|
| MD5 |
7b21ebad0c15100a29312fbf6b19783a
|
|
| BLAKE2b-256 |
0ebfe7e899a6ce32c5de3a9acfe3fc63bf04dbc62789313dfda15b5b724a9afd
|
Provenance
The following attestation bundles were made for govhub_lakehouse-0.1.0.tar.gz:
Publisher:
ci.yml on bottinolucas/govhub-data-lakehouse
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
govhub_lakehouse-0.1.0.tar.gz -
Subject digest:
f69242caecab50b576451f066da292fcee587ad5708bc74fbc75e0d361c1159e - Sigstore transparency entry: 2594919946
- Sigstore integration time:
-
Permalink:
bottinolucas/govhub-data-lakehouse@8cbc99441712e4acafc304cc6e9861e586992663 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/bottinolucas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@8cbc99441712e4acafc304cc6e9861e586992663 -
Trigger Event:
push
-
Statement type:
File details
Details for the file govhub_lakehouse-0.1.0-py3-none-any.whl.
File metadata
- Download URL: govhub_lakehouse-0.1.0-py3-none-any.whl
- Upload date:
- Size: 38.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e494df6c48aac04bb031ff3e632d1469cda194cd55a39b6e55f1c93d844abb45
|
|
| MD5 |
e98fdb65e0652d2e8ccbda472e2dc7a2
|
|
| BLAKE2b-256 |
a3cd0fe930ce26c3552bebb4817ca4327a5eece176b2c2b7a346b6a0a2f4cc16
|
Provenance
The following attestation bundles were made for govhub_lakehouse-0.1.0-py3-none-any.whl:
Publisher:
ci.yml on bottinolucas/govhub-data-lakehouse
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
govhub_lakehouse-0.1.0-py3-none-any.whl -
Subject digest:
e494df6c48aac04bb031ff3e632d1469cda194cd55a39b6e55f1c93d844abb45 - Sigstore transparency entry: 2594920137
- Sigstore integration time:
-
Permalink:
bottinolucas/govhub-data-lakehouse@8cbc99441712e4acafc304cc6e9861e586992663 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/bottinolucas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@8cbc99441712e4acafc304cc6e9861e586992663 -
Trigger Event:
push
-
Statement type: