Manifesto de domínio
central.domain.json declara models, campos, fórmulas e validações sem um arquivo JavaScript por model — o Core constrói schema, metadata, CRUD e regras protegidas.
O arquivo backend/central.domain.json é carregado durante o bootstrap, antes de src/models, src/validations, src/triggers e demais diretórios de extensão.
A Central declara o domínio e as regras. O OonCore constrói schema Mongoose, metadata, CRUD, cálculos protegidos e validações.
As expressões são interpretadas por um avaliador fechado. O Core não usa eval, Function nem executa código vindo do manifesto.
Exemplo
{
"name": "Central SS Eventos",
"slug": "ss-eventos",
"schemaVersion": 1,
"models": [
{
"name": "ProjetoItem",
"singular": "item",
"basePath": "/itens",
"crud": { "enabled": true, "permissions": { "read": "itens.read", "write": "itens.write" } },
"fields": {
"quantidade": { "kind": "number", "required": true },
"diarias": { "kind": "number", "required": true },
"valorUnitario": { "kind": "currency", "required": true },
"percentualFee": { "kind": "number", "default": 0 },
"valorContratado": { "kind": "currency", "default": 0 },
"valorPago": { "kind": "currency", "default": 0 },
"statusIntegracao": { "kind": "string", "readonly": true },
"subtotal": {
"kind": "currency",
"computed": {
"precision": 2,
"expression": { "op": "multiply", "args": [{ "field": "quantidade" }, { "field": "diarias" }, { "field": "valorUnitario" }] }
}
},
"valorFee": {
"kind": "currency",
"computed": {
"precision": 2,
"expression": {
"op": "divide",
"args": [{ "op": "multiply", "args": [{ "field": "subtotal" }, { "field": "percentualFee" }] }, { "value": 100 }]
}
}
},
"total": {
"kind": "currency",
"computed": { "precision": 2, "expression": { "op": "add", "args": [{ "field": "subtotal" }, { "field": "valorFee" }] } }
}
},
"validations": [
{
"name": "pagamento-limitado-ao-contratado",
"code": "PAGAMENTO_ACIMA_CONTRATADO",
"field": "valorPago",
"message": "O valor pago não pode superar o valor contratado.",
"assert": { "op": "lte", "args": [{ "field": "valorPago" }, { "field": "valorContratado" }] }
}
]
}
]
}
Estrutura
| Propriedade | Obrigatória | Descrição |
|---|---|---|
name |
sim | Nome legível da declaração. |
slug |
não | Minúsculas, números e hífens. |
schemaVersion |
sim | Deve ser 1. |
models |
sim | Lista não vazia de models. |
Model
| Propriedade | Obrigatória | Descrição |
|---|---|---|
name |
sim | PascalCase, usado no registry e no Mongoose. |
singular |
não | Nome singular. |
basePath |
não | Caminho iniciado por /. |
crud |
não | Mesmo contrato de defineModel. |
options |
não | Opções JSON do schema Mongoose. |
fields |
sim | Objeto com pelo menos um campo. Tipos em Campos. |
validations |
não | Regras executadas depois dos cálculos. |
Escopo da versão 1
Cobre: identidade, models e caminhos de API, CRUD, campos primitivos/enum/ref/moedas, obrigatoriedade, default, busca, unicidade e índice simples, limites numéricos e de texto, campos readonly protegidos, campos calculados com dependências ordenadas, precisão, tratamento de ausentes e validações entre campos — com todos os problemas retornados numa única exceção.
Ainda não cobre: índices compostos, triggers e transições (use o manifesto de processo), migrações automáticas, mappings de integração e funções JavaScript embutidas.
Proteção de campos somente leitura
A proteção não depende do frontend:
- valor readonly enviado na criação é rejeitado;
- alteração de valor readonly é rejeitada;
- em edição, o mesmo valor pode voltar no payload e é removido antes da persistência;
- campos calculados podem voltar no payload somente quando coincidem com o resultado do servidor;
- tentativa de adulterar um campo calculado é rejeitada;
- services recebem somente campos permitidos e os resultados recalculados.
Isso permite formulários que enviam o registro completo sem abrir espaço para alterar totais, status técnicos ou identificadores controlados pelo sistema.
Erros do manifesto
Um manifesto estruturalmente inválido lança DomainManifestError, agregando todos os problemas para corrigir em uma rodada:
{
name: "DomainManifestError",
code: "OON_DOMAIN_MANIFEST_INVALID",
statusCode: 422,
issues: [
{
path: "models[0].fields.total.computed.expression",
message: "dependência circular entre campos calculados: total -> fee -> total."
}
]
}
APIs públicas
Na operação normal você não precisa chamá-las: oonCore-back start descobre o manifesto automaticamente.
const {
validateDomainManifest,
domainManifestToDefinitions,
registerDomainManifest,
loadDomainManifest,
evaluateDomainExpression,
applyDomainMutation,
validateDomainRecord,
detectChangedFields,
DomainManifestError,
DomainRuleError,
DOMAIN_EXPRESSION_OPERATORS,
SUPPORTED_DOMAIN_FIELD_KINDS,
} = require("@oondemand/oon-core-back");
Migração gradual
A ordem de carga é central.config.js → central.domain.json → diretórios em src/. Migre model por model; defineValidation continua disponível e roda depois das fórmulas e validações declarativas.