Gerador de relatórios para Next.js

Conceitos

O modelo mental por trás do cosmemilton-report: uma definição em código, camadas de configuração que se sobrepõem, views que o usuário controla e um caminho para criar relatórios sem deploy.

Definição declarativa

Um objeto puro — colunas, formatos e regras de exportação. Nada de JSX de tabela, nada de loop manual.

defineReport apenas valida que não há colunas com a mesma key e preenche o sortOrder default pelo índice de cada coluna — o objeto continua sendo dado, não um componente.

Formatos suportados (format)

textnumberintegercurrencypercentdatedatetime

key

Campo do tipo T — mas aceita chaves livres também, para colunas derivadas que não existem no dado bruto (como situacao acima).

format

Um de text, number, integer, currency, percent, date, datetime — aplica a formatação padrão pt-BR/BRL automaticamente.

exportValue

Sobrescreve o valor usado em CSV, XLSX e JSON. É onde vive a lógica de colunas calculadas para os formatos de planilha.

pdfRender

Sobrescreve a célula só no PDF, recebendo { row, value, formatted, column, style } — devolve qualquer elemento do @react-pdf/renderer.

Camadas de configuração

resolveReport() combina cinco camadas, da menos para a mais específica. Cada uma só sobrescreve o que define — um campo undefined deixa a camada anterior valer.

  1. 1

    Defaults do módulo

    Ponto de partida embutido no pacote: papel A4 retrato, margens 15/15/10/10 mm, locale e moeda pt-BR/BRL, cabeçalho e estilo padrão da tabela.
    defaultReportGlobalConfig
  2. 2

    globalConfig

    Config do app inteiro — razão social, logo, papel, moeda — passada uma vez no ReportRenderInput. Cada campo undefined deixa o default da camada anterior valer.
    ReportGlobalConfig
  3. 3

    definição (código)

    Colunas, resumo, agrupamento e eventuais overrides de header/style do relatório — escrita em código, nunca persistida. É a única camada que pode ter funções.
    ReportDefinition<T>
  4. 4

    view

    Cópia salva pelo usuário no editor: oculta, reordena ou renomeia colunas, ajusta estilo. Só campos serializáveis — nenhuma função sobrevive a esta camada.
    ReportView
  5. 5

    overrides

    A última palavra, aplicada na hora do render: título, subtítulo, papel, orientação. Ideal para customizações pontuais, como um relatório agendado com título dinâmico.
    ReportRenderOverrides

Views: variantes de layout

Cada slug tem uma view do sistema, somente leitura, e quantas cópias do usuário quiser.

View system

isSystem: trueisDefault até alguém assumir

Criada por createSystemView, uma por slug: id "system:{slug}", sem overrides de coluna, header ou style — reflete a definição de código como está. Somente leitura.

Cópia do usuário

isSystem: falsequantas quiser

Nasce de uma view existente, salva pelo editor com id próprio. Guarda só os overrides que o usuário mudou — o resto continua herdando da definição.

isDefault decide qual view carrega quando ninguém escolhe uma explicitamente. ensureReportViews provisiona a view system uma única vez por slug e nunca sobrescreve o que já existe — se o slug já tem alguma view default (de uma execução anterior ou de um usuário), a view system nasce com isDefault: false para não roubar o default de ninguém.

O editor de layout só grava ReportViewColumn (key, header, width, align, format, visible, sortOrder) e os overrides serializáveis de header/style/summary — nunca uma função. Os detalhes de onde essas views moram ficam no guia de Persistência e views.

Relatórios em runtime

Sem deploy: o usuário desenha o relatório na tela a partir de fontes de dados que o app já registrou.

O app registra ReportDataSource[] — id, nome e os campos disponíveis, cada um com seu format. O CmReportDesigner usa essa lista para deixar o usuário escolher colunas, resumo e agrupamento visualmente.

O resultado é uma SerializableReportDefinition: mesma forma de uma ReportDefinition, mas sem exportValue nem pdfRender — só dados, prontos para virar JSON. parseReportDefinition valida qualquer JSON não confiável campo a campo e nunca lança; hidratar de volta é só passar adiante, porque toda SerializableReportDefinition já é uma ReportDefinition válida.