praxis-dynamic-form

Este documento e a referencia canonica da API JSON de praxis-dynamic-form.

Summary

  • Tipo documental: API reference canonica de contrato JSON.
  • Source of truth: runtime e codigo declarados no frontmatter.
  • Objetivo operacional: consulta rapida, auditavel e deterministica sob pressao.
  • Resumo funcional herdado: Referencia canonica da JSON API do praxis-dynamic-form, com foco em:

Canonical authoring semantics

  • Em Geral → Dados do formulário, Modo de dados e Modo de exibição são preferências independentes.

  • bindings.presentationModeGlobal reutiliza o input runtime existente: true = Apresentação (efetiva somente em view), false = Campos de formulário, null/ausência = Automático, seguindo layoutPolicy.

  • Em replace-all, omitir a preferência remove o override anterior; false deve ser preservado. Não existe um quarto valor em bindings.mode.

  • O Page Builder projeta a preferência nos inputs do widget, preservando ausência de config em formulários schema-driven. No editor do runtime, Apply/Save também publicam mode e presentationModeGlobal em configPatchChange.inputPatch.

  • contextSnapshot.presentation continua reservado aos estilos (tipografia, densidade e alinhamento), editáveis nos dois caminhos pela aba Estilo da apresentação; não é o seletor de ativação. O Filter Form não oferece o seletor de exibição porque seu runtime não suporta apresentação.

  • DynamicFormAuthoringDocument e o snapshot canonico completo de autoria de praxis-dynamic-form.

  • Quando aplicado por fluxos canonicos de editor, config, bindings e contextSnapshot possuem semantica replace-all.

  • Ausencia de bindings.mode limpa o binding persistido e restaura o modo default efetivo do host.

  • Ausencia de backConfig, presentation ou schemaPrefs no documento canonico significa remocao explicita do bloco ausente.

  • backConfig, presentation e schemaPrefs permanecem fora de FormConfig, mas fazem parte oficialmente do documento autoral persistivel em contextSnapshot.

  • APIs de compatibilidade como applyConfigFromAdapter(...) continuam aceitando payloads legados/parciais com semantica merge-compat, preservando campos nao informados.

Backend-owned reactive determinations

  • x-ui.reactiveDeterminations e lido exclusivamente do request schema exato retornado por /schemas/filtered; nao integra nem e persistido em FormConfig.
  • O runtime aceita somente o contrato fechado normalizado por normalizeReactiveDeterminations: trigger on-change, scope de create/edit, capability POST, no maximo 64 bindings totais, JSON Pointers sem duplicidade ou sobreposicao hierarquica e provenance estrutural. A lista e um unico grafo canonico: uma definicao invalida rejeita a projecao inteira, sem execucao parcial.
  • href, request/response schemas e bindings sao compilados pelo Praxis Metadata. O Angular nao aceita callback, headers, method, URL ou write policy autorados pelo host/editor/LLM.
  • Cada valor ou status relevante invalida imediatamente a geracao anterior, antes do debounce da proxima chamada; somente a geracao ainda autoritativa pode aplicar a resposta.
  • Hrefs protocol-relative, com separadores codificados ou resolvidos fora da origem configurada da API falham de forma fechada.
  • A resposta so e aplicada quando todos os bindings existem. Os controles alvo aninhados sao preenchidos antes da notificacao dos observers; determinacoes encadeadas recebem um unico sinal logico depois do commit completo, nao um disparo por output. A ordem da cadeia e derivada dos bindings existentes: downstream aguarda a geracao upstream e so executa apos outputs autoritativos ou inputs confirmados como inalterados. Output upstream null/undefined e geracao upstream com erro, invalida ou cancelada encerram downstream como skipped, sem chamada com dado ausente ou obsoleto. Se um controle rejeitar a escrita, o runtime tenta restaurar os anteriores e emite falha terminal. O resultado tem semantica fechada server-derived e substitui o draft alvo; o commit e um batch coordenado no cliente, sem promessa de transacao ACID.
  • O estado permanece pending durante debounce, validacao assincrona e execucao. Uma tentativa de submit aguarda estabilizacao com timeout e repete a espera depois de hooks que podem alterar controles.
  • Controles de output sao desabilitados transitoriamente como valores server-derived, sem mutar/persistir FormConfig; seus valores continuam em getRawValue(), valueChange e no payload de submit. Depois da hidratacao, fonte inicialmente preenchida entra em pending e e determinada antes de o draft ser considerado estavel; fonte inicial vazia encerra como skipped/initial-source-empty, satisfeita e sem HTTP. Alteracao programatica posterior em output owned invalida a autoridade anterior e reexecuta a capability.
  • reactiveDeterminationExecuted publica apenas IDs, paths, provenance, estado (pending, success, skipped ou error), duracao, correlation ID e motivo. Valores do formulario e da resposta nao participam da evidencia.
  • Hosts compostos recebem estado agregado por reactiveDeterminationPendingChange. Antes de navegar ou fechar, devem consultar hasPendingReactiveDeterminations() e hasUnsatisfiedReactiveDeterminations() e aguardar waitForReactiveDeterminations(timeoutMs?); retorno false indica timeout ou geração mais recente sem draft autoritativo e bloqueia a transição. Correlações canceladas recebem terminal skipped/superseded.
  • Cascatas de opcoes continuam em optionSource.dependsOn; recommendations, side-effect refresh, backend validation e workflow actions permanecem capacidades separadas.
  • O comando backend final continua responsavel por autorizacao, recomputacao e validacao de qualquer decisao consequente.

AI assistant and semantic authoring boundary

praxis-dynamic-form usa o copiloto semantico Praxis como superficie assistiva contextual, nao como fonte primaria de regra de negocio. O componente pode abrir o assistente a partir de controles de configuracao, floating help ou selecao do canvas, mas a presenca global, minimizacao e retomada da sessao pertencem ao PraxisAssistantSessionRegistryService.

