0038 — Uma identidade por app: app_id == slug¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-09-21 · Decidido em: 2026-09-21
Contexto¶
A 0024 normatizou o slug como identificador público e nome da imagem, e
decidiu explicitamente que ele pode divergir do app_id, com a razão registrada: "mexer nele
quebra grants e identidade no broker. Logo, slug ≠ app_id por decisão, não por acidente."
A frota seguiu a norma à risca. Levantamento de 2026-09-21 mostrou dois namespaces, cada um
internamente coerente — o app_id casando com o projeto GlitchTip e com db_auth.apps em todas
as linhas:
slug (entrega) |
app_id (catálogo) |
|---|---|
onpetro-bi |
bi-comercial |
onpetro-xls |
bi-comercial-xls |
vantroba-bi |
bi-transporte |
vantroba-xls |
bi-transporte-xls |
thoms-webstorm |
thoms-integracao-produto-ecom |
integrador-sascar |
int-sascar |
central-ui |
central-apps-auth |
integrador-server |
integrador |
O custo apareceu no uso, não na norma. Com dois nomes por app, toda investigação que atravessa
sistemas — achar no Coolify o app cuja issue está no GlitchTip, ligar um alarme ao recurso de deploy —
exige uma tradução mental que ninguém tem de cabeça, e a divergência é indistinguível de defeito para
quem chega. Dois defeitos reais ficaram escondidos justamente por isso, porque pareciam ser mais um
caso do padrão: o integrador-server apontava para projeto GlitchTip inexistente (o campo só é
lido pelo job build_web, skipped nele, então falhava calado), e o rename auth →
central-backend estava pela metade havia semanas.
Decisão¶
Uma identidade por app. O app_id do docs/app.json é igual ao slug, e esse nome é o mesmo em
todos os sistemas. Isto substitui a cláusula "slug pode ≠ app_id" da 0024;
todo o resto da 0024 (forma do slug, slug == nome da imagem, slug deriva o nome do recurso Coolify)
segue valendo.
A invariante completa:
<identidade> == app.json slug == app.json app_id
== nome do repo (Forgejo e GitHub)
== imagem do registry (fonte.xadm.biz/xadm/<id>)
== prefixo do recurso Coolify (<id>[-<instancia>]-<alvo>-pull)
== caminho do docs-site (docs-sites/<id>)
== db_auth.apps.app_id e db_auth.apps.slug
== slug do projeto GlitchTip
== app_provider_resources.resource_ref.project_slug
== features.glitchtip.project do app.json
== o app_id que o app manda no login
Decisões de apoio:
- A forma do nome continua a da 0024:
<cliente_id>-<projeto>para app de cliente,<projeto>para app da X-Adm, kebab-case. Foi o que corrigiuho-scraper→sulplata-ho-scraper, o único app de cliente cujo slug não levava o prefixo do cliente. - Os dois campos continuam existindo no
app.json, agora obrigatoriamente iguais. Não se colapsa num só campo: é o par que permite a migração ser por app, e é nele que o gate bate. - A PASTA do repo não é identidade. O caminho na raiz multi-repo é legibilidade humana:
clientes/onpetro/bi-comercialse lê melhor queclientes/onpetro/onpetro-bi, porque o caminho já carrega o cliente. A ligação pasta↔identidade é odocs/app.json, e só ele. Medido: renomear as pastas custaria ~350 referências reais emetc/tests(compose dos e2e, scripts.ps1, allowlists de.claude/settings.json) para ganho funcional zero. - A URL pública não é identidade.
<função>.<cliente>.xadm.bizé para humano digitar;excel.onpetro.xadm.bizservindo o apponpetro-xlsestá correto.
Como migrar sem quebrar — a razão da 0024 era real¶
A 0024 dizia que mexer no app_id quebra grants. Está certa, e só para uma classe de app: o app
que manda o próprio app_id no login, compilado no bundle.
// clientes/onpetro/bi-comercial/lib/core/config/app_config.dart:122
appId: ouPadrao(const String.fromEnvironment('APP_ID'), 'bi-comercial'),
// .../features/000_login/services/social_auth_service.dart:188
body: jsonEncode({'cliente': cfg.authTenant, 'app_id': cfg.appId}),
Renomear a linha do catálogo sem reconstruir o app faz o login mandar um id fora do catálogo: o claim
oauth_app_id deixa de ser emitido e o acesso escopado cai.
Só 2 dos 11 apps estão nessa classe (os dois BIs Flutter). Os outros 9 têm app_id apenas como
dado de catálogo — convergem com um UPDATE e um rename de projeto, sem release. Levantado por
grep -rl app_id src/main lib: devolve 0 em integrador-server, int-sascar, os dois xls,
maxsul-pied e thoms-webstorm; e no central-ui as 8 ocorrências são todas de consumo de
app_id vindo da API, nunca a própria identidade.
Para os 2 que mandam, a migração é por app, na release do próprio app, com coexistência das duas linhas para janela zero e sem tocar no central-backend:
app_idnovo noapp.json— e garantir que o build injetaAPP_ID(obi-transporteinjeta,Dockerfile:65; obi-comercialnão, então hoje ignora oapp.jsone usa o default compilado — corrigir isso primeiro, senão oapp.jsonmente);- inserir a linha nova no catálogo mantendo a antiga, duplicando
app_roleseapp_user_accessnas duas (obi-comercialtem 4 papéis e 10 acessos); - release do app;
- remover a linha antiga, renomear o projeto GlitchTip e atualizar o
resource_ref.
O que NÃO acompanha o rename automaticamente¶
Duas linhas da invariante não se movem sozinhas, e são a fonte das armadilhas:
app_provider_resources.resource_ref.project_slug— é dele, e não doapp_id, que o central-ui monta o link do GlitchTip (AppCatalogService). Renomear o projeto e atualizar o ref são um passo atômico. Confirmado na prática durante a execução: na janela entre os dois, um script de monitoração que consultava/projects/x-adm/integrador/issues/passou a devolver vazio, em silêncio — sem erro, o que é o pior modo de falha possível.- o
app_idcompilado no bundle — ver acima.
E um sistema fica deliberadamente fora: o Aptabase. O resource_ref.aptabase_app guarda o nome
do app no SaaS externo; ele só muda quando for renomeado lá, e até então o valor antigo é o correto
em relação àquele sistema.
Consequências¶
- Rename de projeto GlitchTip é barato e não perde evento: o DSN referencia o id numérico
(
bug.xadm.biz/16), não o slug. Verificado: histórico das issues intacto nos 7 projetos renomeados. - Nada no registry mudou: as 10 imagens já eram o slug canônico, então a convergência não custou rebuild, retag nem recurso Coolify de app.
- O deploy não é afetado por
app_id: oPOST /api/ci/deploy(0026) recebe um campo chamadoapp_idmas o usa comoregistry_slug, sem consultar a tabelaapps. Com uma identidade só a ambiguidade desaparece; o nome do campo deve ser corrigido pararegistry_slug(hoje o próprio javadoc admite: "app_id (== registry_slug do reconcile)"). - Gate obrigatório, senão a convenção volta a ser só convenção: o
/xadm-docsconfere a invariante, e em especialfeatures.glitchtip.project == app_id == slug. É a checagem que pegaria sozinha os dois defeitos que motivaram esta decisão. - Estado em 2026-09-21: 9 dos 11 apps convergidos (catálogo, GlitchTip e
app.json). Faltambi-comercial→onpetro-biebi-transporte→vantroba-bi, cada um na release do seu app.