Arquitetura - alexandrebrt14-sys/geo-finops GitHub Wiki
Arquitetura
Última revisão: 08/07/2026, sobre o estado do branch main (v2.0.0).
Visão geral do pipeline
adapters por projeto (papers e caramaschi ativos em 30/09/2026)
|
v
geo_finops.track_call
|
v
~/.config/geo-finops/calls.db (SQLite, modo WAL; override via GEO_FINOPS_CONFIG_DIR)
|
sync diário 23:50 (Task Scheduler no Windows / cron no Linux e Mac)
|
v
Supabase: tabela finops_calls
|
v
snapshot JSON (scripts/export_snapshot.py)
|
v
alexandrecaramaschi.com/finops + /api/finops/llm-usage (ISR 1h)
Camada local (SQLite)
Tabela única llm_calls com: timestamp (ISO 8601 UTC), project, run_id, task_type, model_id, provider (inferido do model_id), tokens_in, tokens_out, cost_usd, success, metadata (JSON), sync_status (pending | synced | error) e synced_at.
Deduplicação garantida por índice único em (timestamp, project, COALESCE(run_id, ''), model_id) combinado com INSERT OR IGNORE.
A evolução de schema é gerenciada por Alembic (alembic.ini + geo_finops/migrations/, baseline 0001 idempotente) — objeto da decisão B-014 (issue #3).
Sincronização com Supabase
- Worker noturno (
geo_finops/sync.py) envia as linhaspendingpara a tabelafinops_calls. - Idempotência no destino:
Prefer: resolution=ignore-duplicatesno POST (PostgRESTON CONFLICT DO NOTHING); HTTP 409 é tratado como sucesso silencioso. - Retry: até 3 tentativas com backoff exponencial (1s, 2,5s, 5s) em 5xx e erros de rede; 4xx fatais (401/403/422) não fazem retry.
- Credenciais (
SUPABASE_URL+SUPABASE_KEYouSUPABASE_SERVICE_ROLE_KEY) vêm de variáveis de ambiente ou de um.envno chain deconfig.candidate_env_files(). Desde o PR #5 (08/07/2026),.enve.env.*estão no.gitignore.
Estrutura do pacote
| Módulo | Papel |
|---|---|
geo_finops/config.py |
Paths, parsing de env, credenciais (fonte única) |
geo_finops/db.py |
Schema + conexão WAL |
geo_finops/tracker.py |
track_call + query_calls + inferência de provider |
geo_finops/aggregates.py |
SQL reutilizável (totals, daily_timeseries, top_models) |
geo_finops/sync.py |
Worker noturno → Supabase |
geo_finops/migrate.py |
Migração dos 4 trackers legados (executada em 07/04/2026) |
geo_finops/cli.py |
status / summary / list / migrate / sync |
geo_finops/prices.py + prices.yaml |
Cálculo de custo (5 providers, 11 modelos, versão 2026-04-09, defasada em relação ao parque vigente) — decisão B-020 (issue #4) |
geo_finops/digest/ |
Digest FinOps semanal (cloud estimators, builders, formatters, reporters); desde 10/08/2026 o payload declara valid_for_hours e stale_after |
geo_finops/migrations/ |
Alembic |
scripts/ |
health_check.py (13 dimensões), export_snapshot.py, aggregate_dashboard.py, weekly_digest.py, bootstrap_supabase.py |
Adapters por projeto
Cada projeto consumidor tem um adapter thin que importa geo_finops.track_call via sys.path e vira no-op se o pacote não estiver disponível — o tracking jamais quebra a call principal.
| Projeto | Adapter | Estado em 30/09/2026 |
|---|---|---|
| papers | src/finops/unified_adapter.py |
ativo |
| caramaschi | src/scripts/caramaschi_finops.py |
ativo |
| geo-orchestrator | src/unified_finops.py |
removido em 08/09/2026 (refatoração 5.1); o orquestrador mantém o próprio FinOps em output/.finops/ |
| curso-factory | src/unified_finops.py |
arquivo não existe mais |
CI de testes
Workflow tests (.github/workflows/test.yml, criado em 09/08/2026 no PR #8): pytest em Python 3.11 e 3.12 a cada push e PR contra main, mais uma sentinela que reprova o build se a coleta cair abaixo de 155 testes. A sentinela existe porque a bateria passou meses sem rodar em servidor e um teste quebrado ficou um mês anotado sem cobrança.
CI de segurança
Workflow Security scan (Python) (agendado semanalmente + workflow_dispatch): bandit, pip-audit e gitleaks. Ficou vermelho de forma crônica até 08/07/2026 por falsos positivos B608 do bandit (queries com where parametrizado), corrigidos no PR #5 com # nosec B608 justificado; os 3 jobs voltaram a ficar verdes na sequência. Gotcha operacional: o GitHub desabilita workflows agendados após cerca de 60 dias sem atividade no repositório (disabled_inactivity).