Skip to content

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:

typescript
{
  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:

typescript
{
  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:

typescript
{
  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:

typescript
{
  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:

typescript
{
  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:

typescript
{
  fieldType: "BOOLEAN",
  defaultValue: false
}

Uso comum:

  • Documento público?
  • Requer aprovação?
  • Digitalizado?
  • Arquivado?

Exemplo:

┌─────────────────────────────────────┐
│ ☑ Documento digitalizado            │
└─────────────────────────────────────┘

Gerenciamento de Campos

Acessar Configurações

  1. Login como ADMIN ou SUPER
  2. Navegue para /settings?tab=campos
  3. 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:

typescript
// 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:

  1. Clique no ícone de editar (lápis)
  2. Modal abre com dados atuais
  3. Modifique as propriedades
  4. 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:

  1. Clique no ícone de excluir (lixeira)
  2. Sistema verifica uso em documentos
  3. Se em uso, exibe erro:
    ❌ Não é possível remover este campo pois está
       vinculado a 45 documento(s)
  4. Se não em uso, confirma exclusão
  5. 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ínimo
  • maxLength: Tamanho máximo
  • pattern: Regex de validação

TEXTAREA:

  • minLength: Tamanho mínimo
  • maxLength: Tamanho máximo

NUMBER:

  • min: Valor mínimo
  • max: 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:

typescript
// 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:

typescript
{
  fieldKey: "cpf",
  label: "CPF",
  fieldType: "TEXT",
  pattern: "^\\d{3}\\.\\d{3}\\.\\d{3}-\\d{2}$"
}

Exemplo: Email:

typescript
{
  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:

typescript
// 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 → documentNumber

Reordenaçã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

  1. Edite o campo
  2. Altere a propriedade "Seção"
  3. Salve as alterações
  4. Campo aparece na nova seção

Configuração por Usuário

Cada usuário pode ter configurações personalizadas de campos.

UserFieldConfiguration

Modelo:

prisma
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 renderizado

Exemplo:

typescript
// 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:

typescript
// 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:

typescript
const { control, formState: { errors } } = useForm({
  resolver: zodResolver(formSchema),
  defaultValues: generateDefaultValues(fieldConfigs)
});

Validação no Backend

Backend valida apenas campos obrigatórios e tipos:

typescript
// 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:

typescript
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):

typescript
numeroProcesso     // ✅ Correto
numero_processo    // ❌ Evite
NumeroProcesso     // ❌ Evite

label (Português, capitalizado):

typescript
"Número do Processo"     // ✅ Correto
"numero do processo"     // ❌ Evite
"NÚMERO DO PROCESSO"     // ❌ Evite

Organização

  1. Agrupe campos relacionados na mesma seção
  2. Use sortOrder sequencial (1, 2, 3...)
  3. Deixe gaps (5, 10, 15) para inserções futuras
  4. Campos obrigatórios primeiro em cada seção

Performance

  1. Evite criar centenas de campos
  2. Use SELECT para opções fixas (não TEXT)
  3. Limite maxLength de TEXTAREA
  4. Não abuse de validações regex complexas

Próxima Etapa

Continue para Auditoria para aprender sobre o sistema de rastreamento.

Sistema de Gestão de Arquivos Digitais