Pular para conteúdo

0008 — cliente_id é a chave canônica do tenant

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

Contexto

Um incidente (loop §6, feedback de um repo de app) revelou uma conflação no padrão da casa: o app.json tinha um só campo cliente ("Vantroba" — rótulo de exibição, maiúsculo) e ele era mandado como cliente_id onde a plataforma espera a chave canônica clientes.cliente_id (minúscula, "vantroba"). A conflação vivia no template app.json, na skill /xadm-setup e, por cópia, nos repos de app — fora do auth. O auth (§7) sempre definiu cliente_id como chave canônica, mas o manifesto público nunca a declarava: só carregava o display, e o setup derivava a chave do rótulo — que quebra quando a chave ≠ minúsculo do display (onpetrotrading, e o próprio caso "Vantroba" × "vantroba").

Decisão

cliente_id (chave canônica, minúscula) e cliente (rótulo de exibição) são campos distintos; a plataforma escopa pela chave declarada e nunca a deriva do display. Camadas (a+b):

  • (a) Chave explícita no app.json. Novo campo cliente_id (minúsculo kebab, clientes.cliente_id), obrigatório quando grupo=cliente, distinto do cliente (display). O template/app.json e o exemplo da central-de-apps declaram os dois.
  • (b) Guarda fail-closed no /xadm-setup. A skill lê cliente_id (nunca deriva de cliente), valida contra o catálogo clientes do auth antes de provisionar — chave desconhecida não provisiona — e manda a chave ao broker; o cliente só rotula (coleção Metabase, path no portal).
  • Guarda barata offline (§6). O valida-frontmatter rejeita cliente_id presente e malformado (não-minúsculo/kebab) — pega o display-como-chave no gate do app, sem rede, antes do broker. Fixtures versionadas: cliente-id-maiusculo (o incidente → erro) + ok com cliente_id válido (happy-path).

Alternativas consideradas

  • (b) só derivar/validar na skill (sem campo novo): menos ripple nos app.json, mas derivar slug(display) assume que a chave é o minúsculo do rótulo — a premissa que causou o incidente. Preterido como fonte única; a validação-contra-catálogo sobrevive como guarda de (a).
  • Exigir cliente_id no valida-frontmatter (hard): quebraria o CI de todo app de cliente legado na hora (o validador é baixado fresco do toolchain). Preterido: presença é dirigida por template/skill/§7; o validador só barra o valor malformado (o incidente), sem detonar pipelines.

Consequências

  • Adoção oportunista (§1.6): apps de cliente existentes ganham cliente_id ao re-derivar o template; enquanto não têm, o setup para e pede (fail-closed), não adivinha.
  • Fronteira Camada 2: a validação-contra-catálogo roda no broker do auth (como a 0005); o central entrega o contrato (template + skill + norma) e a guarda offline do valida-frontmatter.
  • api-rest.md/contrato de erro e os 2 testes de negócio são do PR do repo do incidente — o central cobre o padrão (para os próximos apps não repetirem).