Contratos de ambiente de tempo de execução
Este documento define o contrato do ambiente de tempo de execução usado para inicializar adaptadores de API e perfis de processo PM2.
Propósito
Garanta um comportamento determinístico de inicialização para:
- Adaptadores API REST
- Adaptadores API em tempo real (WebSocket, gRPC)
- Editor de perfil de tempo de execução do Service Management
Todos os pontos de entrada de inicialização do tempo de execução devem seguir este contrato.
Chaves de tempo de execução
As seguintes chaves são obrigatórias em arquivos env em apps/backend-template/src/config/:
-
JUMENTIX_HTTP_FRAMEWORK- padrão:
express - valores atuais suportados:
expressfastifyrestifycloudflare-workersvercel-functionsloopbacksails-jsfeathersderby-jsadonis-jstotal-js
- decisão sobre aliases (JUM-461):
derby-jsesails-jssão as grafias canônicas. Os aliasesderbyesailsNÃO são aceitos — oRuntimeEnvironment.tsfalha imediatamente com eles.hyper-expressfoi removido do runtime (JUM-27) e também é rejeitado. O seletor do Service Management oferece exatamente os 11 valores canônicos acima; as opções da UI e a validação de enum do servidor devem sempre concordar. - usado por:
apps/backend-template/src/interface/HTTP/adapters/start-rest-api.ts
- padrão:
-
JUMENTIX_REALTIME_API- padrão:
não - valores suportados:
sim,não - usado por:
apps/backend-template/src/interface/WebSocket/adapters/start-websocket-api.tsapps/backend-template/src/interface/gRPC/adapters/start-grpc-api.ts
- padrão:
-
JUMENTIX_REALTIME_API_PROTOCOL- padrão:
websocket - valores suportados:
websocket,grpc - usado por:
apps/backend-template/src/interface/WebSocket/adapters/start-websocket-api.tsapps/backend-template/src/interface/gRPC/adapters/start-grpc-api.ts
- padrão:
-
JUMENTIX_DATABASE_DRIVER- padrão:
InMemory - valores suportados (a união
DriverNameempackages/database-client-factory/src/compileDatabaseClient.ts):InMemoryIndexedDBMongoPostgreSQLMySQLMSSQLOracleSQLiteDynamoDBCassandraFirebaseAuroraRDS
- o driver do banco de dados PRINCIPAL da aplicação (persistência da REST API).
Distinto de
JUMENTIX_REALTIME_API_DATABASE_DRIVER: alterar um nunca afeta o outro.IndexedDBé o driver de navegador (Cana) e lança erro se selecionado para um processo server-side sem uma fábricaindexedDbClientconectada. - usado por:
packages/database-client-factory(compileDatabaseClient), conectado emapps/backend-template/src/infra/persistence/compileDatabaseClient.ts
- padrão:
-
JUMENTIX_REALTIME_API_DATABASE_DRIVER- padrão:
Mongo - valores suportados:
MongoPostgreSQLMySQLMS SQLRDSAuroraCassandra
- apenas o driver de banco de dados da API em TEMPO REAL (WebSocket/gRPC) — não
altera o banco de dados principal da aplicação (
JUMENTIX_DATABASE_DRIVER). - usado por: metadados de perfil de tempo de execução e fluxos de trabalho de configuração de gerenciamento de serviços.
- padrão:
-
JUMENTIX_DATABASE_DRIVER- padrão:
InMemory - valores suportados (conjunto canônico
DriverName; o backend também aceita aliases comuns sem distinção entre maiúsculas e minúsculas, mas as grafias canônicas são o contrato):InMemoryIndexedDBMongoPostgreSQLMySQLMSSQLOracleSQLiteDynamoDBCassandraFirebaseAuroraRDS
- usado por:
packages/database-client-factory/src/compileDatabaseClient.ts
- padrão:
-
JUMENTIX_KEYVALUESTORAGE_DRIVER- padrão:
redis(qualquer valor diferente das grafias em memória seleciona Redis) - valores suportados:
inmemory,redis - usado por:
packages/key-value-storage/src/compileKeyValueStorageClient.ts
- padrão:
-
JUMENTIX_MESSAGE_MEDIATOR_ADAPTER- padrão:
inmemory - valores suportados:
inmemory,rabbitmq,bullmq - usado por:
packages/message-mediator/src/compileMessageMediator.ts
- padrão:
-
JUMENTIX_WEBSOCKET_SOCKETIO_ADAPTER- padrão: vazio (adaptador Socket.IO na memória)
- valores suportados:
cluster,redis-streams - usado por:
apps/backend-template/src/interface/WebSocket/adapters/socket-io/socket-io.ts
-
JUMENTIX_WEBSOCKET_CLUSTER_WORKERS- contagem de trabalhadores opcional para modo de cluster Socket.IO.
- padrão: contagem de núcleos da CPU.
- usado por:
apps/backend-template/src/interface/WebSocket/adapters/start-websocket-api.ts
-
JUMENTIX_WEBSOCKET_REDIS_URL- URL de conexão Redis dedicada opcional para adaptador de escalonamento Socket.IO.
- exemplo:
redis://127.0.0.1:6379/1 - usado por:
apps/backend-template/src/interface/WebSocket/adapters/socket-io/redisStreamsAdapter.ts
-
JUMENTIX_REDIS_URL- substituto de URL Redis global opcional usado pelo adaptador de escalabilidade WebSocket quando
JUMENTIX_WEBSOCKET_REDIS_URLnão está definido. - usado por:
apps/backend-template/src/interface/WebSocket/adapters/socket-io/redisStreamsAdapter.ts
- substituto de URL Redis global opcional usado pelo adaptador de escalabilidade WebSocket quando
Pontos de entrada de inicialização
- DESCANSO:
apps/backend-template/src/interface/HTTP/adapters/start-rest-api.ts-WebSocket:apps/backend-template/src/interface/WebSocket/adapters/start-websocket-api.ts-gRPC:apps/backend-template/src/interface/gRPC/adapters/start-grpc-api.ts
Esses arquivos são os pontos de entrada oficiais do processo usados pelos perfis do ecossistema PM2.
Scripts auxiliares de protocolo único também roteiam através desses pontos de entrada (dev:http, prod:http, dev:websocket, dev:grpc).
Modelo de Processo PM2
Para ambientes VM, cada interface é executada em seu próprio processo PM2:
- Processo
API REST - Processo
API WebSocket - Processo
API gRPC - Processo de
Gestão de Serviços
Perfis de tempo de execução:
API RESTAPI WebSocket + API RESTAPI gRPC + API REST
API de ambiente de execução de gerenciamento de serviços
O Service Management expõe pontos de extremidade de leitura/gravação do ambiente de tempo de execução:
GET /api/runtime/env?environment=dev|development|staging|ci|testPOST /api/runtime/env
O editor env altera apenas as chaves aprovadas deste contrato, preservando as proteções.
API de visualização do ecossistema PM2 (JUM-480)
O Service Management também expõe um endpoint PM2 somente leitura, a fonte única da visualização de perfil de tempo de execução do designer:
GET /api/runtime/pm2-ecosystem?environment=dev|development|staging|production|prod|ci|test
O endpoint lê o arquivo real pm2/ecosystem.*.cjs do ambiente selecionado
(diretório configurável via JUMENTIX_SERVICE_MANAGEMENT_PM2_DIR, padrão
<repo-root>/pm2) e retorna { environment, fileName, path, exists, apps },
onde cada app carrega { name, script, interpreter, interpreterArgs, env, command }. command deriva da definição do ecossistema —
pm2 start <caminho do ecossistema> --only <nome do app> --update-env — nunca
uma string de gerenciador de pacotes embutida, de modo que a migração para Bun
(JUM-33/JUM-40) não pode invalidar silenciosamente a visualização. O módulo do
ecossistema é carregado sem cache: editar um arquivo de ecossistema muda a
resposta sem reiniciar o servidor e sem alteração de código.
Os estados de falha e de borda seguem a mesma disciplina de honestidade da API de arquivos env:
- Ambiente desconhecido:
400 { "error": "Invalid environment request.", … }nomeando o valor e a lista aceita — nunca convertido silenciosamente paradev. - Arquivo de ecossistema ausente (por exemplo
ci, que não possui um):200comexists: falsee listaappsvazia — um estado explícito que a UI renderiza como “sem ecossistema para este ambiente”, não uma visualização silenciosamente vazia. - Arquivo de ecossistema ilegível ou sintaticamente quebrado:
500 { "error": "PM2 ecosystem file operation failed.", "code", "path", "details" }.
Localização dos arquivos env
Os arquivos env de tempo de execução ficam em apps/backend-template/src/config/ (.env.dev,
.env.staging, .env.ci). O servidor resolve o diretório de configuração como
JUMENTIX_SERVICE_MANAGEMENT_CONFIG_DIR (resolvido como absoluto) quando definido,
caso contrário <repo-root>/apps/backend-template/src/config, e falha fechado na
inicialização — mensagem no stderr nomeando o diretório ausente, código de saída 1 —
quando o diretório não existe.
Níveis de chaves e listas de permissão
As listas de leitura e gravação são conjuntos separados; cada chave pertence a exatamente um nível.
A classificação autoritativa por chave (com justificativas) está em
.agents/requirements/software/126-service-management-ownership-and-public-contracts.md.
- Editável (leitura + gravação) — seletores de topologia de tempo de execução:
JUMENTIX_HTTP_FRAMEWORK,JUMENTIX_REALTIME_API,JUMENTIX_REALTIME_API_PROTOCOL,JUMENTIX_REALTIME_API_DATABASE_DRIVER,JUMENTIX_DATABASE_DRIVER,JUMENTIX_KEYVALUESTORAGE_DRIVER,JUMENTIX_MESSAGE_MEDIATOR_ADAPTER,JUMENTIX_WEBSOCKET_SOCKETIO_ADAPTER,JUMENTIX_WEBSOCKET_REDIS_URL. - Somente leitura — endpoints de conexão e configuração não secreta:
JUMENTIX_DATABASE_NAME,JUMENTIX_ENABLE_BASIC_AUTH,JUMENTIX_JWT_ISSUER,JUMENTIX_JWT_AUDIENCE,JUMENTIX_REDIS_HOST,JUMENTIX_REDIS_PORT,JUMENTIX_REDIS_DATABASE,JUMENTIX_RABBITMQ_EXCHANGE,JUMENTIX_RABBITMQ_REQUEST_QUEUE,JUMENTIX_RABBITMQ_PREFETCH,JUMENTIX_CORS_ALLOWED_ORIGINS,JUMENTIX_AUTH_MAX_LOGIN_ATTEMPTS,JUMENTIX_AUTH_LOGIN_WINDOW_SECONDS,JUMENTIX_AUTH_LOCKOUT_SECONDS. - Nunca exposta (nem leitura nem gravação) — segredos e valores com credenciais:
JUMENTIX_JWT_TOKEN_SECRET_KEY,JUMENTIX_REDIS_PASSWORD,JUMENTIX_RABBITMQ_URL.
GET retorna { environment, fileName, editableKeys, values } onde values
cobre os níveis editável e somente leitura e editableKeys nomeia a lista de
permissão de gravação. POST ignora qualquer chave fora de editableKeys.
Validação de enum
Chaves editáveis com conjunto enum aceitam apenas os valores canônicos listados em
Chaves de tempo de execução; valores fora do enum
são rejeitados com a lista de aceitos e nada é escrito.
JUMENTIX_WEBSOCKET_SOCKETIO_ADAPTER também aceita vazio (padrão do backend).
JUMENTIX_WEBSOCKET_REDIS_URL aceita vazio ou uma URL redis:///rediss://
válida sem credenciais embutidas — valores com userinfo são rejeitados para que
nenhum segredo possa ser armazenado através do endpoint.
Ambientes aceitos
dev→.env.devdevelopment→.env.dev(alias)staging→.env.stagingci→.env.citest→.env.ci(alias)
A comparação é insensível a maiúsculas após remoção de espaços. Ambientes
desconhecidos são explicitamente rejeitados — 400 com a lista de aceitos, nenhum
arquivo escrito, nunca silenciosamente convertidos para dev. Quando omitido, o
ambiente padrão é NODE_ENV ou dev.
Classificação de chaves
Cada chave de ambiente pertence a exatamente um de três níveis, cada um com uma razão declarada:
- Editável — seletores de topologia de tempo de execução (frameworks, drivers, adaptadores, alternâncias de protocolo); legível via GET e gravável via POST.
- Somente leitura — endpoints de conexão e configuração não secreta; visível no GET para que o designer reflita a realidade, nunca gravável via POST.
- Nunca exposta — segredos e valores portadores de credenciais; não devem aparecer na resposta do GET e não devem ser graváveis, pois a resposta cruza o mesmo limite de confiança que a escrita.
O conjunto editável atual são os quatro seletores de topologia listados em
Chaves de tempo de execução (JUMENTIX_HTTP_FRAMEWORK,
JUMENTIX_REALTIME_API, JUMENTIX_REALTIME_API_PROTOCOL,
JUMENTIX_REALTIME_API_DATABASE_DRIVER), e a superfície de leitura é limitada às
mesmas quatro. A classificação completa por chave dos arquivos env nesses níveis
chega via JUM-460; as decisões de classificação autoritativas — uma por chave, cada
uma com uma razão escrita — estão no
Requisito 126.
Toda adição ao conjunto editável é uma decisão de segurança.
Conjuntos de enum e decisão de alias
Valores fora do enum aceito para cada chave (listados em Chaves de tempo de execução) são rejeitados com a lista de aceitos.
Decisão de alias (JUM-461): derby/derby-js e sails/sails-js são o mesmo
framework sob duas grafias. As grafias canônicas são derby-js e sails-js — as
formas aceitas por
apps/backend-template/src/interface/runtime/RuntimeEnvironment.ts — e o seletor
da UI oferece exatamente os valores que o servidor aceita: um valor que a UI oferece
deve ser um valor que o servidor aceita, e vice-versa. Separadamente,
JUMENTIX_DATABASE_DRIVER e JUMENTIX_REALTIME_API_DATABASE_DRIVER são chaves
distintas e devem ser rotuladas e editáveis separadamente na UI.
Postura de segurança
- Bind padrão é
127.0.0.1(apenas loopback); vincular a uma interface não loopback é um opt-in explícito viaJUMENTIX_SERVICE_MANAGEMENT_HOST. - A porta padrão é
3200, substituível viaJUMENTIX_SERVICE_MANAGEMENT_PORT. - Quando
JUMENTIX_SERVICE_MANAGEMENT_AUTH_TOKENestá definido,POST /api/runtime/envrequerAuthorization: Bearer <token>e rejeita qualquer outra coisa com401 { "error": "Unauthorized." }; quando não definido, a operação apenas em loopback é permitida sem token. - Log de auditoria de mutações registra timestamp, ambiente e chaves alteradas (não valores).
Contrato de erro
As respostas distinguem falhas de parse, validação e filesystem (entregue pelo JUM-543; Requisito 126 §3):
- Corpo JSON malformado (POST):
400 { "error": "Invalid payload.", "details": … }. Otryde parse é restrito apenas aoJSON.parse, de modo que este envelope nunca pode relatar uma falha de filesystem. - Ambiente não suportado:
400 { "error": "Invalid environment request.", "details": … }cujodetailsnomeia o valor não suportado e a lista de aceitos — tanto no GET quanto no POST; nenhum arquivo é escrito. - Falhas de filesystem — arquivo env ausente (código de erro
ENV_FILE_NOT_FOUND), erros de permissão, disco cheio:500 { "error": "Environment file operation failed.", "code": …, "path": …, "details": … }, ondecodeéENV_FILE_NOT_FOUNDou o código de erro dofssubjacente epathé o path resolvido do arquivo env. Uma instalação quebrada é uma classe de falha distinta e identificável — nunca400 Invalid payload.. - Valor fora do enum ou com credenciais para uma chave editável:
400nomeando a chave, o valor rejeitado e a lista de aceitos; nenhum arquivo é escrito. - Token bearer ausente ou incorreto:
401 { "error": "Unauthorized." }quando o token de auth está configurado.
A UI apresenta essas falhas através de superfícies de status não bloqueantes
com aria-live (uma região toast global mais uma linha de status inline no
painel de ambiente de runtime), não window.alert; o cliente renderiza
exatamente o que a API retorna — error, details, e na classe 500 também
code e path — sem remapeamento no cliente.
Guarda-corpos
JUMENTIX_HTTP_FRAMEWORKnão suportado deve falhar rapidamente.- O bootstrap REST deve sempre resolver o framework através do carregador
start-rest-api. - A inicialização em tempo real não deve iniciar quando:
JUMENTIX_REALTIME_APInão ésim, ouJUMENTIX_REALTIME_API_PROTOCOLnão corresponde ao ponto de entrada do adaptador.
- A persistência do ambiente de tempo de execução deve ser explícita e direcionada ao ambiente (
dev,staging,ci).
Exemplos Operacionais
RESTO apenas:
JUMENTIX_HTTP_FRAMEWORK=express
JUMENTIX_REALTIME_API=noWebSocket + REST:
JUMENTIX_HTTP_FRAMEWORK=express
JUMENTIX_REALTIME_API=yes
JUMENTIX_REALTIME_API_PROTOCOL=websocket
JUMENTIX_WEBSOCKET_SOCKETIO_ADAPTER=cluster
JUMENTIX_WEBSOCKET_CLUSTER_WORKERS=4WebSocket + REST (multihost via Redis Streams):
JUMENTIX_HTTP_FRAMEWORK=express
JUMENTIX_REALTIME_API=yes
JUMENTIX_REALTIME_API_PROTOCOL=websocket
JUMENTIX_WEBSOCKET_SOCKETIO_ADAPTER=redis-streams
JUMENTIX_WEBSOCKET_REDIS_URL=redis://127.0.0.1:6379/1gRPC + REST:
JUMENTIX_HTTP_FRAMEWORK=express
JUMENTIX_REALTIME_API=yes
JUMENTIX_REALTIME_API_PROTOCOL=grpc