@oondemand/create-central-oon 0.7.4 → 0.7.8

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.
Files changed (47) hide show
  1. package/README.md +18 -14
  2. package/bin/cli.js +12 -2
  3. package/docs/AGENTS.md +12 -56
  4. package/docs/AGENT_WORKFLOW.md +8 -15
  5. package/docs/BACKEND_API.md +5 -5
  6. package/docs/BACKEND_DOMAIN_MANIFEST.md +1 -1
  7. package/docs/CAPABILITIES.md +11 -3
  8. package/docs/CHECKLIST_IMPLEMENTACAO.md +4 -5
  9. package/docs/CORE_UPGRADE.md +17 -14
  10. package/docs/ERRORS.md +1 -1
  11. package/docs/EXECUTABLE_EXAMPLE.md +42 -0
  12. package/docs/NATIVE_RESOURCES.md +94 -0
  13. package/docs/OON_APP_AGENT_GUIDE.md +26 -45
  14. package/docs/PDF_RENDERING.md +2 -3
  15. package/docs/PUBLIC_CONTRACTS.md +124 -0
  16. package/docs/RBAC_SECURITY.md +1 -1
  17. package/docs/ROUTES_HOOKS_WORKERS.md +19 -8
  18. package/docs/SECRETS.md +54 -0
  19. package/docs/TASK_EXAMPLES.md +134 -0
  20. package/docs/TASK_INDEX.md +36 -0
  21. package/docs/TESTING_CONFORMANCE.md +12 -19
  22. package/docs/TRANSACTIONAL_EMAIL.md +1 -1
  23. package/examples/first-journey/FIRST_JOURNEY.md +27 -0
  24. package/examples/first-journey/backend/central.domain.json +141 -0
  25. package/examples/first-journey/backend/central.process.json +105 -0
  26. package/examples/first-journey/backend/emails/confirmacao.json +12 -0
  27. package/examples/first-journey/backend/src/models/Documento.js +9 -0
  28. package/examples/first-journey/backend/src/models/Pessoa.js +6 -0
  29. package/examples/first-journey/backend/src/routes/integracao.js +23 -0
  30. package/examples/first-journey/backend/src/routes/jornada.js +10 -0
  31. package/examples/first-journey/backend/src/routes/recursos.js +26 -0
  32. package/examples/first-journey/backend/src/routes/segredos.js +27 -0
  33. package/examples/first-journey/backend/src/services/confirmacao.js +11 -0
  34. package/examples/first-journey/frontend/src/pages/JourneyPage.tsx +32 -0
  35. package/examples/first-journey/frontend/src/pages/NativeResourcesPage.tsx +50 -0
  36. package/examples/first-journey/frontend/src/pages/SecretsPage.tsx +31 -0
  37. package/package.json +3 -2
  38. package/schemas/central.app.schema.json +12 -0
  39. package/src/doctor.js +90 -0
  40. package/src/example.js +39 -0
  41. package/src/index.js +31 -16
  42. package/templates/_base/README.md +17 -46
  43. package/templates/_base/backend/package.json +1 -1
  44. package/templates/_base/frontend/package.json +1 -1
  45. package/templates/_base/frontend/src/app/app.tsx +2 -2
  46. package/templates/_base/frontend/src/pages/HomePage.tsx +3 -3
  47. package/templates/_base/package.json +2 -2
