Skip to Content
PortuguêsDocumentação JumentixReferênciaConsole de Operações do Service Management

Console de operações do Service Management

Este é o documento E5 da cadeia de documentação E1–E8 do Service Management (JUM-482 ). Ele documenta o console de operações — as superfícies que transformam o designer de uma ferramenta de modelagem em algo que descreve e controla um serviço em execução — exatamente como o código se comporta hoje, após a entrega da frente do console de operações (JUM-480 , JUM-481 , JUM-543 , JUM-544 , JUM-546 ).

O console abrange a aba Service Configuration (perfil de runtime, a prévia do ecossistema PM2 e o editor de ambiente de runtime), a aba Deploy Management e — por suas regras de ciclo de vida — o Communication Interface Designer. Essas abas carregam regras que um usuário não consegue descobrir clicando: quais combinações de run-mode × cloud-provider e de service-type × deploy-target são válidas e por que uma inválida é rejeitada, qual arquivo de ambiente uma gravação escreve e de onde a prévia do PM2 obtém sua lista de processos. Este documento torna essas regras legíveis, nomeia a verificação que comprova cada uma e estabelece a regra da fonte compartilhada que as impede de divergir.

Dois limites deliberados:

A matriz de capacidades compartilhada (JUM-544, JUM-481)

As duas superfícies de validação do console — Service Configuration e Deploy Management — leem as matrizes do Requisito 059 de uma única fonte legível por máquina: packages/designer-core/src/model/deployCapabilityMatrix.js, o leitor dos dois documentos de matriz (JUMENTIX-DEPLOY-TARGET-AND-PACKAGING-MATRIX e JUMENTIX-SERVICE-FACTORY-CAPABILITIES-MATRIX).

A regra da fonte compartilhada: a matriz é transcrita exatamente uma vez, neste módulo. Um futuro contribuidor que estender ou corrigir a matriz edita o módulo fonte — e os documentos de matriz no mesmo PR, como o próprio cabeçalho do módulo exige — nunca uma segunda cópia dentro da validação de uma aba. Os dois validadores do console já demonstram o porquê:

  • collectServiceConfigurationIssues (serviceConfigurationValidation.js, JUM-544) consome o mapa de suporte run-mode × cloud-provider e o mapa de portas ativas.
  • collectDeployTargetIssues (deployTargetValidation.js, JUM-481) consome o mapa de suporte service-type × deploy-target, o mapa de protocolos por service type, o conjunto de targets gerenciados por PM2 e os vocabulários de drivers.

O que a matriz codifica, e por que uma combinação inválida é rejeitada:

  • Run mode × cloud provider. dedicated-server roda em self-hosted; virtual-machine em aws/google/azure; container em docker ou self-hosted; functions em aws/vercel/cloudflare. Qualquer coisa fora dessas linhas (por exemplo functions + self-hosted, ou um run mode baseado em PM2 contra vercel) não tem deploy target na matriz do Requisito 059 — o design não poderia ser construído por nenhuma linha de empacotamento que a factory entrega, portanto é rejeitado em vez de registrado.
  • Service type × deploy target. As linhas gerenciadas por PM2 (dedicated-server, vm, ec2) aceitam serviços restapi, websocket+restapi e grpc+restapi; as linhas de funções (lambda, vercel-functions, cloudflare-workers) aceitam apenas functions. Um serviço functions em um target PM2 — ou um serviço REST/realtime em um target de funções — não tem linha na matriz.
  • Exposição de protocolos. Um service type expõe apenas os protocolos que ele realmente vincula: restapi serve HTTP, websocket+restapi adiciona WebSocket, grpc+restapi adiciona gRPC, e APIs de funções são entrypoints HTTP. Pedir que um serviço restapi vincule WebSocket é rejeitado porque o runtime nunca iniciaria tal listener.
  • Aplicabilidade do perfil PM2. Apenas targets gerenciados por PM2 carregam um pm2Profile (dev/staging/production); um perfil em um target gerenciado pelo provedor (serverless) é um design que a matriz não consegue construir, e um perfil ausente em um target gerenciado por PM2 deixa o perfil de ecossistema sem escolha.
  • Portas ativas por service kind. Um serviço rest-api não vincula nenhum listener realtime, portanto suas portas WebSocket/gRPC não utilizadas não são validadas — apenas as portas que o service kind selecionado realmente vincula precisam ser inteiros em 1–65535 e mutuamente distintos.

