# 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 ```json title="backend/central.domain.json" { "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](/docs/backend/campos#tipos-no-manifesto-de-dominio). | | `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](/docs/backend/esteiras-e-processos)), 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: ```javascript { 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. ```javascript 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. Fonte: https://sdk.oonapps.com/docs/backend/manifesto-de-dominio