package/src/example.js ADDED
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ const fs = require("node:fs");
3
+ const path = require("node:path");
4
+ const { resolveCentralRoot } = require("./index");
5
+ const { listFiles } = require("./conformance");
6
+
7
+ // Explicit opt-in after generating the canonical base. Never overwrite an App.
8
+ function installExample({ cwd = process.cwd() } = {}) {
9
+ const root = resolveCentralRoot(cwd);
10
+ const source = path.join(__dirname, "../examples/first-journey");
11
+ const files = listFiles(source);
12
+ const manifestPath = path.join(root, "central.app.json");
13
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
14
+ if (manifest.tenancyModel !== "single_tenant" || manifest.deploymentMode !== "dedicated") throw new Error("Exemplo requer single_tenant dedicado da base oficial.");
15
+ for (const file of files) {
16
+ if (fs.existsSync(path.join(root, file))) throw new Error(`Exemplo não sobrescreve ${file}. Use um App recém-gerado.`);
17
+ }
18
+ const composition = ["routes.tsx", "navigation.ts"];
19
+ for (const name of composition) {
20
+ const relative = `frontend/src/app/${name}`;
21
+ const base = fs.readFileSync(path.join(__dirname, "../templates/_base", relative), "utf8");
22
+ if (fs.readFileSync(path.join(root, relative), "utf8") !== base) throw new Error(`Exemplo requer composição original: ${relative}. Nenhum arquivo foi alterado.`);
23
+ }
24
+ manifest.capabilities = [...new Set([...manifest.capabilities, "core.secrets"])];
25
+ manifest.capabilitySettings = { ...manifest.capabilitySettings, "core.secrets": { enabled: true } };
26
+ const permissions = ["segredos.manage", "pessoas.read", "pessoas.write", "tickets.read", "tickets.write", "jornada.write", "integracao.test", "contratos.read", "contratos.write", "parcelas.read", "parcelas.write", "documentos.read", "documentos.write", "pdf.render"];
27
+ manifest.rbac.permissions = [...new Set([...manifest.rbac.permissions, ...permissions])];
28
+ for (const file of files) {
29
+ fs.mkdirSync(path.dirname(path.join(root, file)), { recursive: true });
30
+ fs.copyFileSync(path.join(source, file), path.join(root, file));
31
+ }
32
+ const routes = path.join(root, "frontend/src/app/routes.tsx");
33
+ fs.writeFileSync(routes, fs.readFileSync(routes, "utf8").replace('import { HomePage }', 'import { SecretsPage } from "../pages/SecretsPage";\nimport { NativeResourcesPage } from "../pages/NativeResourcesPage";\nimport { JourneyPage } from "../pages/JourneyPage";\nimport { HomePage }').replace(' { path: "/", component: HomePage },', ' { path: "/", component: HomePage },\n { path: "/jornada", component: JourneyPage },\n { path: "/recursos", component: NativeResourcesPage },\n { path: "/segredos", component: SecretsPage },'));
34
+ const navigation = path.join(root, "frontend/src/app/navigation.ts");
35
+ fs.writeFileSync(navigation, fs.readFileSync(navigation, "utf8").replace(' { label: "Início", href: "/", order: 10 },', ' { label: "Início", href: "/", order: 10 },\n { label: "Primeira jornada", href: "/jornada", order: 20 },\n { label: "Recursos nativos", href: "/recursos", order: 30 },\n { label: "Segredos", href: "/segredos", order: 40 },'));
36
+ fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
37
+ console.log("Exemplo instalado em /jornada, com navegação, endpoints e permissões. Siga FIRST_JOURNEY.md.");
38
+ }
39
+ module.exports = { installExample };
package/src/index.js CHANGED
@@ -47,6 +47,21 @@ function readPackageVersion() {
47
47
  return pkg.version;
48
48
  }
49
49
 