Dois fatos de vocabulário que vale conhecer antes de estender a matriz:

  • Duas grafias coexistem por design. O Service Configuration usa o vocabulário de armazenamento do Requisito 126 (serviceKind: rest-api, websocket-rest-api, grpc-rest-api); o Deploy Management usa as grafias da própria matriz (serviceType: restapi, websocket+restapi, grpc+restapi, functions), que são anteriores a ele. O módulo documenta a divergência em vez de disfarçá-la.
  • Os vocabulários de drivers espelham o contrato de ambiente de runtime por referência. databaseDriver/keyValueDriver são definidos pela matriz do Requisito 059 como “o JUMENTIX_DATABASE_DRIVER selecionado”, portanto o módulo espelha os conjuntos de enum do Contrato 1 — e a paridade é verificada por teste, não presumida (abaixo).

Comprovado por: serviceConfigurationValidation.test.ts e deployTargetValidation.test.ts — este último também lê o script.js e os enums da allowlist do server.js para garantir que os vocabulários de drivers não possam divergir do contrato de ambiente de runtime.

Service Configuration: validar antes do estado (JUM-544)

O portão de gravação da aba valida o perfil candidato antes de ele tocar o estado (script.js): collectServiceConfigurationIssues roda sobre os valores do formulário, e cada issue tem severidade error, portanto um perfil inválido é recusado e relatado na superfície de status da aba — o comportamento anterior silenciosamente coagia portas ruins de volta aos padrões. O mesmo coletor revalida o perfil persistido sempre que a aba é renderizada (renderServiceConfigStatus em inspectors.js), de modo que um estado inválido vindo do armazenamento é sinalizado em vez de exibido como válido. As regras:

  1. Vocabulário — serviceKind, runMode e cloudProvider precisam ser valores que o esquema de armazenamento (Requisito 126, Contrato 2) e os selects da UI conhecem.
  2. Portas — cada porta que o service kind selecionado realmente vincula precisa ser um inteiro em 1–65535, e nenhum par de portas ativas pode colidir; portas inativas são ignoradas.
  3. Run mode × cloud provider — a combinação precisa existir na matriz compartilhada (acima), e a rejeição nomeia os provedores que a matriz realmente suporta para o run mode escolhido.

Edição multi-ambiente (JUM-480) — por referência cruzada

O contrato do editor de ambiente de runtime — ambientes aceitos e seu mapeamento de arquivos, a classificação de chaves em três níveis (editável / somente leitura / nunca exposta), conjuntos de enum por chave, semântica de gravação e o envelope de erro — está fixado no Requisito 126, Contratos 1 e 1b e no documento E1, Contratos de ambiente de runtime. O que este documento adiciona é apenas o comportamento desse contrato no lado do console:

  • A edição é sequencial e por arquivo. O seletor de Environment (dev, staging, ci) carrega exatamente um ambiente por vez através de GET /api/runtime/env; o painel sempre nomeia o arquivo exato que a próxima gravação escreve (Editing target: .env.dev (environment "dev"), direto do payload da API); e uma gravação escreve somente aquele arquivo — não existe edição em lote entre arquivos. A linha de direcionamento por arquivo é fixada por pm2EcosystemUi.contract.test.ts.
  • Um ambiente não aceito é rejeitado, nunca coagido. O servidor resolve o parâmetro environment contra um conjunto explícito de valores aceitos (dev/development → .env.dev, staging → .env.staging, ci/test → .env.ci) e responde a um valor desconhecido com 400 nomeando a lista de aceitos — ele nunca cai silenciosamente para dev.
  • A gravação é validada e confirmada. Apenas chaves da allowlist de escrita são aceitas, os valores são verificados contra os conjuntos de enum do Contrato 1 (valores fora do enum são rejeitados com a lista de aceitos e nada é escrito), a escrita é atômica (arquivo temporário, fsync, rename) e a resposta retorna o estado pós-gravação que o painel confirma (Environment "staging" saved to .env.staging).

