Pular para conteúdo

Umami, GrowthBook, Auth e v1.0.0: dois dias até o release do Portal

Sábado de manhã o portal não tinha analytics, nem autenticação, nem feature flags. Domingo à noite, tínhamos Umami Analytics com IAP, GrowthBook com dual-service, autenticação Google OAuth, push notifications com service worker, e a tag v1.0.0 no ar. Foram ~25 PRs em 6 repos, com 3 serviços novos no Cloud Run, e uma release que consolida semanas de trabalho.


Contexto: o que faltava para o v1.0.0

O portal já tinha busca semântica, artigos, feeds RSS e o pipeline de dados rodando event-driven. Mas para uma release pública, três pilares estavam ausentes:

  1. Analytics: sem dados de uso, estávamos voando às cegas
  2. Experimentação: sem feature flags, qualquer mudança era tudo-ou-nada
  3. Autenticação: sem login, funcionalidades personalizadas (como notificações push) ficavam limitadas

O plano: resolver os três em um fim de semana.


Sábado (2/mar): a plataforma de analytics e experimentação

Umami Analytics no Cloud Run

Primeira escolha: Umami Analytics como alternativa privacy-first ao Google Analytics. Open source, self-hosted, sem cookies.

infra#101 provisionou tudo de uma vez: - Cloud Run service com a imagem oficial do Umami - Database umami + user umami_app no Cloud SQL existente - Secrets auto-gerados no Secret Manager - Scale-to-zero, health checks, service account dedicado

O primeiro deploy não subiu. Começou o ciclo clássico de ajustes: - infra#102 — imagem do ghcr.io precisava de mirror; GrowthBook falhava com startup probes - infra#103 — remove startup probes do Umami (primeiro deploy sem dados = liveness check falha) - infra#104DATABASE_URL faltava localhost (Cloud SQL Auth Proxy escuta em localhost, não no Unix socket)

GrowthBook: dual-service architecture

GrowthBook foi mais complexo. Uma única instância serve tanto o frontend (dashboard) quanto a API (SDK endpoints para o portal). O problema: o frontend precisa ser protegido (acesso interno), mas a API precisa ser pública (portal consome SDK em runtime).

A solução em infra#105: dois Cloud Run services a partir da mesma imagem: - growthbook (porta 3000): container completo com PM2 — frontend Next.js + API interno - growthbook-api (porta 3100): Express backend only — SDK endpoints públicos

Secrets separados (encryption-key, jwt-secret), CORS configurado, MongoDB Atlas como backend.

IAP: protegendo dashboards com Identity-Aware Proxy

Com Umami e GrowthBook no ar, qualquer um com a URL poderia acessar os dashboards. A solução: IAP (Identity-Aware Proxy) do GCP com HTTPS Load Balancer compartilhado.

infra#107 criou: - IP estático + certificado SSL gerenciado - Backend services com IAP habilitado - Umami com DISABLE_LOGIN=1 (IAP resolve auth, sem login duplo) - GrowthBook frontend com ingress restrito ao LB - GrowthBook API continua pública (sem IAP — SDK do portal precisa acessar) - Domínios nip.io derivados automaticamente do IP estático

Dois fixes depois (infra#108 — adicionar email ao IAP, infra#110 — scheme EXTERNAL_MANAGED para o LB), os dashboards estavam protegidos.

Ingestão Umami → BigQuery

Com o Umami coletando dados, o próximo passo: trazer esses dados para o data warehouse.

data-platform#101 criou a DAG sync_umami_to_bigquery: - Sync incremental de pageviews e custom events - Queries validadas contra o banco de produção do Umami - 28 testes unitários novos - data-platform#102 — refactor removendo pandas/pyarrow (desnecessários)

Infra companion: infra#109 — connection umami_postgres via Secret Manager no Composer.

Documentação operacional

  • docs#36 — páginas de referência Umami + GrowthBook no docs site
  • infra#106 — runbooks operacionais

Domingo (3/mar): autenticação, push e release

Autenticação Google OAuth

Lucas implementou autenticação com NextAuth.js v5 (Auth.js):

portal#81 — provider condicional: - Google OAuth para dev e preview - Gov.Br OIDC preparado para produção (pendente aprovação SGD + domínio .gov.br) - Botão de login aparece apenas quando variáveis estão configuradas

Security hardening: - portal#88 — migra AUTH_SECRET de env var plain text para Secret Manager - portal#87 — remove fetch extra no AuthButton (perf)

Push Notifications: bell icon + Service Worker

portal#82 trouxe a experiência completa de push notifications ao portal:

  • Service Worker (sw.js): recebe push events, exibe notificações nativas do browser
  • ServiceWorkerRegistrar: registra o SW no mount, incluído no layout root
  • PushSubscriber: ícone de sino no header com Sheet lateral
  • 25 checkboxes de temas L1
  • Subscribe/unsubscribe via Web Push API (VAPID)
  • Persistência de filtros no localStorage
  • Integração com o backend push-notifications via Pub/Sub

Fixes e melhorias

Streamlit: panorama-dgb

infra#113 — novo app Streamlit panorama-dgb registrado na plataforma. Dashboard interno para visualização do estado do projeto.

Release v1.0.0

portal#89Release v1.0.0 consolida tudo:

  • Notificações Push (SW + bell icon + subscriber UI)
  • Autenticação Google OAuth via NextAuth.js
  • Widget de leitura recente (Firestore)
  • Feeds RSS/Atom/JSON
  • Fix de imagens quebradas
  • Migração de AUTH_SECRET para Secret Manager
  • Otimização de performance no AuthButton

O antes e depois

Portal na sexta (28/fev)

Portal Next.js
├── Busca semântica (Typesense)
├── Artigos com paginação
├── Feeds RSS/Atom/JSON
└── (sem analytics, sem auth, sem push)

Portal no domingo (2/mar)

Portal Next.js v1.0.0
├── Busca semântica (Typesense)
├── Artigos com paginação
├── Feeds RSS/Atom/JSON
├── Google OAuth (NextAuth.js)
├── Push Notifications (VAPID + SW)
├── Umami Analytics (self-hosted, privacy-first)
├── GrowthBook Feature Flags (dual-service)
└── IAP protegendo dashboards

Números

Métrica Valor
PRs mergeados ~25
Repos tocados 6 (portal, infra, data-platform, docs, scraper, reusable-terraform)
Serviços Cloud Run novos 3 (Umami, GrowthBook, GrowthBook API)
Testes novos 35+
Release tag v1.0.0
Dias 2 (sáb-dom)

Lições

  1. IAP > login duplo. Proteger dashboards com Identity-Aware Proxy e desabilitar o login nativo da ferramenta elimina fricção. Um único ponto de autenticação (Google Workspace) para todos os dashboards internos.

  2. Dual-service resolve o dilema público/privado. Quando um serviço precisa ser parcialmente público (API) e parcialmente privado (dashboard), dois Cloud Run services da mesma imagem com configs diferentes é mais limpo que network policies complexas.

  3. Feature flags desde o dia zero. GrowthBook estava no ar antes de precisarmos de um A/B test. Quando o primeiro teste for necessário, a infraestrutura já existe.

  4. Scale-to-zero é amigo de serviços auxiliares. Umami e GrowthBook provavelmente ficam idle 95% do tempo. Com scale-to-zero, o custo é praticamente zero quando não há acesso.

  5. Release as consolidation, not event. O v1.0.0 não foi um big bang — foi uma tag num commit que já estava rodando em produção há horas. Cada feature foi deployada e validada individualmente via PRs. A release apenas formalizou.


Próximo post: Bot Telegram e scraper resiliente