50
+ // Documentation examples follow the installed release, including docs sync/check.
51
+ // Hash the rendered bytes so consumers can verify the exact generated cache.
52
+ function renderDoc(content) {
53
+ const version = readPackageVersion();
54
+ const [major, minor] = version.split(".").map(Number);
55
+ return content
56
+ .replace(/__OONCORE_VERSION__/g, version)
57
+ .replace(/__OONCORE_LINE__/g, `${major}.${minor}`)
58
+ .replace(/__OONCORE_RANGE__/g, `>=${major}.${minor}.0 <${major}.${minor + 1}.0`);
59
+ }
60
+
61
+ function readDoc(file) {
62
+ return renderDoc(fs.readFileSync(path.join(DOCS_DIR, file), "utf8"));
63
+ }
64
+
50
65
  function listDocFiles(dir = DOCS_DIR, prefix = "") {
51
66
  if (!fs.existsSync(dir)) return [];
52
67
  const files = [];
@@ -71,7 +86,7 @@ function docsHash(files = listDocFiles()) {
71
86
  const normalized = file.split(path.sep).join("/");
72
87
  hash.update(normalized);
73
88
  hash.update("\n");
74
- hash.update(fs.readFileSync(path.join(DOCS_DIR, file)));
89
+ hash.update(readDoc(file));
75
90
  hash.update("\n");
76
91
  }
77
92
  return hash.digest("hex");
@@ -95,9 +110,9 @@ function rootAgentEntrypoint() {
95
110
  return [
96
111
  "# OonCore — entrada para IA/Agents",
97
112
  "",
98
- "Leia o contrato canônico completo em [docs/AGENTS.md](docs/AGENTS.md).",
113
+ "Leia a entrada curta em [docs/AGENTS.md](docs/AGENTS.md) e consulte apenas a tarefa necessária.",
99
114
  "",
100
- "Confira \`.ooncore/manifest.json\` e execute \`npm run ooncore:docs:check\` antes de alterar o App.",
115
+ "Execute \`npm run check\` para validar cache e conformidade; regenere o cache somente pelo comando oficial.",
101
116
  "",
102
117
  ].join("\n");
103
118
  }
@@ -105,7 +120,7 @@ function rootAgentEntrypoint() {
105
120
  function entrypointContents(files = listDocFiles()) {
106
121
  return {
107
122
  "AGENTS.md": rootAgentEntrypoint(),
108
- "CODEX.md": fs.readFileSync(path.join(DOCS_DIR, "CODEX.md"), "utf8"),
123
+ "CODEX.md": readDoc("CODEX.md"),
109
124
  "context.generated.md": buildContext(files),
110
125
  };
111
126
  }
@@ -168,7 +183,9 @@ function copyDocs(srcDir, destDir) {
168
183
  if (entry.isDirectory()) {
169
184
  copyDocs(from, to);
170
185
  } else if (entry.isFile()) {
171
- fs.copyFileSync(from, to);
186
+ fs.writeFileSync(to, entry.name.endsWith(".md")
187
+ ? renderDoc(fs.readFileSync(from, "utf8"))
188
+ : fs.readFileSync(from));
172
189
  }
173
190
  }
174
191
  }
@@ -180,14 +197,14 @@ function buildContext(files = listDocFiles()) {
180
197
  "> Arquivo gerado automaticamente por `create-central-oon docs sync`.",
181
198
  "> Não edite manualmente. A fonte de verdade está no pacote `@oondemand/create-central-oon` instalado.",
182
199
  "",
183
- "Este contexto consolida os contratos públicos para Codex, ChatGPT, Kimi, Manus ou qualquer Agent compatível.",
200
+ "Compilação opcional para consulta. Comece por docs/OON_APP_AGENT_GUIDE.md e docs/TASK_INDEX.md; não é necessário ler este arquivo inteiro.",
184
201
  "",
185
202
  ].join("\n");
186
203
 
187
204
  const sections = files
188
205
  .map((file) => {
189
206
  const normalized = file.split(path.sep).join("/");
190
- const content = fs.readFileSync(path.join(DOCS_DIR, file), "utf8").trim();
207
+ const content = readDoc(file).trim();
191
208
  return [
192
209
  "---",
193
210
  "",
@@ -232,7 +249,7 @@ function syncDocs(opts = {}) {
232
249
 
233
250
  fs.writeFileSync(path.join(outDir, "AGENTS.md"), rootAgentEntrypoint());
234
251
  const codexSource = path.join(DOCS_DIR, "CODEX.md");
235
- if (fs.existsSync(codexSource)) fs.copyFileSync(codexSource, path.join(outDir, "CODEX.md"));
252
+ if (fs.existsSync(codexSource)) fs.writeFileSync(path.join(outDir, "CODEX.md"), readDoc("CODEX.md"));
236
253
 
237
254
  fs.writeFileSync(path.join(outDir, "context.generated.md"), buildContext(files));
238
255
  fs.writeFileSync(path.join(outDir, "manifest.json"), `${JSON.stringify(buildManifest(files), null, 2)}\n`);
@@ -299,7 +316,7 @@ function checkDocs(opts = {}) {
299
316
  throw new Error(`Documentação OonCore desatualizada:\n- ${problems.join("\n- ")}\nRode \`npm run ooncore:docs\`.`);
300
317
  }
301
318
 
302
- console.log(`✔ Documentação OonCore atualizada (versão ${version}).`);
319
+ if (!opts.quiet) console.log(`✔ Documentação OonCore atualizada (versão ${version}).`);
303
320
  }
304
321
 
305
322
  async function run(opts) {
@@ -350,15 +367,13 @@ function printNextSteps(tokens, opts) {
350
367
  ✅ Central "${tokens.name}" pronta.
351
368
 
352
369
  Próximos passos:
353
- ${cd} # Sincronizar/validar documentação local do Core para Agents
354
- npm run ooncore:docs
355
- npm run ooncore:docs:check
356
-
357
- # Runtime local desconectado (backend + frontend)
370
+ ${cd} # Instale as dependências se usou --no-install ou se a instalação falhou.
371
+ # Configure MongoDB e os .env conforme README.md.
358
372
  npm run dev
359
373
 
360
- O backend expõe /core/metadata; o frontend renderiza as telas a partir dele.
361
- Crie páginas, componentes e features em frontend/src e modele o domínio no backend.
374
+ Siga .ooncore/docs/OON_APP_AGENT_GUIDE.md: gerar, executar, implementar uma
375
+ jornada, validar e publicar pelo fluxo existente. Para alterar, consulte
376
+ .ooncore/docs/TASK_INDEX.md. npm run check valida cache e conformidade.
362
377
  `);
363
378
  }
364
379
 
@@ -1,62 +1,33 @@
1
1
  # __NAME__
2
2
 
3
- App Oon code-first gerado com `create-central-oon`.
3
+ App Oon code-first gerado com `create-central-oon`. Comece pela entrada curta `.ooncore/AGENTS.md` e pelo roteiro `.ooncore/docs/OON_APP_AGENT_GUIDE.md`; escolha referências em `.ooncore/docs/TASK_INDEX.md` conforme a tarefa. Não é necessário ler o contexto consolidado nem fonte privada.
4
4
 
5
- ## Comece aqui
5
+ ## Executar
6
6
 
7
- A pasta `.ooncore/` contém o contrato público versionado para criar e customizar este App. Um Agent deve usar somente esta árvore do projeto: não é necessário consultar fonte privada do OonCore, `node_modules` ou outros Apps.
8
-
9
- 1. Leia `.ooncore/AGENTS.md`.
10
- 2. Rode `npm run ooncore:docs:check`.
11
- 3. Siga `.ooncore/docs/OON_APP_AGENT_GUIDE.md`.
12
- 4. Consulte `.ooncore/docs/CAPABILITIES.md` e o guia específico da tarefa.
13
-
14
- Se faltar um contrato, registre a lacuna documental em vez de inventar API ou infraestrutura.
15
-
16
- ## Fronteira arquitetural
17
-
18
- - `central.app.json` declara identidade, `appKind`, tenant, acesso, módulos, capabilities funcionais e compatibilidade;
19
- - `oon.deploy.json` declara runtime e dependências de infraestrutura da publicação;
20
- - `backend/src/models` e demais extensões code-first contêm o domínio;
21
- - `backend/central.domain.json` é opcional quando o projeto adota o contrato declarativo documentado;
22
- - `frontend/src/app` compõe rotas, navegação, layouts e temas;
23
- - `frontend/src/{pages,components,features}` contém a experiência local;
24
- - `backend/central.config.js` fica reservado a extensões documentadas de runtime;
25
- - `frontend/src/main.tsx` chama `startOonApp`.
26
-
27
- Autenticação, guards, shell, RBAC, metadata, CRUD e infraestrutura pertencem ao OonCore.
28
-
29
- ## Documentação e conformidade
7
+ Requer Node compatível com os pacotes e MongoDB local. Ajuste `MONGO_URI` para um banco de desenvolvimento.
30
8
 
31
9
  ```bash
32
- npm run ooncore:docs # sincroniza .ooncore/
33
- npm run ooncore:docs:check # valida versão/hash do cache local
34
- npm run ooncore:conformance # valida a fronteira da Central
35
- npm run check # executa os gates locais
36
- npm test
10
+ npm install
11
+ npm install --prefix backend
12
+ npm install --prefix frontend
13
+ cp backend/.env.example backend/.env
14
+ cp frontend/.env.example frontend/.env
15
+ npm run dev
37
16
  ```
38
17
 
39
- `.ooncore/` é um cache regenerável da documentação publicada no pacote. Não edite `context.generated.md` manualmente; versione a pasta junto com o App para que humanos e Agents recebam o mesmo contrato.
18
+ O runtime local funciona em loopback com sessão técnica; não cadastra recursos na Plataforma. Capabilities dependentes da Plataforma falham fechado quando indisponíveis.
19
+
20
+ ## Entregar a primeira jornada
40
21
 
41
- ## Rodando
22
+ Implemente página, navegação, endpoint e permissão usando `.ooncore/docs/PUBLIC_CONTRACTS.md`. Domínio fica em `backend/src`; `backend/central.domain.json` é opcional. Composição de UX fica em `frontend/src/app` e `frontend/src/pages`. `central.app.json` declara identidade e acesso; `oon.deploy.json` declara requisitos de publicação.
42
23
 
43
24
  ```bash
44
- npm install
45
25
  npm run check
46
-
47
- cp backend/.env.example backend/.env
48
- cp frontend/.env.example frontend/.env
49
- npm run dev
26
+ npm run build --prefix frontend
50
27
  ```
51
28
 
52
- 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. Capabilities de plataforma falham fechado quando não resolvidas. Não implemente autenticação, ativação ou infraestrutura paralela.
53
-
54
- ## Evoluindo a Central
29
+ `check` inclui cache documental e conformance. Execute os testes relevantes quando declarados; a base neutra não contém script raiz `test`. Prove a jornada, versione código/manifestos/lockfiles/cache e publique pelo fluxo existente do Workspace/Plataforma. Registre o commit e a validação autenticada em Dev. Build, publicação e homologação são estados distintos.
55
30
 
56
- 1. Modele o domínio por exports públicos em `backend/src` ou adote o manifesto declarativo conforme `BACKEND_DOMAIN_MANIFEST.md`.
57
- 2. Crie rotas, páginas, componentes, layouts e temas nos pontos documentados.
58
- 3. Declare capabilities no manifesto indicado pelo guia dedicado.
59
- 4. Use validações, triggers, hooks, mappings e regras somente para comportamento específico do negócio.
60
- 5. Execute `npm run check` e `npm test` antes de abrir o PR.
31
+ Lacuna documental: registre, use extensão pública adequada no App e continue as partes independentes; não invente APIs nem remova autenticação, autorização ou isolamento. POC não exige roadmap completo nem matriz final de perfis. Não reimplemente nem homologue novamente os serviços já homologados da Plataforma.
61
32
 
62
- O OonCore fornece a fundação; o App implementa sua experiência e seu domínio.
33
+ `.ooncore/` é cache gerado: atualize a fonte do pacote e use `npm run ooncore:docs`; nunca edite manualmente. Upgrade coordenado está em `.ooncore/docs/CORE_UPGRADE.md`.
@@ -12,6 +12,6 @@
12
12
  "deploy": "oonCore-back deploy"
13
13
  },
14
14
  "dependencies": {
15
- "@oondemand/oon-core-back": "^0.7.4"
15
+ "@oondemand/oon-core-back": "^0.7.8"
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.7.4",
14
+ "@oondemand/oon-core-front": "^0.7.8",
15
15
  "@chakra-ui/react": "^3.13.0",
16
16
  "@emotion/react": "^11.14.0",
17
17
  "@tanstack/react-query": "^5.65.0",
@@ -18,8 +18,8 @@ export const app = defineOonApp({
18
18
  meusAppsUrl: import.meta.env.DEV ? undefined : import.meta.env.VITE_MEUS_APPS_URL,
19
19
  },
20
20
  runtimeMode: import.meta.env.DEV ? "local" : "platform",
21
- routes,
22
- navigation,
21
+ routes: [...routes],
22
+ navigation: [...navigation],
23
23
  theme,
24
24
  shell: { shell: "default" },
25
25
  });
@@ -1,9 +1,9 @@
1
1
  import { Stack, Text } from "@chakra-ui/react";
2
- import { CorePage, CorePageHeader, CoreStatusPanel, CoreSummaryCards } from "@oondemand/oon-core-front/ui";
2
+ import { CorePageHeader, CoreStatusPanel, CoreSummaryCards } from "@oondemand/oon-core-front/ui";
3
3
 
4
4
  export function HomePage() {
5
5
  return (
6
- <CorePage>
6
+ <Stack gap={6} p={6}>
7
7
  <CorePageHeader
8
8
  title="Boas-vindas ao __NAME__"
9
9
  description="A fundação técnica está pronta para receber a experiência e o domínio do app."
@@ -20,6 +20,6 @@ export function HomePage() {
20
20
  />
21
21
  <Text color="text.muted">Menus, rotas, layouts e temas ficam em src/app e podem combinar componentes locais com blocos públicos do OonCore.</Text>
22
22
  </Stack>
23
- </CorePage>
23
+ </Stack>
24
24
  );
25
25
  }
@@ -7,12 +7,12 @@
7
7
  "ooncore:docs": "create-central-oon docs sync",
8
8
  "ooncore:docs:check": "create-central-oon docs check",
9
9
  "ooncore:conformance": "create-central-oon conformance",
10
- "check": "npm run ooncore:docs:check && npm run ooncore:conformance",
10
+ "check": "create-central-oon doctor",
11
11
  "dev": "create-central-oon dev",
12
12
  "dev:backend": "npm run dev --prefix backend",
13
13
  "dev:frontend": "npm run dev --prefix frontend"
14
14
  },
15
15
  "devDependencies": {
16
- "@oondemand/create-central-oon": "0.7.4"
16
+ "@oondemand/create-central-oon": "0.7.8"
17
17
  }
18
18
  }