A prévia do ecossistema PM2 (JUM-480) — pela fonte, não pela string de comando

O painel de perfil de runtime prévia os processos PM2 sob os quais o service kind desenhado rodaria. A propriedade mais importante dessa prévia — e a mais provável de ser desfeita por um atalho futuro — é de onde ela lê:

  • A prévia lê os arquivos reais pm2/ecosystem.*.cjs através de GET /api/runtime/pm2-ecosystem (Requisito 126, Contrato 1b), nunca uma lista de processos embutida no código. Adicionar um app a um arquivo de ecossistema muda a prévia sem mudança de código e sem reinício do servidor — o endpoint carrega o módulo de ecossistema com cache invalidado a cada leitura. A justificativa pertence ao registro escrito: no dia em que um contribuidor embutir uma lista literal de processos ou uma invocação de gerenciador de pacotes no designer, a prévia começa a mentir sobre a realidade, e a transição para o Bun (JUM-33 , JUM-40 ) mudará o formato de invocação por baixo dela. É por isso que o Contrato 1b proíbe qualquer string de gerenciador de pacotes (pnpm run, bun run, npm run) ou nome de script pm2:start:* no servidor e no designer: o comando relatado é derivado da definição do ecossistema (seu caminho e o nome do app), portanto permanece verdadeiro qualquer que seja o gerenciador de pacotes que invoque o PM2. Este documento, portanto, descreve a prévia pela sua fonte, não pelas strings literais de comando que ela produz hoje.
  • Estados de borda honestos, nunca um painel silenciosamente vazio. Um ambiente sem arquivo de ecossistema (ci/test mapeiam para ecosystem.ci.cjs, que o repositório não define) é um estado explícito exists: false renderizado como “No PM2 ecosystem file for environment …”, não um erro e não uma lista vazia apresentada como real. Um arquivo de ecossistema ilegível ou sintaticamente quebrado emerge como o envelope da classe 500 com code e path — paralelo à classe de sistema de arquivos dos env (JUM-543) — de modo que um pm2/ecosystem.*.cjs quebrado é identificável como um problema de instalação, nunca confundido com uma requisição malformada.
  • O ambiente da prévia é independente do ambiente de edição. O seletor da prévia oferece os ambientes para os quais o repositório define ecossistemas — dev, staging, production (fixado pela suíte de contrato da UI) — enquanto o editor de env mira os arquivos env editáveis. Produção tem um ecossistema, mas nenhum arquivo env editável; o console mantém esses eixos separados em vez de confundi-los.
  • A filtragem é por service kind; os nomes vêm do arquivo. O painel seleciona os apps do ecossistema cujos nomes terminam com os sufixos que o service kind desenhado implica (restapi para REST-only, mais websocketapi ou grpcapi para os kinds realtime) e sugere um único comando derivado cobrindo exatamente esses apps. A correspondência por sufixo funciona para todo prefixo de ambiente porque nenhum nome de app é enumerado no designer.
  • A prévia é transitória. Ela vive em estado de UI no nível do módulo, nunca no payload persistido service-management.v1 (Requisito 126, Contrato 2) — um retrato derivado do servidor não é estado de design.

O dashboard de monitoramento PM2 — stream WebSocket (Contrato 1e) + HTTP one-shot (1c)

