Skip to content

Upload de PDFs

Este guia detalha o sistema de upload de arquivos PDF e processamento automático de páginas.

Visão Geral

O ArqSystem possui um sistema robusto de upload de PDFs com:

  • Upload direto para Cloudflare R2 (storage em nuvem)
  • Processamento assíncrono em background
  • Extração automática de páginas
  • Conversão para formato WebP otimizado
  • Criação automática de documento vinculado

Acesso

Requisito: Apenas usuários autenticados podem fazer upload.

Rota: /upload

Como acessar:

  1. Faça login no sistema
  2. Menu lateral: clique em "Upload"
  3. Ou acesse diretamente /upload

Tipos de Arquivo

Formato aceito: Apenas arquivos PDF

Restrições:

  • ✅ Arquivos .pdf
  • ❌ Imagens (jpg, png, etc.)
  • ❌ Documentos Word, Excel
  • ❌ Outros formatos

Validação:

  • Frontend: Atributo accept="application/pdf" no input
  • Backend: Verificação de extensão .pdf

Interface de Upload

Dropzone

Área de arrastar e soltar (drag-and-drop):

┌─────────────────────────────────────────┐
│    📁 Arraste um arquivo PDF aqui       │
│           ou clique para selecionar      │
│                                          │
│    Apenas arquivos PDF são aceitos      │
└─────────────────────────────────────────┘

Interações:

  • Arraste arquivo PDF para a área
  • Ou clique para abrir seletor de arquivos
  • Apenas 1 arquivo por vez

Preview do Arquivo

Após seleção, exibe card com informações:

┌─ Arquivo Selecionado ──────────────────┐
│ 📄 relatorio-anual-2024.pdf            │
│ Tamanho: 2.5 MB                        │
│                                    [X] │
└────────────────────────────────────────┘

Ações:

  • Botão [X]: Remove arquivo selecionado
  • Possível selecionar outro arquivo

Botão de Upload

Após seleção do arquivo:

[Enviar PDF] (azul, destacado)

Estado desabilitado durante upload:

[Enviando...] (cinza, desabilitado)

Processo de Upload

Fluxo Completo

1. Usuário seleciona arquivo PDF
2. Sistema valida formato
3. Clique em "Enviar PDF"
4. Modal de progresso aparece
5. Upload para R2 (0-100%)
6. Confirmação de upload
7. Criação automática de documento (V2)
8. Processamento em background inicia
9. Notificação de conclusão

Upload com Progresso

Modal exibido durante upload:

┌─ Enviando Arquivo ─────────────────────┐
│                                         │
│  relatorio-anual-2024.pdf               │
│                                         │
│  [████████████░░░░░░] 75%               │
│                                         │
│  Preparando upload...                   │
│                                         │
│                                    [X]  │
└─────────────────────────────────────────┘

Fases do progresso:

ProgressoStatusDescrição
0-10%Preparando upload...Requisitando URL presigned
10-90%Enviando arquivo...Upload para R2
90-100%Finalizando...Confirmando upload
100%Concluído!Upload finalizado

Cancelamento:

  • Botão [X] no modal
  • Cancela upload em progresso
  • Arquivo não é salvo

Estados Visuais

Estado Idle (antes de selecionar):

  • Borda azul claro (border-blue-200)
  • Fundo azul claro (bg-blue-50)

Estado Uploading:

  • Borda azul (border-blue-300)
  • Badge "Enviando" com spinner

Estado Success:

  • Borda verde (border-green-500)
  • Fundo verde claro (bg-green-50)
  • Badge "Enviado com sucesso" verde
  • Ícone CheckCircle2

Estado Error:

  • Borda vermelha (border-red-500)
  • Fundo vermelho claro (bg-red-50)
  • Badge "Falha no envio" vermelho
  • Ícone AlertTriangle
  • Botão "Tentar Novamente"

Tratamento de Erros

Erro de Validação:

❌ Apenas arquivos PDF são aceitos.

Erro de Upload:

┌─ Erro no Upload ───────────────────────┐
│                                         │
│  ⚠️  Erro ao enviar PDF                 │
│                                         │
│  Falha ao conectar com o servidor.     │
│  Verifique sua conexão e tente         │
│  novamente.                             │
│                                         │
│  [Fechar]  [Tentar Novamente]          │
└─────────────────────────────────────────┘

Ações em erro:

  • Fechar: Fecha modal, reseta estado
  • Tentar Novamente: Reinicia upload do mesmo arquivo

Armazenamento

Estrutura de Diretórios

Os arquivos são organizados hierarquicamente:

YYYY/MM/DD/file-name/file-name.pdf

Exemplo prático:

2026/01/14/relatorio-anual/relatorio-anual.pdf

