CORTEX · doc

Institutional Service

regra comercial e painel de comando

11 regras · v0.4.1 · rascunho · owner: plataforma · 22 KB · institutional-service · sumário em JSON

CORTEX — institutional-service (regra comercial e painel de comando)

Versão: 0.4.1 · Data: 2026-10-14 · Status: Rascunho · Owner: Plataforma Caminho canônico: cortex-docs/services/INSTITUTIONAL_SERVICE.md Documentos irmãos: cortex-docs/ECOSYSTEM.md (mapa do ecossistema) · cortex-docs/standards/UNISCALE_ENGINEERING_STANDARDS.md (padrões técnicos) · cortex-docs/services/STORAGE_SERVICE.md (política de upload — §7, que casa com a §3 deste doc)

Este documento define as regras do institutional-service — o cérebro de configuração do CORTEX e o painel de comando por onde os times governam o negócio e o comportamento das IAs, sem tocar em código. É make puro: não há o que terceirizar — é onde mora o juízo comercial. Rascunho pendente de revisão.

O princípio que organiza todo o ecossistema (ECOSYSTEM §2): executor burro, regra no institutional. Os demais serviços e as IAs aplicam o que o institutional configura — não decidem. Quando a regra muda, muda aqui, num lugar só, e vale para toda a operação.


1. Fonte única da regra de negócio (Obrigatório)

O institutional-service é o dono e a fonte única da regra de negócio: produtos, lotes, preços, descontos, alçadas de aprovação, a tradução para IDs de terceiros (jacad e afins) e a topologia do CRM (pipes, raias, mapa estado→raia).

  • Nenhum outro serviço ou IA decide essas regras — eles recebem a configuração e aplicam. O ai-sales não inventa preço (aplica o lote vigente); o tracking não decide raia (aplica o mapa); o order-service não traduz (usa os IDs já prontos).
  • É aqui que mora a resposta para o "desconto que some": conta de dinheiro é regra, não texto de prompt — a IA chama a regra, o institutional a calcula/valida.

A regra só existe quando configurada aqui. Serviço que precise de uma regra que não está no institutional para e pede — não inventa (mesma disciplina de FALLBACK dos repos).

2. Configuração sem deploy, versionada e distribuída por fato (Obrigatório)

A configuração é editada pela área (não por dev, não por deploy): muda no painel e passa a valer. Para isso:

  • Sem deploy. Ajustar uma regra (preço, desconto, alçada, mapa de CRM, política — §3) é mudança de dado, não de código.
  • Versionada com autoria. Toda mudança registra quem alterou e gera uma versão (UNISCALE §23.6 + colunas base). O institutional guarda o histórico completo de edição (é o dono).
  • Distribuída por fato/evento, não por banco compartilhado. Os executores não leem o banco do institutional nem fazem chamada síncrona no caminho crítico. Cada mudança publica um fato (mesma mecânica de fila do ecossistema — ECOSYSTEM §5, UNISCALE §28); quem consome mantém réplica local versionada e aplica upsert idempotente pela versão (banco-por-serviço; desacoplamento e performance).

3. Dono, editor e publicador da política de upload (Obrigatório)

A política de upload consumida pelo storage-service (STORAGE_SERVICE §7, ecosystem.services.storage-upload-policy) é propriedade do institutional — esta é a regra recíproca daquela. A política é endereçada pela tripla tenant_id × context × content_type e carrega os critérios do upload (teto de tamanho, content-type permitido, TTLs de upload/GET/pending, enabled).

  • Autorização do editor. Só usuário autorizado (por tenant/context, conforme as alçadas — §1) pode criar, alterar ou desabilitar uma política. Quem pode editar o quê é regra do institutional, não do storage.
  • Publicação do fato. Toda criação/edição/desabilitação publica o fato "política de upload alterada", carregando a nova versão e a política (a tripla-chave + os campos), no envelope-padrão de evento (UNISCALE §28.2). É esse fato que o storage-service consome para atualizar sua réplica (upsert idempotente pela versão — §2 + STORAGE §7).
  • Nunca banco compartilhado. O institutional não expõe seu banco ao storage; a única via é o fato. O storage não chama o institutional no caminho do upload.
  • A presença de uma política para a tripla é a permissão; ausência → upload negado no storage (deny-by-default lá). O institutional, ao não publicar (ou ao desabilitar), revoga a permissão.