A aba Monitoramento é telemetria runtime, não outra prévia estática.

  • Caminho primário da UI: WS /api/runtime/pm2-ws (Requisito 126, Contrato 1e). A aba abre um WebSocket quando ativa, assina ambiente + intervalo de refresh (500–2000 ms, padrão 1000) e renderiza gráficos de host (CPU/memória/disco) com D3 vendored (sem CDN), stacks de processo, filtros e ações start/stop/restart. O histórico agregado + sparks por processo persiste no Cana em monitoringHistory dentro de service-management.v1 (Contrato 2). Sair da aba fecha o socket.
  • HTTP one-shot: GET /api/runtime/pm2-metrics (Contrato 1c) permanece para testes e ferramentas. Ambos os transportes coletam via API Node do PM2, comparam nomes live com o ecosystem, incluem métricas de host, disk I/O por processo (Linux; Darwin via Bun FFI / proc_pid_rusage; Windows) e scrapes opcionais de async-context-metrics (counters + recentStores do Map ALS com redact). O scrape usa GET http://127.0.0.1:<JUMENTIX_HTTP_PORT>/async-context-metrics em cada processo com essa porta — reinicie o RestAPI a partir de um checkout que inclua a rota (JUM-767+) se o Monitoring reportar ASYNC_CONTEXT_ROUTE_MISSING. Cada linha de processo expõe um controle de ajuda descrevendo o papel do app.

Se o PM2 não puder ser carregado, conectado ou listado, o endpoint HTTP falha com o envelope explícito de métricas PM2 e o WebSocket emite error / action-result falho em vez de inventar processos saudáveis.

Comprovado por: pm2Ecosystem.integration.test.ts (leituras do ecossistema, shape de métricas + host, subscribe/ações WebSocket, edição refletida sem reinício, arquivo ausente, envelope 500, rejeição de ambientes desconhecidos) e pm2EcosystemUi.contract.test.ts (garantia estrutural de nenhum comando embutido e UI de Monitoring via WebSocket).

Deploy Management: o contrato de metadados do Requisito 059 (JUM-481)

Todo deploy target carrega o contrato de metadados do Service Management do Requisito 059 — { name, region, runtime, serviceType, deployTarget, runtimeProtocol, databaseDriver, keyValueDriver, pm2Profile } — fixado como uma extensão retrocompatível do esquema de armazenamento (Requisito 126, Contrato 2: a chave versionada permanece inalterada). As regras da aba:

  • O que um target pode conter é de responsabilidade de collectDeployTargetIssues (deployTargetValidation.js): os seis vocabulários, a linha da matriz service-type × deploy-target, a exposição de protocolos e a aplicabilidade do perfil PM2 — cada rejeição nomeia a restrição violada (a seção da matriz compartilhada acima dá as razões). Toda issue tem severidade error.
  • A lista revalida cada entrada persistida. renderDeployments (inspectors.js) roda o coletor sobre cada target armazenado e sinaliza uma entrada rejeitada inline com suas issues, em vez de renderizá-la como um design construível. A validação, portanto, é aplicada na superfície onde os targets são consumidos, independentemente de como a entrada chegou lá.
  • Entradas legadas migram para frente na carga, sem perdas. normalizeDeploymentInput (designerState.js) migra o formato pré-JUM-481 { name, type, region, runtime }: type torna-se deployTarget através de um mapa de aliases (dedicated → dedicated-server), e os metadados ausentes recebem padrões derivados da matriz — o primeiro service type que o target suporta, o primeiro protocolo desse type, os drivers padrão do contrato de ambiente de runtime e o perfil PM2 dev apenas em targets gerenciados por PM2. Valores legados sem contraparte na matriz (por exemplo azure-functions) são mantidos literalmente — a migração nunca descarta informação silenciosamente; a regra de vocabulário sinaliza a entrada, e o operador decide. O fato de normalizeStatePayload restaurar a seção deployments é a exceção do JUM-481 ao recorte de carga fixado.

Comprovado por: deployTargetValidation.test.ts e a cobertura de migração na carga em designerState.test.ts.

Ciclo de vida dos deploy targets: edição, duplicação e validação de campos (JUM-546)

