Pular para conteúdo

0013 — Analytics (Aptabase): auto-provisão forjando o token de sessão

Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-07-03 · Decidido em: 2026-07-03

Contexto

Fase 6 da Central de Apps: a feature analytics. Apps X-Adm (Flutter) usam Aptabase (self-hosted); a app_key (A-SH-*, pública) era criada na mão e hardcoded. O broker deve provisionar — mas o Aptabase não tem API de provisão (auth é magic-link/sessão; o AppsController é [IsAuthenticated], sem API token — verificado na fonte aptabase/aptabase).

Decisão

  1. Aptabase provisiona os eventos da feature analytics. (À época, analytics = [aptabase] só — o Metabase estava fora. Atualizado pela decisão 0014: o Metabase foi re-escopado para dentro de analytics, que agora provisiona [aptabase, metabase].)
  2. Auto-provisão forjando o token de sessão. O magic-link do Aptabase é um JWT HS256 assinado com o AUTH_SECRET (bytes ASCII; claims {type, name, email, iss:"aptabase-sh", exp} — verificado em AuthTokenManager/EnvSettings). O broker forja um token de Register (o /continue cria a conta setup se não existe e loga) e abre sessão:
  3. forja o JWT (HS256, AUTH_SECRET).
  4. GET /api/_auth/continue?token=… → cookie de sessão (sem seguir o redirect).
  5. GET /api/_apps → lista-antes-de-criar (reusa por nome=app_id).
  6. POST /api/_apps {name: app_id} → app_key (client-grade → app.json). Sem e-mail, sem log, sem Coolify.
  7. Idempotência: list-before-create no Aptabase + reuso da key persistida no ProvisioningService (não re-faz o fluxo quando já ligada).
  8. Sem corretor runtime (o app manda eventos direto ao ingest com a app_key pública).

Operar (config no recurso auth)

Provisão 100% automática via /xadm-setup (feature analytics) → POST /api/setup/provision. Não há runbook separado (não há procedimento manual — o broker forja o token e cria/reusa o app). O operador só liga a feature setando estas envs uma vez no recurso auth (Coolify):

Variável Valor Secret?
APTABASE_ADMIN_URL https://aptabase.xadm.biz não
APTABASE_SETUP_EMAIL e-mail da conta setup (ex. setup@xadm.biz) — o /continue cria se não existe não
APTABASE_SETUP_NAME nome da conta (default X-Adm Setup) não
APTABASE_AUTH_SECRET = o AUTH_SECRET do serviço Aptabase (mesmo valor) sim ✅

Opcional APTABASE_ISS (default aptabase-sh). Ausência das obrigatórias → o provider recusa (boot ok). Não precisa de APTABASE_COOLIFY_UUID nem de COOLIFY_*.

Pegar o AUTH_SECRET (no host do Coolify, terminal):

docker inspect $(docker ps --filter "name=aptabase" -q | head -1) \
  --format '{{json .Config.Env}}' | tr ',' '\n' | grep -i AUTH_SECRET
(ou na aba Environment Variables do recurso Aptabase no Coolify). Copie pro APTABASE_AUTH_SECRET.

Diagnóstico — o /provision responde providers[].last_error (fail-fast, nunca key falsa): falha ao forjar o token — AUTH_SECRET < 32 bytes? (secret vazio/curto); continue HTTP 4xx — token rejeitado (APTABASE_AUTH_SECRET ≠ o real, ou iss errado); GET /_apps … (sessão não abriu?) (o cookie do /continue não pegou — mudança de versão?).

Alternativas consideradas (a saga)

  • Login e-mail+senha: inválido — o Aptabase não tem senha (magic-link).
  • Manual-register (dev cria na UI + informa a key): funcional, mas o alvo era 100% automático.
  • Raspar o magic-link do log do Coolify: inviável — o Aptabase é um Coolify service (compose) e a API do Coolify não expõe logs de service (só de application — verificado em routes/api.php). Descartado.
  • Forjar o token (escolhido): robusto, independe de logs/infra, funciona pra service.

Consequências / riscos

  • Segurança — credencial poderosa: o AUTH_SECRET no env do broker permite forjar sessão de qualquer usuário do Aptabase. Aceito como infra do broker (é o mesmo nível dos outros admin tokens que o auth guarda), mas é o secret mais sensível dessa feature — só no env do auth.
  • Guardas (endpoints/claims internos, não-documentados): versão do Aptabase fixada (main: /api/_auth/continue, /api/_apps, claim type=Register, iss=aptabase-sh) — reconferir em upgrade. Fail-fast: qualquer passo falho (forja, continue 4xx, sessão, parse) → state=falha+last_error; nunca key falsa (resposta honesta 0.17.6).
  • Config nova (recurso auth): ver Operar acima (envs + como pegar o AUTH_SECRET). APTABASE_COOLIFY_UUID não é mais necessário.
  • Lado Flutter (fora do auth): o client_config traz aptabase_key + aptabase_host — a key A-SH- self-hosted é inútil no cliente sem o host, porque o SDK Flutter exige InitOptions(host:). O host é o próprio APTABASE_ADMIN_URL (URL pública da instância; admin e ingestão no mesmo host). O /xadm-setup grava ambos em features.analytics no app.json e scaffolda o helper (mirror sulplata); vêm do app.json, não hardcoded.