@oondemand/create-central-oon 0.3.8 → 0.3.10

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.
@@ -0,0 +1,77 @@
1
+ # Padrões Frontend
2
+
3
+ O frontend da Central deve ser declarativo. Shell, providers, rotas, menu, datagrid, formulários, documentos e esteiras pertencem ao `@oondemand/oon-core-front`.
4
+
5
+ Para a lista completa de opções do manifesto, use `FRONTEND_MANIFEST_REFERENCE.md`.
6
+
7
+ ## Estrutura esperada
8
+
9
+ ```txt
10
+ frontend/
11
+ ├── central.ui.json
12
+ └── src/
13
+ ├── main.tsx
14
+ ├── collections/
15
+ ├── documents/
16
+ ├── pipelines/
17
+ ├── dashboards/
18
+ └── overrides/
19
+ ```
20
+
21
+ ## central.ui.json
22
+
23
+ Use `central.ui.json` como entrada principal para declarar:
24
+
25
+ - menu;
26
+ - coleções;
27
+ - campos exibidos;
28
+ - filtros;
29
+ - ações;
30
+ - formulários;
31
+ - documentos;
32
+ - esteiras;
33
+ - dashboards;
34
+ - agrupamentos;
35
+ - layout v2;
36
+ - páginas por blocos;
37
+ - renderers por chave.
38
+
39
+ ## Manifesto v1 e v2
40
+
41
+ - Manifesto sem `schemaVersion` mantém compatibilidade v1.
42
+ - Manifesto com `schemaVersion: 2` habilita composição por `layout`, `navigation`, `pages` e `blocks`.
43
+ - Componentes React não devem ser serializados no JSON; use chaves e registre os componentes no `registry` em TypeScript.
44
+
45
+ ## Regras
46
+
47
+ - Não recrie layout completo se o Core já renderiza.
48
+ - Não duplique chamada REST manual se o SDK do Core já atende.
49
+ - Não coloque regra de permissão apenas no frontend.
50
+ - Não hardcode endpoints quando a metadata puder fornecer.
51
+ - Não crie variações visuais fora do padrão sem necessidade real.
52
+ - Use overrides pequenos, específicos e documentados.
53
+
54
+ ## Overrides
55
+
56
+ Overrides são permitidos para:
57
+
58
+ - campo especial;
59
+ - ação específica;
60
+ - card customizado;
61
+ - cabeçalho customizado;
62
+ - dashboard customizado;
63
+ - integração visual pontual.
64
+
65
+ Overrides não devem virar uma reimplementação do Core.
66
+
67
+ ## Experiência padrão
68
+
69
+ A Central deve manter o padrão OonCore:
70
+
71
+ - navegação consistente;
72
+ - datagrids densos;
73
+ - formulários claros;
74
+ - feedback visual;
75
+ - status por badges;
76
+ - ações rastreáveis;
77
+ - responsividade.
@@ -0,0 +1,50 @@
1
+ # Arquitetura OonCore
2
+
3
+ O OonCore é a base para criar Centrais operacionais sob demanda com arquitetura padronizada, segura e evolutiva.
4
+
5
+ A Central gerada não deve nascer como um sistema completo do zero. Ela deve nascer como uma camada de domínio que consome os recursos do Core.
6
+
7
+ ## Separação de responsabilidades
8
+
9
+ ```txt
10
+ Central
11
+ ├── backend/ domínio, regras, validações, integrações e esteiras
12
+ └── frontend/ declaração de telas, coleções, documentos e overrides
13
+
14
+ OonCore Back
15
+ ├── boot Express
16
+ ├── Mongo/Mongoose
17
+ ├── autenticação
18
+ ├── RBAC
19
+ ├── CRUD metadata-driven
20
+ ├── auditoria
21
+ ├── triggers/hooks
22
+ └── APIs padrão
23
+
24
+ OonCore Front
25
+ ├── shell React
26
+ ├── providers
27
+ ├── roteamento
28
+ ├── menu
29
+ ├── datagrid
30
+ ├── formulários
31
+ ├── documentos
32
+ ├── esteiras
33
+ └── SDK REST
34
+ ```
35
+
36
+ ## Modelo mini-monolítico
37
+
38
+ Cada Central começa como um mini-monolito de negócio: pequeno, coeso, isolado e capaz de entregar valor rapidamente. Quando uma parte do domínio se tornar reutilizável, crítica ou independente, ela pode evoluir para conector, serviço compartilhado ou micro-serviço.
39
+
40
+ ## Fonte de verdade
41
+
42
+ - Dados e regras ficam no backend.
43
+ - Metadata operacional é exposta pelo backend.
44
+ - Frontend renderiza a experiência a partir da metadata.
45
+ - Permissões são decididas no backend.
46
+ - Integrações são tratadas como conectores, mappings, triggers e esteiras de integração.
47
+
48
+ ## Objetivo do Codex
49
+
50
+ O Codex deve acelerar a construção da Central usando a arquitetura existente. O objetivo não é gerar um app genérico, mas sim completar a camada de domínio com segurança e aderência ao Core.
@@ -0,0 +1,35 @@
1
+ # RBAC e Segurança
2
+
3
+ A segurança da Central deve ser aplicada no backend. O frontend pode ocultar ou exibir ações, mas não é a fonte de decisão.
4
+
5
+ ## Regras obrigatórias
6
+
7
+ - Toda operação sensível deve validar usuário autenticado.
8
+ - Toda alteração de dados deve validar permissão.
9
+ - Toda ação de integração deve validar permissão e contexto.
10
+ - Nunca confiar em `tenantId`, `appId`, `perfil` ou `roles` enviados livremente pelo frontend.
11
+ - Segredos devem vir de variáveis de ambiente ou vault equivalente.
12
+ - Logs não devem expor tokens, senhas, app keys ou dados sensíveis desnecessários.
13
+
14
+ ## RBAC
15
+
16
+ Use o RBAC do Core para:
17
+
18
+ - controlar acesso por app;
19
+ - controlar perfis;
20
+ - controlar ações;
21
+ - filtrar funcionalidades;
22
+ - proteger rotas;
23
+ - permitir evolução de permissões sem reconstruir telas.
24
+
25
+ ## Checklist de segurança para Codex
26
+
27
+ Antes de concluir uma alteração, confirme:
28
+
29
+ - Existe validação de entrada?
30
+ - Existe validação de permissão no backend?
31
+ - Existe tratamento de erro?
32
+ - A operação gera rastreabilidade?
33
+ - Algum segredo foi colocado no código?
34
+ - Algum dado sensível foi exposto no frontend?
35
+ - O comportamento funciona para múltiplos usuários e múltiplos apps?
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@oondemand/create-central-oon",
3
- "version": "0.3.8",
3
+ "version": "0.3.10",
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 backend declarativo e frontend padrão Central Minexco: menu, datagrids, formulários e esteiras.",
9
+ "description": "Gerador de Centrais Oon com backend declarativo, frontend padrão e documentação interna OonCore para Codex.",
10
10
  "main": "src/index.js",
