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:
- Analytics: sem dados de uso, estávamos voando às cegas
- Experimentação: sem feature flags, qualquer mudança era tudo-ou-nada
- 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#104 — DATABASE_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¶
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-notificationsvia Pub/Sub
Fixes e melhorias¶
portal#84— ampliaremotePatternsno Next.js para corrigir imagens quebradas nos cards (closes #86)scraper#10— distribui ~155 DAGs uniformemente em slots de 10min (antes: 156 simultâneas)scraper#11— API retorna HTTP 500/207 para falhas (antes: sempre 200)infra#114,infra#115,reusable-terraform#3,reusable-terraform#4— ignore scaling drift no Cloud Run (Terraform ficava querendo reverter autoscaling)
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#89 — Release 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¶
-
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.
-
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.
-
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.
-
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.
-
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