@oondemand/create-central-oon 0.4.30 → 0.5.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/README.md +8 -8
- package/bin/cli.js +12 -4
- package/docs/ADVANCED_UX_PATTERNS.md +2 -2
- package/docs/AGENTS.md +47 -0
- package/docs/AGENT_WORKFLOW.md +13 -0
- package/docs/AUTH_ACTIVATION_RBAC.md +28 -0
- package/docs/BACKEND_API.md +43 -0
- package/docs/CAPABILITIES.md +24 -0
- package/docs/CODEX.md +8 -79
- package/docs/CORE_UPGRADE.md +20 -0
- package/docs/ERRORS.md +18 -0
- package/docs/FRONTEND_API.md +34 -0
- package/docs/FRONTEND_MANIFEST_REFERENCE.md +2 -2
- package/docs/LOCAL_DEVELOPMENT.md +34 -0
- package/docs/LOCAL_SECURITY_BOUNDARY.md +24 -0
- package/docs/METADATA_CRUD_UI.md +11 -0
- package/docs/OONCORE_ARCHITECTURE.md +2 -2
- package/docs/RBAC_SECURITY.md +27 -1
- package/docs/ROUTES_HOOKS_WORKERS.md +11 -0
- package/docs/RUNTIME_MODES.md +16 -0
- package/docs/TESTING_CONFORMANCE.md +30 -0
- package/docs/TROUBLESHOOTING.md +18 -0
- package/docs/releases/0.5.0.md +25 -0
- package/package.json +2 -2
- package/src/conformance.js +19 -0
- package/src/dev.js +77 -0
- package/src/index.js +86 -14
- package/templates/_base/README.md +4 -3
- package/templates/_base/backend/env.example +3 -10
- package/templates/_base/backend/package.json +1 -1
- package/templates/_base/central.app.json +2 -2
- package/templates/_base/frontend/env.example +3 -9
- package/templates/_base/frontend/package.json +1 -1
- package/templates/_base/frontend/src/main.tsx +3 -3
- package/templates/_base/frontend/vite.config.ts +9 -0
- package/templates/_base/package.json +4 -3
package/README.md
CHANGED
|
@@ -36,8 +36,8 @@ Toda Central gerada possui um manifesto raiz com identidade e capabilities:
|
|
|
36
36
|
"capabilities": ["core.collections"],
|
|
37
37
|
"compatibility": {
|
|
38
38
|
"core": {
|
|
39
|
-
"minVersion": "0.
|
|
40
|
-
"maxVersionExclusive": "0.
|
|
39
|
+
"minVersion": "0.5.0",
|
|
40
|
+
"maxVersionExclusive": "0.6.0"
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -57,7 +57,7 @@ Responsabilidades do manifesto:
|
|
|
57
57
|
- faixa compatível do OonCore;
|
|
58
58
|
- metadados declarativos de ativação.
|
|
59
59
|
|
|
60
|
-
`backend/central.config.js` fica reservado a extensões excepcionais de runtime. Em Centrais `member-central` e `portal-cockpit`, identidade, módulos e autenticação não podem ser reintroduzidos nesse arquivo. O
|
|
60
|
+
`backend/central.config.js` fica reservado a extensões excepcionais de runtime. Em Centrais `member-central` e `portal-cockpit`, identidade, módulos e autenticação não podem ser reintroduzidos nesse arquivo. O desenvolvimento local usa sessão aleatória HttpOnly; tokens fixos são reprovados pela conformidade.
|
|
61
61
|
|
|
62
62
|
## Verificação de conformidade
|
|
63
63
|
|
|
@@ -87,7 +87,7 @@ O comando falha quando encontra, entre outros desvios:
|
|
|
87
87
|
|
|
88
88
|
A CI de uma Central deve executar o comando antes do build e da publicação.
|
|
89
89
|
|
|
90
|
-
## Documentação
|
|
90
|
+
## Documentação distribuída para IA/Agents
|
|
91
91
|
|
|
92
92
|
O pacote inclui documentação canônica em `docs/`. Ao criar uma Central, o CLI gera `.ooncore/` como cache local da documentação da versão instalada.
|
|
93
93
|
|
|
@@ -96,7 +96,7 @@ npm run ooncore:docs
|
|
|
96
96
|
npm run ooncore:docs:check
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
`.ooncore/AGENTS.md` é a entrada neutra e `.ooncore/docs/` contém os contratos completos de backend, frontend e capacidades. A pasta pode ser regenerada a partir do pacote npm sem sobrescrever o `AGENTS.md` da raiz.
|
|
100
100
|
|
|
101
101
|
## Templates funcionais
|
|
102
102
|
|
|
@@ -133,9 +133,9 @@ O bootstrap gerado importa `central.app.json` e `central.ui.json` e chama `start
|
|
|
133
133
|
```bash
|
|
134
134
|
cd <central>
|
|
135
135
|
npm run check
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
cp backend/.env.example backend/.env
|
|
137
|
+
cp frontend/.env.example frontend/.env
|
|
138
|
+
npm run dev
|
|
139
139
|
```
|
|
140
140
|
|
|
141
141
|
Evoluir a Central significa declarar domínio, UI, mappings e regras específicas. O OonCore implementa como a aplicação funciona.
|
package/bin/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
-
const { run, listTemplates, syncDocs, checkDocs } = require("../src/index");
|
|
4
|
+
const { run, listTemplates, syncDocs, checkDocs, runLocalDevelopment } = require("../src/index");
|
|
5
5
|
const { checkConformance } = require("../src/conformance");
|
|
6
6
|
|
|
7
7
|
function parseArgs(argv) {
|
|
@@ -35,8 +35,11 @@ function parseArgs(argv) {
|
|
|
35
35
|
else if (!arg.startsWith("-")) positionals.push(arg);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
if (["docs", "conformance"].includes(positionals[0]))
|
|
39
|
-
|
|
38
|
+
if (["docs", "conformance", "dev"].includes(positionals[0])) {
|
|
39
|
+
opts.command = positionals[0];
|
|
40
|
+
if (opts.command === "docs" && positionals[1] === "check") opts.docsCheck = true;
|
|
41
|
+
if (opts.command === "docs" && positionals[1] === "sync") opts.docsSync = true;
|
|
42
|
+
} else opts.name = positionals[0];
|
|
40
43
|
return opts;
|
|
41
44
|
}
|
|
42
45
|
|
|
@@ -44,8 +47,9 @@ function printUsage() {
|
|
|
44
47
|
console.error("Uso:");
|
|
45
48
|
console.error(" npx create-central-oon <nome-da-central> [--template=basic]");
|
|
46
49
|
console.error(" npx create-central-oon --list");
|
|
47
|
-
console.error(" npx create-central-oon docs
|
|
50
|
+
console.error(" npx create-central-oon docs sync|check");
|
|
48
51
|
console.error(" npx create-central-oon conformance [--root .] [--json]");
|
|
52
|
+
console.error(" npx create-central-oon dev");
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
async function main() {
|
|
@@ -76,6 +80,10 @@ async function main() {
|
|
|
76
80
|
}
|
|
77
81
|
process.exit(result.ok ? 0 : 1);
|
|
78
82
|
}
|
|
83
|
+
if (opts.command === "dev") {
|
|
84
|
+
runLocalDevelopment({ cwd: process.cwd() });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
79
87
|
if (!opts.name) {
|
|
80
88
|
printUsage();
|
|
81
89
|
process.exit(1);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ADVANCED_UX_PATTERNS.md — UX Avançada Declarativa no OonCore
|
|
2
2
|
|
|
3
|
-
Este documento orienta
|
|
3
|
+
Este documento orienta Agents a usarem o máximo de recursos do OonCore antes de criar telas customizadas. O foco é transformar padrões recorrentes de sistemas operacionais em **manifesto declarativo** e componentes reutilizáveis.
|
|
4
4
|
|
|
5
5
|
## Objetivo
|
|
6
6
|
|
|
@@ -161,7 +161,7 @@ Use componente customizado apenas quando:
|
|
|
161
161
|
|
|
162
162
|
Mesmo nesses casos, prefira plugar o componente em uma aba `customComponent` da modal, e não substituir a página inteira.
|
|
163
163
|
|
|
164
|
-
## Checklist para
|
|
164
|
+
## Checklist para Agents
|
|
165
165
|
|
|
166
166
|
Antes de criar tela customizada:
|
|
167
167
|
|
package/docs/AGENTS.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# OonCore — entrada canônica para IA/Agents
|
|
2
|
+
|
|
3
|
+
Este arquivo é o contrato inicial neutro para Codex, ChatGPT, Kimi, Manus e outros Agents que alterem uma Central Oon.
|
|
4
|
+
|
|
5
|
+
## Ordem de leitura
|
|
6
|
+
|
|
7
|
+
1. Leia primeiro o `AGENTS.md` da raiz do projeto consumidor, quando existir.
|
|
8
|
+
2. Confirme `schemaVersion`, `version`, `docsHash` e `entrypointsHash` em `.ooncore/manifest.json`.
|
|
9
|
+
3. Rode `npm run ooncore:docs:check`; se falhar, rode `npm run ooncore:docs` e verifique novamente.
|
|
10
|
+
4. Consulte `docs/CAPABILITIES.md` antes de criar código.
|
|
11
|
+
5. Leia os contratos de backend, frontend, runtime, RBAC ou integração indicados abaixo.
|
|
12
|
+
6. Leia a documentação de domínio do projeto consumidor.
|
|
13
|
+
|
|
14
|
+
O `AGENTS.md` da raiz pertence ao projeto e nunca pode ser sobrescrito pelo scaffold ou pelo sync do Core.
|
|
15
|
+
|
|
16
|
+
## Roteamento por tarefa
|
|
17
|
+
|
|
18
|
+
| Tarefa | Leitura obrigatória |
|
|
19
|
+
|---|---|
|
|
20
|
+
| Domínio, models, validações e fórmulas | `BACKEND_API.md`, `BACKEND_DOMAIN_MANIFEST.md`, `BACKEND_PATTERNS.md`, `REACTIVE_DOMAIN_FORMULAS.md` |
|
|
21
|
+
| CRUD, metadata e UI | `METADATA_CRUD_UI.md`, `FRONTEND_API.md`, `FRONTEND_MANIFEST_REFERENCE.md` |
|
|
22
|
+
| Auth, ativação, tenant ou permissões | `AUTH_ACTIVATION_RBAC.md`, `RBAC_SECURITY.md`, `DO_AND_DONT.md` |
|
|
23
|
+
| Execução local | `RUNTIME_MODES.md`, `LOCAL_DEVELOPMENT.md`, `LOCAL_SECURITY_BOUNDARY.md` |
|
|
24
|
+
| Rotas, hooks, jobs e filas | `ROUTES_HOOKS_WORKERS.md`, `BACKEND_PATTERNS.md` |
|
|
25
|
+
| Integrações | `CONNECTORS_AND_INTEGRATIONS.md`, `LOCAL_SECURITY_BOUNDARY.md` |
|
|
26
|
+
| Upgrade do Core | `CORE_UPGRADE.md`, `TESTING_CONFORMANCE.md`, `releases/0.5.0.md` |
|
|
27
|
+
| UX avançada | `ADVANCED_UX_PATTERNS.md`, `DETAIL_MODAL_AND_RELATED_GRIDS.md`, `PORTAL_COCKPIT_PATTERNS.md` |
|
|
28
|
+
|
|
29
|
+
## Fronteira obrigatória
|
|
30
|
+
|
|
31
|
+
- A Central declara domínio e experiência; o Core fornece bootstrap, autenticação, ativação, RBAC, tenant, CRUD, metadata, shell, componentes genéricos, integração operacional e deployment.
|
|
32
|
+
- Use somente exports públicos documentados. Arquivos internos de `src/` não são contrato de extensão.
|
|
33
|
+
- Autorização, tenant e regras que alteram dados são sempre validados no backend.
|
|
34
|
+
- Não crie autenticação, ativação, RBAC, CRUD, shell, registry ou infraestrutura paralelos.
|
|
35
|
+
- Não coloque segredos em manifesto, frontend, log, URL permanente ou documentação.
|
|
36
|
+
- Recursos de plataforma devem falhar fechado no runtime local.
|
|
37
|
+
|
|
38
|
+
## Gates antes de concluir
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm run ooncore:docs:check
|
|
42
|
+
npm run ooncore:conformance
|
|
43
|
+
npm run check
|
|
44
|
+
npm test
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Se um contrato público exigir leitura do repositório privado do OonCore, registre a lacuna: a documentação distribuída está incompleta.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Fluxo de trabalho para Agents
|
|
2
|
+
|
|
3
|
+
1. **Descobrir:** leia `AGENTS.md`, manifesto documental e `CAPABILITIES.md`.
|
|
4
|
+
2. **Classificar:** separe contrato do Core, domínio da Central e recurso exclusivo da plataforma.
|
|
5
|
+
3. **Escolher extensão:** manifesto → validation/trigger/hook/mapping → renderer/rota pequena → código customizado somente se necessário.
|
|
6
|
+
4. **Implementar:** use exports públicos; preserve segurança, tenant, auditoria e idempotência.
|
|
7
|
+
5. **Executar local:** `npm run dev`, sem cadastro ou conexão com a plataforma.
|
|
8
|
+
6. **Validar:** docs check, conformance, testes, typecheck e provas específicas do projeto.
|
|
9
|
+
7. **Relatar:** arquivos, contratos usados, riscos, limitações e evidências.
|
|
10
|
+
|
|
11
|
+
Prompt operacional:
|
|
12
|
+
|
|
13
|
+
> Atualize os três pacotes OonCore para a linha 0.5.x, preserve o domínio e o AGENTS.md do projeto, sincronize `.ooncore`, consulte os contratos públicos de back e front, use apenas extensões suportadas, execute os gates e homologue em `127.0.0.1` sem conexão com a plataforma. Não crie autenticação, ativação, RBAC, CRUD, shell ou infraestrutura paralelos.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Autenticação, ativação e RBAC
|
|
2
|
+
|
|
3
|
+
## Plataforma
|
|
4
|
+
|
|
5
|
+
O backend verifica o token no escopo do App, resolve tenant e acesso, aplica a política local de RBAC e cria `req.accessContext`. O frontend usa permissões somente para experiência; o backend autoriza cada operação.
|
|
6
|
+
|
|
7
|
+
Ativação de plataforma cria a identidade operacional usada por integrações autorizadas. Rotas de login, launch exchange, ativação e primeiro acesso não estão disponíveis no runtime local.
|
|
8
|
+
|
|
9
|
+
## Catálogo público de perfis
|
|
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.
|
|
12
|
+
|
|
13
|
+
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
|
+
|
|
15
|
+
## Local
|
|
16
|
+
|
|
17
|
+
O principal técnico é `local:developer`, sem usuário/tenant/licença na plataforma. O papel inicial é `developer` quando declarado, seguido por admin ou primeiro papel. A troca de perfil aceita apenas o manifesto e atualiza a sessão local.
|
|
18
|
+
|
|
19
|
+
O estado é `ativa_local`; o `ActivationGuard` não cria nem consulta `InstanciaEcossistema`. Isso não equivale a `ativa` publicada.
|
|
20
|
+
|
|
21
|
+
## Regras para extensões
|
|
22
|
+
|
|
23
|
+
- use `requirePermission` em rotas customizadas;
|
|
24
|
+
- derive filtros de `req.accessContext`;
|
|
25
|
+
- nunca autorize por header/body de perfil ou tenant;
|
|
26
|
+
- não implemente `verifyToken` em Central member/portal;
|
|
27
|
+
- não persista bearer no frontend;
|
|
28
|
+
- não trate simulação local como identidade operacional.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# API pública do `@oondemand/oon-core-back`
|
|
2
|
+
|
|
3
|
+
Importe exclusivamente de `@oondemand/oon-core-back`. Caminhos internos não têm estabilidade garantida.
|
|
4
|
+
|
|
5
|
+
## Boot e definição
|
|
6
|
+
|
|
7
|
+
- `start(options)`: carrega a Central, conecta Mongo, inicializa capabilities e inicia HTTP. `options.listen=false` devolve somente o app.
|
|
8
|
+
- `createApp()`: cria o Express já protegido e com rotas do Core.
|
|
9
|
+
- `activate()`: fluxo legado de ativação; não é usado no runtime local.
|
|
10
|
+
- `defineCentral`, `defineModel`, `defineCollection`, `defineDocument`, `definePipeline`, `defineOmieMapping`, `defineRoutes`, `defineValidation`, `defineTrigger`: extensões imperativas suportadas.
|
|
11
|
+
- `fields`: factories de campos compatíveis com schema e metadata.
|
|
12
|
+
- `registry`: registry do processo; use APIs `define*`, não mutações internas.
|
|
13
|
+
|
|
14
|
+
## Segurança, RBAC e tenant
|
|
15
|
+
|
|
16
|
+
- `requirePermission(permission)`: middleware obrigatório em rotas sensíveis.
|
|
17
|
+
- `CORE_PERMISSIONS`, `rbacPolicy`, `roleByCode`, `permissionGranted`: leitura e avaliação da política declarada.
|
|
18
|
+
- `TENANT_HEADER`, `TENANCY_MODELS`, `DATA_SCOPES`: constantes canônicas.
|
|
19
|
+
- `createAccessContext`, `readRequestedTenantId`: produzem contexto validado.
|
|
20
|
+
- `scopeFilter`, `mergeScopedFilter`, `scopeMutation`, `scopedIdFilter`: aplicam isolamento aos dados. Nunca aceite tenant do body como autoridade.
|
|
21
|
+
|
|
22
|
+
## Manifestos
|
|
23
|
+
|
|
24
|
+
- App: `APP_MANIFEST_FILENAME`, `APP_MANIFEST_SCHEMA_VERSION`, `SUPPORTED_APP_KINDS`, `SUPPORTED_APP_MODULES`, `AppManifestError`, `validateAppManifest`, `resolveAppManifestPath`, `appManifestToConfig`, `registerAppManifest`, `loadAppManifest`.
|
|
25
|
+
- Domínio: `DOMAIN_MANIFEST_FILENAME`, `DOMAIN_MANIFEST_SCHEMA_VERSION`, `SUPPORTED_DOMAIN_FIELD_KINDS`, `DOMAIN_EXPRESSION_OPERATORS`, `DomainManifestError`, `DomainRuleError`, `validateDomainManifest`, `domainManifestToDefinitions`, `registerDomainManifest`, `loadDomainManifest`, `evaluateDomainExpression`, `applyDomainMutation`, `validateDomainRecord`, `detectChangedFields`.
|
|
26
|
+
- Processo: `PROCESS_MANIFEST_FILENAME`, `PROCESS_MANIFEST_SCHEMA_VERSION`, `ProcessManifestError`, `validateProcessManifest`, `registerProcessManifest`, `loadProcessManifest`, `prepareProcessMutation`, `resolveProcessBindings`, `assertReferencePolicies`, `assertAtomicInvariants`, `assertDeleteAllowed`, `recalculateDependents`, `drainProcessJobs`.
|
|
27
|
+
|
|
28
|
+
Erros de manifesto carregam `code`, `statusCode` e `issues[]` com `path` e `message`.
|
|
29
|
+
|
|
30
|
+
## Integrações e capabilities
|
|
31
|
+
|
|
32
|
+
- `integrations`, `registerIntegrationProvider`, `enqueueIntegration`, `receiveIntegrationWebhook`.
|
|
33
|
+
- `omie`, `omieModule`, `createOmieClient`, `OmieApiError`, `enqueueOmieCall`, `ensureOmieProviderRegistered`, `collectOmieDefinitions`, `describeOmieDefinitions`, `saveOmieConfiguration`, `listOmieConfigurations`, `testOmieConnection`.
|
|
34
|
+
- `capabilities`, `PdfRenderingError`, `TransactionalEmailError`.
|
|
35
|
+
- `operationalRequestHeaders(options)`: headers de identidade do Deployment. Retorna `LOCAL_OPERATION_NOT_SUPPORTED` no runtime local; nunca improvise identidade local.
|
|
36
|
+
|
|
37
|
+
## Runtime local
|
|
38
|
+
|
|
39
|
+
O namespace público `localDevelopment` expõe detecção, validação de loopback e utilitários de teste/integração do runtime. Apps consumidores normalmente apenas definem `OON_RUNTIME_MODE=local` e usam o scaffold.
|
|
40
|
+
|
|
41
|
+
## Erros
|
|
42
|
+
|
|
43
|
+
`GenericError(message, { statusCode, code, details })` é o erro operacional base. Rotas devem lançá-lo e deixar o middleware do Core produzir o envelope sanitizado.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Catálogo de capacidades do OonCore
|
|
2
|
+
|
|
3
|
+
Consulte este catálogo antes de criar infraestrutura ou componentes customizados.
|
|
4
|
+
|
|
5
|
+
| Capacidade | Backend | Frontend | Declaração/extensão | Local | Plataforma |
|
|
6
|
+
|---|---|---|---|---|---|
|
|
7
|
+
| Models e CRUD | `defineModel`, domain manifest, `/core/*` | `CoreCollection`, hooks de API | `central.domain.json`, `central.ui.json` | Sim | Sim |
|
|
8
|
+
| Metadata | registry e `/core/metadata` | `useCoreMetadata`, renderers | models/domain manifest | Sim | Sim |
|
|
9
|
+
| Validações e fórmulas | `defineValidation`, domain rules | prévia reativa | domain manifest/validation | Sim | Sim |
|
|
10
|
+
| Esteiras | process manifest/runtime | `CorePipeline` | `central.process.json`, UI manifest | Sim | Sim |
|
|
11
|
+
| Documentos | `defineDocument` | `CoreDocument` | UI/domain manifest | Sim | Sim |
|
|
12
|
+
| Dashboards | agregações e rotas | `CoreDashboard` | UI manifest | Sim | Sim |
|
|
13
|
+
| RBAC | policy, middleware e `requirePermission` | `PermissionGate`, `can` | `central.app.json` | Simulação declarada | Identidade real |
|
|
14
|
+
| Tenant e escopo | access context e scope helpers | `TenantProvider` | `central.app.json` | Contexto técnico | Contexto autorizado |
|
|
15
|
+
| Auditoria | CRUD e request context | headers do SDK | automática/extensão | Local | Operacional |
|
|
16
|
+
| Rotas customizadas | `defineRoutes` | página/ação declarada | `backend/src/routes` | Sim | Sim |
|
|
17
|
+
| Jobs e workers | process/integration workers | status operacional | manifestos/hooks | Sim | Sim |
|
|
18
|
+
| Integrações | runtime/provider registry | `CoreIntegration` | mapping/provider suportado | Dublê ou credencial local | Credencial operacional |
|
|
19
|
+
| E-mail transacional | capability nativa | `CoreTransactionalEmail` | capability settings | Dublê/local | Provider configurado |
|
|
20
|
+
| PDF | capability nativa | consumo por ação | capability contract | Dublê/local | Provider configurado |
|
|
21
|
+
| Publicação/promoção | contratos de delivery | indisponível no App | CLI/ponte pública | Não | Sim |
|
|
22
|
+
| Runtime local | sessão e guardas locais | bootstrap/cookie/banner | `OON_RUNTIME_MODE=local` | Sim | Não aplicável |
|
|
23
|
+
|
|
24
|
+
Para cada capacidade, use o manifesto quando houver contrato declarativo; use código da Central apenas em pontos de extensão documentados.
|
package/docs/CODEX.md
CHANGED
|
@@ -1,83 +1,12 @@
|
|
|
1
|
-
# CODEX.md —
|
|
1
|
+
# CODEX.md — ponte de compatibilidade
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A fonte canônica, completa e neutra do OonCore é `AGENTS.md`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Ao trabalhar em uma Central:
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
1. leia primeiro o `AGENTS.md` da raiz do projeto, quando existir;
|
|
8
|
+
2. leia `.ooncore/AGENTS.md`;
|
|
9
|
+
3. valide `.ooncore/manifest.json` com `npm run ooncore:docs:check`;
|
|
10
|
+
4. siga as referências de `.ooncore/docs/` indicadas para a tarefa.
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
2. Se estiver desatualizado, rode `npm run ooncore:docs`.
|
|
11
|
-
3. Leia `.ooncore/context.generated.md`.
|
|
12
|
-
4. Identifique o recurso do Core que resolve a necessidade antes de criar código customizado.
|
|
13
|
-
|
|
14
|
-
## Leitura obrigatória por tipo de tarefa
|
|
15
|
-
|
|
16
|
-
### Backend/domínio
|
|
17
|
-
|
|
18
|
-
- `BACKEND_DOMAIN_MANIFEST.md`
|
|
19
|
-
- `BACKEND_PATTERNS.md`
|
|
20
|
-
- `COLLECTIONS_AND_PIPELINES.md`
|
|
21
|
-
- `CONNECTORS_AND_INTEGRATIONS.md`
|
|
22
|
-
- `RBAC_SECURITY.md`
|
|
23
|
-
|
|
24
|
-
### Frontend/manifesto
|
|
25
|
-
|
|
26
|
-
- `FRONTEND_PATTERNS.md`
|
|
27
|
-
- `FRONTEND_MANIFEST_REFERENCE.md`
|
|
28
|
-
- `REACTIVE_DOMAIN_FORMULAS.md`
|
|
29
|
-
|
|
30
|
-
### UX avançada, modais, abas e itens relacionados
|
|
31
|
-
|
|
32
|
-
Leia antes de criar páginas customizadas:
|
|
33
|
-
|
|
34
|
-
- `ADVANCED_UX_PATTERNS.md`
|
|
35
|
-
- `DETAIL_MODAL_AND_RELATED_GRIDS.md`
|
|
36
|
-
|
|
37
|
-
Use estes documentos quando a necessidade envolver:
|
|
38
|
-
|
|
39
|
-
- modal com abas;
|
|
40
|
-
- dados principais agrupados;
|
|
41
|
-
- grids relacionados;
|
|
42
|
-
- edição inline;
|
|
43
|
-
- ações por linha;
|
|
44
|
-
- registros filhos como itens, parcelas, produtos, documentos ou pagamentos;
|
|
45
|
-
- telas onde o usuário opera um registro principal e seus relacionamentos.
|
|
46
|
-
|
|
47
|
-
## Princípios obrigatórios
|
|
48
|
-
|
|
49
|
-
- Escreva apenas o domínio da Central.
|
|
50
|
-
- Use `central.domain.json` para models, campos, fórmulas e validações cobertos pelo contrato declarativo vigente.
|
|
51
|
-
- Não repita fórmulas do domínio em componentes React: os formulários do Core geram a prévia reativa a partir da metadata e o backend recalcula antes de persistir.
|
|
52
|
-
- Use `@oondemand/oon-core-back` para boot, autenticação, RBAC, CRUD, metadata, auditoria e padrões de API.
|
|
53
|
-
- Use `@oondemand/oon-core-front` para shell, rotas, menu, datagrid, formulários, badges, ações e renderização por metadata.
|
|
54
|
-
- Não recrie infraestrutura que já existe no Core.
|
|
55
|
-
- Não crie autenticação paralela.
|
|
56
|
-
- Não duplique RBAC no frontend.
|
|
57
|
-
- Não hardcode tenant, app, usuário, perfil, permissões, URLs sensíveis ou segredos.
|
|
58
|
-
- Não exponha chaves em código, templates ou documentação gerada.
|
|
59
|
-
- Não altere arquivos gerados do Core se houver extensão declarativa disponível.
|
|
60
|
-
- Prefira manifestos, validations, triggers, hooks, mappings, documents, pipelines, integrations e overrides declarativos.
|
|
61
|
-
- Antes de criar uma página React customizada, tente resolver com `central.ui.json`, `detailModal`, `form.groups`, `relatedGrid`, `readonlyGrid` e `rowActions`.
|
|
62
|
-
|
|
63
|
-
## Ordem de decisão
|
|
64
|
-
|
|
65
|
-
Ao implementar uma necessidade, siga esta ordem:
|
|
66
|
-
|
|
67
|
-
1. Configuração existente do Core.
|
|
68
|
-
2. Declaração em `central.config.js`, `central.domain.json` ou `central.ui.json`.
|
|
69
|
-
3. Validation, trigger, hook ou mapping no backend da Central.
|
|
70
|
-
4. Modal, abas, grid relacionado, ação e renderer declarativos do Core.
|
|
71
|
-
5. Override local pequeno e isolado.
|
|
72
|
-
6. Código customizado somente quando o Core não oferecer extensão adequada.
|
|
73
|
-
|
|
74
|
-
## Entrega segura
|
|
75
|
-
|
|
76
|
-
Toda alteração deve manter:
|
|
77
|
-
|
|
78
|
-
- rastreabilidade;
|
|
79
|
-
- validação de entrada;
|
|
80
|
-
- RBAC no backend;
|
|
81
|
-
- ausência de segredo hardcoded;
|
|
82
|
-
- separação entre domínio da Central e infraestrutura do Core;
|
|
83
|
-
- compatibilidade com atualização futura dos pacotes `@oondemand/*`.
|
|
12
|
+
Não mantenha regras exclusivas neste arquivo. Codex, ChatGPT, Kimi, Manus e outros Agents devem consumir o mesmo contrato versionado.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Atualização coordenada do OonCore
|
|
2
|
+
|
|
3
|
+
Os três pacotes devem permanecer na mesma linha:
|
|
4
|
+
|
|
5
|
+
- `@oondemand/oon-core-back`;
|
|
6
|
+
- `@oondemand/oon-core-front`;
|
|
7
|
+
- `@oondemand/create-central-oon`.
|
|
8
|
+
|
|
9
|
+
## Procedimento para Agent
|
|
10
|
+
|
|
11
|
+
1. Leia o `AGENTS.md` da raiz e preserve regras/domínio do projeto.
|
|
12
|
+
2. Registre versões atuais, lockfiles e `central.app.json`.
|
|
13
|
+
3. Atualize os três pacotes para a mesma versão `0.5.x`.
|
|
14
|
+
4. Ajuste compatibilidade para `>=0.5.0 <0.6.0` somente quando a migração estiver pronta.
|
|
15
|
+
5. Rode `npm run ooncore:docs` e revise o diff de `.ooncore/`.
|
|
16
|
+
6. Remova `DEV_TOKEN`, `VITE_DEV_TOKEN`, tokens fixos e URLs da plataforma do caminho local.
|
|
17
|
+
7. Preserve `AGENTS.md` raiz, models, regras, provas e documentação do domínio.
|
|
18
|
+
8. Execute docs check, conformance, typecheck, testes e smoke offline.
|
|
19
|
+
|
|
20
|
+
Não atualize somente um pacote e não copie arquivos do Core manualmente para a Central.
|
package/docs/ERRORS.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Contrato de erros
|
|
2
|
+
|
|
3
|
+
Erros operacionais usam `{ error: { code, message, details?, requestId? } }` e status HTTP coerente.
|
|
4
|
+
|
|
5
|
+
| Código | Significado |
|
|
6
|
+
|---|---|
|
|
7
|
+
| `LOCAL_RUNTIME_ENV_INVALID` | modo local fora de development |
|
|
8
|
+
| `LOCAL_RUNTIME_PLATFORM_IDENTITY` | identidade de plataforma/Kubernetes presente |
|
|
9
|
+
| `LOCAL_RUNTIME_BIND_FORBIDDEN` | bind fora de loopback |
|
|
10
|
+
| `LOCAL_HOST_FORBIDDEN` / `LOCAL_ORIGIN_FORBIDDEN` | acesso de rede recusado |
|
|
11
|
+
| `LOCAL_PROXY_FORBIDDEN` | tentativa de proxy no modo local |
|
|
12
|
+
| `LOCAL_BOOTSTRAP_INVALID` | código ausente, reutilizado ou expirado |
|
|
13
|
+
| `LOCAL_SESSION_INVALID` | cookie ausente, inválido ou expirado |
|
|
14
|
+
| `LOCAL_CSRF_INVALID` | mutação sem prova CSRF |
|
|
15
|
+
| `LOCAL_ROLE_NOT_DECLARED` | perfil fora do manifesto |
|
|
16
|
+
| `LOCAL_OPERATION_NOT_SUPPORTED` | recurso exclusivo da plataforma |
|
|
17
|
+
|
|
18
|
+
Não faça branching por texto de mensagem; use `code`. Logs e respostas nunca devem conter token, cookie, credencial, senha ou conteúdo sensível.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# API pública do `@oondemand/oon-core-front`
|
|
2
|
+
|
|
3
|
+
Importe exclusivamente da raiz do pacote.
|
|
4
|
+
|
|
5
|
+
## Bootstrap e manifestos
|
|
6
|
+
|
|
7
|
+
- `start`, `oonCoreFront.start`: inicialização com configuração completa.
|
|
8
|
+
- `startFromManifest`, `startCentralFromManifest`, `manifestToConfig`: caminho preferencial para uma Central declarativa.
|
|
9
|
+
- Tipos: `CentralUiManifest`, `CentralAppManifest`, `CentralManifestBundle`, `CentralUiOnlyManifest`, `ManifestRuntime`.
|
|
10
|
+
- `ManifestRuntime.runtimeMode`: `local` usa sessão HttpOnly; `platform` usa o contrato de autenticação publicado.
|
|
11
|
+
|
|
12
|
+
## Views e componentes
|
|
13
|
+
|
|
14
|
+
- Definições: `defineCollectionView`, `defineDocumentView`, `definePipelineView`, `defineDashboard`, `defineOonModule`.
|
|
15
|
+
- Componentes: `CoreCollection`, `CoreDocument`, `CorePipeline`, `CoreIntegration`, `CoreCurrency`, `CoreAssistant`, `CoreDashboard`, `CoreUsersAccess`, `CoreTransactionalEmail`, `CorePage`.
|
|
16
|
+
- Primitivas UI v2: `CorePageHeader`, `CoreToolbar`, `CoreDataGrid`, `CoreCards`, `CoreForm`, `CoreField`, `CoreRelationField`, `CoreActions`, `CoreEmptyState`, `CoreLoadingState`.
|
|
17
|
+
- Registre componentes customizados por chave em `registry`; não serialize React no JSON.
|
|
18
|
+
|
|
19
|
+
## Hooks, sessão e autorização
|
|
20
|
+
|
|
21
|
+
- `useOonAuth`, `can`, `PermissionGate`, `Can`: experiência baseada em permissões já resolvidas pelo backend.
|
|
22
|
+
- `useOonTenant`, `createTenantStorage`: seleção de tenant; o backend continua sendo a autoridade.
|
|
23
|
+
- `useOonApi`, `useOonResource`, `useCoreMetadata`, `useModelSchema`: acesso HTTP/metadata padronizado.
|
|
24
|
+
- O runtime local não grava bearer no `localStorage`, envia cookie com `withCredentials` e usa CSRF double-submit nas mutações.
|
|
25
|
+
|
|
26
|
+
## Domínio reativo
|
|
27
|
+
|
|
28
|
+
- `DomainExpressionError`, `evaluateDomainExpression`, `applyReactiveFormulas`, `buildDomainMutationPayload`, `coerceDomainFormValue`.
|
|
29
|
+
- Tipos `OonDomainExpression`, `OonComputedFieldDefinition`, `OonReactiveFormField` e `ReactiveFormulaResult`.
|
|
30
|
+
- A prévia do frontend nunca substitui o recálculo e a validação do backend.
|
|
31
|
+
|
|
32
|
+
## Tipos públicos
|
|
33
|
+
|
|
34
|
+
Os tipos exportados incluem config, app, auth, runtime, módulos, rotas, menus, UI v1/v2, layout, registry, páginas, blocos, ações, views, campos, metadata, paginação, erros e usuário. Consulte `dist/index.d.ts` da versão instalada quando precisar da assinatura exata; ele faz parte do pacote público.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Referência do Manifesto Frontend OonCore
|
|
2
2
|
|
|
3
|
-
Este documento é a referência operacional para
|
|
3
|
+
Este documento é a referência operacional para qualquer Agent criar ou alterar manifestos do frontend OonCore.
|
|
4
4
|
|
|
5
5
|
Use este arquivo junto com `FRONTEND_PATTERNS.md`. O arquivo de padrões explica como pensar a UI; este arquivo lista as opções do contrato atual e das extensões planejadas para UX avançada.
|
|
6
6
|
|
|
@@ -41,7 +41,7 @@ Existem três níveis importantes:
|
|
|
41
41
|
2. `CentralUiManifest`: contrato lido por `startFromManifest`.
|
|
42
42
|
3. `OonUiManifest` / `OonCoreFrontConfig`: contrato interno mais completo do Core Front.
|
|
43
43
|
|
|
44
|
-
Para
|
|
44
|
+
Para Agents, a ordem recomendada é:
|
|
45
45
|
|
|
46
46
|
1. Começar pelo `central.ui.json`.
|
|
47
47
|
2. Usar `pages` e `blocks` quando precisar de UI v2.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Desenvolvimento local desconectado
|
|
2
|
+
|
|
3
|
+
## Início
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
cp backend/.env.example backend/.env
|
|
7
|
+
cp frontend/.env.example frontend/.env
|
|
8
|
+
npm install
|
|
9
|
+
npm run dev
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
O orquestrador inicia backend em `127.0.0.1:4000`, frontend em `127.0.0.1:5173`, gera códigos aleatórios e independentes para navegador e automação/seed, e abre o navegador. O Vite encaminha `/api` ao backend para manter cookies e CSRF na mesma origem.
|
|
13
|
+
|
|
14
|
+
O primeiro acesso troca o código de uso único por:
|
|
15
|
+
|
|
16
|
+
- cookie de sessão `HttpOnly`, `SameSite=Strict`;
|
|
17
|
+
- cookie CSRF de double-submit;
|
|
18
|
+
- sessão local cujo banco armazena somente hashes e expiração.
|
|
19
|
+
|
|
20
|
+
O prazo padrão é 30 dias. Reiniciar o processo rotaciona o segredo sem ampliar o prazo. Excluir o banco local cria um novo período; essa limitação é aceita na linha 0.5.
|
|
21
|
+
|
|
22
|
+
A decisão vem de `LocalExecutionPolicyProvider`. A fonte embarcada funciona offline e permite 30 dias. Uma fonte HTTP assinada poderá ser adicionada futuramente para novas emissões/renovações sem transformar a plataforma em dependência obrigatória.
|
|
23
|
+
|
|
24
|
+
## Perfis
|
|
25
|
+
|
|
26
|
+
O banner permite selecionar apenas papéis declarados em `central.app.json`. A permissão é recalculada no backend. Convites e usuários reais não são criados. Apps com tenant usam o contexto virtual fixo `local:tenant`, sem criar um tenant persistente ou aceitar um tenant arbitrário do cliente.
|
|
27
|
+
|
|
28
|
+
## Integrações
|
|
29
|
+
|
|
30
|
+
Use dublês ou credenciais explicitamente fornecidas no `.env` local do projeto. O Core não busca secrets da plataforma e não cria Deployment/binding/entitlement.
|
|
31
|
+
|
|
32
|
+
## Encerramento
|
|
33
|
+
|
|
34
|
+
`Ctrl+C` encerra os dois processos. Nunca use `--host 0.0.0.0`; conformance e startup devem reprovar essa configuração.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Fronteira de segurança local
|
|
2
|
+
|
|
3
|
+
## Garantias
|
|
4
|
+
|
|
5
|
+
- bind real em loopback;
|
|
6
|
+
- Host e Origin limitados a `localhost`, `127.0.0.1` e `::1`;
|
|
7
|
+
- cabeçalhos de proxy recusados;
|
|
8
|
+
- códigos independentes de navegador e automação/seed, aleatórios, curtos e consumidos uma vez;
|
|
9
|
+
- segredo de sessão em cookie HttpOnly e somente hashes no banco;
|
|
10
|
+
- logout revoga a sessão no backend e invalida cookies anteriores;
|
|
11
|
+
- CSRF obrigatório nas mutações;
|
|
12
|
+
- nenhum bearer local no bundle ou `localStorage`;
|
|
13
|
+
- nenhuma identidade operacional ou chamada silenciosa à plataforma;
|
|
14
|
+
- `operationalRequestHeaders` falha com `LOCAL_OPERATION_NOT_SUPPORTED`;
|
|
15
|
+
- produção, Kubernetes e bind externo falham fechado.
|
|
16
|
+
- o contexto virtual `local:tenant` isola dados locais sem criar recurso na plataforma.
|
|
17
|
+
|
|
18
|
+
`Secure` é adicionado aos cookies quando `OON_LOCAL_HTTPS=true`; em HTTP loopback o cookie mantém `HttpOnly` e `SameSite=Strict`.
|
|
19
|
+
|
|
20
|
+
## Limitações explícitas
|
|
21
|
+
|
|
22
|
+
Quem controla código, banco e relógio locais pode reiniciar ou alterar o prazo. Os 30 dias são uma regra de experiência, não licenciamento inviolável. Uma política remota futura pode afetar novas emissões/renovações, mas não revoga imediatamente sessão offline já emitida.
|
|
23
|
+
|
|
24
|
+
O objetivo de segurança é impedir exposição da máquina/rede e impedir que identidade local escape para o Ecossistema.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Contrato ponta a ponta de metadata, CRUD e UI
|
|
2
|
+
|
|
3
|
+
1. `central.domain.json` ou `defineModel` registra model, campos, CRUD, roles e metadata.
|
|
4
|
+
2. O backend expõe `/core/metadata`, `/core/models` e o router CRUD do `basePath`.
|
|
5
|
+
3. Escopo de tenant/usuário, validação, fórmulas, referência, auditoria e triggers são aplicados no servidor.
|
|
6
|
+
4. `central.ui.json` declara coleções, formulários, filtros, relações, esteiras, documentos e dashboards.
|
|
7
|
+
5. O frontend consulta metadata e monta componentes do Core.
|
|
8
|
+
|
|
9
|
+
O CRUD padrão inclui listagem paginada, leitura, criação, atualização parcial, exclusão e import/export quando habilitados. Use rota customizada somente quando a operação não puder ser representada por CRUD, ação declarativa ou processo.
|
|
10
|
+
|
|
11
|
+
Campos calculados são exibidos reativamente no frontend e recalculados no backend. Campos de escopo são internos e imutáveis. Referências devem usar os filtros declarados; não faça consultas sem escopo.
|
|
@@ -45,6 +45,6 @@ Cada Central começa como um mini-monolito de negócio: pequeno, coeso, isolado
|
|
|
45
45
|
- Permissões são decididas no backend.
|
|
46
46
|
- Integrações são tratadas como conectores, mappings, triggers e esteiras de integração.
|
|
47
47
|
|
|
48
|
-
## Objetivo
|
|
48
|
+
## Objetivo dos Agents
|
|
49
49
|
|
|
50
|
-
O
|
|
50
|
+
O Agent deve acelerar a construção da Central usando a arquitetura existente. O objetivo não é gerar um app genérico, mas completar a camada de domínio com segurança e aderência ao Core.
|
package/docs/RBAC_SECURITY.md
CHANGED
|
@@ -22,7 +22,33 @@ Use o RBAC do Core para:
|
|
|
22
22
|
- proteger rotas;
|
|
23
23
|
- permitir evolução de permissões sem reconstruir telas.
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## Catálogo canônico de perfis
|
|
26
|
+
|
|
27
|
+
```http
|
|
28
|
+
GET /core/role-catalog
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Resposta:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"schemaVersion": 1,
|
|
36
|
+
"appCode": "central-compras",
|
|
37
|
+
"enabled": true,
|
|
38
|
+
"roles": [
|
|
39
|
+
{
|
|
40
|
+
"code": "viewer",
|
|
41
|
+
"name": "Consulta",
|
|
42
|
+
"description": "Somente leitura.",
|
|
43
|
+
"admin": false
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Use esse endpoint para montar seletores e validar grants por App. Não mantenha códigos de perfil paralelos no frontend ou no Control Plane. O consumidor deve validar versão e App, bloquear redirects e destinos de rede privados, revalidar o perfil no backend e tratar catálogo inválido como indisponível. O endpoint usa cache público de cinco minutos e nunca expõe a lista de permissões; a autorização efetiva continua no App.
|
|
50
|
+
|
|
51
|
+
## Checklist de segurança para Agents
|
|
26
52
|
|
|
27
53
|
Antes de concluir uma alteração, confirme:
|
|
28
54
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Rotas, hooks, triggers e workers
|
|
2
|
+
|
|
3
|
+
- `defineRoutes(basePath, router)`: registra rota específica do domínio. Proteja com auth já montada, `requirePermission`, validação e `req.accessContext`.
|
|
4
|
+
- `defineValidation(model, fn)`: valida o estado consolidado antes de persistir.
|
|
5
|
+
- `defineTrigger(model, fn)`: efeito de domínio rastreável associado à mutação.
|
|
6
|
+
- Process manifest: transições, bindings, invariantes, recálculos e jobs transacionais.
|
|
7
|
+
- Integration runtime: outbox/inbox, retry, lock, idempotência, histórico e webhook.
|
|
8
|
+
|
|
9
|
+
Não crie processo web paralelo, registry local, timer genérico ou worker que replique o Core. Jobs devem ser idempotentes, limitar retry, sanitizar payload/erro e encerrar com o lifecycle do processo.
|
|
10
|
+
|
|
11
|
+
No runtime local, workers e filas podem operar contra Mongo local, mas operações que exigem identidade da plataforma devem retornar `LOCAL_OPERATION_NOT_SUPPORTED`.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Modos de runtime
|
|
2
|
+
|
|
3
|
+
| Contrato | `local` | `platform` |
|
|
4
|
+
|---|---|---|
|
|
5
|
+
| Configuração | `NODE_ENV=development`, `OON_RUNTIME_MODE=local` | ambiente publicado |
|
|
6
|
+
| Bind | somente loopback | contrato da infraestrutura |
|
|
7
|
+
| Identidade | principal técnico local | usuário/tenant/Deployment reais |
|
|
8
|
+
| Ativação | `ativa_local` | estados da plataforma |
|
|
9
|
+
| Sessão | cookie HttpOnly, TTL de até 30 dias | auth/SSO configurado |
|
|
10
|
+
| RBAC | simula somente papéis do manifesto | acessos reais |
|
|
11
|
+
| Plataforma | nenhuma chamada obrigatória | conforme capability |
|
|
12
|
+
| Publicar/promover | bloqueado | por contratos autorizados |
|
|
13
|
+
|
|
14
|
+
`local` não é o ambiente publicado `desenvolvimento`. Ele não possui `deploymentId`, `instanceId`, `bindingId`, `entitlementId`, licença ou credencial operacional.
|
|
15
|
+
|
|
16
|
+
O Core falha no startup local quando encontra produção, Kubernetes, identidade operacional, bind não-loopback ou `PUBLIC_APP_URL` externa.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Testes e conformidade
|
|
2
|
+
|
|
3
|
+
## Gates do projeto consumidor
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm run ooncore:docs:check
|
|
7
|
+
npm run ooncore:conformance
|
|
8
|
+
npm run check
|
|
9
|
+
npm test
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Runtime local
|
|
13
|
+
|
|
14
|
+
Comprove:
|
|
15
|
+
|
|
16
|
+
- `127.0.0.1` e `localhost` funcionam;
|
|
17
|
+
- `0.0.0.0`, IP de LAN, Host/Origin externos e proxy falham;
|
|
18
|
+
- nenhuma chamada alcança a plataforma;
|
|
19
|
+
- cookies existem e bearer não aparece no `localStorage`;
|
|
20
|
+
- bootstraps de navegador e automação não podem ser reutilizados nem invalidar um ao outro;
|
|
21
|
+
- expiração bloqueia a sessão e reiniciar o processo não amplia o prazo;
|
|
22
|
+
- Apps multi-tenant recebem somente o contexto virtual fixo `local:tenant`;
|
|
23
|
+
- perfis fora do manifesto falham;
|
|
24
|
+
- CRUD, metadata, dashboards, processos e integrações locais funcionam;
|
|
25
|
+
- `operationalRequestHeaders` falha fechado;
|
|
26
|
+
- apagar o Mongo local inicia novo prazo, como limitação documentada.
|
|
27
|
+
|
|
28
|
+
## Documentação
|
|
29
|
+
|
|
30
|
+
`docs --check` valida fonte, versão, schema, entrada `AGENTS.md`, hashes dos documentos e entrypoints, além da presença de todos os arquivos. O tarball npm deve conter docs, templates e schemas. Exemplos devem compilar ou executar em CI.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
| Sintoma | Verificação | Correção |
|
|
4
|
+
|---|---|---|
|
|
5
|
+
| `LOCAL_RUNTIME_ENV_INVALID` | `NODE_ENV` | use `development` |
|
|
6
|
+
| bind proibido | `HOST`, Vite `server.host` | use `127.0.0.1` |
|
|
7
|
+
| bootstrap inválido | URL antiga/reutilizada | reinicie `npm run dev` e use a nova URL |
|
|
8
|
+
| 401 local | cookie apagado/expirado | abra a URL de bootstrap atual |
|
|
9
|
+
| `LOCAL_SESSION_EXPIRED` no startup | prazo local de 30 dias encerrado | exclua os dados locais para iniciar o período aceito na linha 0.5 |
|
|
10
|
+
| seed invalida o navegador | código incorreto usado no script | use exclusivamente o código **Automação/seed** |
|
|
11
|
+
| 403 CSRF | frontend não está na mesma origem/proxy | use `/api` pelo proxy Vite |
|
|
12
|
+
| docs desatualizados | versão/hash | `npm run ooncore:docs` |
|
|
13
|
+
| perfil ausente | `central.app.json.rbac.roles` | declare o papel e sincronize/reinicie |
|
|
14
|
+
| operação de plataforma bloqueada | código `LOCAL_OPERATION_NOT_SUPPORTED` | use dublê/credencial local ou homologue publicado |
|
|
15
|
+
| Mongo indisponível | `MONGO_URI`, replica set quando exigido | inicie Mongo local conforme o projeto |
|
|
16
|
+
| porta ocupada | 4000/5173 | encerre processo conflitante; não exponha outra interface |
|
|
17
|
+
|
|
18
|
+
Nunca resolva erro local adicionando token fixo, `0.0.0.0`, proxy externo ou credencial de Deployment.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# OonCore 0.5.0
|
|
2
|
+
|
|
3
|
+
## Mudança principal
|
|
4
|
+
|
|
5
|
+
Runtime de desenvolvimento local desconectado, com sessão automática por até 30 dias, loopback obrigatório e documentação canônica distribuída para IA/Agents.
|
|
6
|
+
|
|
7
|
+
## Migração obrigatória
|
|
8
|
+
|
|
9
|
+
- alinhar back, front e create-central em `0.5.x`;
|
|
10
|
+
- usar `OON_RUNTIME_MODE=local` apenas com `NODE_ENV=development`;
|
|
11
|
+
- remover `DEV_TOKEN`, `VITE_DEV_TOKEN` e o valor `dev-local`;
|
|
12
|
+
- usar Vite em `127.0.0.1` com proxy `/api`;
|
|
13
|
+
- sincronizar `.ooncore/` e preservar o `AGENTS.md` raiz;
|
|
14
|
+
- usar o código dedicado de automação para seed, preservando o bootstrap do navegador;
|
|
15
|
+
- atualizar compatibilidade do App para `>=0.5.0 <0.6.0` após homologação.
|
|
16
|
+
|
|
17
|
+
## Segurança
|
|
18
|
+
|
|
19
|
+
Local não emite nem reutiliza identidade operacional. Rotas de plataforma são bloqueadas; cookies/CSRF substituem bearer local. Apps com tenant usam apenas `local:tenant`. Reiniciar processos não renova uma sessão expirada; reset do banco reinicia o prazo e permanece uma limitação conhecida.
|
|
20
|
+
|
|
21
|
+
O manifesto documental inclui hash dos documentos e dos entrypoints gerados (`AGENTS.md`, `CODEX.md` e `context.generated.md`).
|
|
22
|
+
|
|
23
|
+
## Compatibilidade
|
|
24
|
+
|
|
25
|
+
`DEV_TOKEN` explícito permanece temporariamente apenas para testes/CI legados fora de `OON_RUNTIME_MODE=local`; novos scaffolds não o geram.
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oondemand/create-central-oon",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/oondemand/oon-platform.git",
|
|
7
7
|
"directory": "packages/create-central-oon"
|
|
8
8
|
},
|
|
9
|
-
"description": "Gerador de Centrais Oon com contratos declarativos,
|
|
9
|
+
"description": "Gerador de Centrais Oon com contratos declarativos, runtime local e documentação versionada para IA/Agents.",
|
|
10
10
|
"main": "src/index.js",
|
|
11
11
|
"exports": {
|
|
12
12
|
".": "./src/index.js",
|
package/src/conformance.js
CHANGED
|
@@ -197,6 +197,7 @@ function checkBootstrap(root, files, issues) {
|
|
|
197
197
|
(candidate) => candidate.startsWith("frontend/src/")
|
|
198
198
|
&& candidate !== file
|
|
199
199
|
&& candidate !== "frontend/src/vite-env.d.ts"
|
|
200
|
+
&& path.basename(candidate) !== ".gitkeep"
|
|
200
201
|
&& !(portalCockpit && isPortalExtension(candidate)),
|
|
201
202
|
);
|
|
202
203
|
for (const extra of extraFrontendSources) {
|
|
@@ -270,6 +271,23 @@ function checkAllowedExtensions(files, issues) {
|
|
|
270
271
|
}
|
|
271
272
|
}
|
|
272
273
|
|
|
274
|
+
function checkLocalRuntimeSafety(root, files, issues) {
|
|
275
|
+
const checks = [
|
|
276
|
+
{ pattern: /\b(?:VITE_)?DEV_TOKEN\b/, code: "LOCAL_FIXED_TOKEN", message: "token local fixo não é permitido; use a sessão automática do OonCore." },
|
|
277
|
+
{ pattern: /["']dev-local["']/, code: "LOCAL_PREDICTABLE_TOKEN", message: "credencial previsível dev-local não é permitida." },
|
|
278
|
+
{ pattern: /\bhost\s*:\s*["'](?:0\.0\.0\.0|::)["']/, code: "LOCAL_BIND_EXTERNAL", message: "servidor de desenvolvimento deve usar 127.0.0.1." },
|
|
279
|
+
];
|
|
280
|
+
const candidates = files.filter((file) =>
|
|
281
|
+
/(?:^|\/)(?:env\.example|\.env\.example|vite\.config\.[cm]?[jt]s|main\.[jt]sx?|package\.json)$/.test(file),
|
|
282
|
+
);
|
|
283
|
+
for (const file of candidates) {
|
|
284
|
+
const source = readText(root, file);
|
|
285
|
+
for (const check of checks) {
|
|
286
|
+
if (check.pattern.test(source)) addIssue(issues, check.code, file, check.message);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
273
291
|
function checkConformance({ cwd = process.cwd() } = {}) {
|
|
274
292
|
const root = path.resolve(cwd);
|
|
275
293
|
const files = listFiles(root);
|
|
@@ -280,6 +298,7 @@ function checkConformance({ cwd = process.cwd() } = {}) {
|
|
|
280
298
|
checkDomainManifest(root, issues);
|
|
281
299
|
checkExecutableFiles(root, files, issues);
|
|
282
300
|
checkAllowedExtensions(files, issues);
|
|
301
|
+
checkLocalRuntimeSafety(root, files, issues);
|
|
283
302
|
return { ok: issues.length === 0, root, filesChecked: files.length, issues };
|
|
284
303
|
}
|
|
285
304
|
|
package/src/dev.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const crypto = require("node:crypto");
|
|
4
|
+
const { spawn } = require("node:child_process");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
const fs = require("node:fs");
|
|
7
|
+
|
|
8
|
+
function npmCommand() {
|
|
9
|
+
return process.platform === "win32" ? "npm.cmd" : "npm";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function openBrowser(url) {
|
|
13
|
+
const command = process.platform === "win32"
|
|
14
|
+
? ["cmd", ["/c", "start", "", url]]
|
|
15
|
+
: process.platform === "darwin"
|
|
16
|
+
? ["open", [url]]
|
|
17
|
+
: ["xdg-open", [url]];
|
|
18
|
+
const child = spawn(command[0], command[1], { detached: true, stdio: "ignore" });
|
|
19
|
+
child.on("error", () => {});
|
|
20
|
+
child.unref();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function runLocalDevelopment({ cwd = process.cwd(), open = true } = {}) {
|
|
24
|
+
const root = path.resolve(cwd);
|
|
25
|
+
for (const directory of ["backend", "frontend"]) {
|
|
26
|
+
if (!fs.existsSync(path.join(root, directory, "package.json"))) {
|
|
27
|
+
throw new Error(`Projeto inválido: ${directory}/package.json não encontrado.`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const bootstrapCode = crypto.randomBytes(32).toString("base64url");
|
|
32
|
+
const automationBootstrapCode = crypto.randomBytes(32).toString("base64url");
|
|
33
|
+
const env = {
|
|
34
|
+
...process.env,
|
|
35
|
+
NODE_ENV: "development",
|
|
36
|
+
OON_RUNTIME_MODE: "local",
|
|
37
|
+
OON_LOCAL_BOOTSTRAP_CODE: bootstrapCode,
|
|
38
|
+
OON_LOCAL_AUTOMATION_BOOTSTRAP_CODE: automationBootstrapCode,
|
|
39
|
+
};
|
|
40
|
+
const children = ["backend", "frontend"].map((directory) => spawn(
|
|
41
|
+
npmCommand(),
|
|
42
|
+
["run", "dev", "--prefix", directory],
|
|
43
|
+
{ cwd: root, env, stdio: "inherit" },
|
|
44
|
+
));
|
|
45
|
+
|
|
46
|
+
const url = `http://127.0.0.1:5173/?oon_local_bootstrap=${bootstrapCode}`;
|
|
47
|
+
console.log("\nOonCore local desconectado");
|
|
48
|
+
console.log(`Frontend: ${url}`);
|
|
49
|
+
console.log("Backend: http://127.0.0.1:4000");
|
|
50
|
+
console.log(`Automação/seed: ${automationBootstrapCode}`);
|
|
51
|
+
if (open) setTimeout(() => openBrowser(url), 2500).unref();
|
|
52
|
+
|
|
53
|
+
let stopping = false;
|
|
54
|
+
function stop(signal = "SIGTERM") {
|
|
55
|
+
if (stopping) return;
|
|
56
|
+
stopping = true;
|
|
57
|
+
for (const child of children) if (!child.killed) child.kill(signal);
|
|
58
|
+
}
|
|
59
|
+
process.once("SIGINT", () => stop("SIGINT"));
|
|
60
|
+
process.once("SIGTERM", () => stop("SIGTERM"));
|
|
61
|
+
for (const child of children) {
|
|
62
|
+
child.once("exit", (code) => {
|
|
63
|
+
if (!stopping && code) {
|
|
64
|
+
stop();
|
|
65
|
+
process.exitCode = code;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
child.once("error", (error) => {
|
|
69
|
+
console.error("Falha ao iniciar runtime local:", error.message);
|
|
70
|
+
stop();
|
|
71
|
+
process.exitCode = 1;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return { children, url, automationBootstrapCode, stop };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
module.exports = { runLocalDevelopment, openBrowser };
|
package/src/index.js
CHANGED
|
@@ -5,6 +5,7 @@ const path = require("node:path");
|
|
|
5
5
|
const crypto = require("node:crypto");
|
|
6
6
|
const { spawnSync } = require("node:child_process");
|
|
7
7
|
const { copyTemplate } = require("./render");
|
|
8
|
+
const { runLocalDevelopment } = require("./dev");
|
|
8
9
|
|
|
9
10
|
const PACKAGE_ROOT = path.join(__dirname, "..");
|
|
10
11
|
const TEMPLATES_DIR = path.join(PACKAGE_ROOT, "templates");
|
|
@@ -90,6 +91,49 @@ function docsHash(files = listDocFiles()) {
|
|
|
90
91
|
return hash.digest("hex");
|
|
91
92
|
}
|
|
92
93
|
|
|
94
|
+
function copiedDocsHash(docsDir, files) {
|
|
95
|
+
const hash = crypto.createHash("sha256");
|
|
96
|
+
for (const file of files) {
|
|
97
|
+
const normalized = file.split(path.sep).join("/");
|
|
98
|
+
const absolute = path.join(docsDir, file);
|
|
99
|
+
if (!fs.existsSync(absolute)) return null;
|
|
100
|
+
hash.update(normalized);
|
|
101
|
+
hash.update("\n");
|
|
102
|
+
hash.update(fs.readFileSync(absolute));
|
|
103
|
+
hash.update("\n");
|
|
104
|
+
}
|
|
105
|
+
return hash.digest("hex");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function entrypointContents(files = listDocFiles()) {
|
|
109
|
+
return {
|
|
110
|
+
"AGENTS.md": fs.readFileSync(path.join(DOCS_DIR, "AGENTS.md"), "utf8"),
|
|
111
|
+
"CODEX.md": fs.readFileSync(path.join(DOCS_DIR, "CODEX.md"), "utf8"),
|
|
112
|
+
"context.generated.md": buildContext(files),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function contentMapHash(entries) {
|
|
117
|
+
const hash = crypto.createHash("sha256");
|
|
118
|
+
for (const [name, content] of Object.entries(entries).sort(([a], [b]) => a.localeCompare(b))) {
|
|
119
|
+
hash.update(name);
|
|
120
|
+
hash.update("\n");
|
|
121
|
+
hash.update(content);
|
|
122
|
+
hash.update("\n");
|
|
123
|
+
}
|
|
124
|
+
return hash.digest("hex");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function copiedEntrypointsHash(outDir, names) {
|
|
128
|
+
const entries = {};
|
|
129
|
+
for (const name of names) {
|
|
130
|
+
const absolute = path.join(outDir, name);
|
|
131
|
+
if (!fs.existsSync(absolute)) return null;
|
|
132
|
+
entries[name] = fs.readFileSync(absolute, "utf8");
|
|
133
|
+
}
|
|
134
|
+
return contentMapHash(entries);
|
|
135
|
+
}
|
|
136
|
+
|
|
93
137
|
function resolveCentralRoot(cwd = process.cwd()) {
|
|
94
138
|
const current = path.resolve(cwd);
|
|
95
139
|
const parent = path.dirname(current);
|
|
@@ -134,12 +178,12 @@ function copyDocs(srcDir, destDir) {
|
|
|
134
178
|
|
|
135
179
|
function buildContext(files = listDocFiles()) {
|
|
136
180
|
const header = [
|
|
137
|
-
"# OonCore Contexto
|
|
181
|
+
"# OonCore — Contexto consolidado para IA/Agents",
|
|
138
182
|
"",
|
|
139
|
-
"> Arquivo gerado automaticamente por `create-central-oon docs
|
|
183
|
+
"> Arquivo gerado automaticamente por `create-central-oon docs sync`.",
|
|
140
184
|
"> Não edite manualmente. A fonte de verdade está no pacote `@oondemand/create-central-oon` instalado.",
|
|
141
185
|
"",
|
|
142
|
-
"Este contexto consolida
|
|
186
|
+
"Este contexto consolida os contratos públicos para Codex, ChatGPT, Kimi, Manus ou qualquer Agent compatível.",
|
|
143
187
|
"",
|
|
144
188
|
].join("\n");
|
|
145
189
|
|
|
@@ -162,12 +206,15 @@ function buildContext(files = listDocFiles()) {
|
|
|
162
206
|
}
|
|
163
207
|
|
|
164
208
|
function buildManifest(files = listDocFiles()) {
|
|
209
|
+
const entrypoints = entrypointContents(files);
|
|
165
210
|
return {
|
|
211
|
+
schemaVersion: 1,
|
|
166
212
|
source: "@oondemand/create-central-oon",
|
|
167
213
|
version: readPackageVersion(),
|
|
168
|
-
generatedAt: new Date().toISOString(),
|
|
169
214
|
docsMode: "generated-cache",
|
|
215
|
+
entrypoint: "AGENTS.md",
|
|
170
216
|
docsHash: docsHash(files),
|
|
217
|
+
entrypointsHash: contentMapHash(entrypoints),
|
|
171
218
|
files: files.map((file) => file.split(path.sep).join("/")),
|
|
172
219
|
};
|
|
173
220
|
}
|
|
@@ -186,9 +233,9 @@ function syncDocs(opts = {}) {
|
|
|
186
233
|
removeDir(docsOutDir);
|
|
187
234
|
copyDocs(DOCS_DIR, docsOutDir);
|
|
188
235
|
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
fs.copyFileSync(
|
|
236
|
+
for (const entrypoint of ["AGENTS.md", "CODEX.md"]) {
|
|
237
|
+
const source = path.join(DOCS_DIR, entrypoint);
|
|
238
|
+
if (fs.existsSync(source)) fs.copyFileSync(source, path.join(outDir, entrypoint));
|
|
192
239
|
}
|
|
193
240
|
|
|
194
241
|
fs.writeFileSync(path.join(outDir, "context.generated.md"), buildContext(files));
|
|
@@ -205,6 +252,8 @@ function checkDocs(opts = {}) {
|
|
|
205
252
|
const version = readPackageVersion();
|
|
206
253
|
const files = listDocFiles();
|
|
207
254
|
const currentHash = docsHash(files);
|
|
255
|
+
const expectedEntrypoints = entrypointContents(files);
|
|
256
|
+
const expectedEntrypointsHash = contentMapHash(expectedEntrypoints);
|
|
208
257
|
|
|
209
258
|
if (!fs.existsSync(manifestPath)) {
|
|
210
259
|
throw new Error("Documentação OonCore local não encontrada. Rode `npm run ooncore:docs`.");
|
|
@@ -217,6 +266,10 @@ function checkDocs(opts = {}) {
|
|
|
217
266
|
problems.push(`fonte esperada @oondemand/create-central-oon, encontrada ${manifest.source || "(vazia)"}`);
|
|
218
267
|
}
|
|
219
268
|
|
|
269
|
+
if (manifest.schemaVersion !== 1 || manifest.entrypoint !== "AGENTS.md") {
|
|
270
|
+
problems.push("manifesto documental não possui schemaVersion=1 e entrypoint=AGENTS.md");
|
|
271
|
+
}
|
|
272
|
+
|
|
220
273
|
if (manifest.version !== version) {
|
|
221
274
|
problems.push(`versão local ${manifest.version || "(vazia)"} diferente da instalada ${version}`);
|
|
222
275
|
}
|
|
@@ -225,6 +278,27 @@ function checkDocs(opts = {}) {
|
|
|
225
278
|
problems.push("hash da documentação local diferente da documentação instalada");
|
|
226
279
|
}
|
|
227
280
|
|
|
281
|
+
if (manifest.entrypointsHash !== expectedEntrypointsHash) {
|
|
282
|
+
problems.push("hash dos entrypoints gerados diferente da documentação instalada");
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const localHash = copiedDocsHash(path.join(root, ".ooncore", "docs"), files);
|
|
286
|
+
if (!localHash || localHash !== manifest.docsHash) {
|
|
287
|
+
problems.push("arquivos de .ooncore/docs estão ausentes ou foram alterados");
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const entrypointNames = Object.keys(expectedEntrypoints);
|
|
291
|
+
for (const entrypoint of entrypointNames) {
|
|
292
|
+
if (!fs.existsSync(path.join(root, ".ooncore", entrypoint))) {
|
|
293
|
+
problems.push(`entrada obrigatória ausente: .ooncore/${entrypoint}`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const localEntrypointsHash = copiedEntrypointsHash(path.join(root, ".ooncore"), entrypointNames);
|
|
298
|
+
if (!localEntrypointsHash || localEntrypointsHash !== manifest.entrypointsHash) {
|
|
299
|
+
problems.push("entrypoints de .ooncore estão ausentes ou foram alterados");
|
|
300
|
+
}
|
|
301
|
+
|
|
228
302
|
if (problems.length) {
|
|
229
303
|
throw new Error(`Documentação OonCore desatualizada:\n- ${problems.join("\n- ")}\nRode \`npm run ooncore:docs\`.`);
|
|
230
304
|
}
|
|
@@ -261,7 +335,7 @@ async function run(opts) {
|
|
|
261
335
|
// 2. Overlay do template escolhido (vence sobre o _base).
|
|
262
336
|
copyTemplate(path.join(TEMPLATES_DIR, template.id), targetDir, tokens);
|
|
263
337
|
|
|
264
|
-
// 3. Contexto local para
|
|
338
|
+
// 3. Contexto local neutro para Agents derivado da versão instalada.
|
|
265
339
|
syncDocs({ cwd: targetDir });
|
|
266
340
|
|
|
267
341
|
console.log("✔ Arquivos gerados.");
|
|
@@ -289,15 +363,12 @@ function printNextSteps(tokens, opts) {
|
|
|
289
363
|
✅ Central "${tokens.name}" pronta.
|
|
290
364
|
|
|
291
365
|
Próximos passos:
|
|
292
|
-
${cd} # Sincronizar/validar documentação local do Core para
|
|
366
|
+
${cd} # Sincronizar/validar documentação local do Core para Agents
|
|
293
367
|
npm run ooncore:docs
|
|
294
368
|
npm run ooncore:docs:check
|
|
295
369
|
|
|
296
|
-
#
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
# Frontend (só declaração — central.ui.json)
|
|
300
|
-
cd ../frontend && cp .env.example .env && npm run dev
|
|
370
|
+
# Runtime local desconectado (backend + frontend)
|
|
371
|
+
npm run dev
|
|
301
372
|
|
|
302
373
|
O backend expõe /core/metadata; o frontend renderiza as telas a partir dele.
|
|
303
374
|
Edite backend/src/models e frontend/central.ui.json para evoluir a Central.
|
|
@@ -313,4 +384,5 @@ module.exports = {
|
|
|
313
384
|
syncDocs,
|
|
314
385
|
checkDocs,
|
|
315
386
|
resolveCentralRoot,
|
|
387
|
+
runLocalDevelopment,
|
|
316
388
|
};
|
|
@@ -29,11 +29,12 @@ A pasta `.ooncore/` é um cache regenerável da documentação publicada no paco
|
|
|
29
29
|
npm install
|
|
30
30
|
npm run check
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
cp backend/.env.example backend/.env
|
|
33
|
+
cp frontend/.env.example frontend/.env
|
|
34
|
+
npm run dev
|
|
34
35
|
```
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
O comando inicia backend e frontend exclusivamente em loopback, abre uma sessão local aleatória e não consulta nem cria recursos na plataforma. Não implemente autenticação ou ativação paralela na Central.
|
|
37
38
|
|
|
38
39
|
## Evoluindo a Central
|
|
39
40
|
|
|
@@ -3,19 +3,12 @@ SERVICE_NAME=__SLUG__
|
|
|
3
3
|
SERVICE_VERSION=0.1.0
|
|
4
4
|
PORT=4000
|
|
5
5
|
NODE_ENV=development
|
|
6
|
+
OON_RUNTIME_MODE=local
|
|
6
7
|
|
|
7
8
|
# Banco
|
|
8
9
|
MONGO_URI=mongodb://localhost:27017/__SLUG__
|
|
9
10
|
|
|
10
|
-
# Autenticacao e autorizacao pela Central de Ativacoes
|
|
11
|
-
# URL publica/frontend da Central de Ativacoes.
|
|
12
|
-
CENTRAL_ATIVACAO_URL=https://central-ativacao.central.oondemand.online
|
|
13
|
-
# URL canonica do backend/API da Central de Ativacoes.
|
|
14
|
-
CENTRAL_ATIVACAO_API_URL=https://central-ativacao.central.oondemand.online/api/
|
|
15
11
|
APP_CODE=__SLUG__
|
|
16
|
-
AUTH_PROVIDER_TIMEOUT_MS=10000
|
|
17
|
-
# Compatibilidade temporaria: CENTRAL_ATIVACAO_BACKEND_URL, MEUS_APPS_BACKEND_URL e APP_KEY tambem sao aceitas.
|
|
18
12
|
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
DEV_TOKEN=dev-local
|
|
13
|
+
# O runtime local cria uma sessão aleatória por 30 dias e escuta apenas em loopback.
|
|
14
|
+
# Não configure credenciais, URLs ou tokens da plataforma neste arquivo.
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
# Opcional: login externo/SSO. Sem essa variável, o Core usa /login.
|
|
5
|
-
# VITE_MEUS_APPS_URL=https://login.example.com
|
|
6
|
-
|
|
7
|
-
# Desenvolvimento local: deve ser igual ao DEV_TOKEN do backend.
|
|
8
|
-
# O frontend envia este token para /auth/validar-token antes de qualquer redirect.
|
|
9
|
-
VITE_DEV_TOKEN=dev-local
|
|
1
|
+
# O Vite encaminha /api ao backend em 127.0.0.1:4000.
|
|
2
|
+
# Não configure token ou URL da plataforma para desenvolvimento local.
|
|
3
|
+
VITE_API_URL=/api
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"sync:metadata": "oonCore-front sync:metadata"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@oondemand/oon-core-front": "^0.
|
|
14
|
+
"@oondemand/oon-core-front": "^0.5.1",
|
|
15
15
|
"@chakra-ui/react": "^3.13.0",
|
|
16
16
|
"@emotion/react": "^11.14.0",
|
|
17
17
|
"@tanstack/react-query": "^5.65.0",
|
|
@@ -3,7 +3,7 @@ import app from "../../central.app.json";
|
|
|
3
3
|
import ui from "../central.ui.json";
|
|
4
4
|
|
|
5
5
|
startCentralFromManifest({ app, ui }, {
|
|
6
|
-
apiBaseUrl: import.meta.env.VITE_API_URL ?? "
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
apiBaseUrl: import.meta.env.VITE_API_URL ?? "/api",
|
|
7
|
+
runtimeMode: import.meta.env.DEV ? "local" : "platform",
|
|
8
|
+
meusAppsUrl: import.meta.env.DEV ? undefined : import.meta.env.VITE_MEUS_APPS_URL,
|
|
9
9
|
});
|
|
@@ -4,7 +4,16 @@ import react from "@vitejs/plugin-react";
|
|
|
4
4
|
export default defineConfig({
|
|
5
5
|
plugins: [react()],
|
|
6
6
|
server: {
|
|
7
|
+
host: "127.0.0.1",
|
|
7
8
|
port: 5173,
|
|
9
|
+
strictPort: true,
|
|
10
|
+
proxy: {
|
|
11
|
+
"/api": {
|
|
12
|
+
target: "http://127.0.0.1:4000",
|
|
13
|
+
changeOrigin: false,
|
|
14
|
+
rewrite: (path) => path.replace(/^\/api/, ""),
|
|
15
|
+
},
|
|
16
|
+
},
|
|
8
17
|
fs: { allow: [".."] },
|
|
9
18
|
},
|
|
10
19
|
});
|
|
@@ -4,14 +4,15 @@
|
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Central Oon __NAME__ gerada com create-central-oon.",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"ooncore:docs": "create-central-oon docs
|
|
8
|
-
"ooncore:docs:check": "create-central-oon docs
|
|
7
|
+
"ooncore:docs": "create-central-oon docs sync",
|
|
8
|
+
"ooncore:docs:check": "create-central-oon docs check",
|
|
9
9
|
"ooncore:conformance": "create-central-oon conformance",
|
|
10
10
|
"check": "npm run ooncore:docs:check && npm run ooncore:conformance",
|
|
11
|
+
"dev": "create-central-oon dev",
|
|
11
12
|
"dev:backend": "npm run dev --prefix backend",
|
|
12
13
|
"dev:frontend": "npm run dev --prefix frontend"
|
|
13
14
|
},
|
|
14
15
|
"devDependencies": {
|
|
15
|
-
"@oondemand/create-central-oon": "0.
|
|
16
|
+
"@oondemand/create-central-oon": "0.5.1"
|
|
16
17
|
}
|
|
17
18
|
}
|