11
11
  "exports": {
12
12
  ".": "./src/index.js"
@@ -19,6 +19,7 @@
19
19
  "bin",
20
20
  "src",
21
21
  "templates",
22
+ "docs",
22
23
  "README.md"
23
24
  ],
24
25
  "engines": {
@@ -30,7 +31,9 @@
30
31
  "central",
31
32
  "scaffold",
32
33
  "create",
33
- "generator"
34
+ "generator",
35
+ "codex",
36
+ "docs"
34
37
  ],
35
38
  "license": "SEE LICENSE IN LICENSE",
36
39
  "publishConfig": {
package/src/index.js CHANGED
@@ -2,10 +2,13 @@
2
2
 
3
3
  const fs = require("node:fs");
4
4
  const path = require("node:path");
5
+ const crypto = require("node:crypto");
5
6
  const { spawnSync } = require("node:child_process");
6
7
  const { copyTemplate } = require("./render");
7
8
 
8
- const TEMPLATES_DIR = path.join(__dirname, "..", "templates");
9
+ const PACKAGE_ROOT = path.join(__dirname, "..");
10
+ const TEMPLATES_DIR = path.join(PACKAGE_ROOT, "templates");
11
+ const DOCS_DIR = path.join(PACKAGE_ROOT, "docs");
9
12
 
10
13
  const TEMPLATES = [
11
14
  { id: "basic", description: "Central mínima com uma coleção dinâmica (Pessoa)." },
@@ -52,6 +55,183 @@ function npmInstall(dir) {
52
55
  return !r.status && !r.error;
53
56
  }
54
57
 
58
+ function readPackageVersion() {
59
+ const pkg = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, "package.json"), "utf8"));
60
+ return pkg.version;
61
+ }
62
+
63
+ function listDocFiles(dir = DOCS_DIR, prefix = "") {
64
+ if (!fs.existsSync(dir)) return [];
65
+ const files = [];
66
+
67
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
68
+ const relative = path.join(prefix, entry.name);
69
+ const absolute = path.join(dir, entry.name);
70
+
71
+ if (entry.isDirectory()) {
72
+ files.push(...listDocFiles(absolute, relative));
73
+ } else if (entry.isFile() && entry.name.endsWith(".md")) {
74
+ files.push(relative);
75
+ }
76
+ }
77
+
78
+ return files.sort((a, b) => a.localeCompare(b));
79
+ }
80
+
81
+ function docsHash(files = listDocFiles()) {
82
+ const hash = crypto.createHash("sha256");
83
+ for (const file of files) {
84
+ const normalized = file.split(path.sep).join("/");
85
+ hash.update(normalized);
86
+ hash.update("\n");
87
+ hash.update(fs.readFileSync(path.join(DOCS_DIR, file)));
88
+ hash.update("\n");
89
+ }
90
+ return hash.digest("hex");
91
+ }
92
+
93
+ function resolveCentralRoot(cwd = process.cwd()) {
94
+ const current = path.resolve(cwd);
95
+ const parent = path.dirname(current);
96
+
97
+ if (fs.existsSync(path.join(current, "backend")) && fs.existsSync(path.join(current, "frontend"))) {
98
+ return current;
99
+ }
100
+
101
+ if (
102
+ ["backend", "frontend"].includes(path.basename(current)) &&
103
+ fs.existsSync(path.join(parent, "backend")) &&
104
+ fs.existsSync(path.join(parent, "frontend"))
105
+ ) {
106
+ return parent;
107
+ }
108
+
109
+ return current;
110
+ }
111
+
112
+ function removeDir(dir) {
113
+ if (fs.existsSync(dir)) fs.rmSync(dir, { recursive: true, force: true });
114
+ }
115
+
116
+ function copyDocs(srcDir, destDir) {
117
+ if (!fs.existsSync(srcDir)) {
118
+ throw new Error(`Diretório de documentação não encontrado: ${srcDir}`);
119
+ }
120
+
121
+ fs.mkdirSync(destDir, { recursive: true });
122
+
123
+ for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
124
+ const from = path.join(srcDir, entry.name);
125
+ const to = path.join(destDir, entry.name);
126
+
127
+ if (entry.isDirectory()) {
128
+ copyDocs(from, to);
129
+ } else if (entry.isFile()) {
130
+ fs.copyFileSync(from, to);
131
+ }
132
+ }
133
+ }
134
+
135
+ function buildContext(files = listDocFiles()) {
136
+ const header = [
137
+ "# OonCore Contexto Consolidado para Codex",
138
+ "",
139
+ "> Arquivo gerado automaticamente por `create-central-oon docs --sync`.",
140
+ "> Não edite manualmente. A fonte de verdade está no pacote `@oondemand/create-central-oon` instalado.",
141
+ "",
142
+ "Este contexto consolida as regras mínimas para codificar Centrais Oon com segurança, usando o máximo dos recursos do OonCore.",
143
+ "",
144
+ ].join("\n");
145
+
146
+ const sections = files
147
+ .map((file) => {
148
+ const normalized = file.split(path.sep).join("/");
149
+ const content = fs.readFileSync(path.join(DOCS_DIR, file), "utf8").trim();
150
+ return [
151
+ "---",
152
+ "",
153
+ `<!-- source: ${normalized} -->`,
154
+ "",
155
+ content,
156
+ "",
157
+ ].join("\n");
158
+ })
159
+ .join("\n");
160
+
161
+ return `${header}\n${sections}`;
162
+ }
163
+
164
+ function buildManifest(files = listDocFiles()) {
165
+ return {
166
+ source: "@oondemand/create-central-oon",
167
+ version: readPackageVersion(),
168
+ generatedAt: new Date().toISOString(),
169
+ docsMode: "generated-cache",
170
+ docsHash: docsHash(files),
171
+ files: files.map((file) => file.split(path.sep).join("/")),
172
+ };
173
+ }
174
+
175
+ function syncDocs(opts = {}) {
176
+ const root = resolveCentralRoot(opts.cwd);
177
+ const outDir = path.join(root, ".ooncore");
178
+ const docsOutDir = path.join(outDir, "docs");
179
+ const files = listDocFiles();
180
+
181
+ if (!files.length) {
182
+ throw new Error("Nenhum arquivo .md encontrado em packages/create-central-oon/docs.");
183
+ }
184
+
185
+ fs.mkdirSync(outDir, { recursive: true });
186
+ removeDir(docsOutDir);
187
+ copyDocs(DOCS_DIR, docsOutDir);
188
+
189
+ const codexSource = path.join(DOCS_DIR, "CODEX.md");
190
+ if (fs.existsSync(codexSource)) {
191
+ fs.copyFileSync(codexSource, path.join(outDir, "CODEX.md"));
192
+ }
193
+
194
+ fs.writeFileSync(path.join(outDir, "context.generated.md"), buildContext(files));
195
+ fs.writeFileSync(path.join(outDir, "manifest.json"), `${JSON.stringify(buildManifest(files), null, 2)}\n`);
196
+
197
+ console.log(`✔ Documentação OonCore sincronizada em ${path.relative(process.cwd(), outDir) || ".ooncore"}`);
198
+ console.log(` Versão: ${readPackageVersion()}`);
199
+ console.log(` Arquivos: ${files.length}`);
200
+ }
201
+
202
+ function checkDocs(opts = {}) {
203
+ const root = resolveCentralRoot(opts.cwd);
204
+ const manifestPath = path.join(root, ".ooncore", "manifest.json");
205
+ const version = readPackageVersion();
206
+ const files = listDocFiles();
207
+ const currentHash = docsHash(files);
208
+
209
+ if (!fs.existsSync(manifestPath)) {
210
+ throw new Error("Documentação OonCore local não encontrada. Rode `npm run ooncore:docs`.");
211
+ }
212
+
213
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
214
+ const problems = [];
215
+
216
+ if (manifest.source !== "@oondemand/create-central-oon") {
217
+ problems.push(`fonte esperada @oondemand/create-central-oon, encontrada ${manifest.source || "(vazia)"}`);
218
+ }
219
+
220
+ if (manifest.version !== version) {
221
+ problems.push(`versão local ${manifest.version || "(vazia)"} diferente da instalada ${version}`);
222
+ }
223
+
224
+ if (manifest.docsHash !== currentHash) {
225
+ problems.push("hash da documentação local diferente da documentação instalada");
226
+ }
227
+
228
+ if (problems.length) {
229
+ throw new Error(`Documentação OonCore desatualizada:\n- ${problems.join("\n- ")}\nRode \`npm run ooncore:docs\`.`);
230
+ }
231
+
232
+ console.log(`✔ Documentação OonCore atualizada (versão ${version}).`);
233
+ }
234
+
55
235
  async function run(opts) {
56
236
  const template = TEMPLATES.find((t) => t.id === opts.template);
57
237
  if (!template) {
@@ -81,13 +261,19 @@ async function run(opts) {
81
261
  // 2. Overlay do template escolhido (vence sobre o _base).
82
262
  copyTemplate(path.join(TEMPLATES_DIR, template.id), targetDir, tokens);
83
263
 
264
+ // 3. Contexto local para Codex derivado da documentação da versão instalada.
265
+ syncDocs({ cwd: targetDir });
266
+
84
267
  console.log("✔ Arquivos gerados.");
85
268
 
86
269
  if (opts.install) {
87
270
  console.log("\n📦 Instalando dependências (best-effort)...");
271
+ const rootOk = fs.existsSync(path.join(targetDir, "package.json"))
272
+ ? npmInstall(targetDir)
273
+ : true;
88
274
  const backOk = npmInstall(path.join(targetDir, "backend"));
89
275
  const frontOk = npmInstall(path.join(targetDir, "frontend"));
90
- if (!backOk || !frontOk) {
276
+ if (!rootOk || !backOk || !frontOk) {
91
277
  console.warn(
92
278
  "\n⚠ npm install falhou em um dos projetos (esperado se os pacotes @oondemand/* ainda não foram publicados). Rode manualmente depois."
93
279
  );
@@ -103,7 +289,11 @@ function printNextSteps(tokens, opts) {
103
289
  ✅ Central "${tokens.name}" pronta.
104
290
 
105
291
  Próximos passos:
106
- ${cd} # Backend (só domínio models/validations/triggers/...)
292
+ ${cd} # Sincronizar/validar documentação local do Core para Codex
293
+ npm run ooncore:docs
294
+ npm run ooncore:docs:check
295
+
296
+ # Backend (só domínio — models/validations/triggers/...)
107
297
  cd backend && cp .env.example .env && npm run dev
108
298
 
109
299
  # Frontend (só declaração — central.ui.json)
@@ -114,4 +304,13 @@ Edite backend/src/models e frontend/central.ui.json para evoluir a Central.
114
304
  `);
115
305
  }
116
306
 
117
- module.exports = { run, listTemplates, toSlug, toPascal, toTitle };
307
+ module.exports = {
308
+ run,
309
+ listTemplates,
310
+ toSlug,
311
+ toPascal,
312
+ toTitle,
313
+ syncDocs,
314
+ checkDocs,
315
+ resolveCentralRoot,
316
+ };
@@ -1,7 +1,6 @@
1
1
  # __NAME__
2
2
 
3
- Central Oon gerada com `create-central-oon`. É composta por dois projetos
4
- mínimos que consomem o Core:
3
+ Central Oon gerada com `create-central-oon`. É composta por dois projetos mínimos que consomem o Core:
5
4
 
6
5
  - **backend/** — só domínio (`src/models`, `validations`, `triggers`, …).
7
6
  Sobe com `oonCore-back dev`. Toda a infra (boot, db, auth, RBAC, metadata,
@@ -10,9 +9,26 @@ mínimos que consomem o Core:
10
9
  dev`. Shell, providers, roteamento, auth e telas vêm do
11
10
  `@oondemand/oon-core-front`, renderizados a partir do `/core/metadata` do back.
12
11
 
12
+ ## Documentação local do OonCore
13
+
14
+ A pasta `.ooncore/` é gerada automaticamente a partir da versão instalada do pacote `@oondemand/create-central-oon`.
15
+
16
+ Ela serve como contexto local para o Codex codificar sem depender de site externo.
17
+
18
+ ```bash
19
+ npm run ooncore:docs # sincroniza .ooncore/
20
+ npm run ooncore:docs:check # valida versão/hash da documentação local
21
+ ```
22
+
23
+ Não edite `.ooncore/context.generated.md` manualmente. Atualize o pacote e rode o sync.
24
+
13
25
  ## Rodando
14
26
 
15
27
  ```bash
28
+ # raiz da Central
29
+ npm install
30
+ npm run ooncore:docs:check
31
+
16
32
  # backend
17
33
  cd backend && cp .env.example .env && npm install && npm run dev
18
34
 
@@ -24,4 +40,5 @@ cd frontend && cp .env.example .env && npm install && npm run dev
24
40
 
25
41
  1. Crie models em `backend/src/models` (só schema + CRUD).
26
42
  2. Declare as telas em `frontend/central.ui.json` (coleções/esteiras/documentos).
27
- 3. O resto — grid, form, rotas, menu é montado pelo Core automaticamente.
43
+ 3. Use validations, triggers, hooks, mappings e integrations para regras e processos.
44
+ 4. O resto — grid, form, rotas, menu — é montado pelo Core automaticamente.
@@ -12,6 +12,6 @@
12
12
  "deploy": "oonCore-back deploy"
13
13
  },
14
14
  "dependencies": {
15
- "@oondemand/oon-core-back": "^0.3.8"
15
+ "@oondemand/oon-core-back": "^0.3.10"
16
16
  }
17
17
  }
@@ -10,7 +10,7 @@
10
10
  "sync:metadata": "oonCore-front sync:metadata"
11
11
  },
12
12
  "dependencies": {
13
- "@oondemand/oon-core-front": "^0.3.8",
13
+ "@oondemand/oon-core-front": "^0.3.10",
14
14
  "@chakra-ui/react": "^3.13.0",
15
15
  "@emotion/react": "^11.14.0",
16
16
  "@tanstack/react-query": "^5.65.0",
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "__SLUG__",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "description": "Central Oon __NAME__ gerada com create-central-oon.",
6
+ "scripts": {
7
+ "ooncore:docs": "create-central-oon docs --sync",
8
+ "ooncore:docs:check": "create-central-oon docs --check",
9
+ "dev:backend": "npm run dev --prefix backend",
10
+ "dev:frontend": "npm run dev --prefix frontend"
11
+ },
12
+ "devDependencies": {
13
+ "@oondemand/create-central-oon": "^0.3.8"
14
+ }
15
+ }