Skip to content

basedosdados/desafio-data-eng-junior

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 

Repository files navigation

Desafio Engenheiro(a) de Dados Júnior — Base dos Dados

Repositório de instrução para o desafio técnico da vaga de Pessoa Engenheira de Dados Júnior da Base dos Dados.

O objetivo do desafio é emular, em escala reduzida, o fluxo real de ingestão e publicação de uma tabela no projeto basedosdados: extrair os dados na fonte, tratar conforme o Manual de estilo da BD, materializar com dbt e orquestrar com Prefect, mantendo a tabela atualizável.

Descrição do desafio

Você deverá construir uma pipeline de ingestão e atualização para o conjunto de dados Unidades de Conservação, publicado pelo Ministério do Meio Ambiente (MMA) no portal dados.gov.br.

A pipeline deve, ao final, materializar uma tabela pública seguindo as convenções da BD — nome do dataset, nome da tabela, snake_case sem acentos, tipos do BigQuery (ou do warehouse equivalente), e schema documentado. Sugestão de nomenclatura, conforme o manual:

  • Dataset: br_mma_unidades_conservacao
  • Tabela: unidade_conservacao

O objetivo é que a tabela final reflita o status mais recente das unidades de conservação publicado na fonte. A estratégia de atualização (full refresh com overwrite, append incremental, snapshot, merge por chave, etc.) fica a seu critério — escolha a abordagem que considerar mais adequada para o volume e a cadência de mudanças desse conjunto, e justifique a decisão no README da sua solução. Espera-se apenas que rodar a pipeline mais de uma vez não corrompa a tabela.

Fluxo esperado

A arquitetura deve emular o fluxo de dados da BD (fluxo de dados e infraestrutura):

Fonte (dados.gov.br)
  └─ download + tratamento (Python, dentro do flow Prefect)
       └─ arquivo parquet/csv local
            └─ upload para storage (GCS ou S3/MinIO)
                 └─ tabela externa em <dataset>_staging
                      └─ dbt run/test (target=dev)  → <dataset>.<tabela> (materializado)
                           └─ promoção para "prod" (cópia do storage + dbt run target=prod)

Você pode implementar a separação dev/prod com dois projetos BigQuery (recomendado, mais próximo do real) ou com dois schemas/databases dentro do mesmo warehouse local — desde que o conceito de gate de qualidade entre as duas zonas fique claro: nada vai para prod antes de passar nos testes dbt.

Requisitos funcionais

  1. Ingestão: baixar os arquivos de Unidades de Conservação direto da fonte (sem versionar os dados brutos no repositório).
  2. Tratamento: limpar tipos, normalizar nomes de colunas para snake_case, remover acentos, padronizar UFs/municípios usando os códigos do IBGE (consulte o Manual de estilo para os diretórios canônicos). Ver detalhes em Etapas de tratamento abaixo.
  3. Upload: gravar o arquivo tratado em um bucket (<bucket>/staging/br_mma_unidades_conservacao/unidade_conservacao/).
  4. Modelagem dbt: criar models/br_mma_unidades_conservacao/br_mma_unidades_conservacao__unidade_conservacao.sql e seu schema.yml com description, tipos e os testes obrigatórios descritos abaixo.
  5. Orquestração: o flow Prefect deve encadear extração → upload → dbt rundbt test → promoção, abortando se qualquer teste dbt falhar.
  6. Atualização: a pipeline deve ser capaz de refletir mudanças da fonte em execuções subsequentes (ver discussão da estratégia mais acima).
  7. Agendamento: configurar um schedule Prefect (mesmo que mensal) e demonstrar que ele dispara o flow.

Requisitos não-funcionais

  • Código organizado, com pyproject.toml/uv/poetry, lint e formatação configurados.
  • Variáveis sensíveis (credenciais GCP, chaves S3) fora do código — use .env ou Prefect Blocks/Secrets.
  • README da sua solução com: como rodar localmente, como rodar o flow no Prefect, como apontar para o bucket, e decisões de arquitetura.

Etapas de tratamento