(O desenho exato do schema do fato e dos campos segue o contrato de evento — ver Fronteiras e STORAGE §7 para a tabela de campos da política.)

4. Governança dos prompts das IAs (Obrigatório)

O comportamento das IAs é configurado aqui: os prompts de cada IA — estrutural, institucional, de segurança e de conteúdo — são geridos pelo institutional, versionados e com autoria (§2).

  • Mudança de prompt não vai ao ar em tempo real. Antes de chegar à IA final, a alteração passa por uma etapa de análise automática — concordância, lógica, idioma e segurança — feita por outra IA treinada para revisar, e só é aplicada após aprovação.
  • É um portão que mitiga erro, ambiguidade e quebra de idioma/segurança antes de afetar o atendimento — sem tirar a autonomia da área (os checks rodam em segundos, sem dev no meio).
  • A IA final aplica o prompt aprovado; quem decide o comportamento é a área, pelo institutional.

(O conjunto exato de análises, o critério de aprovação e o versionamento do prompt são detalhe de implementação — ver Fronteiras.)

5. Registro e distribuição de tenants (Obrigatório)

O institutional-service é o registro de tenants do ecossistema: quem cadastra a instituição (o tenant) e a quem cada propriedade digital (site, LP, formulário) pertence. Os demais serviços não cunham tenant_id — recebem-no pronto e o aplicam (uniscale.columns.multi-tenancy).

  • Distribuído por fato, como o resto da config (§2). Criar/alterar um tenant publica institutional.tenant.created / institutional.tenant.updated (exchange institutional, envelope padrão); quem consome mantém réplica local versionada e faz upsert idempotente pela versão. Ninguém lê o banco do institutional.
  • Fecha uma fronteira que já quebrou. Sem dono, o mesmo Hub nascia com tenant_id diferente em cada serviço (uma constante de seed de um lado, uma migration do outro), e a primeira consulta entre serviços voltou vazia. O provisionamento deixa de ser "preenchido à mão" (ai-wallet §8, identity Fronteiras).
  • É o institutional quem amarra propriedade → tenant. É isso que permite o tracking resolver o dono do lead pela write_key (ecosystem.services.tracking-ingest-tenancy): a write_key da LP X pertence ao tenant 1, a da LP Y ao tenant 2, e essa associação nasce aqui.
  • platform.tenants é a fonte; o registro carrega colunas base e autoria (§2).

6. Menu único, recortado por permissão (Obrigatório)

O painel tem um único menu, com todas as áreas do Hub. Não há seletor de unidade de negócio, nem menu diferente por área: o que muda de pessoa para pessoa é o que ela enxerga, e isso é decidido pela permissão.

  • A permissão é granular, no formato <área>.<recurso>.<ação> (platform.users.create, leads.contacts.reveal). Perfis apenas agrupam permissões; quem autoriza é a permissão, nunca o perfil em si.
  • Uma área aparece no menu quando o usuário tem ao menos uma permissão nela. Um agrupamento aparece quando um filho dele aparece — senão o filho ficaria órfão na barra lateral.
  • A chave da área sai do catálogo de permissões, não de fatiar o código por ponto. O código é <área>.<recurso>.<ação>, mas a chave da área nem sempre é o primeiro segmento (ai-wallet contra ai.wallet.contents.read). Derivar por corte de string faz o menu sumir sem ninguém entender por quê — o catálogo diz a qual área cada permissão pertence.
  • Área não construída aparece desabilitada, não escondida. O menu comunica o que o produto terá; esconder faria cada área nova parecer surpresa. Habilitar é mudança de dado, não deploy do front (§2).
  • A interface esconde por conveniência; a API recusa por segurança. O front usa a permissão para não oferecer o que não se pode fazer, mas toda rota exige a mesma permissão — esconder botão não é controle de acesso.