A JUM-481 é dona do que um target pode conter; a JUM-546 é dona de como os targets são gerenciados. O ciclo de vida completo da aba é adicionar, editar in-place, duplicar e excluir:

  • Edição in-place. Edit carrega a entrada no formulário; o botão de adição torna-se Save Target (com a opção Cancel Edit) e o mesmo portão de validação se aplica à substituição. Uma edição pode manter o próprio nome — a verificação de unicidade exclui a entrada que está sendo substituída — e excluir uma entrada no meio de uma edição cancela a edição (ou reposiciona o índice) em vez de sobrescrever outro target.
  • Duplicação. Duplicate armazena uma cópia profunda independente — nunca uma referência compartilhada — renomeada pela regra (copy) (nome (copy), depois nome (copy 2), … até ser único, comparado sem distinção de maiúsculas). Deploy targets são a única coisa que operadores criam em conjuntos quase idênticos (o mesmo serviço em staging e produção, a mesma configuração em várias regiões); a duplicação é a defesa primária contra as inconsistências de redigitação que a validação de campos teria de capturar.
  • Validação de campos — collectDeployTargetFieldIssues em deployTargetLifecycleValidation.js, executada no portão de adição/edição junto às regras de matriz da JUM-481: o nome é obrigatório e único; o runtime/version é obrigatório e deve seguir um padrão de nome-mais-versão (nodejs22.x, python3.12 — texto livre como latest é rejeitado); a região é obrigatória em todo target de nuvem e opcional na linha self-hosted Dedicated Server (SSH), onde o campo pode carregar informação de host. O conjunto self-hosted é lido do leitor compartilhado da matriz (SELF_HOSTED_DEPLOY_TARGETS em packages/designer-core/src/model/deployCapabilityMatrix.js), nunca transcrito. Toda rejeição nomeia a razão na superfície de status da JUM-543, e o candidato nunca toca o estado.
  • Dicas de campo por tipo de target. A linha de dica sob o formulário (deployTargetFieldHint) acompanha a linha da matriz selecionada: targets gerenciados por PM2 (linhas VM/dedicado) são orientados à informação de host e ao perfil PM2; provedores de funções, ao runtime/version, com o select de perfil PM2 desabilitado e limpo — perfil PM2 não se aplica.

Comprovado por: deployTargetLifecycle.test.ts (as regras como funções puras) e deployTargetLifecycle.browser.integration.test.ts (a UI real em WebKit: adição validada, razões de rejeição na região de status, a regra de renomeação (copy), independência da edição in-place, a regra de região por tipo e o comportamento da dica e do select de PM2).

Regras de ciclo de vida — o que existe hoje e o que está aberto

A cadeia de issues reserva o ciclo de vida completo (edição in-place, duplicação, validação em nível de campo, unicidade) das duas listas do console para JUM-545  (interface adapters) e JUM-546  (deploy targets). A JUM-545 e a JUM-546 foram entregues — esta seção registra o ciclo de vida que o código realmente implementa hoje.

Interface adapters (Communication Interface Designer). Um adapter é adicionado, editado in-place e excluído (JUM-545). Os portões de adição e edição compartilham um único caminho de validação (upsertInterfaceAdapter em src/validation/interfaceAdapterValidation.js): o framework deve pertencer ao subconjunto por tipo de interface da matriz de tempo de execução canônica (src/model/interfaceFrameworkMatrix.js — as grafias canônicas da JUM-461, sem duplicatas de alias derby/sails), o entrypoint deve ser um caminho TypeScript/JavaScript sob src/interface/, o mapeamento de controller deve seguir o formato XController.action, e duplicatas — mesmo tipo + entrypoint, ou mesmo mapeamento de controller — são rejeitadas com o motivo na superfície de status. Entradas persistidas anteriores ao portão são sinalizadas inline em vez de passarem como designs válidos.

Deploy targets (Deploy Management). O ciclo de vida completo foi entregue com a JUM-546 — adicionar, editar in-place, duplicar e excluir, com validação em nível de campo (nome único, padrão de runtime/version, região por tipo de target) no portão de adição/edição e a regra de renomeação (copy) nas duplicações. Ver a seção da JUM-546 acima.

