Pular para conteúdo

0005 — Central de Apps: paradigma build-time

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

Contexto

A Central de Apps (spec 013) transforma o auth num plano de controle dos apps (observabilidade/GlitchTip, arquivos/Garage, analytics/Aptabase+Metabase, docs) e a central na sua UI. O primeiro desenho era runtime: cada app buscava a própria config no boot (GET /api/apps/config + token de consumo por par (cliente, app)), o auth provisionava no provedor ao ligar a funcionalidade, e o manifesto era empurrado por CI (token de publicação escopado por app). Isso trazia ciclo de vida de token por par, fetch no boot e push de manifesto — complexidade que não se pagava para apps que já deployam por build (web via Coolify, mobile via CI).

Decisão

Build-time. O app declara o que usa num único manifesto — o app.json (bloco features como objeto por funcionalidade). Uma skill nova, /xadm-setup (roda depois de codar, antes do /xadm-release), lê o app.json, pergunta o que ligar, provisiona via auth-broker (que detém os tokens admin dos provedores) e grava o resultado client-grade (DSN, key, bucket) de volta no app.json — que o build embute. Sem fetch no boot.

  • Runtime fica mínimo:corretores (URL assinada/expirável — embed do Metabase, presign do Garage) e feature flags (protocolo próprio, spec 014).
  • Papéis: auth = broker + configurador de secrets (Coolify/CI) + corretor + auth; central = dashboard.
  • 3 checkpoints: /xadm-setup → guard soft na /xadm-release → guard de deploy (no ci.yml).
  • 2 naturezas × plataforma: client-grade (DSN/key) → app.json (web = build-arg via Coolify; mobile = --dart-define no CI); secret → org-CI (org-wide) ou Coolify (por app, web/server; mobile não tem secret por app — usa presign/corretor).
  • Fronteira de dados: DB do auth = autenticação/autorização + catálogo; DB do app = dado de domínio (e estado de flag, na 014). cliente_id = FK no auth, claim e coluna de escopo no app — sem FK cross-DB.

Detalhe do contrato em central-de-apps e na constituição §7 (v0.17.0). O app_id (kebab) é o identificador canônico, num namespace único com os oauth_grants.

Alternativas consideradas

  • Plano de controle runtime (GET /api/apps/config + token de consumo por par + provisionamento ao ligar + push de manifesto por CI): resolve mobile (que não redeploya binário), mas para o resto adiciona fetch no boot, ciclo de vida de token por par e push de manifesto — indireção sem ganho quando a config client-grade pode ser embutida no build. Preterido; o que o runtime resolvia de fato (segredo que não pode ir no bundle, dado que muda sem redeploy) sobrevive enxuto nos corretores + flags.
  • Arquivo separado tipo firebase.json/xadm.json: mais um manifesto a versionar e manter em sincronia. Preterido — tudo no app.json (fonte única, §1.9).

Consequências

  • Feature flags saem daqui para a spec 014: estado no DB do app (não no auth); auth/central = painel; canal de controle = endpoint do app + JWT validado pelo JWKS do auth; extensível por model (powersync agora, firebase-remote no futuro).
  • Manifesto: features deixou de ser lista e virou objeto; o validador rejeita a lista legada com erro de migração e chave desconhecida com erro (vocabulário fechado glitchtip|garage|analytics|docs).
  • Handoff Camada 2 (specs de andaime, a refinar/implementar pelos apps): auth.ia/005-central-de-apps.spec.md (broker + configurador de secrets + corretores + modelo V7 apps/app_provider_resources + backfill dos grants); authui.ia/002-central-de-apps-ui.spec.md (UI centrada em Apps: cards, detalhe, autorizar acessos). Ambas atendem só a 013 — flags (014) ficam fora por ora.
  • Guard de deploy no ci.yml entregue como placeholder comentado opt-in — o broker/ensure-secrets do auth e a API set-secret do Coolify são Camada 2 (REGRA Nº 3, deferido explícito).