7. Unidade de negócio é atributo de pessoa, não regra de acesso (Obrigatório)

O usuário interno pertence a uma unidade de negócio (comercial, financeiro, acadêmico, CRM, marketing…) — nunca a duas. A unidade diz de qual área a pessoa é; ela não decide o que a pessoa vê.

  • Quem decide o que aparece é sempre a permissão (§6). Duas pessoas da mesma unidade com perfis diferentes enxergam coisas diferentes; duas de unidades diferentes com o mesmo perfil enxergam o mesmo.
  • Por que separar. Amarrar visibilidade à unidade cria uma segunda autorização, paralela à permissão e invisível no perfil — e as duas divergem no primeiro caso de exceção ("ele é do comercial mas precisa ver o financeiro"). Com a separação, a exceção é um perfil, não um remendo.
  • A unidade é opcional: conta de serviço não tem, e pessoa sem unidade definida continua operando normalmente.

8. Alçada não é permissão (Obrigatório)

Permissão responde "pode executar esta ação?". Alçada responde "até que ponto a decisão dele vale sozinha?". São dois eixos, e colapsá-los num só é o erro que a §1 já antecipa ao citar "alçadas de aprovação" junto da regra comercial.

  • Permissão é booleana e por ação: tem ou não tem commercial.discount.approve.
  • Alçada é um limite com um aprovador acima: aprova desconto até X; acima disso, o pedido sobe. Carrega valor, faixa e cadeia de aprovação — coisas que uma permissão não expressa.
  • Consequência prática: a mesma pessoa pode ter permissão para aprovar e ainda assim não poder aprovar aquele desconto. Um sistema que só tem permissão resolve isso criando perfis por faixa de valor (desconto-ate-10, desconto-ate-20), que é onde o modelo apodrece.
  • Não implementado ainda. Fica registrado para que ninguém resolva alçada com permissão enquanto o modelo não existe (o vocabulário exato segue nas Fronteiras).

9. Propriedade digital e write_key são emitidas aqui, por propriedade (Obrigatório)

Regra recíproca de ecosystem.services.tracking-ingest-tenancy e ecosystem.services.tracking-key-rotation. O institutional cadastra cada propriedade digital (site, LP, formulário, conteúdo), a amarra ao tenant (§5) e emite a write_key que a identifica na captura.

  • Uma chave por propriedade, nunca por tenant. É o que permite atribuição verificada no servidor, allowlist de origem restrita àquela página e revogação com raio contido — os três motivos estão no tracking §8 e não se repetem aqui.
  • Uma marca é uma propriedade digital (um site), não um nível à parte. O modelo tem dois níveis — tenant (a instituição) → propriedade digital — e não há camada "marca" entre eles: uma marca é um site, cadastrado como propriedade com a sua write_key. Marca que precise de segregação total (dado, regra, isolamento) é outro tenant (§5), não um nível novo.
  • Distribuída por fato versionado (§2), com réplica local no tracking. Ninguém lê o banco do institutional, nem no caminho da captura.
  • Rotação tem duas chaves válidas ao mesmo tempo. A chave em retirada carrega valid_until; a sequência é emitir a nova → publicar nas páginas → só então marcar a antiga. A decisão de revogar consulta a telemetria de uso que o tracking mantém (tracking §8-bis) — revogar sem consultá-la é aposta.
  • O institutional não sabe o que acontece na página. Ele cadastra a propriedade e emite a chave; comportamento, sessão e evento são do tracking. Executor burro vale nos dois sentidos.
  • Não implementado ainda — entra junto com o consumo do fato no tracking.

10. Área de Leads: o painel compõe, não é dono (Obrigatório)