Componentes do path:

  • YYYY: Ano (4 dígitos)
  • MM: Mês (2 dígitos)
  • DD: Dia (2 dígitos)
  • file-name: Nome sanitizado do arquivo (pasta)
  • file-name.pdf: Arquivo PDF original

Sanitização de Nomes

O sistema sanitiza nomes de arquivo usando slugify:

Transformações aplicadas:

  • Conversão para lowercase
  • Remoção de caracteres especiais
  • Espaços substituídos por hífens
  • Acentos removidos
  • Trim de espaços em branco

Exemplos:

"Portfólio Cerâmica .pdf"     → "portfolio-ceramica"
"Relatório Anual 2024.PDF"    → "relatorio-anual-2024"
"Documento (FINAL) v2.pdf"    → "documento-final-v2"

Tratamento de Duplicatas

Quando um arquivo com mesmo nome já existe:

Sistema de sufixo numérico:

primeira tentativa  → documento/documento.pdf
segunda tentativa   → documento-1/documento-1.pdf
terceira tentativa  → documento-2/documento-2.pdf

Limite: Máximo 100 duplicatas por dia por nome de arquivo.

Erro após 100 tentativas:

❌ Limite de duplicatas atingido para este arquivo hoje.
   Aguarde 24 horas ou renomeie o arquivo.

Processamento em Background

Visão Geral

Após upload confirmado (100%), o sistema inicia processamento assíncrono.

Vantagens:

  • Usuário pode continuar usando o sistema
  • Não bloqueia a interface
  • Processamento otimizado em fila
  • Retry automático em caso de falha

Pipeline de Processamento

┌─────────────────────────────────────────────┐
│ 1. PENDING                                  │
│    Aguardando processamento                 │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ 2. GENERATING_IMAGES                        │
│    Executando pdftoppm                      │
│    Extraindo páginas como PNG               │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ 3. CONVERTING_IMAGES                        │
│    Convertendo PNG → WebP (Sharp)           │
│    Qualidade: 85%, Esforço: 6               │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ 4. COMPLETED                                │
│    Todas as páginas processadas             │
│    Registros criados no banco               │
└─────────────────────────────────────────────┘

Fases do Processamento

1. PENDING

Status inicial após confirmação de upload.

Ações:

  • Registro criado no banco de dados
  • Job adicionado à fila PROCESS_PDF
  • Status: processingStatus = PENDING

2. GENERATING_IMAGES

Extração de páginas do PDF usando pdftoppm.

Comando executado:

bash
pdftoppm -png /tmp/file.pdf /tmp/page

Saída:

/tmp/page-1.png
/tmp/page-2.png
/tmp/page-3.png
...
/tmp/page-N.png

Atualização no banco:

typescript
{
  processingStatus: "GENERATING_IMAGES",
  processingStartedAt: new Date()
}

3. CONVERTING_IMAGES

Conversão PNG → WebP usando Sharp.

Configuração:

typescript
sharp(pngBuffer)
  .webp({
    quality: 85,  // 0-100
    effort: 6     // 0-6 (maior = mais compressão)
  })
  .toBuffer();

Processo:

  1. Para cada página PNG:
    • Carrega PNG em buffer
    • Converte para WebP
    • Gera nome: file-name-pg-1.webp
    • Upload para R2
    • Coleta metadados (tamanho, key)

Estrutura de saída:

2026/01/14/relatorio-anual/relatorio-anual-pg-1.webp
2026/01/14/relatorio-anual/relatorio-anual-pg-2.webp
2026/01/14/relatorio-anual/relatorio-anual-pg-3.webp

Atualização no banco:

typescript
{
  processingStatus: "CONVERTING_IMAGES",
  totalPages: N
}

4. COMPLETED

Finalização do processamento.

Ações:

  1. Criação de registros UploadedFilePage para cada página
  2. Atualização do status final
  3. Cleanup de arquivos temporários

Banco de dados:

typescript
// UploadedFile
{
  processingStatus: "COMPLETED",
  processingCompletedAt: new Date(),
  totalPages: N
}

// UploadedFilePage (para cada página)
{
  uploadedFileId: "uuid",
  pageNumber: 1,
  r2FileKey: "2026/01/14/file/file-pg-1.webp",
  fileName: "file-pg-1.webp",
  fileSize: 123456,
  contentType: "image/webp"
}

Status de Erro

FAILED: Processamento falhou.

Causas comuns:

  • PDF corrompido
  • Falha no pdftoppm
  • Erro de conversão Sharp
  • Falha no upload para R2
  • Timeout de processamento

Atualização no banco:

typescript
{
  processingStatus: "FAILED",
  processingError: "Erro detalhado aqui",
  processingCompletedAt: new Date()
}

Retry Policy (BullMQ):

  • Máximo 3 tentativas
  • Backoff exponencial: 5s, 10s, 20s

Monitoramento

Consultar status de processamento:

typescript
// API endpoint
GET /api/trpc/upload.getPdfPages?input={"fileId":"uuid"}