Além da limpeza geral (snake_case, sem acentos, tipos corretos), a tabela final precisa atender às regras abaixo. A ideia é que ela fique cruzável com qualquer outra tabela publicada em basedosdados que use as mesmas chaves.

  1. Coluna id_municipio — a tabela final deve conter uma coluna id_municipio com o código IBGE de 7 dígitos do município da unidade de conservação. A fonte traz, em geral, o nome do município e a UF; cabe à pipeline fazer a conversão para o código IBGE usando o diretório oficial da BD como referência:

    br_bd_diretorios_brasil.municipio — diretório canônico de municípios brasileiros mantido pela BD. Use as colunas id_municipio (7 dígitos), nome e sigla_uf para a junção.

    Casos a tratar explicitamente (e documentar no README da sua solução):

    • Unidades que cobrem mais de um município: defina a granularidade da tabela (uma linha por UC × município, ou uma linha por UC com lista, etc.) e justifique.
    • Unidades marinhas / sem município definido: como representar id_municipio quando não se aplica.
    • Nomes que não casam com o diretório (acentuação, grafia antiga, abreviações): a estratégia de normalização precisa ser reprodutível, não um conjunto de fixes manuais.

Testes dbt obrigatórios

O schema.yml da tabela unidade_conservacao deve declarar, no mínimo:

Na coluna de identificador único da unidade de conservação:

  1. Unicidadeunique: garantir que a coluna de ID não possui valores repetidos.
  2. Não-nulonot_null: garantir que a coluna de ID não possui valores nulos.

Na coluna id_municipio:

  1. Não-nulonot_null: toda linha precisa ter um município associado. Para UCs marinhas ou casos sem município definido, a estratégia adotada (sentinela, linha extra, exclusão) precisa estar documentada e o teste precisa passar — não é aceitável deixar nulo sem justificativa.
  2. Relacionamentorelationships: cada id_municipio precisa existir no diretório oficial da BD (br_bd_diretorios_brasil.municipio). Esse teste valida que a junção foi feita corretamente e que não há códigos IBGE inventados ou desatualizados.

Esses testes precisam rodar dentro do flow Prefect (etapa dbt test) e abortar a promoção para prod caso falhem — é o gate de qualidade descrito no fluxo da BD.

Testes adicionais (accepted_values para categorias de UC / esfera administrativa, ranges para áreas e datas, etc.) contam como diferencial.

Stack obrigatória

Componente Tecnologia
Orquestração Prefect 3 (docs)
Transformação dbt (Core, adapter à sua escolha)
Storage GCS ou compatível com S3 (AWS S3, MinIO, Backblaze B2, etc.)
Warehouse BigQuery ou equivalente (DuckDB local, Postgres) — desde que o dbt rode contra ele
Linguagem Python 3.11+ para o flow
Versionamento Git + GitHub

Sobre infraestrutura

Você tem duas opções, ambas aceitas:

  • GCP trial (cadastro) — recomendado por ser idêntico ao que usamos na BD. Crie um projeto, ative BigQuery e GCS, e use service account com permissões mínimas.
  • Stack local com S3-compatíveldocker-compose com MinIO + DuckDB (ou Postgres) como warehouse. Mais simples de subir, sem depender de cartão de crédito. O dbt precisa estar conectado ao warehouse local via o adapter correspondente (dbt-duckdb ou dbt-postgres), com profiles.yml apontando para o serviço subido pelo docker-compose e lendo os arquivos do bucket MinIO (no caso do DuckDB, via extensão httpfs com as credenciais do MinIO). A separação dev/prod nesse cenário é feita com dois schemas/databases distintos, e o gate dbt continua valendo.

Se optar pela GCP, não exponha a service account no repositório; envie a chave por e-mail no momento da entrega — ver checklist abaixo.

Reprodução com GCP — checklist (caminho da service account)

Caso você opte pelo caminho GCP, a revisão é feita contra o seu próprio projeto, usando a service account que você nos enviar. Para que isso funcione sem fricção, sua entrega precisa cumprir todos os itens abaixo:

APIs habilitadas

No projeto que você criou, habilite explicitamente (uma vez, via console ou gcloud services enable):

  • bigquery.googleapis.com
  • storage.googleapis.com
  • iam.googleapis.com

Service account — papéis mínimos

Crie uma service account dedicada ao desafio (ex.: desafio-bd-runner@<projeto>.iam.gserviceaccount.com) com os papéis:

  • roles/bigquery.dataEditor — criar/popular datasets e tabelas no projeto.
  • roles/bigquery.jobUser — executar dbt run/dbt test.
  • roles/storage.objectAdmin no bucket criado para o desafio (não no projeto inteiro).

Não atribua roles/owner nem roles/editor — uma SA com permissão excessiva é critério de desconto.