A tela de Leads — lista, detalhe e jornada — é do institutional. O dado não é: comportamento é do tracking, pessoa e PII são do identity. O painel compõe as duas fontes e não guarda cópia de nenhuma.

  • Leads é área de topo, não um item dentro do comercial: o dado é de dois serviços de plataforma e várias áreas o consultam.
  • Nome é PII e obedece à permissão. A lista exibe o nome para quem tem a permissão de revelar e ***** para quem não tem — e a máscara é aplicada no servidor. Mascarar na tela seria teatro: o acesso já teria acontecido e já teria entrado no pii_access_log do identity. Quem não pode ver não dispara leitura nenhuma.
  • Lista usa list_display_names; detalhe usa get_person (identity §9). Ler nome em lista com a leitura completa geraria uma linha de auditoria por linha da tabela.
  • Navegador compartilhado não vira pessoa. Lead com mais de um person_id exibe a situação "compartilhado", não atribui o comportamento a ninguém e recusa a revelação — escolher uma das pessoas faria a ficha de uma exibir o que a outra navegou (tracking §18). A tela diz o motivo, em vez de mostrar um campo vazio.
  • O painel não escreve no tracking nem no identity. O que ele produz são fatos (institutional.merge_candidate.resolved, institutional.person_merge.requested — identity §16); leitura é síncrona e autenticada (uniscale.service-internals.service-auth).

11. Usuário interno pode pertencer a mais de uma organização (Obrigatório)

O usuário interno (operador do painel) pode pertencer a mais de uma organização/tenant — o vínculo usuário ↔ tenant é N:N. (Lead/pessoa é outra coisa: a mesma pessoa física em dois tenants são duas pessoas sem ligação — identity §13; esta regra é sobre o operador, não sobre o lead.)

  • Opera em um tenant ativo por vez. O isolamento "nunca cross-tenant" (identity §13, tracking §16) não se afrouxa: a sessão nunca mistura dados de dois tenants, e não existe visão agregada multi-org de dado. Pertencer a várias organizações é poder trocar o contexto ativo, não ver tudo junto.
  • A permissão (§6) é resolvida no contexto do tenant ativo. O mesmo operador pode ter permissões diferentes em cada organização — platform.users.create numa, só leads.contacts.reveal noutra. Não há permissão "global entre orgs".
  • A unidade de negócio (§7) é por organização: o "uma unidade, nunca duas" vale dentro de cada tenant — um operador multi-org tem no máximo uma unidade em cada.
  • Como a organização ativa viaja na sessão/credencial é decisão de token, e está decidida: uniscale.service-internals.token-format (UNISCALE §29.8) — o token carrega uma org, e trocar de organização reemite o token; não existe token multi-org com a requisição dizendo qual. Esta regra segue fixando só o modelo (N:N, um ativo por vez, permissão e unidade por org, isolamento intacto); o encoding é da camada de plataforma.

Fronteiras a definir (não inventar)

Itens reconhecidos mas ainda não regrados. Quem precisar deles para e pede a regra — não improvisa.

  • Schema das regras e da config — o desenho das tabelas (produtos/lotes/preços/descontos, alçadas, mapa de CRM, política de upload) não está fechado; deriva caso a caso. Coerente com "docs documentam o como, não o schema".
  • Contrato exato dos fatos de configuração — o envelope segue UNISCALE §28.2, mas o data de cada fato (ex.: "política de upload alterada", "regra comercial alterada") e a granularidade (um fato por mudança? por entidade?) ficam a definir.
  • Modelo de alçadas — o vocabulário exato de "quem pode aprovar o quê" (desconto acima do limite, edição de política por tenant/contexto) está em aberto; o §8 agora explica por que ele não pode ser resolvido com permissão.
  • Pipeline de análise de prompt (§4) — quais checks, em que ordem, com qual critério de aprovação e qual IA revisora; e o versionamento/rollback do prompt.
  • Cockpit de atendimento humano — hoje é o bitrix24; o institutional como alvo do cockpit é fronteira (ECOSYSTEM §4). A fila de fusão do identity (§16 de lá), servida pela área de Leads (§10), é a primeira tela desse cockpit a existir de fato — inaugura a fronteira, em vez de mantê-la só aberta.

CHANGELOG

