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: só 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 (noci.yml). - 2 naturezas × plataforma: client-grade (DSN/key) →
app.json(web = build-arg via Coolify; mobile =--dart-defineno 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 noauth, 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 noapp.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 doauth; extensível pormodel(powersync agora, firebase-remote no futuro). - Manifesto:
featuresdeixou de ser lista e virou objeto; o validador rejeita a lista legada com erro de migração e chave desconhecida com erro (vocabulário fechadoglitchtip|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 V7apps/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.ymlentregue como placeholder comentado opt-in — o broker/ensure-secretsdoauthe a API set-secret do Coolify são Camada 2 (REGRA Nº 3, deferido explícito).