A razão de esta seção de lacuna honesta existir: as listas do console são as superfícies onde um design se torna uma intenção operacional, e uma entrada que só se torna válida após um reload — ou uma entrada duplicada que nada rejeita — é uma regra que o usuário não consegue ver. Nomear as issues responsáveis mantém a regra visível até o código alcançá-la.

O contrato de superfície de status que toda superfície do console segue (JUM-543)

O console nunca bloqueia para dar feedback. A JUM-543 substituiu todos os window.alert por superfícies de status não bloqueantes, e cada painel do console segue o mesmo modelo:

  • Uma única região de toast aria-live (#status-region, role="status", aria-live="polite") anuncia mensagens de validação e falhas de API; avisos de severidade info se ocultam automaticamente, erros persistem. Os portões de ações destrutivas mantêm deliberadamente seu window.confirm — um toast não substitui um portão.
  • Linhas de status inline por painel — o status da prévia do PM2, o status do Service Configuration, o status do ambiente de runtime e a linha de direcionamento por arquivo — carregam falhas com ambiente, arquivo e causa onde o usuário está olhando, em vez de um erro silencioso no console.
  • O cliente renderiza o envelope de erro da API literalmente. error / details, mais code e path nas classes 500 de sistema de arquivos, são exibidos exatamente como retornados — não há remapeamento de erro no lado do cliente, de modo que a separação parse/validação/sistema de arquivos documentada no Requisito 126 chega intacta ao usuário.

O que este documento deliberadamente não cobre

  • Persistência e comportamento de boot — a porta IDesignerStore e a migração para o Cana já entregue (JUM-484 ) pertencem ao documento E3, e suas promessas ao usuário ao documento E6.
  • Exportação/importação das abas do console — desde o JUM-547 as seções interfaces, serviceConfiguration e deployments atravessam a exportação JSON de suíte completa, e runtimeEnvironment atravessa apenas como a seleção de ambiente; o documento E4 é o dono desse escopo e de sua prova em Garantias de paridade de contratos do Service Management.
  • O formato literal de invocação do PM2 — fixado pelo Requisito 126, Contrato 1b, e com mudança prevista na transição para o Bun (JUM-33 , JUM-40 ); a prévia é documentada pela sua fonte precisamente para que este documento sobreviva a essa transição.

Referências

  • Leitor compartilhado da matriz: packages/designer-core/src/model/deployCapabilityMatrix.js; documentos de matriz: JUMENTIX-DEPLOY-TARGET-AND-PACKAGING-MATRIX, JUMENTIX-SERVICE-FACTORY-CAPABILITIES-MATRIX
  • Validadores: serviceConfigurationValidation.js, deployTargetValidation.js, deployTargetLifecycleValidation.js
  • Endpoints do servidor: server.js; cola da UI: script.js, inspectors.js, estado/migração: designerState.js
  • Fontes de ecossistema: pm2/ecosystem.dev.config.cjs, pm2/ecosystem.staging.config.cjs, pm2/ecosystem.production.config.cjs
  • Suítes: serviceConfigurationValidation.test.ts, deployTargetValidation.test.ts, deployTargetLifecycle.test.ts, designerState.test.ts, pm2EcosystemUi.contract.test.ts, runtimeEnvUi.contract.test.ts, pm2Ecosystem.integration.test.ts, runtimeEnv.integration.test.ts, runtimeEnvContract.integration.test.ts, deployTargetLifecycle.browser.integration.test.ts
  • Requisitos: Requisito 126, Contratos 1 e 1b (Contratos 1, 1b e 2), 059 (as matrizes de deploy e da factory), 076 (paridade EN/PT)
  • Documentos irmãos da cadeia E: Contratos de ambiente de runtime (E1), Arquitetura de módulos do Service Management (E3), Garantias de paridade de contratos do Service Management (E4), Aplicativo Service Management, Funcionalidades e uso do Domain Designer
  • Linear: JUM-480 , JUM-481 , JUM-543 , JUM-544 , JUM-545 , JUM-546 , JUM-547 , JUM-464 , JUM-33 , JUM-40