Região

Crie o dataset BigQuery e o bucket GCS na mesma região (recomendado: US ou southamerica-east1). Tabela externa só funciona se dataset e bucket compartilham região.

Parametrização

Tudo que é específico do seu projeto deve vir de variável de ambiente — nada hardcoded no código nem no profiles.yml. No mínimo:

  • GCP_PROJECT_ID
  • GCS_BUCKET_NAME
  • BQ_DATASET_DEV / BQ_DATASET_PROD (ou um único dataset com convenção _staging)
  • GOOGLE_APPLICATION_CREDENTIALS apontando para o JSON da SA

Inclua um .env.example no repositório com todas as variáveis listadas (sem valores reais). O profiles.yml do dbt deve ler via {{ env_var('...') }}.

Dev vs prod

Para emular o fluxo da BD, use dois datasets BigQuery dentro do mesmo projeto (<dataset>_dev_staging + <dataset>_dev e <dataset>_staging + <dataset>) — não exige dois projetos. Se preferir dois projetos, documente.

Entrega da credencial

No e-mail de envio do desafio, anexe (ou compartilhe via link com expiração):

  • O JSON da service account.
  • O project_id e o bucket_name que você usou (a menos que sejam óbvios pelo .env.example).
  • Confirmação de que a SA estará ativa pelos próximos 14 dias corridos a partir do envio. Se for desativada antes, avise.

Cleanup

Após receber retorno da avaliação, você é responsável por deletar a service account, o bucket e o projeto (ou pelo menos revogar a chave da SA). Não deixe credenciais ativas indefinidamente.

O que iremos avaliar

  • Aderência ao manual de estilo: nomes, tipos, snake_case, diretórios — leia o Manual de estilo antes de codar. A maior parte dos ajustes que pedimos em PRs reais é, na prática, manual de estilo.
  • Fidelidade ao fluxo da BD: dev → gate de qualidade → prod, com tabela externa em _staging e materializada via dbt.
  • Idempotência e atualização: a pipeline aguenta rodar de novo? Detecta mudanças na fonte?
  • Qualidade do código: legibilidade, modularização, ausência de duplicação, tratamento de erros razoável.
  • Testes dbt: pelo menos os básicos (not_null, unique, accepted_values onde fizer sentido).
  • Documentação: README claro, descrições de colunas no schema.yml, decisões justificadas.
  • Simplicidade: solução direta, sem complexidade gratuita.

Diferenciais (não obrigatórios)

  • Testes unitários do código Python de tratamento.
  • CI no GitHub Actions rodando lint + testes + dbt parse em PRs.
  • update_django_metadata-like: ao final do flow, atualizar um JSON/YAML com cobertura temporal (max_date da tabela) — emulando o que fazemos no backend GraphQL.
  • Observabilidade: logs estruturados, métricas mínimas do flow.

Etapas sugeridas

  1. Ler o Manual de estilo e o fluxo de dados da BD por inteiro.
  2. Definir nomes (dataset/tabela/colunas) antes de escrever código.
  3. Subir o ambiente (GCP trial ou docker-compose com MinIO + warehouse local).
  4. Escrever o script de extração + tratamento.
  5. Subir o arquivo tratado no bucket e criar a tabela externa em <dataset>_staging.
  6. Escrever o modelo dbt em models/br_mma_unidades_conservacao/ + schema.yml com testes.
  7. Encadear tudo num flow Prefect 3 com schedule.
  8. Implementar a estratégia de atualização e demonstrar que funciona (rodar duas vezes, simular fonte atualizada).
  9. Escrever o README da sua solução com instruções de reprodução.

Entrega

  • A solução deve ser publicada em um repositório público no seu GitHub (pode fazer fork deste, ou criar um novo).
  • Envie o link do repositório para gabriel.pisa@basedosdados.org com o assunto "Desafio Engenheiro de Dados Júnior — BD".
  • Caso seja aprovado(a) para a próxima etapa, você apresentará a solução para a equipe, explicando decisões de arquitetura, trade-offs e o que faria diferente com mais tempo.
  • Se não conseguirmos reproduzir a solução localmente seguindo o seu README, ela não será avaliada — capriche nas instruções.

Referências

Dúvidas

Fale conosco em gabriel.pisa@basedosdados.org.

About

Desafio tecnico para vaga de Pessoa Engenheira de Dados Junior na Base dos Dados

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors