@oondemand/create-central-oon 0.6.13 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/AGENTS.md CHANGED
@@ -28,15 +28,13 @@ O `AGENTS.md` da raiz pertence ao projeto e nunca pode ser sobrescrito pelo scaf
28
28
  | Domínio, models, validações e fórmulas | [BACKEND_API.md](BACKEND_API.md), [BACKEND_DOMAIN_MANIFEST.md](BACKEND_DOMAIN_MANIFEST.md), [BACKEND_PATTERNS.md](BACKEND_PATTERNS.md), [REACTIVE_DOMAIN_FORMULAS.md](REACTIVE_DOMAIN_FORMULAS.md) |
29
29
  | CRUD, metadata e UI | [METADATA_CRUD_UI.md](METADATA_CRUD_UI.md), [FRONTEND_API.md](FRONTEND_API.md), [FRONTEND_CODE_FIRST.md](FRONTEND_CODE_FIRST.md) |
30
30
  | Auth, ativação, tenant ou permissões | [AUTH_ACTIVATION_RBAC.md](AUTH_ACTIVATION_RBAC.md), [RBAC_SECURITY.md](RBAC_SECURITY.md), [DO_AND_DONT.md](DO_AND_DONT.md) |
31
- | Renderizar, visualizar ou baixar PDF | [APP_LICENSING.md](APP_LICENSING.md), [PDF_RENDERING.md](PDF_RENDERING.md), [BACKEND_API.md](BACKEND_API.md), [FRONTEND_API.md](FRONTEND_API.md) |
32
- | Configurar templates ou enviar e-mail | [APP_LICENSING.md](APP_LICENSING.md), [TRANSACTIONAL_EMAIL.md](TRANSACTIONAL_EMAIL.md), [RBAC_SECURITY.md](RBAC_SECURITY.md) |
31
+ | Renderizar, visualizar ou baixar PDF | [PDF_RENDERING.md](PDF_RENDERING.md), [BACKEND_API.md](BACKEND_API.md), [FRONTEND_API.md](FRONTEND_API.md) |
32
+ | Configurar templates ou enviar e-mail | [TRANSACTIONAL_EMAIL.md](TRANSACTIONAL_EMAIL.md), [RBAC_SECURITY.md](RBAC_SECURITY.md) |
33
33
  | Execução local | [RUNTIME_MODES.md](RUNTIME_MODES.md), [LOCAL_DEVELOPMENT.md](LOCAL_DEVELOPMENT.md), [LOCAL_SECURITY_BOUNDARY.md](LOCAL_SECURITY_BOUNDARY.md) |
34
- | Rotas, hooks, jobs e filas | [APP_LICENSING.md](APP_LICENSING.md), [ROUTES_HOOKS_WORKERS.md](ROUTES_HOOKS_WORKERS.md), [BACKEND_PATTERNS.md](BACKEND_PATTERNS.md) |
35
- | Upgrade do Core | [CORE_UPGRADE.md](CORE_UPGRADE.md), [TESTING_CONFORMANCE.md](TESTING_CONFORMANCE.md), [releases/0.6.0.md](releases/0.6.0.md) |
34
+ | Rotas, hooks, jobs e filas | [ROUTES_HOOKS_WORKERS.md](ROUTES_HOOKS_WORKERS.md), [BACKEND_PATTERNS.md](BACKEND_PATTERNS.md) |
35
+ | Upgrade do Core | [CORE_UPGRADE.md](CORE_UPGRADE.md), [TESTING_CONFORMANCE.md](TESTING_CONFORMANCE.md), [releases/0.7.0.md](releases/0.7.0.md) |
36
36
  | UX avançada | [ADVANCED_UX_PATTERNS.md](ADVANCED_UX_PATTERNS.md), [DETAIL_MODAL_AND_RELATED_GRIDS.md](DETAIL_MODAL_AND_RELATED_GRIDS.md), [PORTAL_COCKPIT_PATTERNS.md](PORTAL_COCKPIT_PATTERNS.md) |
37
37
 
38
- Antes de copiar exemplos de efeitos de negócio, determine a categoria do App pelo contrato governado. Em App comercial licenciado, aplique [APP_LICENSING.md](APP_LICENSING.md) antes de cada novo efeito. Root/globais tenantless não recebem tenant ou licença comercial artificiais; ausência de tenant em um App comercial não é isenção. Runtime local permanece sem efeitos operacionais.
39
-
40
38
  ## Fronteira obrigatória
41
39
 
42
40
  - O App declara domínio e experiência em código; o Core fornece bootstrap, autenticação, ativação, RBAC, tenant, CRUD, metadata, shell, componentes genéricos e deployment.
@@ -56,4 +54,3 @@ npm test
56
54
  ```
57
55
 
58
56
  Uma entrega que depende da leitura de fonte privada ou de outro App não está concluída: registre a lacuna na documentação distribuída.
59
-
@@ -11,7 +11,7 @@
11
11
 
12
12
  ## Regra closed-book
13
13
 
14
- Mantenha os três pacotes OonCore na linha 0.6.x declarada pelo App e sincronize `.ooncore` após qualquer atualização.
14
+ Mantenha os três pacotes OonCore na linha 0.7.x declarada pelo App e sincronize `.ooncore` após qualquer atualização.
15
15
 
16
16
  Trabalhe somente com o App e sua `.ooncore/`. Não leia fonte privada, `node_modules` ou outros Apps para descobrir como usar o Core. Se faltar assinatura, declaração, exemplo, erro ou limite necessário, interrompa essa parte e registre a lacuna documental.
17
17
 
@@ -8,7 +8,9 @@ Ativação de plataforma cria a identidade operacional usada por integrações a
8
8
 
9
9
  ## Catálogo público de perfis
10
10
 
11
- Todo App com RBAC declarado expõe `GET /core/role-catalog`. O contrato `schemaVersion: 1` contém apenas `appCode`, `enabled` e `roles[]` com `code`, `name`, `description` e `admin`. Permissões internas não são expostas.
11
+ Todo App com RBAC declarado expõe `GET /core/role-catalog`. O contrato `schemaVersion: 1` contém `appCode`, `enabled` e `roles[]` com `code`, `name`, `description` e `admin`. Desde o SDK 0.7.1, a extensão aditiva opcional `roles[].commercialPermissions` publica nomes explícitos de permissões funcionais permitidas pelo papel. Wildcards são expandidos somente pelas permissões declaradas em `rbac.permissions`; wildcard literal e namespaces `tenant`, `publications`, `homologation`, `production`, `apps`, `users` e `roles` são excluídos. Políticas internas e permissões técnicas não são publicadas.
12
+
13
+ O campo permanece opcional no schemaVersion 1: catálogos anteriores são conformes para descoberta e fluxos existentes. O novo aceite comercial inicial requer essa capacidade e deve falhar fechado com `APP_ROLE_CATALOG_UNAVAILABLE` quando ausente; não se infere autoridade do nome admin. Consumidores antigos devem tolerar campos adicionais. O runtime continua intersectando cada grant explícito com a política local atual.
12
14
 
13
15
  O catálogo serve para descoberta e seleção de perfis pelo Control Plane. Ele não concede acesso: o backend consumidor deve validar `schemaVersion` e `appCode`, consultar somente o Deployment resolvido pela plataforma, revalidar o perfil antes de persistir o grant e falhar fechado quando o catálogo estiver ausente ou inválido.
14
16
 
@@ -38,12 +38,7 @@ O namespace público `capabilities` contém:
38
38
 
39
39
  O App nunca configura URL, credencial interna ou implementação de uma capability. A única exceção é a injeção de dublês documentada para testes automatizados.
40
40
 
41
- `operationalRequestHeaders({ tenantId, correlationId })` produz headers de identidade do Deployment. O tenant vem do contexto validado e correlationId é opcional. Retorna `LOCAL_OPERATION_NOT_SUPPORTED` no runtime local; nunca improvise identidade local.
42
-
43
- ## Licença por App
44
-
45
- `licensing.assertBusinessOperation` e `licensing.verifyConsumerRequest` (0.6.7):
46
- consulte [APP_LICENSING.md](APP_LICENSING.md) para escopo, erros, local, jobs e reconciliação.
41
+ `operationalRequestHeaders(options)` produz headers de identidade do Deployment. Retorna `LOCAL_OPERATION_NOT_SUPPORTED` no runtime local; nunca improvise identidade local.
47
42
 
48
43
  ## Runtime local
49
44
 
@@ -10,8 +10,8 @@ Os três pacotes devem permanecer na mesma linha:
10
10
 
11
11
  1. Leia o `AGENTS.md` da raiz e preserve regras/domínio do projeto.
12
12
  2. Registre versões atuais, lockfiles e `central.app.json`.
13
- 3. Atualize os três pacotes para a mesma versão `0.6.x`.
14
- 4. Ajuste compatibilidade para `>=0.6.0 <0.7.0` somente quando a migração estiver pronta.
13
+ 3. Atualize os três pacotes para a mesma versão `0.7.x`.
14
+ 4. Ajuste compatibilidade para `>=0.7.0 <0.8.0` somente quando a migração estiver pronta.
15
15
  5. Rode `npm run ooncore:docs` e revise o diff de `.ooncore/`.
16
16
  6. Remova `DEV_TOKEN`, `VITE_DEV_TOKEN`, tokens fixos e URLs da plataforma do caminho local.
17
17
  7. Preserve `AGENTS.md` raiz, models, regras, provas e documentação do domínio.
@@ -23,18 +23,9 @@ O contrato principal do frontend é code-first.
23
23
  - `useOonApi`, `useOonResource`, `useCoreMetadata`, `useModelSchema`: acesso padronizado;
24
24
  - rotas reservadas e guards obrigatórios pertencem ao Core.
25
25
 
26
- ## Contexto e descarte de estado por tenant
27
-
28
- `useOonTenant()` devolve `{activeTenantId: string | null, switchTenant(id), clearTenant()}`
29
- em Apps com tenancy. Não chame esse hook em Apps `tenancyModel=none`.
30
- O Core atualiza o header e limpa o cache de queries na troca. Estado React local,
31
- formulários, tokens de uso único e respostas assíncronas também devem ser descartados:
32
- uma página filha com `key={activeTenantId ?? "no-tenant"}` é uma composição possível.
33
- `useOonAuth().hasPermission(code)` permite ocultar ações, com autorização obrigatória
34
- e independente no backend. `useOonApi()` fornece `{http}` para o cliente autenticado.
35
-
36
26
  ## Domínio e UI
37
27
 
38
28
  Views declarativas continuam disponíveis como composição opcional dentro do
39
29
  objeto App. Componentes, páginas e layouts locais podem ser usados em qualquer
40
30
  `appKind`. Consulte `FRONTEND_CODE_FIRST.md`.
31
+
@@ -21,12 +21,9 @@ Não adicione URL, usuário, senha ou implementation reference. O runtime resolv
21
21
 
22
22
  ## API pública do backend
23
23
 
24
- O exemplo é para **App comercial licenciado**; leia [APP_LICENSING.md](APP_LICENSING.md) antes de usá-lo. Root/globais tenantless não recebem tenant ou licença artificiais, e ausência de tenant em App comercial não dispensa o guard. A categoria não é escolhida pelo request. Runtime local não autoriza geração operacional.
25
-
26
24
  ```js
27
25
  const {
28
26
  capabilities,
29
- licensing,
30
27
  defineRoutes,
31
28
  GenericError,
32
29
  requirePermission,
@@ -50,10 +47,6 @@ defineRoutes("/pdf", (router) => {
50
47
  res.once("close", abort);
51
48
 
52
49
  try {
53
- await licensing.assertBusinessOperation({
54
- tenantId: req.accessContext?.tenantId,
55
- correlationId: req.id,
56
- });
57
50
  const pdf = await capabilities.pdf.render(
58
51
  {
59
52
  html: req.body.html,
@@ -137,8 +130,6 @@ Nunca envie a geração diretamente a um endpoint de infraestrutura pelo navegad
137
130
 
138
131
  ## Erros
139
132
 
140
- O guard propaga `423` com o código comercial (por exemplo, `APP_LICENSE_SUSPENDED`) ou `503`/`LICENSE_AUTHORITY_UNAVAILABLE`. Preserve o erro no tratamento padrão do Core, mostre o motivo e mantenha a operação pendente; não capture para continuar a geração nem devolva sucesso. O frontend deve tratar esses status também quando a resposta foi solicitada como blob. Contexto comercial ausente também impede a geração.
141
-
142
133
  `PdfRenderingError` expõe `code`, `statusCode`, `retryable` e detalhes sanitizados.
143
134
 
144
135
  | Código | Retry | Significado |
@@ -153,7 +144,7 @@ O guard propaga `423` com o código comercial (por exemplo, `APP_LICENSE_SUSPEND
153
144
  | `PDF_RENDERING_TRANSPORT_ERROR` | sim | falha transitória de transporte |
154
145
  | `PDF_RENDERING_INVALID_OUTPUT` | sim | saída inválida ou acima do limite |
155
146
 
156
- Use retentativas da capability apenas quando `error.retryable === true`, com backoff e idempotência na operação chamadora. Cada nova tentativa de geração deve passar novamente pelo guard; uma decisão anterior ou um job já aceito não autoriza a próxima chamada. A consulta é pontual, não atômica com o start: não cancela nem desfaz geração já iniciada. Downloads de documentos já produzidos não iniciam nova geração e seguem as regras de acesso existentes.
147
+ Use retentativas apenas quando `error.retryable === true`, com backoff e idempotência na operação chamadora.
157
148
 
158
149
  ## Segurança e runtime local
159
150
 
@@ -164,4 +155,3 @@ Use retentativas da capability apenas quando `error.retryable === true`, com bac
164
155
  - propague cancelamento do request por `AbortSignal`;
165
156
  - no runtime local, a capability falha fechado com `PDF_RENDERING_UNAVAILABLE` quando não resolvida;
166
157
  - em testes automatizados, um transport fake pode ser injetado por `capabilities.configurePdfRendering` e deve devolver bytes iniciados por `%PDF-`; não gere um “PDF” textual falso no código do App.
167
-
@@ -54,16 +54,10 @@ Templates usam somente interpolação Handlebars escapada. Blocos, helpers, sube
54
54
 
55
55
  ## Envio no backend
56
56
 
57
- Leia [APP_LICENSING.md](APP_LICENSING.md). O exemplo de **App comercial licenciado** demonstra somente a revalidação antes de enfileirar, verificável com mocks isolados. **Não habilita envio comercial assíncrono operacional**: a pendência do executor abaixo precisa ser resolvida antes disso. Root/globais tenantless seguem autoridade/RBAC próprios, sem tenant ou licença artificiais. A categoria não vem do request; tenant ausente em App comercial não é isenção. Runtime local não autoriza envio operacional.
58
-
59
57
  ```js
60
- const { capabilities, licensing } = require("@oondemand/oon-core-back");
58
+ const { capabilities } = require("@oondemand/oon-core-back");
61
59
 
62
60
  async function enviarConfirmacao({ email, nome, idempotencyKey }, req) {
63
- await licensing.assertBusinessOperation({
64
- tenantId: req.accessContext?.tenantId,
65
- correlationId: req.id,
66
- });
67
61
  return capabilities.transactionalEmail.send(
68
62
  {
69
63
  templateCode: "confirmacao",
@@ -83,14 +77,6 @@ async function enviarConfirmacao({ email, nome, idempotencyKey }, req) {
83
77
 
84
78
  `idempotencyKey` é obrigatória. O retorno é `{ dispatchId, status, correlationId }`; `status` é `accepted` ou `duplicate`. Não trate `accepted` como entrega confirmada.
85
79
 
86
- ### Licenciamento, fila e retentativas
87
-
88
- O guard propaga `423` com o código comercial (por exemplo, `APP_LICENSE_SUSPENDED`) ou `503`/`LICENSE_AUTHORITY_UNAVAILABLE`. Preserve status/código no tratamento padrão do Core, mostre o motivo e mantenha a operação pendente, sem enfileirar ou devolver sucesso. Contexto comercial ausente também impede o enqueue. Não use pagamento, cache positivo ou captura do erro como autorização.
89
-
90
- A autorização no enqueue não autoriza um envio futuro. O executor precisa revalidar a autoridade e o contexto antes de **cada tentativa** no provedor, inclusive retry automático e retry de dead letter. Em OonCore 0.6.10, este exemplo não comprova essa integração no worker; não há neste contrato uma opção pública para adicioná-la. Não habilite esse caminho comercial até existir contrato/implementação e prova isolada de suspensão ou revogação entre enqueue e envio, indisponibilidade, contexto divergente e retentativa. Não contorne essa lacuna acessando internals do SDK ou criando executor paralelo no App.
91
-
92
- Mesmo uma revalidação correta é pontual e não atômica com o envio: não cancela chamada já iniciada nem desfaz e-mail aceito pelo provedor. Recibos, callbacks, reconciliação e histórico de efeitos anteriores devem continuar acessíveis conforme suas regras; não confunda essas operações com um novo envio. `accepted` e `duplicate` não são comprovantes de autorização duradoura nem de entrega.
93
-
94
80
  Outras operações públicas do namespace `capabilities.transactionalEmail` incluem preview e versionamento de templates, consulta de dispatches e retry de dead letter. Para administração interativa, prefira o componente do Core.
95
81
 
96
82
  ## Painel administrativo
@@ -123,4 +109,3 @@ O componente usa as rotas autenticadas em `/core/transactional-email/*`. Credenc
123
109
  - erros usam `TransactionalEmailError` e códigos `EMAIL_*` sanitizados;
124
110
  - no runtime local, falhe fechado até a capability e seu secret store/configuração estarem disponíveis;
125
111
  - testes devem substituir a fronteira externa; não envie e-mail real e não grave credenciais de teste.
126
-
@@ -0,0 +1,9 @@
1
+ # OonCore 0.7.0 — Novo Ecossistema Oon
2
+
3
+ Esta linha é o marco de compatibilidade com a identidade operacional por deployment e a autorização comercial single-tenant do novo ecossistema.
4
+
5
+ Atualize Core Back, Core Front e create-central-oon juntos. Declare compatibilidade `>=0.7.0 <0.8.0` após validar a migração e sincronize `.ooncore`.
6
+
7
+ A abertura por `oon_launch` valida a nova sessão antes de persistir token e tenant. Seleção anterior não acompanha o handshake; logout ou login posterior cancelam a troca pendente. A Central continua sendo a autoridade para tenant, licença, grant, ambiente e deployment.
8
+
9
+ Nenhuma regra de licenciamento deve ser implementada no domínio do App. Após atualizar as dependências, execute docs check, conformance, typecheck e testes; publique e homologue o runtime consumidor com a Central compatível. A atualização do pacote não publica nem migra automaticamente Apps.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oondemand/create-central-oon",
3
- "version": "0.6.13",
3
+ "version": "0.7.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/oondemand/oon-platform.git",
@@ -12,6 +12,6 @@
12
12
  "deploy": "oonCore-back deploy"
13
13
  },
14
14
  "dependencies": {
15
- "@oondemand/oon-core-back": "^0.6.13"
15
+ "@oondemand/oon-core-back": "^0.7.1"
16
16
  }
17
17
  }
@@ -11,7 +11,7 @@
11
11
  "sync:metadata": "oonCore-front sync:metadata"
12
12
  },
13
13
  "dependencies": {
14
- "@oondemand/oon-core-front": "^0.6.13",
14
+ "@oondemand/oon-core-front": "^0.7.1",
15
15
  "@chakra-ui/react": "^3.13.0",
16
16
  "@emotion/react": "^11.14.0",
17
17
  "@tanstack/react-query": "^5.65.0",
@@ -13,6 +13,6 @@
13
13
  "dev:frontend": "npm run dev --prefix frontend"
14
14
  },
15
15
  "devDependencies": {
16
- "@oondemand/create-central-oon": "0.6.13"
16
+ "@oondemand/create-central-oon": "0.7.1"
17
17
  }
18
18
  }
@@ -1,75 +0,0 @@
1
- # Licença comercial por aplicativo — contrato 1 (Core 0.6.7)
2
-
3
- Disponível no namespace público `licensing` de `@oondemand/oon-core-back`.
4
- Requer a Central de Ativações com `/licensing/decision` e `/licensing/identity`.
5
- O SDK não substitui autenticação, RBAC, vínculo de Deployment ou licença organizacional.
6
-
7
- ```js
8
- const { licensing } = require("@oondemand/oon-core-back");
9
- await licensing.assertBusinessOperation({ tenantId: accessContext.tenantId, correlationId });
10
- // Inicie agora o efeito autorizado: PDF, e-mail, emissão ou mutação externa.
11
- ```
12
-
13
- Chame imediatamente antes de **cada novo efeito**, inclusive em jobs aceitos anteriormente.
14
- Não guarde autorização no JWT, snapshot ou cache positivo. A decisão é uma leitura pontual;
15
- uma suspensão posterior não cancela uma chamada já iniciada nem desfaz um efeito confirmado.
16
- Preserve recibos, callbacks, reconciliação, downloads já gerados e histórico sem reiniciar efeitos.
17
-
18
- O Core usa identidade operacional do próprio Deployment e a autoridade configurada pelo
19
- runtime. O App não configura URL da Central, credencial interna ou transporte paralelo.
20
- Timeout de 3 segundos, sem redirects, sem retry e sem cache positivo. Resposta ausente,
21
- incompatível ou de outro escopo retorna `LICENSE_AUTHORITY_UNAVAILABLE` (503).
22
- Runtime local não pode obter identidade operacional: `LOCAL_OPERATION_NOT_SUPPORTED`.
23
- Em testes unitários, injete o guard na camada de domínio; isso nunca habilita operação local real.
24
-
25
- Um contrato bloqueado retorna HTTP 423 com código `APP_LICENSE_REQUIRED`,
26
- `APP_LICENSE_NOT_STARTED`, `APP_LICENSE_EXPIRED`, `APP_LICENSE_SUSPENDED`,
27
- `APP_LICENSE_CANCELLED`, `APP_LICENSE_OVERDUE` ou `APP_LICENSE_INVALID`.
28
- Bloqueios organizacionais e de entitlement também são preservados.
29
- Exiba a razão comercial; deixe a operação pendente. Pagamento não renova nem reativa sozinho.
30
-
31
- ## Aplicabilidade: comercial, root/global e local
32
-
33
- O guard abaixo se aplica a novos efeitos de negócio de um **App comercial licenciado**, com tenant obtido do contexto autenticado do backend. A licença de uso do App e a assinatura própria do cliente são independentes; o consumidor consulta a decisão da Central, sem recalcular essas regras.
34
-
35
- Root e globais tenantless seguem sua autoridade operacional e RBAC próprios: não crie tenant, proprietário comercial ou licença fictícios para fazê-los passar pelo guard. A categoria vem do contrato governado do App, nunca de um booleano enviado pelo cliente, da ausência de tenant ou de um override de ambiente. Contexto de tenant ausente em App comercial deve falhar, sem executar o efeito.
36
-
37
- No runtime local não existe autorização operacional. Use mocks da fronteira de licenciamento e da capability somente em testes isolados; não transforme indisponibilidade em sucesso nem injete credenciais operacionais.
38
-
39
- ## Gateway que recebe chamadas de outros Apps
40
-
41
- ```js
42
- const identity = await licensing.verifyConsumerRequest({
43
- headers: req.headers,
44
- requireLicense: false,
45
- });
46
- // Vincule identity.{tenantId,appCode,environment} ao consumidor cadastrado no gateway.
47
- // Autorize base e operação no domínio do gateway, depois:
48
- await licensing.verifyConsumerRequest({ headers: req.headers, requireLicense: true });
49
- ```
50
-
51
- `requireLicense` é `true` por padrão. `false` consulta apenas a identidade e vínculo
52
- ativo Deployment–tenant, permitindo receber/consultar evidências durante suspensão.
53
- **Não autoriza um efeito novo.** A autenticação específica do consumidor e sua política
54
- continuam obrigatórias. O bearer do gateway nunca é encaminhado à Central.
55
-
56
- Headers obrigatórios: `x-oon-deployment-id`, `x-oon-deployment-token`, `x-app-code`,
57
- `x-oon-tenant-id`. Eles só são confiáveis depois da validação remota. Não aceite App,
58
- ambiente ou tenant do body. Todas as respostas são comparadas com o escopo solicitado.
59
- Nenhum segredo ou diagnóstico bruto do provedor é incluído nos erros normalizados.
60
-
61
- ## Resposta da autoridade
62
-
63
- `POST /licensing/decision` (body vazio): `schemaVersion: 1`, `appCode`, `tenantId`,
64
- `environment`, `allowed`, `code`, `version`, `checkedAt`, `maxAgeSeconds: 0`.
65
- Permissão exige versão positiva e código nulo; negação tem código reconhecido.
66
- `POST /licensing/identity`: `schemaVersion: 1`, `appCode`, `tenantId`, `environment`,
67
- `maxAgeSeconds: 0`. Respostas autenticadas têm `Cache-Control: no-store`.
68
-
69
- ## Limite atual de jobs
70
-
71
- Este contrato oferece o guard de efeitos, não um executor durável de integrações.
72
- A documentação de process jobs existente não especifica registro público de handlers
73
- externos, inbox/outbox e retomada autônoma necessários ao gateway da issue #170.
74
- Essa extensão precisa de contrato e testes próprios antes de declarar I4 concluída.
75
-