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.mdDocumentos 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-salesnão inventa preço (aplica o lote vigente); otrackingnão decide raia (aplica o mapa); oorder-servicenã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-serviceconsome 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(exchangeinstitutional, 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_iddiferente 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,identityFronteiras). - É o institutional quem amarra propriedade → tenant. É isso que permite o
trackingresolver o dono do lead pelawrite_key(ecosystem.services.tracking-ingest-tenancy): awrite_keyda 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-walletcontraai.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 otrackingmanté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 nopii_access_logdoidentity. Quem não pode ver não dispara leitura nenhuma. - Lista usa
list_display_names; detalhe usaget_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_idexibe 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
trackingnem noidentity. 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.createnuma, sóleads.contacts.revealnoutra. 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 umaorg, 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
datade 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. |