Pular para conteúdo

0005 — Central de Apps: paradigma build-time

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

Contexto

A Central de Apps (spec 013) transforma o central-backend 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 central-backend 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 o broker do central-backend (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: só corretores (URL assinada/expirável — embed do Metabase, presign do Garage) e feature flags (protocolo próprio, spec 014).
  • Papéis: central-backend = 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 central-backend = autenticação/autorização + catálogo; DB do app = dado de domínio (e estado de flag, na 014). cliente_id = FK no central-backend, claim e coluna de escopo no app — sem FK cross-DB.

Correção 2026-09-12: a imagem do web é buildada pelo job build_web do pipeline.yml, fora do host de produção, e o client-grade entra por --dart-define no build; o Coolify só puxa a imagem (0026). Não existe guard de deploy que injeta: os checkpoints são dois (/xadm-setup e o guard soft da /xadm-release), o SENTRY_AUTH_TOKEN é secret do repo no GitHub, lido pelo build_web, e injected: false significa setar o env à mão no recurso.

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 central-backend); central-backend/central = painel; canal de controle = endpoint do app + JWT validado pelo JWKS do central-backend; 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): central-backend → .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 central-backend e a API set-secret do Coolify são Camada 2 (REGRA Nº 3, deferido explícito).