diff --git a/docs/infraestrutura/secrets-iam.md b/docs/infraestrutura/secrets-iam.md index d34d21c..f55b175 100644 --- a/docs/infraestrutura/secrets-iam.md +++ b/docs/infraestrutura/secrets-iam.md @@ -39,6 +39,11 @@ flowchart TB | Secret | Descrição | Usado por | |--------|-----------|-----------| | `typesense-api-key` | API Key do Typesense | Portal, Workflows | +| `umami-database-url` | Connection string PostgreSQL do Umami | Cloud Run `destaquesgovbr-umami` | +| `umami-app-secret` | Chave de criptografia de sessões do Umami | Cloud Run `destaquesgovbr-umami` | +| `growthbook-mongodb-uri` | Connection string MongoDB Atlas do GrowthBook | Cloud Run `destaquesgovbr-growthbook`, `-api` | +| `growthbook-encryption-key` | Chave de criptografia do GrowthBook | Cloud Run `destaquesgovbr-growthbook`, `-api` | +| `growthbook-jwt-secret` | Chave JWT do GrowthBook | Cloud Run `destaquesgovbr-growthbook`, `-api` | ### Criar Secret @@ -106,7 +111,9 @@ env { |-----------------|-----| | `github-actions@PROJECT.iam.gserviceaccount.com` | Deploy via GitHub | | `typesense-server@PROJECT.iam.gserviceaccount.com` | VM do Typesense | -| `portal-runner@PROJECT.iam.gserviceaccount.com` | Cloud Run | +| `portal-runner@PROJECT.iam.gserviceaccount.com` | Cloud Run Portal | +| `destaquesgovbr-umami@PROJECT.iam.gserviceaccount.com` | Cloud Run Umami | +| `destaquesgovbr-growthbook@PROJECT.iam.gserviceaccount.com` | Cloud Run GrowthBook | ### Criar Service Account @@ -264,6 +271,10 @@ gh secret set WIF_SERVICE_ACCOUNT --body "github-actions@project.iam.gserviceacc | `TYPESENSE_HOST` | IP interno do Typesense | | `TYPESENSE_PORT` | Porta (8108) | | `TYPESENSE_API_KEY` | API Key do Typesense | +| `NEXT_PUBLIC_UMAMI_WEBSITE_ID` | Website ID do Umami | +| `NEXT_PUBLIC_UMAMI_SCRIPT_URL` | URL do script.js do Umami | +| `NEXT_PUBLIC_GROWTHBOOK_API_HOST` | URL da API GrowthBook | +| `NEXT_PUBLIC_GROWTHBOOK_CLIENT_KEY` | Client Key do SDK GrowthBook | #### `scraper` diff --git a/docs/modulos/growthbook.md b/docs/modulos/growthbook.md new file mode 100644 index 0000000..5454080 --- /dev/null +++ b/docs/modulos/growthbook.md @@ -0,0 +1,231 @@ +# Módulo: GrowthBook + +> Feature flags e testes A/B, self-hosted no GCP Cloud Run com MongoDB Atlas. + +## Visão Geral + +O GrowthBook é a plataforma de **feature flags** e **A/B testing** do portal DestaquesGovBr. Permite: + +- **Feature Flags**: ativar/desativar funcionalidades sem deploy +- **Testes A/B**: comparar variantes de UI e medir conversões +- **Rollout gradual**: liberar features para % dos usuários +- **Targeting**: segmentar por atributos do usuário + +```mermaid +flowchart LR + subgraph Dashboard["GrowthBook Dashboard"] + FE[Frontend
Port 3000] + API[API
Port 3100] + DB[(MongoDB Atlas)] + end + + subgraph Portal["Portal Next.js"] + GBP[GrowthBookProvider] + HK[Hooks: useAB,
useFeatureFlag] + TK[Tracking:
Umami + Clarity] + end + + FE <-->|interno| API + API <--> DB + GBP -->|SDK fetch| API + GBP --> HK + HK --> TK +``` + +--- + +## Dashboard + +### Acesso + +```bash +# Obter URL do dashboard +gcloud run services describe destaquesgovbr-growthbook \ + --region=southamerica-east1 \ + --format='value(status.url)' +``` + +A conta admin é criada no primeiro acesso ao dashboard. + +### Conceitos Principais + +| Conceito | Descrição | +|----------|-----------| +| **Feature** | Flag booleana ou com variantes (string, número, JSON) | +| **Experiment** | Teste A/B que divide tráfego entre variantes | +| **SDK Connection** | Credenciais para o portal consumir features/experiments | +| **Environment** | Ambientes separados (production, development) | + +--- + +## Integração no Portal + +### `GrowthBookProvider` + +O provider inicializa o SDK e disponibiliza o contexto para toda a aplicação: + +```typescript +// src/ab-testing/GrowthBookProvider.tsx +// - Gera user ID persistente (cookie ab_user_id, 1 ano) +// - Inicializa SDK com streaming habilitado +// - Conecta ao API Host para buscar features +``` + +O provider é montado em `src/components/common/Providers.tsx`, envolvendo toda a árvore de componentes. + +### Variáveis de Ambiente + +| Variável | Descrição | +|----------|-----------| +| `NEXT_PUBLIC_GROWTHBOOK_API_HOST` | URL da API GrowthBook (serviço `-api`) | +| `NEXT_PUBLIC_GROWTHBOOK_CLIENT_KEY` | Client Key da SDK Connection | + +Configurar no `.env.local` para desenvolvimento: + +```bash +NEXT_PUBLIC_GROWTHBOOK_API_HOST=https://destaquesgovbr-growthbook-api-xxx.run.app +NEXT_PUBLIC_GROWTHBOOK_CLIENT_KEY=sdk-xxxxx +``` + +### Hooks Disponíveis + +```typescript +import { + useAB, + useFeatureFlag, + useIsVariant, + useABConversion, +} from '@/ab-testing/hooks' +``` + +| Hook | Uso | +|------|-----| +| `useFeatureFlag(key)` | Retorna `true/false` para feature flags | +| `useAB(key, fallback)` | Retorna o valor da variante atribuída | +| `useIsVariant(key, variant)` | Verifica se está em variante específica | +| `useABConversion(key)` | Retorna função para registrar conversão | + +--- + +## Usando Feature Flags + +### 1. Criar no Dashboard + +1. Acessar GrowthBook Dashboard → **Features** +2. Clicar **Add Feature** +3. Preencher: + - **Feature Key**: ex. `dark-mode` (kebab-case) + - **Type**: Boolean + - **Default Value**: `false` (desligado por padrão) +4. Em **Override Rules**, criar regras por ambiente +5. Salvar + +### 2. Usar no Código + +```typescript +import { useFeatureFlag } from '@/ab-testing/hooks' + +function Header() { + const isDarkMode = useFeatureFlag('dark-mode') + + return ( +
+ {/* ... */} +
+ ) +} +``` + +!!! note "Graceful Degradation" + Se o GrowthBook não estiver configurado (variáveis de ambiente ausentes), + os hooks retornam o valor de fallback. O portal funciona normalmente sem GrowthBook. + +--- + +## Criando um Experimento A/B + +### Passo a Passo + +#### 1. Criar Feature com Variantes + +No dashboard → **Features** → **Add Feature**: + +- **Key**: `hero-layout` +- **Type**: String +- **Values**: `control`, `variant-a`, `variant-b` + +#### 2. Adicionar Experiment Rule + +Na feature → **Add Rule** → **Experiment**: + +- **Tracking Key**: `hero-layout-test` +- **Traffic Split**: 33% / 33% / 34% +- **Variation Values**: `control`, `variant-a`, `variant-b` + +#### 3. Implementar no Código + +```typescript +import { useAB, useABConversion } from '@/ab-testing/hooks' + +function HeroSection() { + const variant = useAB('hero-layout', 'control') + const { trackConversion } = useABConversion('hero-layout') + + const handleCTA = () => { + trackConversion('cta_click') + // ... ação do botão + } + + switch (variant) { + case 'variant-a': + return + case 'variant-b': + return + default: + return + } +} +``` + +#### 4. Monitorar Resultados + +- Conversões são enviadas automaticamente para **Umami Analytics** e **Microsoft Clarity** +- No Umami, filtrar eventos `experiment_viewed` e `experiment_conversion` +- No Clarity, os segmentos `ab_*` permitem visualizar heatmaps por variante + +### Tracking Automático + +O `trackingCallback` do GrowthBook envia automaticamente para múltiplas plataformas: + +```typescript +// src/ab-testing/tracking.ts +// experiment_viewed → Umami + Clarity (automático ao entrar no experimento) +// experiment_conversion → Umami + Clarity (ao chamar trackConversion) +``` + +--- + +## SDK Connection + +Para conectar o portal ao GrowthBook: + +1. Dashboard → **Settings → SDK Connections** +2. **Add SDK Connection** +3. Selecionar **React** como linguagem +4. Copiar: + - **Client Key**: `sdk-xxxxx` + - **API Host**: URL do serviço `destaquesgovbr-growthbook-api` + +!!! warning "API Host" + Use a URL do serviço **-api** (porta 3100), não do frontend. + O serviço API é o endpoint que o SDK React consome. + +--- + +## Links Relacionados + +- [GrowthBook Documentation](https://docs.growthbook.io) — docs oficiais +- [GrowthBook React SDK](https://docs.growthbook.io/lib/react) — referência do SDK +- [Infra: GrowthBook Setup](https://github.com/destaquesgovbr/infra/blob/main/docs/growthbook-setup.md) — configuração operacional +- [Umami Analytics](umami.md) — analytics integrado com A/B testing +- [Portal](portal.md) — integração no frontend diff --git a/docs/modulos/umami.md b/docs/modulos/umami.md new file mode 100644 index 0000000..9b0bc46 --- /dev/null +++ b/docs/modulos/umami.md @@ -0,0 +1,187 @@ +# Módulo: Umami Analytics + +> Plataforma de analytics privacy-first, self-hosted no GCP Cloud Run. + +!!! info "Por que não Google Analytics?" + O Umami foi escolhido por ser **privacy-first** (sem cookies de terceiros), **LGPD-compliant** por design, + **self-hosted** (dados no nosso GCP), e **open-source**. Não compartilha dados com terceiros. + +## Visão Geral + +O Umami é a plataforma de analytics do portal DestaquesGovBr. Ele coleta métricas de pageviews, eventos customizados e comportamento de navegação — tudo com respeito à privacidade do usuário e dependente de consentimento explícito. + +```mermaid +flowchart LR + subgraph Portal["Portal Next.js"] + CS[ConsentProvider] + US[UmamiScript.tsx] + UT[useUmamiTrack hook] + end + + subgraph GCP["GCP Cloud Run"] + UA[Umami Server] + PG[(Cloud SQL
PostgreSQL)] + end + + CS -->|consent=true| US + US -->|script.js| UA + UT -->|window.umami.track| UA + UA -->|dados| PG +``` + +--- + +## Dashboard + +### Acesso + +```bash +# Obter URL do dashboard +gcloud run services describe destaquesgovbr-umami \ + --region=southamerica-east1 \ + --format='value(status.url)' +``` + +!!! warning "Senha Padrão" + Login padrão: `admin` / `umami`. **Altere a senha no primeiro acesso.** + +### Métricas Disponíveis + +- **Pageviews** — total e por página +- **Visitantes únicos** — por período +- **Duração da sessão** — tempo médio no site +- **Bounce rate** — taxa de rejeição +- **Referrers** — de onde vem o tráfego +- **Dispositivos** — browser, OS, tamanho de tela +- **Localização** — país e cidade (via IP, sem precisão de GPS) +- **Eventos customizados** — ações rastreadas via código + +### Filtros + +O dashboard permite filtrar por: + +- Período (hoje, 7d, 30d, custom) +- Hostname (produção vs staging) +- URL/página específica +- Referrer, browser, OS, país + +--- + +## Integração no Portal + +### Componente `UmamiScript.tsx` + +O script do Umami é carregado condicionalmente, apenas quando o usuário **aceita cookies**: + +```typescript +// src/components/analytics/UmamiScript.tsx +'use client' +import Script from 'next/script' +import { useConsent } from '@/components/consent/ConsentProvider' + +export function UmamiScript() { + const { hasConsent } = useConsent() + + if (!UMAMI_WEBSITE_ID || !UMAMI_SCRIPT_URL || hasConsent !== true) { + return null // Não carrega sem consentimento + } + + return ( +