Papéis, Permissões e Rotas
Esta documentação serve de referência técnica (inclusive para IA) sobre os níveis de acesso na plataforma Flowi Agentic.
A plataforma possui uma arquitetura SaaS Multi-tenant. O controle de acesso baseia-se primordialmente na coluna global_role do usuário — que vale SUPER_ADMIN ou nada — e no papel (role) do usuário no contexto de um Tenant, gravado em user_tenant_memberships.platform_role.
Nenhum papel vem de um provedor externo
A sessão é sempre um JWT próprio, emitido e validado pela própria aplicação (security/JwtTokenProvider.java, service/AuthService.java). Existe login OIDC — as conexões de SSO em /admin/sso, tratadas por SsoConnectionService e SsoCallbackService —, mas ele só autentica: o provisionamento automático grava globalRole = null (SsoCallbackService.provision), nenhum grupo do diretório vira papel, e nenhum vínculo de tenant é criado. Quem procurar um console de identidade para conceder papéis não vai achar: papel se concede pelo banco da própria plataforma, via /admin/users e /admin/tenants/{id}/members.
1. Perfis e Níveis de Acesso
A. Super Admin (Admin Global)
- Identificação Frontend:
roles.includes('SUPER_ADMIN') - Identificação Backend:
hasRole('SUPER_ADMIN'), resolvido a partir da claim de papel global do JWT emitido pela própria plataforma. - Escopo: Todo o sistema. Não está amarrado a um tenant específico na interface de administração global.
- Responsabilidades: Cadastrar tenants, gerenciar definições de processos globais (BPMN/CMMN), templates DMN, gerenciar configurações de IA e todos os usuários.
B. Tenant Admin (Administrador do Tenant)
- Identificação Frontend:
!isSuperAdmin&¤tTenant?.role === 'ADMIN' - Identificação Backend:
@tenantSec.isCurrentTenantAdmin(authentication)nos recursos/a/*. Não alcança nada em/api/admin/**— oSecurityConfigexigeSUPER_ADMINno matcher, e a authority de um Tenant Admin éROLE_ADMIN. - Escopo: Restrito aos dados do seu próprio Tenant.
- Responsabilidades: Configurar o Business Key padrão do tenant, habilitar/desabilitar processos publicados no seu catálogo, gerenciar robôs e runners, API Keys, Webhooks, caixas de entrada de e-mail, Variáveis e segredos e a Retenção de dados do tenant. Os agentes de IA não são robôs: moram em cada processo, e também o Modelador os configura. Membros do tenant não estão nessa lista:
/api/admin/tenants/{id}/members*éSUPER_ADMINonly.
B.1. Tenant Modeler (Modelador do Tenant)
- Identificação Frontend:
currentTenant?.role === 'MODELER' - Identificação Backend:
@tenantSec.isCurrentTenantModeler(authentication)— aceitaMODELEReADMINcom vínculo (UserTenantMembership) no tenant corrente;SUPER_ADMINpassa sempre. Uma chave de API não tem vínculo e por isso nunca passa. - Escopo: Restrito aos dados do seu próprio Tenant.
- A regra, em uma linha:
MODELERéADMINmenos as chaves do tenant, os robôs, os webhooks, as caixas de entrada, as variáveis e segredos da empresa, a retenção de dados, o consumo de IA do tenant e as pessoas. Ele desenha, configura e publica processo; não administra a organização. - Responsabilidades: catálogo de processos, modelador e versões — inclusive publicar uma versão; formulários; tabelas de decisão (DMN); papéis de processo, variáveis do processo e tipos documentais; bases de conhecimento e agentes de IA do processo; o seletor de Java delegates; a documentação do processo; a regra de gatilho de e-mail (
/a/mail-rules), que hoje mora na aba Configurações da definição, e o log de entregas (/a/mail-deliveries) — uma mensagem que não iniciou processo é diagnóstico sobre o desenho. O log nomeia a caixa de cada mensagem pela lista sem credenciais de/a/mail-rules/inboxes, então o modelador vê o nome da caixa mesmo sem acesso ao cadastro delas. Também dirige o copiloto do modelador e a validação por IA. - O que ele não alcança: membros do tenant (
/a/members), robôs e runners (/a/robots,/a/robot-runners), a geração de robôs com IA (/a/robot-generations), chaves de API (/a/api-keys), webhooks (/a/webhooks) e caixas de entrada de e-mail (/a/mail-inboxes, que guardam credencial de servidor — mesma natureza de uma chave de API). Para escolher a caixa que uma regra usa ele lê/a/mail-rules/inboxes, uma projeção que devolve apenas id, nome e situação — nunca host, usuário ou referência de senha. Também não alcança Variáveis e segredos da empresa (/admin/variables,/a/tenant-variables), Retenção de dados (/admin/retention,/a/retention) nem o Consumo de IA do tenant inteiro (/ai-usage,GET /a/ai-usage) — o consumo de um processo que ele pode alterar ele lê emGET /a/ai-usage/process/{key}. - Ele não é um posto acima do Gerente.
MODELERnão entra emPlatformRole.seesEverythingInTenant(): em execução ele enxerga o que umUSERenxerga. Cancelar, suspender ou reativar instância, ver a fila de jobs com erro e acompanhar/monitorcontinuam sendo do Gerente.
Um não-administrador passa a gastar o dinheiro do tenant
Copiloto e validação por IA consomem a cota de tokens do tenant. Dar essas telas ao modelador é uma troca deliberada — a alternativa seria um papel que não usa a ferramenta em torno da qual o produto é construído. Por isso a linha de ai_usage_logs de um turno de copiloto carrega o user_id além do tenant, e não só o tenant: a tela de governança precisa responder quem gastou. Um teto por pessoa existe em user_ai_quotas e é respeitado tanto na checagem prévia quanto no débito (TenantAiQuotaService); hoje ele só é gravado por PUT /api/admin/users/{id}/ai-quota, que é Super Admin.
B.2. Tenant Manager (Gerente do Tenant)
Identificação Frontend:
currentTenant?.role === 'MANAGER'Identificação Backend:
@tenantSec.isCurrentTenantManager(authentication)— aceitaMANAGEReADMINcom vínculo (UserTenantMembership) no tenant corrente;SUPER_ADMINpassa sempre.Escopo: Restrito aos dados do seu próprio Tenant.
Responsabilidades: o gerente opera o tenant em execução e cuida do conteúdo. Reconhecem o gerente hoje:
- CMS — cria, edita e exclui coleções e registros, carrega tabelas em lote e limpa coleções.
- Instâncias — cancelar (
DELETE /a/instances/{id}), suspender e reativar (PATCH /a/instances/{id}/suspende/activate), a fila de jobs com erro (GET /a/instances/failed-jobs,retryedeadletter) e, num caso CMMN, concluir um estágio (POST /a/instances/{id}/plan-items/{planItemId}/complete-stage). - Falhas de etapa de IA —
retryedismissem/a/ai-task-failures/{id}; a listagem mostra a ele todas as falhas do tenant. - Definições de processo — o acompanhamento por etapa (
/a/definitions/{key}/monitore/monitor/{activityId}), as métricas de SLA (GET /a/definitions/{key}/sla-metrics) e a escrita da documentação do processo (PUTeDELETEem/a/definitions/{key}/documentation). Ler a documentação basta estar autenticado. - Bases de conhecimento — todas as rotas de
/a/knowledge-bases/**e da base por processo em/a/definitions/{key}/knowledge/**, leitura inclusive. - Leitura de tipos documentais —
GET /a/document-types, que preenche o seletor de tipo do construtor de formulários. Criar, editar e excluir continua com Admin e Modelador. - Leitura de membros —
GET /a/members.
A API de agentes de IA do processo (
/a/definitions/{processKey}/ai-agents/**, inclusive o playground) e os catálogos de modelo (/a/ai-models/active,/a/ai-model-classes) também aceitam o gerente no servidor, mas a tela fica em Desenho de processos, que ele não abre. Nos demais módulos ele se comporta como Tenant User. Ao adicionar um novo módulo, decida explicitamente se ele deve reconhecer o gerente.
C. Tenant User (Usuário Padrão)
- Identificação Frontend:
currentTenant?.role === 'USER' - Identificação Backend: Acesso restrito via endpoints operacionais (
/a/*), com o tenant vindo do token da sessão. - Escopo: Restrito à operação do próprio Tenant.
- Responsabilidades: Iniciar instâncias de processo, executar tarefas (
/tasks), preencher formulários e visualizar dashboards operacionais.
2. Rotas do Frontend (React / TanStack Router)
A tabela abaixo cruza as rotas do frontend com a visibilidade de cada perfil — o que a barra lateral (components/Sidebar.tsx) mostra e o que o beforeLoad de cada rota recusa. Não é a matriz de autorização — quem manda é a seção 3 —, mas desde o papel de modelador ela é completa: toda rota restrita passa por requireArea(), e o mapa de rota para área mora em src/lib/access.ts. São seis áreas: design (Admin e Modelador), content (Admin e Gerente), knowledge (Admin, Modelador e Gerente), organisation (só Admin), tenantWideMonitoring (Admin e Gerente) e platform (nenhum papel de tenant — só o Super Admin). Sob /admin, a área padrão é platform: as telas de tenant que moram ali (/admin/webhooks, /admin/knowledge-connections, /admin/api-keys, /admin/variables, /admin/retention, /admin/process-roles, /admin/document-types, /admin/knowledge-bases) são declaradas uma a uma, e qualquer outra recusa o Tenant Admin mesmo digitada na barra de endereço.
A recusa deixou de ser silenciosa: requireArea() manda a pessoa ao /dashboard com ?denied=<área>, e o Dashboard explica em texto traduzido por que aquela tela não é dela.
O ❌ da coluna Super Admin quer dizer "não é o caminho dele", não "bloqueado": nenhum beforeLoad recusa um Super Admin que escolheu um tenant — ele passa a ver na barra lateral e a abrir as mesmas entradas de tenant que o Admin. Sem tenant escolhido, ele abre só as telas da plataforma (a área platform: tudo sob /admin que não é de tenant), o Dashboard, o perfil e a escolha de empresa; qualquer outra tela — inclusive as de tenant que moram sob /admin, como Webhooks, Variáveis, Retenção, API Keys, Tipos Documentais, Papéis de Processo e Bases de Conhecimento — o leva a /select-tenant. Para voltar a esse estado depois de escolher uma empresa, ele usa Toda a plataforma no seletor de empresa do cabeçalho, que troca o token por um sem tenant em POST /api/auth/select-platform.
Selecionar um tenant deixou de depender de vínculo também na tela: o login e GET /api/auth/me/tenants devolvem ao Super Admin todos os tenants ativos — os mesmos que POST /api/auth/select-tenant já aceitava dele —, cada um reportado com o papel SUPER_ADMIN, e o seletor de empresa do cabeçalho aparece para ele. Antes a lista vinha só de UserTenantMembership, e a conta semeada admin@flowiagentic.local, que não tem vínculo nenhum, entrava sem alcançar tenant algum.
| Rota / Path | Módulo / Função | Super Admin | Tenant Admin | Modelador | Gerente | Tenant User |
|---|---|---|---|---|---|---|
/dashboard | Visão geral, gráficos e contadores. | ❌ (Usa admin panel) | ✅ | ✅ | ✅ | ✅ |
/admin/tenants | Listagem e criação global de tenants. | ✅ | ❌ | ❌ | ❌ | ❌ |
/admin/users | Listagem global de usuários. | ✅ | ❌ | ❌ | ❌ | ❌ |
/admin/ai-config | Configuração de IA, em duas abas: Catálogo de Modelos LLM e Banco de Vetores (RAG). | ✅ | ❌ | ❌ | ❌ | ❌ |
/definitions | Definições Locais (Catálogo de Processos) - Para o Admin e o Modelador: visualiza processos publicados, permite ligar/desligar, publicar versão e configurar instâncias, tipos locais e o gatilho por e-mail. | ❌ | ✅ | ✅ | ❌ | ❌ |
/admin/global-templates | Templates Globais - Para SA: Lista tudo, permite criar BPMN/CMMN/DMN e configurar Tipos Documentais, Variáveis e Anexos globais. | ✅ | ❌ | ❌ | ❌ | ❌ |
/admin/process-roles | Catálogo centralizado de Papéis de Processo. | ✅ | ❌ | ✅ | ❌ | ❌ |
/admin/global-templates/$key | Detalhes do template e abas de configuração avançada. | ✅ | ❌ | ❌ | ❌ | ❌ |
/instances | Listagem de instâncias ativas, histórico e erros. | ❌ (Gestão global por API apenas) | ✅ | ✅ | ✅ | ✅ |
/instances/start/* | Formulário para iniciar instâncias. | ❌ (Restrito para evitar instâncias sem tenant) | ✅ | ✅ | ✅ | ✅ |
/tasks | Caixa de entrada e execução de tarefas humanas. | ❌ | ✅ | ✅ | ✅ | ✅ |
/cms | Gerenciamento de conteúdo dinâmico do tenant. - A tela exige Gerente ou Admin, e fica em Trabalho; o Modelador e o usuário comum são recusados com o motivo na tela, porque toda escrita do CMS é de Gerente ou superior. - Escrita (criar/editar/excluir/carga em lote): Gerente ou superior. - ⚠️ A API de leitura ( GET /a/cms/**) continua aberta a qualquer membro autenticado, limitada pelo sigilo da coleção. Esconder a rota no front não fecha o endpoint. | ❌ | ✅ | ❌ | ✅ | ❌ |
/admin/knowledge-bases | Bases de conhecimento do tenant, em Desenho de processos (para o Gerente, em Trabalho). - A tela exige Gerente, Modelador ou Admin, e a API exige o mesmo papel — leitura inclusive. Esconder a rota no front não é o que fecha o endpoint. | ❌ | ✅ | ✅ | ✅ | ❌ |
/monitor | Acompanhamento por etapa: diagrama do processo com a carga parada em cada atividade. Gerente ou superior. | ❌ | ✅ | ❌ | ✅ | ❌ |
/admin/document-types | Catálogo de tipos documentais do tenant, em Desenho de processos. - A tela exige Admin ou Modelador, e a API exige o mesmo para criar, editar e excluir. - A leitura ( GET /a/document-types) desce até Gerente, porque é ela que preenche o seletor de tipo no construtor de formulários; o usuário comum recebe 403. | ❌ | ✅ | ✅ | ❌ | ❌ |
/decisions | Tabelas de Decisão (DMN), em Desenho de processos → Tabelas de Decisão. - O beforeLoad (requireArea('design')) recusa quem não desenha processos — Admin, Modelador e Super Admin passam —, porque GET /a/decisions já exigia esse nível: o usuário comum só via uma lista vazia e botões que respondiam 403.- ⚠️ A avaliação ( POST /a/decisions/{chave}/evaluate) continua aberta a qualquer membro autenticado — é por ela que os processos consultam a tabela. | ✅ | ✅ | ✅ | ❌ | ❌ |
/robots | Automação e bots vinculados ao tenant. - A tela exige Admin do tenant, e a API exige o mesmo em todas as rotas /a/robots/** — inclusive ler e gravar a configuração de parâmetros, que é onde entra a referência de um segredo. | ❌ | ✅ | ❌ | ❌ | ❌ |
/admin/api-keys | Chaves de API programáticas por tenant. | ❌ | ✅ | ❌ | ❌ | ❌ |
/admin/webhooks | Callbacks configurados por tenant. | ❌ | ✅ | ❌ | ❌ | ❌ |
/admin/knowledge-connections | Conexões de conhecimento com o Microsoft 365 (SharePoint e OneDrive), em Integrações e automação. Decidem como a plataforma se autentica no diretório do cliente, por isso são do Admin do tenant; quem cura a base escolhe a conexão e a pasta na aba Fontes. | ❌ | ✅ | ❌ | ❌ | ❌ |
/admin/variables | Variáveis e segredos da empresa, em Administração — variáveis e segredos que valem para o tenant inteiro, fora de processo. - A tela exige Admin do tenant (área organisation), e a API /a/tenant-variables/** exige o mesmo. | ❌ | ✅ | ❌ | ❌ | ❌ |
/admin/retention | Retenção de dados, em Administração — a janela de retenção de cada tabela do tenant. - A tela exige Admin do tenant (área organisation), e a API /a/retention/** exige o mesmo. | ❌ | ✅ | ❌ | ❌ | ❌ |
/ai-usage | Consumo de IA do tenant, em Administração. - A tela exige Admin do tenant (área organisation). | ❌ | ✅ | ❌ | ❌ | ❌ |
/robots/runners | Runners — as máquinas que executam robôs, em Integrações e automação. - Cai no prefixo /robots (área organisation), e a API /a/robot-runners/** exige Admin do tenant. | ❌ | ✅ | ❌ | ❌ | ❌ |
/admin/tenants/$id | Gestão de membros do tenant. Só Super Admin: o beforeLoad redireciona o Tenant Admin ao Dashboard, e todos os endpoints /api/admin/tenants/** exigem SUPER_ADMIN. | ✅ | ❌ | ❌ | ❌ | ❌ |
/mail-inboxes | Caixas de entrada de e-mail do tenant, em Integrações e automação, ao lado de API Keys e Webhooks. - Guarda a conexão IMAP e a referência da senha: é credencial, e por isso fica com o Admin do tenant. - A lista de regras continua ali, em modo leitura, para o administrador ver o que depende daquela conta antes de mudá-la ou apagá-la. | ❌ | ✅ | ❌ | ❌ | ❌ |
/mail-deliveries | Toda mensagem que a plataforma leu e o que fez com ela. - Uma mensagem recusada é diagnóstico do processo que deveria ter iniciado, então o modelador também vê. | ❌ | ✅ | ✅ | ❌ | ❌ |
/admin/rag-config não é uma rota do frontend
rag-config existe só como endpoint de backend (/api/admin/rag-config). Navegar para /admin/rag-config na SPA não abre tela nenhuma — a configuração de RAG é a segunda aba de /admin/ai-config. Vale para qualquer link ou documento que aponte para lá.
3. Endpoints de Backend e Permissões (REST API)
As APIs no Spring Boot são divididas por convenção de URL e filtros de segurança.
O catálogo de caminhos, métodos e parâmetros é API REST; o que esta página acrescenta é quem pode chamar cada um e o que o backend faz quando quem chama não pode.
Prefixos Principais
/admin/**: Endpoints de gestão global.- O filtro de segurança exige
SUPER_ADMIN.ADMINé papel de dentro de um tenant e não abre nada em/api/admin/**; cada controller estreita a partir daí, e a maioria das operações éSUPER_ADMINonly (ver a tabela de administração em API REST). - Operam sem tenant selecionado, cross-tenant onde aplicável.
- O filtro de segurança exige
/a/**: Endpoints operacionais multi-tenant.- Exigem um tenant selecionado no token (
POST /api/auth/select-tenant). - O backend valida se o usuário autenticado possui o tenant listado em suas permissões.
- O prefixo só garante que existe um usuário autenticado no tenant. Quem decide o papel é o
@PreAuthorizede cada controller, e são quatro predicados de tenant:isCurrentTenantAdmin(sóADMIN),isCurrentTenantManager(MANAGERouADMIN),isCurrentTenantModeler(MODELERouADMIN) e a ausência deliberada de anotação, listada em Rotas abertas de propósito.SUPER_ADMINpassa em todos. Rota nova sem decisão de papel reprova emTenantEndpointDeclaresItsRoleTest.
- Exigem um tenant selecionado no token (
Endpoints Chave de Controle de Processo
Não existe /admin/definitions
Deploy, versionamento e publicação de BPMN/CMMN ficam em /a/definitions/..., com escopo de tenant vindo do token. Uma integração escrita contra /admin/definitions recebe 404. Que as definições sejam globais não muda o caminho: o que é global é o artefato publicado, não a rota.
| Endpoint | Método | Contexto | Acesso | Descrição |
|---|---|---|---|---|
/a/definitions | GET | Tenant | Qualquer autenticado | Retorna o catálogo de processos ativos para o tenant. Basta estar autenticado. |
/a/definitions/deploy | POST | Tenant | TA, Modelador | Deploy do arquivo BPMN/CMMN (multipart). Não publica a versão. |
/a/definitions/{key}/versions | GET | Tenant | TA, Modelador | Histórico de versões; a publicada vem com published: true. |
/a/definitions/{key}/versions/{definitionId}/publish | POST | Tenant | TA, Modelador | Move a publicação para a versão indicada. |
/a/definitions/{key}/config | PUT | Tenant | TA, Modelador | Configuração específica do processo no tenant (Business Key Template e política de anexos). |
/a/definitions/{key}/attachment-policy | GET | Tenant | TA, Modelador | Política de anexos vigente do processo. Leitura da tela de catálogo, que já exige Admin do tenant. Quem aplica a política em execução é o servidor (AttachmentAccessService), não o formulário: nenhuma tela de runtime chama esta rota, e por isso ela é fechada. |
/a/definitions/{key}/mcp-policy | GET | Tenant | TA, Modelador | O que um assistente conectado por MCP pode fazer no processo. Mesmo desenho da política de anexos: quem a aplica é o ExecutionMcpTools, dentro do servidor. |
/a/delegates | GET | Tenant | TA, Modelador | Beans de delegate carregados, com o nome da classe Java e os parâmetros declarados de cada um — superfície de informação sobre a instalação. Só o seletor do modelador consome, e o modelador já exige Admin do tenant. |
/a/delegates/active | GET | Tenant | TA | JARs de delegate globais ativos. Já exigia papel antes da #115. |
/a/definitions/{key}/monitor | GET | Tenant | TA, Gerente | Carga parada por etapa do processo, com a quebra por motivo. Aceita ?version=. |
/a/definitions/{key}/monitor/{activityId} | GET | Tenant | TA, Gerente | O que está parado naquela etapa: instância, motivo, responsável ou erro. Aceita ?version=. |
/a/definitions/{key}/toggle | PATCH | Tenant | TA, Modelador | Habilita/Desabilita o processo no catálogo do tenant. |
/a/definitions/{key}/suspend | PUT | Tenant | TA, Modelador | Suspende a definição: nenhuma instância nova começa. É diferente de desabilitar no catálogo. |
/a/definitions/{key}/activate | PUT | Tenant | TA, Modelador | Reativa a definição suspensa. |
/a/instances | POST | Tenant | TA, User | Inicia uma instância de workflow em nome do tenant logado. Gera o Business Key de acordo com fallback hierarchy. |
/a/instances/search | GET | Tenant | TA, User | Busca instâncias por variável. Para usuário comum, procura apenas dentro das instâncias que ele enxerga. |
/a/instances/{id} | DELETE | Tenant | TA, Gerente | Cancela uma instância. Operação destrutiva — não é oferecida a usuário comum, e o backend recusa. |
/a/instances/{id}/suspend | PATCH | Tenant | TA, Gerente | Suspende a instância. |
/a/instances/{id}/activate | PATCH | Tenant | TA, Gerente | Reativa a instância suspensa. |
/a/instances/failed-jobs | GET | Tenant | TA, Gerente | Fila de jobs com erro do tenant. |
/a/instances/failed-jobs/{jobId}/retry | POST | Tenant | TA, Gerente | Reexecuta o job. |
/a/instances/failed-jobs/{jobId}/deadletter | POST | Tenant | TA, Gerente | Move o job para a deadletter. |
/a/instances/{id} | GET | Tenant | TA, User | Detalhe da instância. Usuário comum só alcança instância em que entra; instância alheia responde 404, não 403 — 403 confirmaria que ela existe. |
/a/instances | GET | Tenant | TA, User | Lista paginada de instâncias ativas. Aceita page, size (padrão 20, teto 100) e type. Devolve envelope {content, number, size, totalElements, totalPages} — não um array. O índice da página se chama number na resposta e page na requisição, seguindo o formato do Spring Data usado pelas demais rotas paginadas. |
Quem enxerga uma instância
Gestor e administrador do tenant veem todas as instâncias. Usuário comum vê as instâncias em que entra, e são três origens somadas:
- as que ele iniciou;
- as que ele participa — tem tarefa atribuída, é candidato, ou é candidato por um papel de processo dele;
- as que ele participou — teve tarefa e já concluiu.
É de propósito a mesma regra que a tela de Tarefas aplica: duas telas discordando sobre quem participa é pior que qualquer uma das regras sozinha.
"Vê tudo no tenant" tem uma definição só, em PlatformRole.seesEverythingInTenant(), e vale SUPER_ADMIN, ADMIN e MANAGER. MODELER e USER ficam de fora — e o modelador ficou de fora por decisão, não por ordem do enum: ele desenha o processo, mas em execução enxerga o que um usuário comum enxerga. As duas telas a consultam pelo mesmo caminho (UnifiedTaskService.visibilityOf); nenhuma delas carrega lista de papéis própria. O papel do chamador é lido primeiro das authorities do JWT — a única fonte que carrega o SUPER_ADMIN de plataforma, que não tem vínculo no tenant — e depois do platformRole do vínculo.
O filtro vale para a listagem, para o detalhe, para o diagrama e para a busca por variável — uma busca que enxergasse além da lista transformaria o filtro em formalidade.
Endpoints de Anexos
Anexos de instância de processo (entityType = PROCESS_INSTANCE) não são governados pelo papel de plataforma, e sim pelo papel do usuário naquela definição, conforme a política configurada em /a/definitions/{key}/config. Administradores passam por todas as verificações. Demais tipos de anexo — base de conhecimento, knowledge de processo, anexos globais — seguem as regras dos seus próprios módulos e não são afetados.
| Endpoint | Método | Acesso | Descrição |
|---|---|---|---|
/a/attachments | POST | Conforme uploadMode + uploadRoles | Upload. Recusado em FORM_ONLY para PROCESS_INSTANCE. |
/a/attachments | GET | Membro do tenant | Lista os anexos vigentes da entidade (substituídos ficam de fora). |
/a/attachments/capabilities | GET | Membro do tenant | O que o usuário atual pode fazer: canUpload, canPreview, canReplace. É o que a UI consulta em vez de replicar a regra. |
/a/attachments/{id} | GET | previewRoles | Metadados do anexo. |
/a/attachments/{id}/download | GET | previewRoles | Conteúdo do arquivo. |
/a/attachments/{id}/replace | POST | replaceRoles | Sobe a nova versão e marca a anterior como substituída. |
/a/attachments/{id}/history | GET | previewRoles | Versões substituídas da entidade. |
/a/attachments/{id} | DELETE | Ninguém, para PROCESS_INSTANCE | Recusado inclusive para administradores. Continua valendo para os demais tipos. |
Lista de papéis vazia não significa "liberado"
Uma lista vazia (previewRoles, replaceRoles, uploadRoles) significa qualquer usuário que tenha algum papel naquela definição. Quem não tem papel nenhum no processo não acessa os anexos dele. Processo sem política configurada se comporta como AD_HOC com essa mesma regra padrão.
Tarefa dentro do processo age como o sistema
A política acima responde "qual pessoa pode abrir este arquivo". Uma tarefa que roda dentro do processo não tem pessoa: numa service task assíncrona a thread do job executor não carrega SecurityContext nenhum. Por isso a tarefa do processo tem acesso sistêmico a tudo dentro do tenant dela — quem desenha o processo é o administrador, e cada passo herda a autoridade dele em vez de tomar emprestada a identidade de quem iniciou a instância.
O acesso sistêmico exige as duas condições ao mesmo tempo: estar dentro de uma chamada de ferramenta do agente e ter um tenant roteado. Se o agente declarar um tenant diferente do que está roteado na conexão, o acesso é recusado e a divergência vai para o log em nível error.
O limite entre tenants não depende dessa verificação. A tabela attachments vive no schema tenant_<slug> e a conexão é roteada pelo TenantAwareDataSource — um agente não alcança o anexo de outro tenant nem se toda a checagem de permissão fosse removida, porque a conexão não enxerga o outro schema.
A exclusão continua recusada para todo mundo, sistema incluído: em PROCESS_INSTANCE a única forma de escrita é a substituição.
Endpoints do CMS
Leitura é aberta a qualquer membro do tenant; escrita exige Gerente ou superior. Em ambos os casos o acesso ainda depende do nível de sigilo da coleção (ver seção 5).
| Endpoint | Método | Acesso | Descrição |
|---|---|---|---|
/a/cms/collections | GET | SA, TA, Gerente, User | Lista apenas as coleções que o solicitante tem clearance para ler. |
/a/cms/collections | POST | SA, TA, Gerente | Cria coleção com seus campos e nível de sigilo. |
/a/cms/collections/{id} | GET | SA, TA, Gerente, User | Detalha a coleção. |
/a/cms/collections/{id} | PUT, DELETE | SA, TA, Gerente | Altera o schema/sigilo ou exclui a coleção. |
/a/cms/collections/{id}/records | GET | SA, TA, Gerente, User | Lista registros paginados. |
/a/cms/collections/{id}/records | POST | SA, TA, Gerente | Cria um registro. |
/a/cms/collections/{id}/records | DELETE | SA, TA, Gerente | Apaga todos os registros da coleção (recarga limpa). |
/a/cms/collections/{id}/records/bulk | POST | SA, TA, Gerente | Carga em lote idempotente de tabelas de referência. |
/a/cms/collections/{id}/records/{rid} | PUT, DELETE | SA, TA, Gerente | Altera ou exclui um registro. |
Chamadas autenticadas por API Key (X-API-Key) escrevem no CMS — é assim que uma tabela de referência é carregada por script —, porém com clearance fixo em Público: uma chave vazada não alcança dado classificado.
A chave ainda precisa do escopo do método: read para os GET da tabela acima, write para os POST, PUT e DELETE. Sem ele a requisição para no filtro com 403, antes de qualquer papel ser avaliado. Detalhe em API REST → Escopos.
Endpoints das Bases de Conhecimento
Diferente do CMS, leitura também exige Gerente, Modelador ou superior: a listagem das bases e dos documentos mostra o que a IA consulta, e isso é curadoria, não conteúdo de consumo. Um usuário comum recebe 403 em qualquer linha abaixo.
| Endpoint | Método | Acesso | Descrição |
|---|---|---|---|
/a/knowledge-bases | GET | SA, TA, Gerente, Modelador | Lista as bases do tenant e as globais visíveis a ele. |
/a/knowledge-bases | POST | SA, TA, Gerente, Modelador | Cria uma base. Marcar isGlobal exige Super Admin — o serviço recusa os demais. |
/a/knowledge-bases/{id} | GET | SA, TA, Gerente, Modelador | Detalha a base com a contagem de documentos. |
/a/knowledge-bases/{id} | DELETE | SA, TA, Gerente, Modelador | Exclui a base. Recusa enquanto houver processo vinculado. Base global só pelo Super Admin. |
/a/knowledge-bases/{id}/search-settings | PATCH | SA, TA, Gerente, Modelador | Troca o idioma da busca por palavra-chave. Base global só pelo Super Admin. |
/a/knowledge-bases/{id}/documents | GET | SA, TA, Gerente, Modelador | Lista os documentos, paginado. |
/a/knowledge-bases/{id}/documents | POST | SA, TA, Gerente, Modelador | Sobe PDF, TXT ou MD; a indexação roda em segundo plano. |
/a/knowledge-bases/{id}/documents/{docId} | DELETE | SA, TA, Gerente, Modelador | Remove o documento e os vetores dele. |
/a/knowledge-bases/{id}/documents/{docId}/classification | PUT | SA, TA, Gerente, Modelador | Muda o nível do documento (PUBLIC, SECRET, TOP_SECRET). Além do papel, exige alcançar o nível atual e o novo (Modelador → Público, Gerente → Secreto, Admin → Ultrassecreto); 403 caso contrário. Reenviar, restaurar, reingerir, baixar e apagar seguem a mesma regra. |
/a/knowledge-bases/{id}/default-classification | PUT | SA, TA, Gerente, Modelador | Nível dos próximos documentos; applyToExisting reclassifica os atuais e exige alcançar todos eles. |
/a/knowledge-bases/{id} | DELETE (nível) | SA, TA, Gerente, Modelador | Além do papel, apagar a base exige alcançar o documento mais restrito dela. Arquivos KB_DOCUMENT não saem por /a/attachments/** (404); só pelas rotas da base. |
/a/knowledge-bases/{id}/access-log | GET | SA, TA | Buscas que devolveram ou negaram trecho classificado da base, paginado. Só Admin: lista quem leu material restrito. |
/a/knowledge-bases (kind: EXTERNAL) | POST | SA, TA | Cria uma base externa (Elasticsearch / OpenSearch). Gerente e Modelador recebem 403: a base define um destino de rede e uma credencial. Global só pelo Super Admin, com referência de cofre. |
/a/knowledge-bases/{id}/external | PUT | SA, TA | Muda a conexão da base externa. A credencial é o nome de uma variável secreta ou uma referência de cofre, nunca o valor. |
/a/knowledge-bases/{id}/external/check | POST | SA, TA | Testar conexão: lê o mapping do índice, os campos e a dimensão do vetor. |
/a/knowledge-bases/{id}/test | POST | SA, TA, Gerente, Modelador | Testar consulta numa base externa existente, no nível de acesso de quem chama. |
/a/knowledge-bases/egress | GET, PUT | SA, TA | Destinos permitidos das bases externas do tenant e o estado de cada base. |
/a/knowledge-bases/{id}/documents/** | todos | — | 409 numa base externa: ela é consultada na origem e não recebe documentos. |
/a/knowledge-bases/process/{key} | GET | SA, TA, Gerente, Modelador | Bases vinculadas àquele processo. |
/a/knowledge-bases/process/{key}/link/{id} | POST | SA, TA, Gerente, Modelador | Vincula a base ao processo. |
/a/knowledge-bases/process/{key}/unlink/{id} | DELETE | SA, TA, Gerente, Modelador | Desfaz o vínculo. |
/a/knowledge-sources/providers | GET | SA, TA, Gerente, Modelador | Provedores de sincronização ligados na instalação e os hosts fixos de cada nuvem. |
/a/knowledge-bases/{id}/sources | GET, POST | SA, TA, Gerente, Modelador | Fontes sincronizadas da base. Criar exige alcançar o nível escolhido; a lista esconde fontes acima do nível de quem pede. |
/a/knowledge-bases/{id}/sources/{sid} | PUT, DELETE | SA, TA, Gerente, Modelador | Edita ou remove a fonte (?keepDocuments=); exige alcançar o nível dela. |
/a/knowledge-bases/{id}/sources/{sid}/estimate · /sync · /confirm-deletes · /cancel-deletes · /failures/retry | POST | SA, TA, Gerente, Modelador | Estimativa da primeira sincronização (arquivos, bytes, teto de tokens — sem valor em dinheiro), sincronizar agora, confirmar ou cancelar a exclusão em massa, reabrir as falhas cujas tentativas se esgotaram. |
/a/knowledge-bases/{id}/sources/{sid}/runs · /failures | GET | SA, TA, Gerente, Modelador | Últimas rodadas e arquivos com falha, com códigos traduzidos na tela. |
/a/knowledge-connections | GET, POST | SA, TA | Conexões com o Microsoft 365. O corpo recusa qualquer campo além de nome, diretório, client ID, nuvem e o nome da variável secreta. |
/a/knowledge-connections/{id} | PUT, DELETE | SA, TA | Edita ou apaga; apagar é recusado (409) enquanto uma fonte usa a conexão. |
/a/knowledge-connections/{id}/test | POST | SA, TA | Testa host de login, token e host do Graph, um a um. |
/a/knowledge-connections/{id}/browse · /options | GET | SA, TA, Gerente, Modelador | Navegar sites, bibliotecas e pastas pela conexão, e listar as conexões (sem credencial) para o assistente de fonte. |
A base de conhecimento por processo — a que a aba RAG do catálogo alimenta — é a mesma capacidade por outro caminho, e por isso exige o mesmo papel. Fechar /a/knowledge-bases sem fechar estas rotas deixaria um usuário comum apagando por aqui o acervo que não pode tocar por lá.
| Endpoint | Método | Acesso | Descrição |
|---|---|---|---|
/a/definitions/{key}/knowledge/documents | GET | SA, TA, Gerente, Modelador | Lista os documentos indexados para aquele processo. |
/a/definitions/{key}/knowledge/documents | POST | SA, TA, Gerente, Modelador | Sobe documento e dispara a indexação. |
/a/definitions/{key}/knowledge/documents/{docId} | DELETE | SA, TA, Gerente, Modelador | Remove o documento e os vetores dele. |
/a/definitions/{key}/knowledge/count | GET | SA, TA, Gerente, Modelador | Quantidade de chunks indexados para o processo. |
/a/definitions/{key}/knowledge | DELETE | SA, TA, Gerente, Modelador | Apaga todos os vetores do processo. Operação destrutiva. |
/a/definitions/{key}/knowledge/reindex | POST | SA, TA, Gerente, Modelador | Limpa e reindexa todos os arquivos anexados. |
Uma chave de API não alcança essas rotas: ela não tem associação de tenant, e a verificação de papel exige uma associação.
Endpoints dos Tipos Documentais
Um tipo documental é referenciado pelo campo Arquivo do formulário, mas quem preenche o formulário nunca chama estas rotas: o documentTypeId já vem gravado no schema publicado e segue direto para /a/attachments. Por isso a leitura fica no Gerente ou no Modelador — é o seletor do construtor de formulários — enquanto manter o catálogo é do Modelador, que é quem desenha o formulário que aponta para o tipo.
| Endpoint | Método | Acesso | Descrição |
|---|---|---|---|
/a/document-types | GET | SA, TA, Gerente, Modelador | Lista os tipos do tenant, ou os globais de um processo com ?isGlobal=true&processKey=. A leitura do global continua aberta ao tenant: são os tipos do processo que ele assina. |
/a/document-types | POST | SA, TA, Modelador | Cria um tipo do tenant. Com ?isGlobal=true, só SA. |
/a/document-types/{id} | PUT | SA, TA, Modelador | Altera nome, descrição ou situação. Se o tipo for global, só SA. |
/a/document-types/{id} | DELETE | SA, TA, Modelador | Exclui o tipo. Formulário publicado que aponte para ele perde a referência. Se o tipo for global, só SA. |
A camada global não é escrita pelo Admin de um tenant
isGlobal=true grava na camada compartilhada: o tipo passa a valer para todos os tenants que assinam o processo. A aba que autora esses tipos vive em Templates Globais, que na interface é Super Admin, mas a API aceitava a flag de qualquer Admin de tenant — e um Admin de tenant só responde pelo próprio. Agora POST ?isGlobal=true, e o PUT/DELETE de um tipo que já é global, respondem 403 para quem não é Super Admin. É o mesmo desenho que já protegia base de conhecimento global (KnowledgeBaseService.createKnowledgeBase) e agente global (AiAgentService.resolveTenant), e os três casos estão no mesmo teste, GlobalLayerIsNotOpenTest.
Endpoints de Robôs
Um robô é código que o tenant publica e a plataforma executa com credenciais do tenant. Por isso todas as rotas de /a/robots/** exigem Admin do tenant — cadastro, envio do JAR, execução, estado, log e também a configuração de parâmetros, que é onde entra o segredo: um parâmetro marcado como secreto guarda a referência (${var.erpToken}) para a variável do tenant que carrega o token. Ler a configuração já nomeia os parâmetros declarados e mostra para onde cada referência aponta, então leitura e escrita ficam no mesmo papel — Gerente e usuário comum recebem 403 nas duas. A tela /robots/$key, única consumidora dessas rotas, já exigia Admin do tenant no beforeLoad; a rota é que estava aberta.
| Endpoint | Método | Contexto | Acesso | Descrição |
|---|---|---|---|---|
/a/robots/{key}/config | GET | Tenant | SA, TA | Configuração de parâmetros do robô naquele tenant, com os parâmetros declarados pelo JAR. |
/a/robots/{key}/config | PUT | Tenant | SA, TA | Grava a configuração de parâmetros. É por aqui que entra a referência de um parâmetro secreto. |
Travado por RobotConfigAuthorizationTest.
Gerar um robô com IA (/a/robot-generations/**) segue a mesma regra: é Admin do tenant em todas as rotas — gerar, refinar, editar, aprovar, testar, ativar e descartar. Gerar um robô é criar um robô, e quem aprova o código precisa poder preencher os parâmetros secretos dele. O Modelador recebe 403 aqui como em /a/robots/**, e o Super Admin só entra com um tenant selecionado: sem tenant a resposta é 400, porque não existe geração de robô global. Travado por ModelerDoesNotAdministerTheTenantTest e TenantEndpointDeclaresItsRoleTest.
Condução de um caso (CMMN)
O plano do caso é conduzido por quem trabalha nele, e fechar o estágio é a única ação de gestão.
| Endpoint | Método | Contexto | Acesso | Descrição |
|---|---|---|---|---|
/a/instances/{id}/plan-items | GET | Tenant | TA, Gerente, User | Etapas vivas do caso, cada uma com as ações que aceita. COMPLETE_STAGE só é oferecida a quem gerencia o tenant. |
/a/instances/{id}/milestones | GET | Tenant | TA, Gerente, User | Marcos que o caso já atingiu. |
/a/instances/{id}/plan-items/{planItemId}/start | POST | Tenant | TA, Gerente, User | Inicia a etapa oferecida. |
/a/instances/{id}/plan-items/{planItemId}/disable | POST | Tenant | TA, Gerente, User | Descarta a etapa opcional. |
/a/instances/{id}/plan-items/{planItemId}/enable | POST | Tenant | TA, Gerente, User | Reoferece a etapa descartada. |
/a/instances/{id}/plan-items/{planItemId}/trigger | POST | Tenant | TA, Gerente, User | Dispara um evento de usuário aguardando. |
/a/instances/{id}/plan-items/{planItemId}/complete-stage | POST | Tenant | SA, TA, Gerente | Fecha o estágio, encerrando as etapas opcionais ainda oferecidas dentro dele. Usuário comum recebe 403. |
As seis primeiras linhas não são "abertas a qualquer autenticado": todas passam por WorkflowInstanceService.requireVisible, o mesmo portão do detalhe da instância, e um caso de que a pessoa não participa responde 404. Travado por CasePlanItemControllerAuthorizationTest e CasePlanItemServiceTest.
Endpoints de IA do modelador
| Endpoint | Método | Contexto | Acesso | Descrição |
|---|---|---|---|---|
/a/ai-validation/bpmn | POST | Tenant | SA, TA, Modelador | Validação semântica do BPMN por LLM. Gerente e usuário comum recebem 403: as telas que disparam a chamada (/definitions, /definitions/{key}, /admin/global-templates/{key}) são do desenho do processo, e cada chamada gasta a cota de tokens do tenant. Cota estourada ou nunca configurada responde 402, não um parecer de validação. |
/a/modeler/copilot/stream | POST | Tenant | SA, TA, Modelador | Copiloto do modelador por SSE. A linha gravada em ai_usage_logs carrega o user_id de quem dirigiu o turno, além do tenant e do executionCorrelationId do turno — sem isso a governança saberia que o tenant gastou, mas não quem. O corpo leva processKey (a chave do processo aberto no modelador) e history (até 12 mensagens anteriores, papel user ou assistant). O servidor impõe essa chave a toda ferramenta que recebe processKey e corta o histórico em 24.000 caracteres. |
/a/modeler/copilot/apply | POST | Tenant | SA, TA, Modelador | Cria, em nome de quem clicou em Criar tudo, o que o copiloto propôs no turno: formulário, agente, base de conhecimento ou coleção. Durante o turno o copiloto só propõe e não grava nada fora do diagrama. Aceita só essas sete ferramentas de criação, roda na ordem e troca as referências provisórias pelos ids reais. Cada ferramenta confere também o próprio papel. Não chama modelo. |
/a/modeler/copilot/validate | POST | Tenant | SA, TA, Modelador | Confere com o motor o diagrama que um turno do copiloto desenhou. Recebe { "xml", "processKey" } e devolve { "findings" }, cada um com severity (ERROR ou WARNING), code, elementId, elementName e message. Com processKey, também aponta etapa que usa um agente ou um formulário que o processo não tem. Não chama modelo nem gasta token. As regras próprias do Flowi (etapa sem formulário, etapa de agente sem agente, saída de decisão sem condição) são só aviso e nunca impedem um deploy. |
Rotas abertas de propósito
Ausência de @PreAuthorize sob /a/** significa "qualquer usuário autenticado do tenant". Nas quatro linhas abaixo isso é decisão, não esquecimento — fechá-las quebraria uma tela que o usuário comum usa. Cada uma tem o limite ao lado da promessa, e cada limite tem teste que o trava.
| Endpoint | Método | Por que fica aberta | Onde está o limite |
|---|---|---|---|
/a/attachments, /a/attachments/{id}/replace, /a/attachments/{id} | POST, DELETE | O usuário comum anexa arquivo pelo formulário da própria tarefa — é o caminho entityType=process, que não é governado. Exigir Admin na rota tiraria o anexo de dentro do processo. | Dentro do serviço, por papel de processo: AttachmentAccessService.requireUpload/requireReplace/requireDeletable, conforme uploadRoles/replaceRoles da política do processo (ver Endpoints de Anexos acima). Travado por AttachmentControllerAuthorizationTest e AttachmentAccessServiceTest. |
/a/notifications, /a/notifications/{id}/read, /a/notifications/read-all | GET, PUT | Todo usuário tem caixa de notificação; papel nenhum se aplica. | O userId vem do token, nunca do corpo ou da URL. NotificationService.markRead recusa quando a notificação é de outro dono, e markAllRead é um UPDATE ... WHERE user_id = :userId. Passar o id de uma notificação alheia responde 403 e não grava nada — recusa de acesso, e não erro de requisição, para que quem chama distinga "id que não existe" (404) de "não é sua" (403). Travado por NotificationControllerAuthorizationTest e NotificationServiceTest. |
/a/dashboard | GET | É a tela inicial de qualquer membro do tenant. | O tenant e a visibilidade de quem olha. Tarefas ativas e processos concluídos passam por UnifiedTaskService.visibilityOf — o mesmo ponto de entrada de Tarefas e Instâncias: quem enxerga o tenant inteiro lê o total, e os demais leem só o que participam. O contador de definições segue sendo do tenant, porque iniciar processo continua aberto ao usuário comum. Travado por DashboardFollowsInstanceVisibilityTest e DashboardCountsOnPostgresTest. |
/a/instances/{id}/plan-items/{planItemId}/start, /disable, /enable, /trigger | POST | Conduzir a própria etapa é o trabalho de quem trabalha no caso, e a tela do caso não tem beforeLoad de papel. Exigir Gerente tiraria do usuário comum o caso que ele mesmo iniciou. | CasePlanItemService chama WorkflowInstanceService.requireVisible antes de qualquer transição: caso de que a pessoa não participa responde 404. O motor recusa a transição que o estado não permite, e availableActions só esconde COMPLETE_STAGE. Travado por CasePlanItemControllerAuthorizationTest e CasePlanItemServiceTest. |
O cartão do dashboard conta o que a pessoa enxerga
GET /a/dashboard já não devolve os mesmos números para todo mundo. Tarefas ativas e processos concluídos são contados pela mesma regra que a listagem aplica: o serviço lê UnifiedTaskService.visibilityOf(tenant, usuário) — o único lugar onde "quem enxerga o tenant inteiro" está escrito, e o mesmo que InstanceVisibilityService consulta. Gerente, Admin e Super Admin continuam lendo o total do tenant; o usuário comum conta só as tarefas em que é responsável ou candidato (direto ou por grupo de papel de processo) e só os processos concluídos em que teve tarefa ou que iniciou.
O escopo é aplicado como predicado da própria contagem, não materializando a lista de ids visíveis: DashboardCountRepository mantém a promessa de duas consultas por carga, quantas instâncias o tenant tenha. O contador de definições segue sendo do tenant inteiro de propósito — é o catálogo do que se pode iniciar, e POST /a/instances continua aberto ao usuário comum.
Quem pode agir sobre uma tarefa
Reivindicar, concluir, salvar rascunho, devolver, delegar e comentar uma tarefa não dependem só de estar autenticado no tenant. ADMIN, MANAGER e SUPER_ADMIN agem em qualquer tarefa. Os demais, inclusive MODELER, só agem como responsável, como dono (delegar) ou como candidato (por usuário ou por papel de processo), e uma tarefa já atribuída a outra pessoa só é concluída por ela. A tarefa que não tem nada a ver com quem chama responde 404; a de uma instância que a pessoa iniciou ou em que trabalhou, mas sobre a qual ela não pode agir, responde 403. Delegar exige que o destino seja membro do tenant. Vale igual para as tarefas humanas de casos CMMN. Ler a tarefa (GET /tasks/{id}, /variables, /comments, /field-provenance, /ai-suggest) pede a mesma relação ou ter iniciado ou trabalhado na instância; quem não tem relação recebe 404. Chave de API não age nem lê tarefa: recebe 403 com mensagem explícita, porque assumir, concluir e ler uma tarefa são atos de uma pessoa; use o token de um usuário.
Variáveis reservadas
Alguns nomes de variável pertencem à plataforma: aiDecision e aiDecisionJustification (escritas só pela ferramenta de roteamento do agente), escalateToHuman, escalationReason, escalationUrgency, a configuração das etapas de IA (aiAgentId, aiInstruction...) e os nomes internos (tenantId, e qualquer nome começando com _ ou ai_). Nenhuma requisição pode enviá-los: concluir ou salvar uma tarefa, iniciar uma instância (com token de usuário, chave de API ou robô), chamar as ferramentas MCP de execução e criar uma variável de tenant com esse nome respondem 400 com a lista dos nomes. Sem essa regra, quem pudesse concluir uma tarefa escolheria a saída de um gateway decidido por IA. Se um campo de formulário precisar de um desses nomes, renomeie o campo.
4. Hierarchy Resolution para Business Keys (Nota para IA)
O backend resolve variáveis de inicialização como o Business Key numa ordem hierárquica (Implementado em WorkflowDefinitionService):
- Chave explícita na requisição: um
businessKeyenviado emPOST /a/instancesvence o template. O template é o padrão para quem não conhece a chave, não uma imposição sobre quem conhece. Valor ausente ou em branco cai para o template. - Template do tenant (
PublishedDefinition.businessKeyTemplate): O Tenant Admin o grava em/a/definitions/{key}/config. - Padrão do Sistema: fallback hardcoded para
DOC-${date:yyyyMMdd}-${random:4}(WorkflowDefinitionService.DEFAULT_BUSINESS_KEY_TEMPLATE).
São só esses dois degraus. Não existe camada global de Business Key: GlobalProcessTemplate não tem campo de template, e resolveBusinessKeyTemplate pula do template do tenant em branco direto para o padrão do sistema.
O template aceita ${nome:-alternativa}, que usa a variável de processo nome quando ela existe e não está em branco, e a alternativa caso contrário. A alternativa pode conter outro placeholder, então um mesmo template serve uma integração que conhece os dados e um formulário que não conhece:
${tipoDoc:-DOC}-${emissao:-${date:yyyyMMdd}}-${cnpjEmissor:-${random:4}}
API, com as variáveis → NFSE-20260305-22060673000170
Tela, sem as variáveis → DOC-20260807-9O63Placeholder sem alternativa e sem variável correspondente recusa o início. A requisição responde 422 Unprocessable Entity, e a instância não chega a ser criada — nada de tarefa, nada de histórico, nada para cancelar depois. O corpo do erro nomeia cada variável que faltou em fieldErrors, então o cliente sabe exatamente o que enviar na segunda tentativa:
{
"status": 422,
"error": "Unprocessable Entity",
"fieldErrors": [
{ "field": "cnpjEmissor", "message": "variável exigida pelo businessKeyTemplate e não informada" }
]
}A mesma recusa vale quando a substituição esvazia a chave por completo — um template que resolveria para NFSE--, só separadores e nenhum conteúdo, é rejeitado em vez de gravado. Chave de negócio é como o documento é encontrado depois; uma chave truncada cria um registro que ninguém acha, e o 422 troca esse problema silencioso por um erro na hora.
Quem depende de iniciar o processo mesmo sem todas as variáveis tem duas saídas: dar uma alternativa ao placeholder (${cnpjEmissor:-${random:4}}) ou mandar o businessKey explícito no corpo do POST /a/instances, que vence o template.
5. Sigilo dos Dados do CMS
Cada coleção do CMS carrega um nível de confidencialidade. O nível exigido para ler ou escrever uma coleção é derivado do papel do usuário no tenant — não existe concessão individual.
| Nível | Papel mínimo | Conteúdo típico |
|---|---|---|
PUBLIC | Tenant User | NCM, CFOP, CEST, centros de custo, catálogo de produtos |
SECRET | Tenant Manager | Margens, política comercial, tabela de preços de fornecedor |
TOP_SECRET | Tenant Admin | Folha de pagamento, jurídico, material de diretoria |
Regras derivadas:
USER → PUBLIC,MODELER → PUBLIC,MANAGER → SECRET,ADMIN → TOP_SECRET,SUPER_ADMIN → TOP_SECRET. O modelador fica emPUBLICde propósito: o CMS é conteúdo do tenant, não desenho de processo, eCmsControllerexige Gerente — dar-lhe outro nível seria uma promessa que rota nenhuma cumpre.- A listagem de coleções omite o que o solicitante não pode ler; o acesso direto responde
403. - Um gerente não consegue classificar uma coleção como
TOP_SECRET— isso o faria criar um dado fora do próprio alcance. - Agentes de IA: a tool
queryCollectionToolrespeita o nível configurado em cada agente (cmsClearance, padrãoPUBLIC). Em processos BPMN não há usuário logado para herdar permissão, por isso o nível é uma configuração explícita do agente. No playground vale o menor entre o nível do usuário e o do agente (AiPlaygroundControllerchamaCmsClassification.lowest). O copiloto de execução não faz essa conta:AiExecutionCopilotControllerusa apenascmsAccessService.currentClearance(), então lá o teto é o papel do usuário, não o do agente. - Robôs (
RobotCmsApi) não são limitados por sigilo: são código publicado por administradores do tenant e alcançam qualquer coleção dele.
Referência de implementação: security/CmsAccessService.java, security/TenantSecurityService.java e a spec specs/content/cms.md.