// Resposta
{
  id: "uuid",
  fileName: "relatorio-anual.pdf",
  processingStatus: "CONVERTING_IMAGES",
  totalPages: 10,
  pages: [
    {
      id: "page-uuid",
      pageNumber: 1,
      r2FileKey: "2026/01/14/file/file-pg-1.webp",
      fileName: "file-pg-1.webp",
      fileSize: 123456
    },
    // ... mais páginas
  ]
}

Criação Automática de Documento (V2)

Visão Geral

Na versão 2, após upload concluído (100%), o sistema cria automaticamente um documento pré-preenchido.

Campos Pré-preenchidos

Metadados extraídos:

  • Título: Nome do arquivo (sem extensão)
  • Data de Inserção: Data/hora do upload
  • Arquivo vinculado: Path do PDF no R2
  • Número de páginas: Quantidade de páginas (após processamento)
  • Status: "Processando" ou "Concluído"
  • Usuário responsável: Usuário que fez upload

Campos a preencher:

  • Tipo Documental (obrigatório CONARQ)
  • Número do Documento (obrigatório)
  • Nível de Acesso (obrigatório para conformidade)
  • Palavras-chave
  • Observações
  • Outros campos dinâmicos

Fluxo Pós-Upload

1. Upload concluído (100%)
2. Sistema cria documento pré-preenchido
3. Status inicial: "Incompleto"
4. Documento aparece na listagem
5. Badge "Requer Atenção" destacado
6. Usuário recebe notificação
7. Acessa /documents/:id/edit
8. Completa campos obrigatórios CONARQ
9. Salva documento
10. Status muda para "Ativo"

Identificação de Documentos Incompletos

Na listagem /documents:

Badge visual:

[⚠️ Incompleto]

Filtro especial:

[Filtro: Documentos Incompletos]

Exibe apenas documentos criados via upload que ainda precisam ser completados.

Instruções e Informações

A página de upload exibe um card informativo "Como funciona":

Instruções Apresentadas

  1. Apenas arquivos PDF são aceitos

  2. 📁 O PDF será armazenado em:

    dd/mm/yyyy/file-name/file-name.pdf
  3. 🖼️ As páginas serão convertidas em imagens WebP automaticamente

    • Formato otimizado
    • Alta qualidade
    • Tamanho reduzido
  4. O processamento ocorre em segundo plano

    • Pode levar alguns minutos
    • Não bloqueia o uso do sistema
    • Notificação quando concluído

Visualização de Arquivos

Árvore de Arquivos

Página /storage exibe todos os arquivos em estrutura hierárquica:

📅 2026
  📅 01 (Janeiro)
    📅 14
      📁 relatorio-anual (3 arquivos)
        📄 relatorio-anual.pdf (2.5 MB)
          Status: ✅ Processado
          Páginas: 10
        🖼️ relatorio-anual-pg-1.webp (245 KB)
        🖼️ relatorio-anual-pg-2.webp (238 KB)
        ...

Informações exibidas:

  • Ícone do tipo (PDF ou imagem)
  • Nome do arquivo
  • Tamanho do arquivo
  • Status de processamento
  • Número de páginas (para PDFs)

Ações:

  • Clicar para expandir/colapsar
  • Botão de download (presigned URL)
  • Botão de exclusão (apenas SUPER usuários)

Limites e Restrições

Limites de Upload

  • Formato: Apenas PDF
  • Quantidade: 1 arquivo por vez
  • Tamanho máximo: Configurável (padrão: 50MB)
  • Páginas: Sem limite definido

Limites de Armazenamento

  • Cloudflare R2: Depende do plano contratado
  • Duplicatas: Máximo 100 por dia por nome
  • Presigned URLs:
    • Upload: 15 minutos de validade
    • Download: 1 hora de validade

Timeouts

  • Upload: Sem timeout (depende da conexão)
  • Processamento: 10 minutos por PDF
  • Conversão: 1 minuto por página

Segurança

Upload Direto para R2

Vantagens:

  • Backend não manipula arquivo
  • Reduz carga no servidor
  • Upload mais rápido
  • Presigned URL segura (15 min)

Fluxo:

1. Frontend requisita URL presigned
2. Backend gera URL com permissões temporárias
3. Frontend faz PUT direto para R2
4. Backend confirma upload bem-sucedido

Proteção de Arquivos

Arquivos não podem ser deletados se:

  • Vinculados a documentos ativos
  • PDF com páginas vinculadas a documentos

Apenas SUPER usuários podem deletar arquivos:

  • Verificação de permissão CASL
  • Validação de uso antes de deletar
  • Mensagem de erro se arquivo em uso

Próxima Etapa

Continue para Busca Full-Text para aprender sobre o sistema de busca.

Sistema de Gestão de Arquivos Digitais