Versão Data Resumo
0.4.1 2026-10-14 A decisão de token que a §11 remetia à plataforma saiu: UNISCALE §29.8 (uniscale.service-internals.token-format). A §11 passa a apontar o registro em vez da pendência — uma org por token, troca de organização reemite —, e o institutional é o emissor do token do ecossistema (é quem tem usuário, perfil e permissão: §5, §6). Nenhuma regra desta doc muda de conteúdo. PATCH.
0.4.0 2026-10-14 Responde duas dúvidas de contexto de tenants/organização (decisões do Guilherme, 14/10). §11 (institutional-user-tenancy, nova): o operador do painel pode pertencer a mais de uma organização/tenant (vínculo N:N), mas opera em um tenant ativo por vez — o isolamento "nunca cross-tenant" (identity §13, tracking §16) não afrouxa, não há visão agregada multi-org; a permissão (§6) e a unidade de negócio (§7) passam a ser resolvidas por organização. Como a "org ativa" viaja na credencial é a decisão de token da uniscale.service-internals.service-auth §29.6 (mecanismo único de plataforma, a registrar por §31.3), fora deste doc — a §11 fixa só o modelo. §9 (esclarecimento): uma marca é uma propriedade digital (um site), não um nível à parte — o modelo tem dois níveis (tenant → propriedade); marca que precise de segregação total é outro tenant (§5), não camada nova. MINOR.
0.3.0 2026-09-24 Promove as regras do painel, com texto da sessão que construiu (implementadas salvo onde marcado). §6 (institutional-menu-permission): menu único recortado por permissão granular <área>.<recurso>.<ação> (perfis só agrupam); área aparece com ≥1 permissão, chave da área vem do catálogo (não de fatiar string), área não construída fica desabilitada, e a API recusa o que o front esconde. §7 (institutional-business-unit): unidade de negócio é atributo de pessoa (uma só), não regra de acesso — quem decide o que se vê é a permissão. §8 (institutional-authority-vs-permission): alçada ≠ permissão (booleana por ação × limite com aprovador acima), registrada para impedir o atalho de resolver alçada com perfis por faixa; não implementada. §9 (institutional-digital-property): recíproca de tracking §8/§8-bis — write_key por propriedade, emitida aqui, distribuída por fato, rotação com valid_until consultando a telemetria do tracking; não implementada (entra com o consumo no tracking). §10 (institutional-leads-area): a área de Leads compõe tracking+identity sem guardar cópia — nome mascarado no servidor por permissão, lista via list_display_names e detalhe via get_person (identity §9), navegador compartilhado não vira pessoa (tracking §18), e o painel só escreve por fato (identity §16). Fronteiras atualizadas: §8 explica por que alçada não é permissão; a fila de fusão do identity inaugura o cockpit. MINOR.
0.2.0 2026-09-24 Acrescenta §5 (institutional-tenant-registry): o institutional é o registro de tenants e os distribui por fato (institutional.tenant.created/.updated), como já faz com o resto da config (§2) — fechando a fronteira de provisionamento de tenant que estava "a definir" em ai-wallet §8 e identity, e que já havia quebrado (mesmo Hub com tenant_id distinto em cada serviço). É o institutional quem amarra propriedade digital → tenant, o que permite o tracking resolver o dono do lead pela write_key. Origem: pedidos da sessão do institutional-service (24/09). O restante do pedido do institutional (menu por permissão, unidade de negócio, alçada≠permissão, área de Leads) fica para uma 0.3.0, com o texto vindo da sessão que construiu. MINOR.
0.1.0 2026-06-17 Rascunho inicial do institutional-service. Promove a @rule o que já está assentado: fonte única da regra de negócio (§1, executor burro / regra no institutional — ECOSYSTEM §2); configuração sem deploy, versionada e distribuída por fato (§2, banco-por-serviço + réplica idempotente); dono/editor/publicador da política de upload (§3, regra recíproca da STORAGE §7 — autorização do editor + fato "política de upload alterada" versionado, nunca banco compartilhado, deny-by-default no storage); governança dos prompts das IAs (§4, mudança passa por análise — concordância/lógica/idioma/segurança — feita por outra IA e só vai à IA final após aprovação). Fronteiras em aberto (schemas, contrato dos fatos, modelo de alçadas, pipeline de análise de prompt, cockpit) marcadas como NÃO-inventar. Regras no namespace ecosystem, área services.