Contrato operacional:

  • a integracao nova deve abrir PraxisAiAssistantShellComponent; PraxisAiAssistantComponent permanece legado para novos fluxos inteligentes;
  • a identidade canonica da sessao segue form:{routeKey}:{componentInstanceId || formId || 'form'};
  • o contexto assistivel publico e PraxisAssistantContextSnapshot, com identity, target, contextItems, authoringManifestRef, resourcePath, schemaFields, digests seguros e hints de governanca;
  • o snapshot pode apontar para field, schemaBackedField, localField, section, row, column, visualBlock, formAction, message ou rule, mas nao deve transportar form.value, rawFormData, config completa, notas privadas, estado runtime bruto, diagnostics arbitrarios, pendingPatch, File, Blob, bytes, base64 ou previewUrl;
  • turnos do assistente usam AgenticAuthoringTurnClientService e /api/praxis/config/ai/authoring/turn/stream/**; indisponibilidade do transporte falha de forma fechada e nao reabre o caminho legado getPatch;
  • o grounding do turno pode incluir schemaFields e dataProfile estruturais produzidos pelo adapter, mas nunca valores dos controles; anexos sao reduzidos a nome, tipo, MIME, tamanho, origem e indicador de preview;
  • edicao local so pode ser aplicada quando a resposta for compilada para componentEditPlan validado pelo manifesto autoral do componente;
  • patches livres retornados por backend/LLM sem plano compilado sao rejeitados pelo turn flow;
  • pedidos sobre regra de negocio compartilhada, elegibilidade, compliance, LGPD, politica, acesso, aprovacao, publicacao, materializacao ou enforcement devem virar handoff governado para domain-rules, nao patch local de formulario;
  • em mode="view" sem customizacao, ou quando o host estiver readonly, o assistente opera apenas em inline-help, explain e diagnose; local-apply e manifest-compile ficam bloqueados.

Essa fronteira preserva a premissa de plataforma: o formulario materializa e explica decisoes governadas, mas nao redefine sozinho a semantica canonica da decisao.

Scope and positioning

  • Escopo: contrato JSON publico e limites de comportamento observavel.
  • Fora de escopo: tutorial de adocao e walkthrough operacional detalhado.
  • Posicionamento: referencia canonicamente governada para consumidores, arquitetos e mantenedores.

Source of truth

Source Kind Notes
projects/praxis-dynamic-form/src/lib/praxis-dynamic-form.ts runtime-code Source de implementacao declarado no repositorio.
projects/praxis-dynamic-form/src/lib/praxis-dynamic-form.html template-style Source de implementacao declarado no repositorio.
projects/praxis-dynamic-form/src/lib/config-editor/praxis-dynamic-form-config-editor.ts runtime-code Source de implementacao declarado no repositorio.
projects/praxis-dynamic-fields/src/lib/directives/dynamic-field-loader.directive.ts runtime-code Source de implementacao declarado no repositorio.
projects/praxis-core/src/lib/models/form/form-config.model.ts runtime-code Source de implementacao declarado no repositorio.
projects/praxis-core/src/lib/models/form/form-layout.model.ts runtime-code Source de implementacao declarado no repositorio.

Support legend

  • Active: suportado e observado no runtime atual.
  • Partial: suporte parcial, com restricoes conhecidas.
  • Declared-only: declarado em tipos/schema sem ligacao runtime confirmada.
  • Schema-only: presente em schema/modelo sem confirmacao de execucao.
  • Deprecated: mantido por compatibilidade legada com migracao prevista.

Contract classification

Canonical paths (public contract)

Path Type Required Default Status Notes
sections[] not-specified not-specified n/a Active Render estrutural principal (section/row/column).
fieldMetadata[] not-specified not-specified n/a Active Fonte de campos para DynamicFieldLoader.
metadata not-specified not-specified n/a Active Usado em reconciliacao/snapshot/status de schema.
actions not-specified not-specified n/a Active Render de praxis-form-actions e roteamento de eventos.
behavior not-specified not-specified n/a Partial Subset funcional (detalhado abaixo).
api not-specified not-specified n/a Declared-only Declarado no modelo; sem binding operacional direto no runtime atual.
messages not-specified not-specified n/a Partial Chaves principais de submit/confirmacao usadas; contrato e mais amplo.
formRules not-specified not-specified n/a Active Aplicadas no pipeline de regras do runtime.
formCommandRules not-specified not-specified n/a Active Regras condicionais de comando avaliadas sobre formData estabilizado depois de formRules; primeiro corte suporta global-action.
formRulesState internal-round-trip Gerado pelo builder visual; nao e alvo de autoria manual ou IA. n/a Internal Estado visual derivado de formRules para reabertura do editor.
hooks not-specified not-specified n/a Active Integracao de ciclo (before/after) via runtime de hooks.
hints not-specified not-specified n/a Declared-only Mantido no contrato/editor; sem render dedicado no template principal.
helpPresentation FormHelpPresentationConfig No { display: "inline" } Active Politica visual para exibir hint/helpText dos campos sem alterar semantica dos DTOs; erros de validacao continuam inline.
presentation FormPresentationConfig No runtime defaults Active Preferencias tipadas de label/value para modos read-only e presentation. Valores numericos de tamanho e largura sao materializados como comprimentos CSS em px; o mesmo shape alimenta o snapshot canonico do editor.
fieldMetadata[].array FieldArrayConfig No n/a Active Contrato de Editable Collection apenas quando fieldMetadata[].controlType === "array" ou quando x-ui.array foi publicado explicitamente.

Nota editorial:

  • praxis-dynamic-form carrega e orquestra FieldMetadata, mas a resolução de valuePresentation em display/read-only pertence ao runtime de @praxisui/dynamic-fields.
  • fieldMetadata[].source, fieldMetadata[].transient e fieldMetadata[].submitPolicy governam campos locais do host. Campos com source: "local" ou transient: true participam de validação, regras, visibilidade e valueChange, mas são omitidos de formSubmit.formData e do payload HTTP por default.
  • fieldMetadata[].submitPolicy tem prioridade sobre source e transient: include força envio, omit força omissão e includeWhenDirty envia apenas quando o controle estiver dirty.
  • Dentro de array.itemSchema.fields, includeWhenDirty considera o item ou subcampo especifico dirty, como participantes.0 ou participantes.0.observacao. O FormArray pai dirty, como participantes, nao torna todos os subcampos de todos os itens elegiveis para submit.
  • O evento formSubmit mantém formData como payload persistível filtrado e expõe rawFormData para hosts que precisam ler os campos locais/transientes no contexto de UI.
  • O evento payloadPreviewChange projeta o payload persistível atual sem executar hooks de submit nem disparar HTTP. formData usa o mesmo pipeline síncrono de normalização/políticas do submit, rawFormData preserva o estado completo e changedFields lista somente paths de controles dirty.
  • Botões com type="reset" preservam a semântica canônica de reset mesmo quando recebem um id editorial próprio. O runtime impede o reset nativo do navegador, restaura o snapshot hidratado, marca o formulário como pristine/untouched e publica nova prévia com reason: "reset".
  • Configs persistidas são reconciliadas com o schema estrutural antes da montagem. Campos locais explícitos são preservados, mas campos server-backed recebem novamente a semântica publicada pelo backend, incluindo endpoint, resourcePath, optionLabelKey e optionValueKey.
  • Para selects com x-ui.endpoint terminando em /options/filter, endpoint é a operação concreta de opções e resourcePath é o recurso dono. O runtime deve chamar /options/filter; não deve converter esse endpoint para /filter.

Supported legacy paths

Nenhum path legado suportado foi identificado nesta revisão baseada em evidência textual preservada.

Internal-only paths

Path Internal consumer Runtime presence Public support Notes
__formConfigKey (storage key derivado) persistencia interna (ASYNC_CONFIG_STORAGE) Yes No Chave computada por formId/componentInstanceId; não faz parte do contrato JSON.
schema-meta:* (storage namespace) verificação de drift de schema Yes No Usado por verifyServerSchemaVersion() para status/outdated.

Experimental paths

Path Enablement (flag/guard) Stability Rollout notes Notes
behavior.reactiveValidation feature flag no contrato + runtime checks Partial Disponível; requer validação de carga para forms grandes Debounce configurável por reactiveValidationDebounceMs.

Overview

Este arquivo foi adaptado para o padrao canonico atual sem remover conteudo tecnico existente. O conteudo detalhado anterior foi preservado para manter rastreabilidade historica e reduzir perda de contexto.

Public contract surface

Top-level configuration blocks

Block Purpose Required Merge strategy Notes
sections[] Estrutura principal de layout (section/row/column) Yes replace-array Base para render e ordenação visual.
fieldMetadata[] Definição dos campos e componentes dinâmicos Yes replace-array Consumido por DynamicFieldLoaderDirective.
metadata Metadados de versão/origem/schema No deep-merge Usado em status, drift e rastreabilidade.
actions Ações de formulário (submit/cancel/custom) No deep-merge Roteadas para outputs e confirmação condicional.
behavior Regras de UX/validação/edição No deep-merge Inclui confirmação em dirty, validação reativa e overlays.
messages Mensagens de UX e feedback No deep-merge Fallback para mensagens default quando ausente.
formRules Regras declarativas de runtime No replace-array Aplicadas no pipeline de rulesService.
formCommandRules Comandos condicionais governados No replace-array Executa GlobalActionRef estruturado depois que valores calculados de formRules estabilizam.
hooks Hooks before/after por estágio No replace-array per stage @Input() hooks pode sobrescrever config.hooks.

Nested configuration blocks

Path Type Required Default Constraints Notes
sections[] not-specified not-specified n/a component-defined Render estrutural principal (section/row/column).
fieldMetadata[] not-specified not-specified n/a component-defined Fonte de campos para DynamicFieldLoader.
metadata not-specified not-specified n/a component-defined Usado em reconciliacao/snapshot/status de schema.
actions not-specified not-specified n/a component-defined Render de praxis-form-actions e roteamento de eventos.
behavior not-specified not-specified n/a component-defined Subset funcional (detalhado abaixo).
api not-specified not-specified n/a component-defined Declarado no modelo; sem binding operacional direto no runtime atual.
messages not-specified not-specified n/a component-defined Chaves principais de submit/confirmacao usadas; contrato e mais amplo.
formRules not-specified not-specified n/a component-defined Aplicadas no pipeline de regras do runtime.
formRulesState internal-round-trip Gerado pelo builder visual; nao e alvo de autoria manual ou IA. n/a internal-derived Estado visual derivado de formRules para reabertura do editor.
hooks not-specified not-specified n/a component-defined Integracao de ciclo (before/after) via runtime de hooks.
sections[].sectionHeader FormSectionHeaderConfig No n/a Active Header visual rico da seção com suporte a avatar dinâmico resolvido a partir de formData.

Editable Collection field contract

Editable Collection e o contrato publico para listas editaveis de objetos dentro de fieldMetadata[].

O runtime trata um campo como Editable Collection somente quando o campo declara controlType: "array" ou quando a metadata veio com array explicitamente. Um schema OpenAPI com type: "array" usado por controles simples, como chipInput ou multiSelect, nao deve receber fieldMetadata[].array por normalizacao implicita.

Subconjunto suportado no beta atual:

Path Type Required Default Status Notes
fieldMetadata[].controlType "array" Yes n/a Active Seleciona pdx-editable-collection via Dynamic Fields.
fieldMetadata[].array.itemType "object" Yes "object" Active O MVP monta cada item como FormGroup. Arrays simples usam controles proprios, nao Editable Collection.
fieldMetadata[].array.mode "cards" No "cards" Active Primeiro renderizador oficial. Modos table, drawer, accordion, wizard, chips permanecem fora do contrato beta.
fieldMetadata[].array.itemSchemaRef string Conditional n/a Active Referencia OpenAPI do DTO de item quando publicada pelo backend.
fieldMetadata[].array.itemSchema.fields FieldMetadata[] Conditional [] Active Metadata resolvida/inline usada para criar os subcontroles do item.
fieldMetadata[].array.itemIdentityField string No n/a Active Preserva identidade de item existente quando o valor inicial contem o campo.
fieldMetadata[].array.minItems number No n/a Active Validador agregado do FormArray.
fieldMetadata[].array.maxItems number No n/a Active Validador agregado e limite operacional de adicao.
fieldMetadata[].array.operations.add boolean No true Active Governanca metadata-driven da acao adicionar.
fieldMetadata[].array.operations.edit boolean No true Active Quando falso, subcampos de item entram em modo somente leitura.
fieldMetadata[].array.operations.remove boolean No true Active Governanca metadata-driven da acao remover.
fieldMetadata[].array.deleteMode "removeFromPayload" No "removeFromPayload" Active Remocao exclui a linha do array final em formSubmit.formData.
fieldMetadata[].array.collectionValidation.uniqueBy string[] No n/a Active Detecta duplicidade somente em chaves completas; linhas incompletas nao geram erro prematuro.
fieldMetadata[].array.collectionValidation.exactlyOne { field, value, message? } No n/a Active Exige exatamente um item com valor tipado estritamente igual.
fieldMetadata[].array.collectionValidation.atLeastOne { field, value, message? } No n/a Active Exige pelo menos um item com valor tipado estritamente igual.

O host deve persistir formSubmit.formData para fluxos normais. formSubmit.rawFormData existe para auditoria, diagnostico e hooks de UI, mas nao substitui o payload normalizado.

Input bindings

initialValue is an active component input for host-authored or complementary field values. In edit/view, the runtime applies it without redefining the canonical remote entity loaded through resourcePath and resourceId. In create, including item-scoped command forms, it is the only supported source of initial values: a contextual resourceId never triggers entity hydration.

Binding/Path Type Required Source Runtime normalization Notes
config FormConfig Conditional component-input normalizeFormConfig(config) Contrato principal quando fornecido diretamente pelo host.
resourcePath string | undefined Conditional component-input crud.configure(resourcePath) Endpoint base para schema e dados remotos. Alternativa canônica: schemaUrl explícito.
resourceId string | number | undefined No component-input update pendingEntityId; hydrate only in edit/view Carrega entidade em modo edit/view. Em create, pode identificar o item dono de um comando sem iniciar leitura nem bloquear os campos.
mode 'create' | 'edit' | 'view' No component-input/storage persistido em formInputsKey Preferência de modo pode ser hidratada do storage.
schemaSource 'resource' | 'filter' No component-input runtime branch Seleciona caminho de obtenção de schema quando schemaUrl não é informado.
schemaUrl string | null | undefined Conditional component-input parsed as /schemas/filtered contract Fonte canônica explícita para inicialização schema-backed sem depender de resourcePath.
readUrl string | null | undefined No component-input resolved via API origin and {id} placeholders URL concreta de leitura publicada por surface VIEW/READ_PROJECTION; quando presente, substitui crud.getById na hidratação da entidade.
submitUrl string | null | undefined Conditional component-input resolved via API origin URL concreta de submit publicada por surface/action; exige submitMethod quando usada para envio HTTP.
submitMethod 'post' | 'put' | 'patch' | null | undefined Conditional component-input normalized lowercase Método HTTP concreto de submit publicado por surface/action; exige submitUrl quando usado para envio HTTP.
submitIdempotencyKey string | null | undefined No action execution contract Idempotency-Key Identidade estável da tentativa; deve ser reutilizada em retries da mesma execução.
submitCorrelationId string | null | undefined No action execution contract X-Correlation-Id Correlação de observabilidade do comando entre host e backend.
submitResourceVersion string | number | null | undefined Conditional action execution contract quoted If-Match Versão esperada do item; obrigatória quando execution.preconditions.resourceVersionTransport é IF_MATCH.
submitResourceVersionTargetResourceKey string | null | undefined Conditional action execution contract exact resource discovery Recurso canônico cujo ETag atual deve ser lido quando a action protege um agregado diferente do recurso dono. Exige submitResourceVersionTargetIdField.
submitResourceVersionTargetIdField string | null | undefined Conditional action execution contract exact request field lookup Campo escalar do payload que identifica o alvo concorrente. Exige submitResourceVersionTargetResourceKey; ausência, divergência de catálogo ou ETag ausente falham fechado.
responseSchemaUrl string | null | undefined No component-input diagnostic only Schema de resposta para diagnóstico e follow-up; não compõe campos editáveis nem o payload do comando.
enableCustomization boolean No component-input boolean coercion Alterna UX de edição visual/configuração.
formId string | undefined Yes (corporate flow) component-input component key scoping Obrigatório para ciclo corporativo com persistência e sync.
componentInstanceId string | undefined No component-input component key scoping Isola persistência por instância.
layout FormLayout | undefined No component-input apply as runtime override Override estrutural de layout quando fornecido.
backConfig BackConfig | undefined No component-input/storage precedence over behavior.confirmOnUnsavedChanges Política de retorno/confirm on dirty.
hooks FormHooksLayout | undefined No component-input overrides config.hooks Fonte de hooks prioritária quando presente.
customEndpoints EndpointConfig No component-input service-level override Sobrescreve endpoints do CRUD interno.

Section header visual contract

Path Type Required Default Status Notes
sections[].icon string No n/a Active Ícone estático tradicional da seção; continua suportado.
sections[].sectionHeader.mode 'icon' | 'avatar-image' | 'avatar-initials' | 'auto' No icon Active Seleciona a estratégia visual do header.
sections[].sectionHeader.sourceField string No n/a Active Field do formData usado como origem de foto/avatar.
sections[].sectionHeader.initialsSourceField string No n/a Active Field textual usado para derivar iniciais.
sections[].sectionHeader.altField string No n/a Active Field usado como texto acessível do avatar e fallback textual para iniciais.
sections[].sectionHeader.fallbackIcon string No sections[].icon Active Ícone usado quando a fonte dinâmica estiver vazia/inválida.
sections[].sectionHeader.emptyState 'fallback-icon' | 'placeholder-avatar' | 'none' No placeholder-avatar Active Resolve o estado inicial comum em formulários de inclusão com default neutro para qualquer domínio; fallback-icon preserva a moldura/avatar e respeita size.
sections[].sectionHeader.size 'sm' | 'md' | 'lg' No md Active Tamanho semântico do avatar; o runtime materializa via tokens --pfx-form-section-avatar-size*.
sections[].sectionHeader.initialsMaxLength number No 2 Active Limita a quantidade de letras no avatar textual e é normalizado para 1..4.
sections[].headerActions FormSectionHeaderAction[] No n/a Active Ações iconográficas renderizadas na borda direita do header da seção e emitidas pelo mesmo output customAction.
sections[].headerActions[].id string Yes n/a Active Identificador estável da ação usado por rules, host e automações.
sections[].headerActions[].label string Yes n/a Active Label acessível usada como fallback de tooltip e aria-label.
sections[].headerActions[].icon string Yes n/a Active Ícone Material/Praxis renderizado no botão do header.
sections[].headerActions[].action string No sections[].headerActions[].id Active Nome lógico emitido no customAction; quando informado, também é a base para mensagens e rules dessa ação.
sections[].headerActions[].tooltip string No sections[].headerActions[].label Active Tooltip opcional da ação do header.
sections[].headerActions[].color 'primary' | 'accent' | 'warn' | 'basic' No basic Active Tom visual mapeado para mat-icon-button.
sections[].headerActions[].visible boolean No true Active Permite ocultar a ação no runtime sem removê-la do contrato.
sections[].headerActions[].disabled boolean No false Active Trava interação da ação do header.
sections[].headerActions[].loading boolean No false Active Renderiza spinner e marca a ação como busy/indisponível enquanto durar o estado de loading.
sections[].headerActions[].className string No n/a Active Classe CSS opcional aplicada ao botão da ação no header.
sections[].headerActions[].style Record<string, any> No n/a Active Estilo inline opcional aplicado ao botão da ação; propriedades inválidas podem ser saneadas pelo pipeline de rules/editor.
  • avatar-image aceita URL, data URL, File, Blob, ArrayBuffer, views tipadas e objetos com chaves como url, src, dataUrl, base64 ou bytes.
  • auto tenta imagem, depois iniciais vindas de initialsSourceField ou altField, e por fim o emptyState.
  • Se nenhum valor estiver disponível ainda, o runtime não falha: aplica emptyState e mantém o cabeçalho estável em fluxos create.
  • Nas superfícies de authoring da lib, sections[].headerActions[].action sugere o catálogo global canônico do core e mantém fallback para valor customizado livre por compatibilidade.
  • Quando a ação global selecionada exigir payload/param obrigatório, o authoring deve sinalizar isso explicitamente ao usuário antes da persistência; no caso de surface.open, o authoring canônico usa editor especializado em vez de texto cru.
  • Em formRules para targetType: 'section', o builder pode governar tanto sectionHeader inteiro quanto subpaths tipados como sectionHeader.mode, sectionHeader.emptyState e sectionHeader.size, além de headerActions como objeto agregado.
  • Em formRules, targets usam IDs canônicos do alvo. Para ações globais de formulário isso continua sendo o ID lógico da action; para ações de header de seção, o ID canônico é section:<sectionId>:header-action:<actionLogicalId>, evitando colisão com actions globais do form e entre seções.
  • Se a seção ainda não tiver id, o runtime aceita o fallback header-action:<actionLogicalId> por compatibilidade; para contratos persistidos, prefira sempre materializar section.id.

Field rule computed value contract

Regras com targetType: "field" podem usar effect.properties.value e effect.propertiesWhenFalse.value para escrever declarativamente o valor do FormControl alvo. O envelope canônico é fechado e exclusivo: exatamente { "expression": <JsonLogic> } para valores calculados ou exatamente { "literal": <valor> } para valores literais estruturados. Primitivos, null e arrays continuam aceitos como literais; objetos JSON Logic legados de operador único continuam aceitos para compatibilidade no runtime. O authoring visual e o editor JSON rejeitam objetos literais ambíguos sem envelope, como { "startDate": "...", "endDate": "..." }, e envelopes com chaves extras, como { "literal": 1, "expression": { "var": "age" } }. Valores calculados são resolvidos em uma fase anterior à aplicação das demais propriedades, com iteração limitada até estabilização, para que regras dependentes não fiquem acopladas à ordem do array.

Conditional command rule contract

Politica de erro do runtime: falhas de GlobalActionService.executeRef(...) em comandos condicionais sao fail-closed. Resultado success: false ou excecao assincrona gera diagnostico e nao reexecuta em loop enquanto a condicao continuar verdadeira. Quando GlobalActionService nao esta disponivel, acoes mutaveis (api.post, api.put, api.patch, api.delete) nao caem para customAction.

formCommandRules separa comandos com side effect das regras de propriedade. A regra é avaliada depois de formRules estabilizar fieldValues, então casos como birthDate -> age -> dialog.alert não dependem da ordem do array. O primeiro corte suporta apenas effects[].kind: "global-action" e executa globalAction via GlobalActionService.executeRef(...). Por padrão, comandos usam trigger: "on-condition-enter" e runOnInitialEvaluation: false; trigger: "while-true" não executa global-action nesta versão. distinct usa chave composta por componente, regra, efeito, action, contexto e valor de distinctBy, e a memória é limpa quando a condição volta a falso. No editor visual, payloadExpr permanece escape hatch de JSON avancado: o editor preserva payloadExpr existente quando nenhum payload estruturado e definido, mas campos estruturados authoram payload literal.

Exemplo:

{
  "formRules": [
    {
      "id": "birth-date-computes-age",
      "targetType": "field",
      "targets": ["age"],
      "effect": {
        "condition": { "!": [{ "isBlank": [{ "var": "birthDate" }] }] },
        "properties": {
          "value": { "expression": { "yearsSince": [{ "var": "birthDate" }] } }
        },
        "propertiesWhenFalse": {
          "value": { "literal": null }
        }
      }
    }
  ]
}

Visual block rule contract

Itens de layout kind: "richContent" podem ser alvo de formRules com targetType: "visualBlock". O target é sempre o id do item em sections[].rows[].columns[].items[]; o bloco visual não recebe entrada em fieldMetadata[], não cria FormControl e não entra em formSubmit.formData nem no payload HTTP.

Subconjunto público de propriedades suportadas para targetType: "visualBlock":

Propriedade Tipo Status Notes
visible / hidden boolean Active Exibe ou oculta o bloco no runtime.
layout "block" | "inline" Active Alterna a apresentação do item quando o layout aceita a variação.
className / rootClassName string Active Aplica classes controladas pelo host/design system.
style Record<string, any> Active Estilo visual saneado pelo pipeline de regras/runtime.
text string Active Sobrescreve texto apenas em documento simples ou node textual seguro.
title string Active Sobrescreve título apenas em documento simples, card/media/timeline suportado ou node identificado.
message string Active Sobrescreve mensagem apenas em documento simples, card/media suportado ou node identificado.
textNodeId / titleNodeId / messageNodeId string Active Seleciona explicitamente o node que receberá text, title ou message; o editor deve tratar como detalhe técnico guiado por seletor.

Exemplo canônico:

{
  "formRules": [
    {
      "id": "employee-guidance-by-status",
      "targetType": "visualBlock",
      "targets": ["employee-guidance-block"],
      "effect": {
        "condition": { "===": [{ "var": "ativo" }, false] },
        "properties": {
          "title": "Revise a inativação",
          "titleNodeId": "custom-title",
          "message": "Informe justificativa antes de salvar.",
          "messageNodeId": "custom-message",
          "className": "employee-guidance-warning"
        },
        "propertiesWhenFalse": {
          "title": "Cadastro ativo",
          "titleNodeId": "custom-title",
          "message": "Mantenha os dados funcionais atualizados.",
          "messageNodeId": "custom-message",
          "className": "employee-guidance-success"
        }
      }
    }
  ]
}

Limites de segurança:

  • text, title e message não aceitam HTML arbitrário, handlers, scripts ou substituição completa do RichContentDocument.
  • Em documentos compostos, prefira sempre textNodeId, titleNodeId ou messageNodeId; sem node explícito, o runtime só aplica override quando encontra alvo simples ou convencional seguro.
  • Regras de visualBlock são visual-only. Use campo local (fieldMetadata[].source: "local") quando a experiência precisar de valor, validação de campo, leitura em rawFormData ou participação explícita no payload via submitPolicy.

Output events

Event Payload Trigger Stability Notes
formSubmit FormSubmitEvent Submit validado do formulario. Partial formData e o payload persistivel filtrado; rawFormData preserva o valor completo do formulario, incluindo campos locais/transientes.
formCancel void Acao cancelar. Partial Preservado da documentação anterior.
formReset void Acao reset. Partial Preservado da documentação anterior.
configChange FormConfig Alteracoes de layout/config durante edicao. Partial Preservado da documentação anterior.
configPatchChange { inputPatch: { config?: FormConfig; resourcePath?: string | null; mode?: DynamicFormMode; presentationModeGlobal?: boolean | null; presentation?: DynamicFormPresentationSnapshot | null } } Alteracoes autoradas de configuracao que devem ser persistidas pelo host. Partial Contrato aditivo para hosts genericos sem alterar o payload legado de configChange.
formReady FormReadyEvent Form pronto para interacao. Partial Preservado da documentação anterior.
valueChange FormValueChangeEvent Alteracao de valor no form runtime. Partial Preservado da documentação anterior.
syncCompleted SyncResult Sincronizacao de schema/config concluida. Partial Preservado da documentação anterior.
initializationError FormInitializationError Falha de inicializacao. Partial Preservado da documentação anterior.
loadingStateChange LoadingState Mudanca de loading (config/schema/render/data). Partial Preservado da documentação anterior.
enableCustomizationChange boolean Alternancia do modo de customizacao. Partial Preservado da documentação anterior.
ruleDiagnosticsChange RuleApplicationDiagnostic[] Mudanca nos diagnosticos de aplicacao de formRules no runtime. Active Emite somente quando a assinatura dos diagnosticos muda; hosts podem exibir alerta, bloquear publicacao ou enviar telemetria.
customAction FormCustomActionEvent Acao custom definida no contrato ou ação do header de seção. Partial source pode ser button, shortcut ou section-header; quando vier de header, o payload inclui sectionId.
actionConfirmation FormActionConfirmationEvent Pedido de confirmacao de acao sensivel. Partial Preservado da documentação anterior.

External side channels

Channel Direction Contract Failure mode Notes
ASYNC_CONFIG_STORAGE bidirectional loadConfig/saveConfig/clearConfig fail-open Persistência de config, prefs de input e status de schema.
CONNECTION_STORAGE bidirectional loadConnection/saveConnection fail-open Hidrata/salva resourcePath quando não vem por input.
SettingsPanelService bidirectional open(...).applied$/saved$ fail-open Atualiza config em runtime sem recarregar host.
GenericCrudService outbound I/O configure/getSchema/filter/... fail-soft Integração de schema/dados remotos com fallback controlado.

Host/runtime dependencies

Dependency Required Environment Purpose Notes
GenericCrudService Yes browser/dev/prod schema/data runtime Fonte remota para criação/sincronização de config.
ASYNC_CONFIG_STORAGE Yes browser/dev/prod persistência Armazena config por formId/instância e flags de schema.
CONNECTION_STORAGE Yes browser/dev/prod persistência de conexão Reutiliza resourcePath salvo previamente.
FormRulesService Yes browser/dev/prod/ssr execução de regras Aplica formRules e recalcula comportamento de campos.
FormConfigService Yes browser/dev/prod/ssr validação e normalização Validação estrutural e utilitários de config.
MatDialog Optional browser/dev/prod confirmações e fluxos de ação Acionada em ações sensíveis conforme contrato.

Coverage matrix

Surface Verified Coverage status Evidence Notes
Runtime false Partial source_of_truth + conteudo preservado Revisao estrutural concluida; validacao comportamental fina pode exigir follow-up.
Schema/Types true Partial interfaces/modelos citados Mapeamento formal de todos os campos ainda pode requerer refinamento.
Editor/Tooling false Partial secoes de editor quando presentes Cobertura de editor/tooling nem sempre confirmada por evidencia direta.

Runtime coverage boundaries

  • Cobertura consolidada com base em documentacao existente e source of truth declarado.
  • Comportamentos fora de evidencia direta foram marcados como not-yet-verified ou Partial.
  • Compatibilidade legada, quando detectada, foi separada em classificacao explicita.

Resolution model

Merge order

  1. inputs explícitos (config, resourcePath, mode, flags globais)
  2. hidratação de preferências de input (formInputsKey) e conexão persistida
  3. initializeForm(): config local persistida (formConfigKey) ou criação a partir do servidor
  4. normalização final via normalizeFormConfig()
  5. overrides de runtime (hooks, backConfig, customEndpoints, presentation vars)

Fallback order

config local persistida -> config default criada do schema remoto -> erro de inicialização (quando formId e uma fonte schema-backed, resourcePath ou schemaUrl, estão ausentes no fluxo corporativo).

Override points

  • @Input() públicos (config, hooks, layout, backConfig, customEndpoints)
  • edição em runtime via SettingsPanelService
  • persistência de host (ASYNC_CONFIG_STORAGE, CONNECTION_STORAGE)

Runtime normalization

  • normalizeFormConfig() estabiliza ids e estrutura antes do build/render.
  • applyPresentationVars() resolve precedência entre configuração persistida e config em memória.
  • resolveSchemaPrefs() consolida preferências locais e fallback global de notificação de drift.

Precedence rules

  • @Input() hooks sobrescreve config.hooks por estágio.
  • backConfig.confirmOnDirty sobrescreve behavior.confirmOnUnsavedChanges.
  • resourcePath explícito no input tem precedência sobre conexão persistida.

Validation and error semantics

Validation model

Path/Rule Validation phase Behavior on fail Error code / warning Notes
formId + (resourcePath ou schemaUrl) no fluxo corporativo init hard-fail + initializationError config-load Inicialização não prossegue sem identidade e fonte schema-backed.
presentationModeGlobal=true com mode != view input-change warning + ignore runtime warning Sem bloqueio; render segue em input mode.
config recebido por input input-change normalize + rebuild n/a normalizeFormConfig antes de renderização.
validação de config (editor/runtime) pre-apply reject when invalid FormConfigService.validateConfig Erros retornados ao host via outputs/eventos.
verificação de hash de schema remoto background runtime mark outdated + emit status schemaStatusChange Não aplica schema remoto automaticamente em background.

Error semantics

Falhas de inicialização (config-load/form-build) são bloqueantes e emitem initializationError. Divergências de schema são tratadas como estado (schemaOutdated) com emissão de evento, sem interromper formulário já carregado.

No submit, RestApiResponse.errors é materializado somente quando a resposta possui status HTTP 4xx conhecido. Cada detalhe cujo target resolve um controle é anexado como erro server, sem remover validadores do cliente, e desaparece quando aquele controle muda. Erros de outros campos permanecem ativos; todos os erros de servidor são limpos no início da próxima tentativa e após sucesso. target aceita path Angular pontuado ou JSON Pointer. Targets desconhecidos não são inferidos por texto e continuam como feedback global.

Precedência do feedback: resposta 4xx com detalhes governados > mensagem customizada de submit ou create/update > fallback normalizado e localizado. Falhas de rede, respostas 5xx e respostas sem status confiável nunca expõem message/errors do payload e usam as chaves global.submitError.*. visibleWhen, mensagens locais e validação visual não substituem a autorização e a validação de negócio do backend.

Fail-open / fail-closed behavior

Condition Mode Runtime behavior Consumer impact
Falha ao ler config local/prefs fail-open segue com fluxo remoto/default formulário ainda inicia quando possível
formId ausente ou sem resourcePath/schemaUrl (fluxo corporativo) fail-closed aborta inicialização host recebe initializationError
schema remoto indisponível com fallback legado disponível fail-open usa fonte legada (crud.getSchema) mantém operação com cobertura parcial
payload de config inválido reject não aplica configuração prevenir estado inconsistente no runtime

Invalid or unknown field handling

  • Campos desconhecidos: comportamento depende da estrategia do componente (ignore, warn ou reject).
  • Campos invalidos: podem gerar fallback, warning ou falha conforme implementacao.
  • Registrar divergencias observadas em Known limitations and mismatches.

Runtime warnings vs hard failures

Condition Severity Observability Consumer action
partial-or-declared-only-coverage warning logs/eventos do componente confirmar ligacao runtime antes de uso critico

Detailed API

Preserved technical reference (normalized from previous revision)

Referencia canonica da JSON API do praxis-dynamic-form, com foco em:

  • contrato declarado (FormConfig + inputs/outputs do componente);
  • comportamento que o runtime consome de fato;
  • limites conhecidos para uso corporativo (governanca, observabilidade, UX e risco).

Legenda de suporte:

  • Active: consumido no runtime atual.
  • Partial: consumido parcialmente (subconjunto funcional).
  • Declared-only: declarado no contrato, sem consumo direto no runtime atual.

Table of contents

Overview

praxis-dynamic-form e um runtime de formulario schema-driven orientado por FormConfig.

Fluxo macro:

  1. Resolve configuracao (local, remota ou defaults).
  2. Normaliza estrutura (sections/rows/columns/fieldMetadata) e IDs.
  3. Monta FormGroup, aplica regras e estados globais.
  4. Renderiza campos via DynamicFieldLoaderDirective.
  5. Executa submit/cancel/reset/custom actions com hooks e mensagens.
  6. Emite eventos para host (estado, erros, sincronizacao e acao).

No ecossistema Praxis, ele funciona tanto como runtime final quanto como superficie de edicao (settings panel + config editor) para round-trip de JSON.

Checklist corporativo pre-flight

  • Defina formId estavel por tela/uso para evitar colisao de persistencia.
  • Em cenarios multi-instancia na mesma pagina, use componentInstanceId.
  • Se o formulario for remoto, valide resourcePath e ciclo de schema (schemaStatusChange).
  • Declare explicitamente estrategia de modos (create/edit/view) no host.
  • Trate fieldRenderError no host para observabilidade de render por campo.
  • Garanta autorizacao no backend para submit/custom actions; regras visuais no front nao sao controle de acesso.

API

Component inputs

initialValue is part of the public runtime contract and accepts Record<string, unknown> | null for local initial values.

Input Tipo Default Status Runtime notes
config FormConfig { sections: [] } Active Contrato principal consumido no ciclo inteiro. sections é opcional somente para forms schema-driven com grounding explícito (metadata.source='schema', schema metadata ou fonte runtime como schemaUrl/resourcePath); ausência de layout manual é normalizada internamente como array vazio e permite que layoutPolicy/schema materializem agrupamentos.
resourcePath string | undefined undefined Active Habilita carga de schema/dados remotos. Opcional quando schemaUrl explícito é fornecido.
resourceId string | number | undefined undefined Active Carrega entidade no modo edit/view; em create, funciona apenas como contexto do item e não dispara hidratação.
mode 'create' | 'edit' | 'view' 'create' Active Governa submit, leitura e apresentacao.
schemaSource 'resource' | 'filter' 'resource' Active Seleciona origem do schema remoto.
schemaUrl string | undefined undefined Active Permite usar schema canonico publicado pelo backend sem heuristica local de path e pode iniciar o fluxo corporativo sem resourcePath.
readUrl string | undefined undefined Active Hidrata dados de surfaces de leitura/projecao pelo endpoint publicado, preservando resourcePath como recurso dono.
apiEndpointKey ApiEndpoint | string | undefined undefined Active Resolve schemaUrl, readUrl e submitUrl relativos contra a origem canonica correta em hosts destacados.
apiUrlEntry ApiUrlEntry | undefined undefined Active Porta a entrada de API ja resolvida para overlays/dialogs que nao herdam o provider de API_URL da rota atual.
domainRules PraxisDynamicFormDomainRulesOptions | boolean | null null Active Opt-in para carregar materializacoes de regras compartilhadas em /api/praxis/config/domain-rules/materializations e combina-las com config.formRules.
submitUrl string | undefined undefined Active Executa submit canonico publicado por surface ou action, sem inferencia local de CRUD.
submitMethod 'post' | 'put' | 'patch' | undefined undefined Active Metodo HTTP do submit canonico; deve acompanhar submitUrl.
submitIdempotencyKey string | undefined undefined Active Envia Idempotency-Key e preserva a identidade entre retries da mesma tentativa.
submitCorrelationId string | undefined undefined Active Envia X-Correlation-Id para rastreabilidade corporativa ponta a ponta.
submitResourceVersion string | number | undefined undefined Active Envia a versão esperada como If-Match, sem inferir concorrência a partir do formulário.
submitResourceVersionTargetResourceKey string | undefined undefined Active Quando não há submitResourceVersion estático, descobre o path do recurso canônico exato e lê o registro selecionado imediatamente antes do comando. É input runtime materializado pela action, não configuração de negócio authorável.
submitResourceVersionTargetIdField string | undefined undefined Active Lê do payload preparado o identificador escalar do alvo concorrente e exige ETag na resposta de leitura. Não aceita labels, objetos de lookup ou fallback para id.
responseSchemaUrl string | undefined undefined Active Porta diagnóstica/read-only; não deve ser usada para mesclar propriedades do schema de resposta no formulário de comando.
enableCustomization boolean false Active Habilita UX de customizacao do layout.
formId string | undefined undefined Active Chave de persistencia e identidade logica.
componentInstanceId string | undefined undefined Active Isola instancias com mesmo formId.
configPersistenceStrategy 'local-first' | 'input-first' 'local-first' Active Em input-first, os inputs fornecidos pelo host, inclusive mode, permanecem autoritativos sobre preferencias persistidas da mesma instancia. Combine com layoutPolicy.persistence='transient' em commands efemeros para nao carregar nem gravar layout local.
layout FormLayout | undefined undefined Partial Funciona como override estrutural em parte dos fluxos de layout/editor.
generatedLayoutPreset 'default' | 'compactPresentation' 'default' Active Usado apenas ao criar a configuracao inicial a partir de schema/metadata; nao reprocessa layouts persistidos ou authorados.
layoutPolicy DynamicFormLayoutPolicy | null null Active Politica opt-in para materializar layout a partir do schema atual. Use source: 'schema' com persistence: 'transient' para detalhe/read-only e command forms schema-driven sem persistir sections geradas nem reabrir configuracao local salva; politicas de host em config, como helpPresentation, continuam sendo aplicadas ao layout materializado. Em mode='view', intent: 'detail' ou preset: 'compactPresentation' ativa apresentacao quando presentationModeGlobal nao foi informado; use [presentationModeGlobal]=false para controles read-only tradicionais. No preset compactPresentation, x-ui.width explicito empacota campos em linhas de 12 colunas e tem precedencia sobre detailSummary.columns por default; campos sem width permanecem full-width, a menos que detailSummary.columns/responsiveColumns declare a densidade do resumo. Use detailSummary.widthPrecedence='summary' quando a densidade do resumo read-only deve sobrescrever x-ui.width apenas nessa surface compacta. No preset groupedCommand, groupedCommand.orphanFieldExpansion controla linhas logicas com um unico campo: medium-and-wide (default) expande spans 6/8, preserve mantem o width publicado e all tambem expande campos compactos. groupedCommand.partialRowStrategy usa preserve por default; fill-compatible particiona o grupo nas linhas visuais depois de resolver visibilidade responsiva, CSS order e wrap em cada breakpoint/container, projeta cada linha parcial elegivel em spans canônicos que completam 12 colunas e mapeia o resultado de volta as colunas authoradas apenas para renderizacao, sem alterar x-ui.width, sections ou o documento de authoring. Um singleton elegivel criado por wrap pode preencher sua linha visual; controles compactos, uploads e tipos desconhecidos preservam seus spans. groupedCommand.contextFields identifica campos schema-backed já hidratados pela surface: eles permanecem no FormGroup e no payload, mas não renderizam controles redundantes. Use responsiveColumns, por exemplo { lg: 3, md: 2, sm: 1 }, para drawers, side sheets e painéis corporativos estreitos sem copiar FormConfig.sections locais. schemaType e schemaOperation sao validados contra schemaUrl quando a URL declara esses parametros.

O authoring emite o warning dynamicForm.config.layout.groupedCommand.row.incomplete quando uma linha gerada com dois ou mais campos ocupa menos de 12 colunas. Com partialRowStrategy='fill-compatible', o warning desaparece quando a projeção resolve a linha; ele permanece acionável para preserve ou quando controles compactos/fixos/desconhecidos não podem ser redistribuídos. | backConfig | BackConfig \| undefined | undefined | Active | Integra retorno/navegacao no painel de configuracao; confirmOnDirty tem precedencia sobre behavior.confirmOnUnsavedChanges no cancel. | | hooks | FormHooksLayout \| undefined | undefined | Active | Override direto de hooks sobre config.hooks. | | customEndpoints | EndpointConfig | {} | Active | Override de endpoints no CRUD service interno. | | removeEmptyContainersOnSave | boolean | false | Active | Sanitiza secoes/linhas/colunas vazias na persistencia de config. | | reactiveValidation | boolean \| null | null | Active | Override de validacao reativa (valueChanges). | | reactiveValidationDebounceMs | number \| null | null | Active | Debounce da validacao reativa. | | notifyIfOutdated | 'inline' \| 'snackbar' \| 'both' \| 'none' | 'both' | Active | Canal de aviso de schema desatualizado quando a customizacao estiver ativa. | | snoozeMs | number | 86400000 | Active | Janela de supressao de notificacao. | | autoOpenSettingsOnOutdated | boolean | false | Active | Auto-abertura do settings quando schema diverge. | | readonlyModeGlobal | boolean \| null | null | Active | Estado global de leitura propagado para loader. | | disabledModeGlobal | boolean \| null | null | Active | Estado global de desabilitado propagado para loader. | | presentationModeGlobal | boolean \| null | null | Active | Modo apresentacao global (efetivo em view). | | fieldIconPolicy | 'all' \| 'presentation-only' \| 'none' | 'all' | Active | Controla icones prefixIcon/suffixIcon vindos da metadata dos campos. all preserva o comportamento atual; presentation-only mantem icones decorativos no modo apresentacao e oculta os slots de icone em controles input/read-only tradicionais; none oculta esses slots em todos os modos. | | visibleGlobal | boolean \| null | null | Active | Visibilidade global propagada para loader. |

Perfil público local somente-leitura

PRAXIS_DYNAMIC_FORM_COMPONENT_METADATA.runtimeProfiles publica public-local-readonly para hosts públicos não confiáveis. O profile aceita somente mode='view', readonlyModeGlobal=true, estratégia input-first, initialValue local e um subconjunto explícito de chaves de config, layout e FieldMetadata. Controles remotos, endpoints, option sources, rich content, hooks, rules, commands, actions, customização, assistente e IDs de persistência invalidam o profile. Chaves desconhecidas também invalidam o documento para que novas capacidades futuras não sejam liberadas implicitamente.

O profile declara effects: [] e não é grant de autorização. O host continua responsável por validar o candidate e bloquear rede por padrão. No runtime, onSubmit() retorna sem emitir evento e sem chamar create/update quando o form está em readonly ou presentation, inclusive em submit programático.

In compactPresentation runtime detail surfaces, rows, columns and sections are visible only when they contain at least one field that can be materialized after metadata visibility and field-rule overrides are resolved. Boolean values, including false, are valid presentation values and must not be treated as empty detail content. If no field in a section is materialized, the section is hidden instead of rendering an orphan title.

Migration baseline for ErgonX-style screens

For enterprise migrations that must become templates for many screens, layoutPolicy, helpPresentation and fieldIconPolicy should be selected as part of the DTO/schema handoff, not patched locally after visual review.

Recommended baseline:

Surface Inputs Contract gate
Detail/read-only layoutPolicy.source='schema', intent='detail', preset='compactPresentation', persistence='transient', schemaType='response' Response DTO publishes business grouping, order, labels, value presentation and safe widths.
Create/edit layoutPolicy.source='schema', intent='command', preset='groupedCommand', persistence='transient', schemaType='request' Request DTO/write contract publishes only editable fields, validators, options and help text required for the command.
Dense command drawer config.helpPresentation.display='auto' with preferPopoverForControls for select, checkbox, toggle, date/datepickers and numeric controls DTO help text is semantic and not a substitute for validation messages.
Input-heavy operational form fieldIconPolicy='presentation-only' Icons remain useful in read-only presentation but do not crowd editable controls.

If a field requires a local label, local help text, local option mapping or local code/description composition to look correct, the schema is not ready for scalable migration. Fix the backend DTO, OpenAPI x-ui metadata or option/value-presentation contract first.

Regras compartilhadas materializadas

domainRules separa regra corporativa compartilhavel de regra materializada no FormConfig. Quando habilitado, o componente consulta o backend de configuracao via DomainRuleFormRulesService, transforma cada materializacao em FormLayoutRule e aplica a lista combinada:

  1. config.formRules
  2. regras vindas de domain_rule_materialization.materializedPayload

Exemplo:

<praxis-dynamic-form
  formId="funcionarios-form-demo"
  [config]="formConfig"
  [domainRules]="{
    enabled: true,
    targetArtifactKey: 'funcionarios-form-demo',
    targetLayer: 'form_config',
    targetArtifactType: 'praxis-dynamic-form',
    status: 'applied'
  }">
</praxis-dynamic-form>

Campos de PraxisDynamicFormDomainRulesOptions:

Campo Tipo Default Observacao
enabled boolean false Deve ser true para consultar o backend.
targetArtifactKey string | null `formId
targetLayer string | null 'form_config' Camada alvo persistida no backend.
targetArtifactType string | null 'praxis-dynamic-form' Tipo do artefato alvo.
status string | null undefined Filtro opcional. Para consumo runtime, prefira applied; pending_review pertence a etapas de governanca antes da aplicacao.

Materializacoes diretas podem persistir um FormLayoutRule em materializedPayload. O adaptador tambem reconhece operation: "rule.visualBlockGuidance.add" e converte para regra targetType: "visualBlock" como projecao visual derivada, preservando rastreabilidade em metadata.domainRule sem transformar o formulario em fonte primaria da regra de negocio. Quando o backend enviar decisionDiagnostics, o adaptador carrega esse envelope para metadata.domainRule.decisionDiagnostics, incluindo sourceHashPresent e sourceHash quando disponiveis, mantendo a explicacao canonica da decisao semanticamente authorada por IA junto da regra derivada, sem transformar o formulario em fonte primaria da regra de negocio.

Teste vivo de referencia:

PAX_PROXY_TARGET=https://praxis-api-quickstart.onrender.com \
node scripts/run-playwright-with-dev-host.js \
  --port 4003 \
  --path /funcionarios-form-demo \
  --spec projects/praxis-dynamic-form/test-dev/e2e/funcionarios-form-demo-domain-rules.playwright.spec.ts

Validado em 2026-04-23 contra praxis-api-quickstart publicado no Render com praxis-config-starter:0.1.0-rc.22: o spec confirmou resposta 200 de /api/praxis/config/domain-rules/materializations e presença de materialização form_config com operation: "rule.visualBlockGuidance.add".

Component outputs

Output Payload Quando emite
formSubmit FormSubmitEvent Submit validado do formulario.
formCancel void Acao cancelar.
formReset void Acao reset.
configChange FormConfig Alteracoes de layout/config durante edicao.
configPatchChange { inputPatch: { config?: FormConfig; resourcePath?: string | null; mode?: DynamicFormMode; presentationModeGlobal?: boolean | null; presentation?: DynamicFormPresentationSnapshot | null } } Alteracoes autoradas de configuracao que devem ser persistidas pelo host.
formReady FormReadyEvent Form pronto para interacao.
valueChange FormValueChangeEvent Alteracao de valor no form runtime.
syncCompleted SyncResult Sincronizacao de schema/config concluida.
initializationError FormInitializationError Falha de inicializacao.
loadingStateChange LoadingState Mudanca de loading (config/schema/render/data).
enableCustomizationChange boolean Alternancia do modo de customizacao.
customAction FormCustomActionEvent Acao custom definida no contrato ou ação do header de seção.
actionConfirmation FormActionConfirmationEvent Pedido de confirmacao de acao sensivel.
schemaStatusChange { outdated, serverHash?, lastVerifiedAt?, formId? } Mudanca de estado de desatualizacao de schema.
fieldRenderError { phase, fieldName, error, fatal } Erro de render de campo emitido pelo DynamicFieldLoader.
ruleDiagnosticsChange RuleApplicationDiagnostic[] Diagnosticos de regras invalidas, incompletas ou parcialmente saneadas durante aplicacao runtime.

Data mode e fluxo

  • mode='create': cria registro ou materializa um comando; nunca carrega a entidade por resourceId, e valores iniciais devem vir de initialValue.
  • mode='edit': carrega entidade por resourceId quando disponivel.
  • mode='view': foco em leitura/apresentacao; actions de edicao podem ser suprimidas.

Precedencias importantes:

  1. Inputs explicitos do host (ex.: reactiveValidation) sobrescrevem comportamento no config.behavior.
  2. hooks input sobrescreve config.hooks.
  3. Preferencias de outdated schema combinam input + widget/global defaults.

FormConfig coverage matrix

JSON path Status Runtime notes
sections[] Active Render estrutural principal (section/row/column).
fieldMetadata[] Active Fonte de campos para DynamicFieldLoader.
metadata Active Usado em reconciliacao/snapshot/status de schema.
actions Active Render de praxis-form-actions e roteamento de eventos.
behavior Partial Subset funcional (detalhado abaixo).
api Declared-only Declarado no modelo; sem binding operacional direto no runtime atual.
messages Partial Chaves principais de submit/confirmacao usadas; contrato e mais amplo.
formRules Active Aplicadas no pipeline de regras do runtime.
formRulesState Internal Persistido somente como estado de round-trip do builder visual; nao e contrato autoravel.
hooks Active Integracao de ciclo (before/after) via runtime de hooks.
hints Declared-only Mantido no contrato/editor; sem render dedicado no template principal.

Behavior e Messages coverage detalhado

behavior.*

Caminho Status Observacao
behavior.confirmOnUnsavedChanges Active Governa confirmacao antes de cancelar quando backConfig.confirmOnDirty nao estiver definido; sem politica explicita, cancel dirty usa fallback seguro com confirmacao.
behavior.disableMountAnimation Active Desliga animacao inicial do form.
behavior.mountAnimation.durationMs/offsetPx/staggerMs Active Ajuste fino da animacao de montagem.
behavior.reactiveValidation Active Liga validacao reativa com hooks afterValidate.
behavior.reactiveValidationDebounceMs Active Debounce da validacao reativa.
behavior.trackHistory Declared-only Sem consumo direto no runtime atual.
behavior.focusFirstError Active No submit invalido, foca o primeiro campo invalido encontrado.
behavior.scrollToErrors Active No submit invalido, faz scroll para o primeiro campo invalido.
behavior.clearAfterSave Active No submit com sucesso, limpa o formulario quando habilitado.
behavior.redirectAfterSave Active No submit com sucesso navega via Router.navigateByUrl quando Router estiver disponivel; sem Router, emite warning e nao navega.

messages.*

Caminho Status Observacao
messages.loading.submit Active Mensagem de loading durante submit.
messages.confirmations.* Active Confirmacoes pre-acao (submit/cancel/reset/custom).
messages.customActions[actionId].confirmation Active Prioridade sobre confirmations[actionId].
messages.customActions.submit.success/error Active Mensagens de resultado no submit customizado.
messages.createRegistrySuccess/updateRegistrySuccess Active Feedback de sucesso create/edit.
messages.createRegistryError/updateRegistryError Active Feedback de erro create/edit.
Campos extras em messages Partial Contrato aceita extensao, mas nem todas as chaves sao exibidas no runtime atual.

DynamicFieldLoader error bridge

praxis-dynamic-form encaminha erros de render por campo para o host via fieldRenderError.

Payload:

{
  phase: 'executeRendering' | 'detectChanges';
  fieldName: string;
  error: unknown;
  fatal: boolean;
}

Politica atual do loader:

  • Erro por campo nao derruba automaticamente o formulario inteiro.
  • Erros de lifecycle Angular (NG0205, injector/view destroyed) sao marcados como fatal=true para o ciclo atual.
  • O runtime evita emissao duplicada quando o erro fatal ja foi reportado em etapa anterior.

Recomendacao corporativa:

  • Capture fieldRenderError no host e envie para telemetria com formId, resourcePath, mode e fieldName.
  • Use alerta operacional apenas para fatal=true repetido em ambiente de producao.

Seguranca e fronteiras de responsabilidade

  • hidden, readonly, disabled, presentation sao controles de UX no front-end.
  • Validacao e autorizacao de negocio devem ser reforcadas no backend.
  • Acoes custom emitidas pelo componente (customAction) nao substituem checagens de permissao server-side.

Exemplos JSON

1) Baseline create/edit (foco em contrato ativo)

{
  "sections": [
    {
      "id": "main",
      "title": "Cadastro",
      "rows": [
        {
          "id": "r1",
          "columns": [
            { "id": "c1", "fields": ["name", "email"] }
          ]
        }
      ]
    }
  ],
  "fieldMetadata": [
    { "name": "name", "label": "Nome", "controlType": "input", "required": true },
    { "name": "email", "label": "Email", "controlType": "input" }
  ],
  "behavior": {
    "confirmOnUnsavedChanges": true,
    "reactiveValidation": true,
    "reactiveValidationDebounceMs": 200
  },
  "messages": {
    "loading": { "submit": "Salvando cadastro..." },
    "confirmations": { "cancel": "Descartar alteracoes?" },
    "createRegistrySuccess": "Registro criado com sucesso",
    "updateRegistrySuccess": "Registro atualizado com sucesso"
  }
}

2) View + apresentacao global

{
  "sections": [
    {
      "id": "view-main",
      "title": "Resumo",
      "rows": [
        {
          "id": "vr1",
          "columns": [
            { "id": "vc1", "fields": ["status", "owner"] }
          ]
        }
      ]
    }
  ],
  "fieldMetadata": [
    { "name": "status", "label": "Status", "controlType": "input" },
    { "name": "owner", "label": "Responsavel", "controlType": "input" }
  ],
  "actions": {
    "submit": { "visible": false, "label": "Salvar" },
    "cancel": { "visible": true, "label": "Voltar" },
    "reset": { "visible": false, "label": "Limpar" }
  }
}

No host Angular:

<praxis-dynamic-form
  [config]="formConfig"
  mode="view"
  [presentationModeGlobal]="true"
  (fieldRenderError)="onFieldRenderError($event)"
  (ruleDiagnosticsChange)="onRuleDiagnosticsChange($event)">
</praxis-dynamic-form>

ruleDiagnosticsChange nao aplica UI propria no formulario. Ele existe para governanca do host: logar regras invalidas, sinalizar configuracao inconsistente ao autor ou impedir publicacao de metadata sem esconder o problema dentro do runtime. O runtime emite target-not-found quando uma regra aponta para section, row, column, action ou visualBlock inexistente no FormConfig resolvido; para campos, o codigo legado field-target-not-found permanece.

Known limitations and pending investigation

  1. FormConfig.api segue Declared-only no runtime principal.
  2. Cobertura de behavior e parcial; varios campos continuam sem binding dedicado.
  3. Cobertura de messages e parcial para chaves fora do fluxo principal de submit/confirmacao.
  4. Ainda falta bateria de stress dedicada para corrida teardown/render alem de NG0205.
  5. hints permanece no contrato/editor sem exposicao no template principal.

Source references

  • projects/praxis-dynamic-form/src/lib/praxis-dynamic-form.ts
  • projects/praxis-dynamic-form/src/lib/praxis-dynamic-form.html
  • projects/praxis-dynamic-form/src/lib/config-editor/praxis-dynamic-form-config-editor.ts
  • projects/praxis-dynamic-fields/src/lib/directives/dynamic-field-loader.directive.ts
  • projects/praxis-core/src/lib/models/form/form-config.model.ts
  • projects/praxis-core/src/lib/models/form/form-layout.model.ts

JSON path index

Path Type Required Default Status Notes
sections[] not-specified not-specified n/a Active Render estrutural principal (section/row/column).
fieldMetadata[] not-specified not-specified n/a Active Fonte de campos para DynamicFieldLoader.
metadata not-specified not-specified n/a Active Usado em reconciliacao/snapshot/status de schema.
actions not-specified not-specified n/a Active Render de praxis-form-actions e roteamento de eventos.
behavior not-specified not-specified n/a Partial Subset funcional (detalhado abaixo).
api not-specified not-specified n/a Declared-only Declarado no modelo; sem binding operacional direto no runtime atual.
messages not-specified not-specified n/a Partial Chaves principais de submit/confirmacao usadas; contrato e mais amplo.
formRules not-specified not-specified n/a Active Aplicadas no pipeline de regras do runtime.
formRulesState internal-round-trip Gerado pelo builder visual; nao e alvo de autoria manual ou IA. n/a Internal Estado visual derivado de formRules para reabertura do editor.
hooks not-specified not-specified n/a Active Integracao de ciclo (before/after) via runtime de hooks.
hints not-specified not-specified n/a Declared-only Mantido no contrato/editor; sem render dedicado no template principal.

Events

Event Payload Trigger Stability Notes
formSubmit FormSubmitEvent Submit validado do formulario. Partial formData e o payload persistivel filtrado; rawFormData preserva o valor completo do formulario, incluindo campos locais/transientes.
formCancel void Acao cancelar. Partial Preservado da documentação anterior.
formReset void Acao reset. Partial Preservado da documentação anterior.
configChange FormConfig Alteracoes de layout/config durante edicao. Partial Preservado da documentação anterior.
configPatchChange { inputPatch: { config?: FormConfig; resourcePath?: string | null; mode?: DynamicFormMode; presentationModeGlobal?: boolean | null; presentation?: DynamicFormPresentationSnapshot | null } } Alteracoes autoradas de configuracao que devem ser persistidas pelo host. Partial Contrato aditivo para hosts genericos sem alterar o payload legado de configChange.
formReady FormReadyEvent Form pronto para interacao. Partial Preservado da documentação anterior.
valueChange FormValueChangeEvent Alteracao de valor no form runtime. Partial Preservado da documentação anterior.
syncCompleted SyncResult Sincronizacao de schema/config concluida. Partial Preservado da documentação anterior.
initializationError FormInitializationError Falha de inicializacao. Partial Preservado da documentação anterior.
loadingStateChange LoadingState Mudanca de loading (config/schema/render/data). Partial Preservado da documentação anterior.
enableCustomizationChange boolean Alternancia do modo de customizacao. Partial Preservado da documentação anterior.
customAction FormCustomActionEvent Acao custom definida no contrato ou ação do header de seção. Partial source pode ser button, shortcut ou section-header; quando vier de header, o payload inclui sectionId.
actionConfirmation FormActionConfirmationEvent Pedido de confirmacao de acao sensivel. Partial Preservado da documentação anterior.

Styling API

Token/Class Scope Purpose Notes
.praxis-dynamic-form root container raiz visual/estrutural do runtime Recebe classes derivadas de modo, estado e montagem no template principal.
.form-loading / .form-error state containers feedback de carregamento e falha de inicializacao Acionados durante bootstrap/config/schema e erros de inicializacao.
.pfx-form-info-banner schema-drift banner aviso de schema desatualizado + CTA de reconciliacao Exibicao condicionada por notifyIfOutdated e estado de drift.
--pdx-form-mount-duration / --pdx-form-mount-offset / --pdx-form-mount-stagger css vars (host style) controle de animacao de montagem Definidos por bindings de estilo no host da raiz do formulario.

Editor and tooling notes

  • Cobertura de editor/tooling foi separada da cobertura de runtime para evitar confusao de suporte.
  • Quando nao houver evidencia direta no codigo, o status deve permanecer not yet verified.

Examples

Minimal valid

{
  "sections": []
}

Typical/common

{
  "sections": [
    {
      "id": "main",
      "title": "Dados",
      "sectionHeader": {
        "mode": "auto",
        "sourceField": "employeePhoto",
        "initialsSourceField": "fullName",
        "altField": "fullName"
      },
      "rows": [
        {
          "id": "r1",
          "columns": [
            {
              "id": "c1",
              "span": 12,
              "fields": ["fullName"]
            }
          ]
        }
      ]
    }
  ],
  "fieldMetadata": [
    { "name": "employeePhoto", "label": "Foto", "controlType": "input" },
    { "name": "fullName", "label": "Nome", "controlType": "input" }
  ]
}

Advanced

{
  "sections": [],
  "behavior": {
    "reactiveValidation": true,
    "reactiveValidationDebounceMs": 300
  },
  "messages": {
    "customActions": {
      "submit": {
        "success": "Registro salvo com sucesso."
      }
    }
  },
  "hooks": {
    "beforeSubmit": [
      {
        "type": "custom",
        "handler": "sanitizePayload"
      }
    ]
  }
}

Enterprise scenario

{
  "sections": [],
  "api": {
    "resourcePath": "customers",
    "schemaSource": "resource"
  },
  "behavior": {
    "notifyIfOutdated": "both",
    "autoOpenSettingsOnOutdated": true
  },
  "messages": {
    "global": {
      "saveError": "Nao foi possivel salvar no momento."
    }
  }
}

Known limitations and mismatches

Path/Behavior Observed behavior (runtime) Desired behavior Impact Tracking issue Target fix
coverage/mapping Evidência textual preservada indica itens Partial/Declared-only. Cobertura confirmada por evidência runtime + schema + editor. Pode gerar uso de paths não totalmente ligados. to-be-linked next-doc-cycle

Compatibility and migration notes

Concern Affected versions Migration action Deadline Notes
legacy aliases and mixed status vocabulary pre-canonical docs unificar para taxonomia canonica (Active/Partial/Declared-only/...) next-doc-cycle manter backward compatibility documentada

Source references

Source type Path/URL Why it is source of truth Last verified (YYYY-MM-DD) Notes
local-file projects/praxis-dynamic-form/src/lib/praxis-dynamic-form.ts Evidencia de implementacao e contrato. 2026-03-05 referencia preservada da versao anterior
local-file projects/praxis-dynamic-form/src/lib/praxis-dynamic-form.html Evidencia de implementacao e contrato. 2026-03-05 referencia preservada da versao anterior
local-file projects/praxis-dynamic-form/src/lib/config-editor/praxis-dynamic-form-config-editor.ts Evidencia de implementacao e contrato. 2026-03-05 referencia preservada da versao anterior
local-file projects/praxis-dynamic-fields/src/lib/directives/dynamic-field-loader.directive.ts Evidencia de implementacao e contrato. 2026-03-05 referencia preservada da versao anterior
local-file projects/praxis-core/src/lib/models/form/form-config.model.ts Evidencia de implementacao e contrato. 2026-03-05 referencia preservada da versao anterior
local-file projects/praxis-core/src/lib/models/form/form-layout.model.ts Evidencia de implementacao e contrato. 2026-03-05 referencia preservada da versao anterior

Presentation style projection and editor UX

  • contextSnapshot.presentation is the canonical style snapshot. The optional runtime input presentation: DynamicFormPresentationSnapshot | null projects it into page widgets independently of schema-generated config. Explicit styles take precedence over stored style preferences; null restores defaults and blocks stale stored overrides; omission retains normal style resolution.
  • Runtime editor Apply/Save emits presentation with mode and presentationModeGlobal in configPatchChange.inputPatch. Widget save/reopen preserves the same snapshot; omitting the document block clears the widget projection with null.
  • Numeric font sizes and label widths are pixels. Capturing a runtime rem size converts it using the host root font size; opening and saving must not reinterpret 0.78rem as 0.78px.
  • Geral → Dados do formulário separates Criar / Editar / Visualizar from Automático / Campos / Apresentação. Selecting presentation in Create/Edit keeps the operation unchanged and explains the inactive state with an explicit action to switch to View.
  • Estilo da apresentação remains discoverable regardless of the current mode. It previews sample data and does not activate presentation by itself. Filter Form does not expose this tab because it has no presentation runtime.
  • Applying or finishing widget editing updates the page draft. Salvar página persists the composition. Shortening sample text affects the preview only.

Orientação antes da seleção de um registro

O editor nativo, em Geral → Sem registro selecionado, materializa o contrato existente PraxisDynamicFormEmptyState em bindings.emptyState. O wrapper Page Builder projeta esse binding para inputs.emptyState; Apply, Save e JSON usam o mesmo documento. Não pertence a FormConfig nem substitui o modo dos dados.

title é obrigatório e não pode conter apenas espaços. description e icon são textos opcionais; a cópia de negócio permanece literal, sem ser interpretada automaticamente como chave i18n. O seletor usa o catálogo canônico de ícones. Restaurar o ícone padrão limpa a escolha explícita. Os controles do editor usam o catálogo i18n Form; a aparência runtime usa os tokens do empty state compartilhado.

As opções de aparência ficam em disclosure avançado: tone (neutral, primary, secondary), variant (card, inline, panel, transparent), alignment (start, center), density (compact, comfortable) e iconContainer (none, circle, soft). Ausência de opção herda o padrão do componente; JSON inválido produz diagnóstico.

A orientação aparece somente em mode=view, sem registro selecionado nem snapshot local. Criar e Editar preservam a configuração sem exibi-la. Desligar grava null, que impede reativação por uma preferência antiga; substituir um documento que omite o binding também limpa a orientação. Em input-first, a página governa o valor. Filter Form não expõe essa seção, pois não possui contexto de seleção equivalente.