Campos Dinâmicos
Este guia detalha o sistema de campos dinâmicos que permite personalizar formulários sem alterar código.
Visão Geral
O ArqSystem possui um sistema 100% dinâmico de campos que permite:
- Criar campos personalizados via interface
- Definir validações e regras por campo
- Organizar campos em seções
- Controlar visibilidade e obrigatoriedade
- Alterar sem necessidade de deployment
Arquitetura de Três Camadas
Tier 1: Campos Auto-Gerados
Campos fixos gerados automaticamente pelo backend:
id (Número do Documento):
- Tipo: Number
- Auto-incremento
- Nunca editável
- Chave primária do banco
digitalId (ID Digital):
- Tipo: String (UUID v4)
- Gerado automaticamente
- Nunca editável
- Identificador único para auditoria
Características:
- Excluídos de todos os schemas de input
- Sempre exibidos como disabled em formulários
- Gerados pelo backend ao criar documento
Tier 2: Campos Padrão Obrigatórios
Campos sempre presentes, gerenciados via GlobalFieldConfiguration:
title (Título do Documento):
- Tipo: TEXT
- Seção: IDENTIFICATION
- Obrigatório: Sim
- Sistema: Sim (não pode ser deletado)
documentType (Tipo de Documento):
- Tipo: SELECT
- Seção: IDENTIFICATION
- Obrigatório: Sim
- Sistema: Sim
- Opções: Tipos cadastrados em
/settings
accessLevel (Nível de Acesso):
- Tipo: SELECT
- Seção: ACCESS
- Obrigatório: Sim (conformidade CONARQ)
- Sistema: Sim
- Opções: Público, Restrito, Confidencial, Secreto
Características:
- Criados automaticamente na inicialização do servidor
- Marcados com
isSystem: true - Não podem ser deletados
- Podem ter visibilidade/ordem configurada
Tier 3: Campos Dinâmicos Personalizados
Todos os outros campos criados por administradores:
- Totalmente configuráveis
- Podem ser adicionados, editados, deletados
- Validações personalizadas
- Organização em seções livre
Tipos de Campo
TEXT (Texto Curto)
Campo de texto de linha única.
Propriedades:
{
fieldType: "TEXT",
minLength: 3, // Opcional
maxLength: 255, // Opcional
pattern: "^[A-Z]", // Regex opcional
defaultValue: ""
}Uso comum:
- Número do documento
- Autor
- Local
- Referências curtas
Exemplo:
┌─────────────────────────────────────┐
│ Número do Documento │
│ [2024/0045 ] │
└─────────────────────────────────────┘TEXTAREA (Texto Longo)
Campo de texto multilinha.
Propriedades:
{
fieldType: "TEXTAREA",
minLength: 10,
maxLength: 5000,
defaultValue: ""
}Uso comum:
- Descrição
- Observações
- Resumo
- Notas
Exemplo:
┌─────────────────────────────────────┐
│ Descrição │
│ ┌─────────────────────────────────┐ │
│ │ Relatório detalhando as │ │
│ │ atividades desenvolvidas │ │
│ │ durante o ano de 2024... │ │
│ │ │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────┘NUMBER (Número)
Campo numérico.
Propriedades:
{
fieldType: "NUMBER",
min: 1, // Opcional
max: 9999, // Opcional
defaultValue: 0
}Uso comum:
- Quantidade de páginas
- Número de volume
- Ano
- Contadores
Exemplo:
┌─────────────────────────────────────┐
│ Número de Páginas │
│ [45 ] │
└─────────────────────────────────────┘DATE (Data)
Campo de seleção de data.
Propriedades:
{
fieldType: "DATE",
defaultValue: null // ou "YYYY-MM-DD"
}Uso comum:
- Data de publicação
- Data de digitalização
- Data de inserção
- Prazo de guarda
Exemplo:
┌─────────────────────────────────────┐
│ Data de Publicação │
│ [14/01/2026 ] [📅] │
└─────────────────────────────────────┘SELECT (Lista de Opções)
Campo de seleção única.
Propriedades:
{
fieldType: "SELECT",
selectOptions: [
"Opção 1",
"Opção 2",
"Opção 3"
],
defaultValue: null
}Uso comum:
- Tipo documental
- Nível de acesso
- Status
- Classificações predefinidas
Exemplo:
┌─────────────────────────────────────┐
│ Tipo de Documento │
│ [Relatório ▼] │
│ Ofício │
│ ► Relatório │
│ Memorando │
│ Ata │
└─────────────────────────────────────┘BOOLEAN (Sim/Não)
Campo de checkbox.
Propriedades:
{
fieldType: "BOOLEAN",
defaultValue: false
}Uso comum:
- Documento público?
- Requer aprovação?
- Digitalizado?
- Arquivado?
Exemplo:
┌─────────────────────────────────────┐
│ ☑ Documento digitalizado │
└─────────────────────────────────────┘Gerenciamento de Campos
Acessar Configurações
- Login como ADMIN ou SUPER
- Navegue para
/settings?tab=campos - Visualize lista de campos existentes
Criar Novo Campo
Interface:
┌─ Adicionar Campo ────────────────────────────┐
│ │
│ Nome do Campo * │
│ [numeroProcesso ] │
│ │
│ Label * │
│ [Número do Processo ] │
│ │
│ Tipo de Campo * │
│ [TEXT ▼] │
│ │
│ Seção * │
│ [IDENTIFICATION ▼] │
│ │
│ ☐ Obrigatório │
│ ☑ Visível │
│ │
│ Ordem │
│ [10 ] │
│ │
│ [Cancelar] [Salvar Campo] │
└───────────────────────────────────────────────┘Propriedades obrigatórias:
- Nome do Campo (fieldKey)
- Label (exibido ao usuário)
- Tipo de Campo
- Seção
Propriedades opcionais:
- Obrigatório (required)
- Visível (visible)
- Ordem (sortOrder)
- Validações específicas do tipo
Exemplo prático:
// Criar campo "Número do Processo"
{
fieldKey: "numeroProcesso",
label: "Número do Processo",
fieldType: "TEXT",
section: "IDENTIFICATION",
required: false,
visible: true,
sortOrder: 5,
minLength: 5,
maxLength: 50,
pattern: "^\\d{4}/\\d{4}$" // Formato: 2024/0045
}Editar Campo Existente
Restrições:
- Campos do sistema não podem ser editados
- Campos em uso não podem ter o tipo alterado
- Nome do campo (fieldKey) não pode ser alterado
Interface:
- Clique no ícone de editar (lápis)
- Modal abre com dados atuais
- Modifique as propriedades
- Salve as alterações
Campos editáveis:
- Label
- Visibilidade
- Obrigatoriedade
- Ordem
- Validações
- Seção
Deletar Campo
Proteções:
- Campos do sistema não podem ser deletados
- Campos em uso não podem ser deletados
Processo:
- Clique no ícone de excluir (lixeira)
- Sistema verifica uso em documentos
- Se em uso, exibe erro:
❌ Não é possível remover este campo pois está vinculado a 45 documento(s) - Se não em uso, confirma exclusão
- Campo removido de todos os formulários
Seções do Formulário
Os campos são agrupados em seções para melhor organização:
IDENTIFICATION (Identificação)
Campos de identificação básica do documento.
Campos comuns:
- id
- digitalId
- title
- documentType
- documentNumber
- volumeNumber
- pageCount
Ordem sugerida: 1-10
PRODUCTION (Contexto de Produção)
Informações sobre a produção do documento.
Campos comuns:
- author
- productionDate
- linkedBody
- productionLocation
- originatingBody
Ordem sugerida: 11-20
CONTENT (Conteúdo e Estrutura)
Descrição do conteúdo do documento.
Campos comuns:
- description
- keywords
- language
- documentStructure
- subjects
Ordem sugerida: 21-30
DIGITIZATION (Dados de Digitalização)
Informações sobre digitalização.
Campos comuns:
- digitizationDate
- digitizationLocation
- responsiblePerson
- equipment
- resolution
Ordem sugerida: 31-40
ACCESS (Acesso e Conformidade)
Controle de acesso e conformidade CONARQ.
Campos comuns:
- accessLevel
- retentionPeriod
- finalDestination
- legalBasis
- classificationDate
Ordem sugerida: 41-50
OTHER (Outros)
Campos diversos e personalizados.
Campos comuns:
- notes
- internalRemarks
- relatedDocuments
- tags
Ordem sugerida: 51-60
ATTACHMENTS (Anexos e Multimídia)
Arquivos anexados ao documento.
Campos comuns:
- attachmentFileIds
- attachmentNotes
Ordem sugerida: 61+
Validações
Validações por Tipo
TEXT:
minLength: Tamanho mínimomaxLength: Tamanho máximopattern: Regex de validação
TEXTAREA:
minLength: Tamanho mínimomaxLength: Tamanho máximo
NUMBER:
min: Valor mínimomax: Valor máximo
SELECT:
selectOptions: Array de opções válidas (obrigatório)
DATE:
- Formato: YYYY-MM-DD (ISO 8601)
BOOLEAN:
- Valores: true ou false
Mensagens de Erro
O sistema gera mensagens automáticas:
// Campo obrigatório vazio
"Título é obrigatório"
// Tamanho mínimo
"Mínimo de 5 caracteres"
// Tamanho máximo
"Máximo de 255 caracteres"
// Pattern inválido
"Formato inválido: esperado AAAA/NNNN"
// Número fora do range
"Valor deve estar entre 1 e 9999"Validação Customizada
Para validações complexas, use o campo pattern com regex:
Exemplo: CPF:
{
fieldKey: "cpf",
label: "CPF",
fieldType: "TEXT",
pattern: "^\\d{3}\\.\\d{3}\\.\\d{3}-\\d{2}$"
}Exemplo: Email:
{
fieldKey: "email",
label: "Email",
fieldType: "TEXT",
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
}Ordem e Organização
Ordenação de Campos
Campos são exibidos na ordem definida por sortOrder dentro de cada seção.
Exemplo:
// IDENTIFICATION
{ fieldKey: "id", sortOrder: 1 }
{ fieldKey: "digitalId", sortOrder: 2 }
{ fieldKey: "title", sortOrder: 3 }
{ fieldKey: "documentType", sortOrder: 4 }
{ fieldKey: "documentNumber", sortOrder: 5 }
// Renderiza na ordem: id → digitalId → title → documentType → documentNumberReordenação via Drag-and-Drop
Interface (futuro):
┌─ IDENTIFICATION ──────────────────┐
│ ☰ id │
│ ☰ digitalId │
│ ☰ title │
│ ☰ documentType │
│ ☰ documentNumber │
└───────────────────────────────────┘Arraste campos para reordenar dentro da mesma seção.
Mover Campo entre Seções
- Edite o campo
- Altere a propriedade "Seção"
- Salve as alterações
- Campo aparece na nova seção
Configuração por Usuário
Cada usuário pode ter configurações personalizadas de campos.
UserFieldConfiguration
Modelo:
model UserFieldConfiguration {
userId String
fieldConfigId String
visible Boolean
required Boolean
customLabel String?
}Permite:
- Ocultar campos específicos por usuário
- Tornar campos obrigatórios para usuários específicos
- Customizar labels para usuários
Herança de Configurações
GlobalFieldConfiguration (padrão para todos)
↓
UserFieldConfiguration (override por usuário)
↓
Formulário renderizadoExemplo:
// Global
{
fieldKey: "author",
visible: true,
required: false
}
// User override
{
userId: "user-123",
fieldConfigId: "author-id",
visible: true,
required: true // Obrigatório apenas para este usuário
}Schemas e Validação
Geração Dinâmica de Schemas
O sistema gera schemas Zod dinamicamente:
// Construção do schema
const formSchema = z.object(
fieldConfigs.reduce((acc, field) => {
let fieldSchema = getFieldSchema(field);
if (field.required) {
fieldSchema = fieldSchema.min(1, `${field.label} é obrigatório`);
}
acc[mapFieldName(field.fieldKey)] = fieldSchema;
return acc;
}, {})
);Validação no Frontend
React Hook Form + Zod:
const { control, formState: { errors } } = useForm({
resolver: zodResolver(formSchema),
defaultValues: generateDefaultValues(fieldConfigs)
});Validação no Backend
Backend valida apenas campos obrigatórios e tipos:
// Schema minimalista
const createDocumentInputSchema = z.looseObject({
attachmentFileIds: z.array(z.string()).optional()
});Validação detalhada é responsabilidade do frontend.
Mapeamento de Campos
FIELD_NAME_MAP
Alguns campos têm nomes diferentes no formulário e no banco:
export const FIELD_NAME_MAP: Record<string, string> = {
documentType: "documentTypeId", // Formulário → Banco
linkedBody: "linkedBodyId",
linkedAgency: "linkedBodyId",
};Por que existe:
- Frontend usa nomes user-friendly
- Banco usa convenção de foreign keys
- Mapeamento transparente
Best Practices
Nomenclatura
fieldKey (camelCase):
numeroProcesso // ✅ Correto
numero_processo // ❌ Evite
NumeroProcesso // ❌ Evitelabel (Português, capitalizado):
"Número do Processo" // ✅ Correto
"numero do processo" // ❌ Evite
"NÚMERO DO PROCESSO" // ❌ EviteOrganização
- Agrupe campos relacionados na mesma seção
- Use sortOrder sequencial (1, 2, 3...)
- Deixe gaps (5, 10, 15) para inserções futuras
- Campos obrigatórios primeiro em cada seção
Performance
- Evite criar centenas de campos
- Use SELECT para opções fixas (não TEXT)
- Limite maxLength de TEXTAREA
- Não abuse de validações regex complexas
Próxima Etapa
Continue para Auditoria para aprender sobre o sistema de rastreamento.