Relatórios (CRUD)#
O servidor armazena definições de relatório e permite operações completas de criação, leitura, atualização e exclusão.
Em deploys multi-tenant, relatórios usam namespace para separar templates
locais de templates globais:
tenanté o padrão e fica visível apenas para o tenant da requisição.-
globalé compartilhado entre todos os tenants e exigecan_edit_globalpara criar, editar, excluir, assinar ou portar.
Veja também Multi-Tenancy.
Listar — GET /api/v1/reports#
Permissão: canList
Query params#
| Param | Tipo | Descrição |
|---|---|---|
q | string | Busca full-text pelo nome/descrição |
group | string | Filtra relatórios visíveis dentro de um grupo |
page | int | Página (começa em 1) |
limit | int | Itens por página (1–100, default 20) |
Quando group é informado, o resultado vem das associações do grupo para o
tenant atual. Veja Grupos de relatórios para criar
grupos, associar relatórios e entender o escopo tenant/global.
Resposta sem paginação#
[
{
"id": "uuid",
"name": "Sales Report",
"namespace": "tenant",
"description": "Monthly sales overview",
"createdAt": "2026-04-06T12:00:00.000Z",
"updatedAt": "2026-04-06T12:00:00.000Z",
"storageKind": "inline"
}
]
Resposta com paginação#
{
"data": [ ... ],
"pagination": {
"page": 1,
"limit": 20,
"total": 42,
"totalPages": 3
}
}
Detalhes — GET /api/v1/reports/:id#
Permissão: canList
Retorna o relatório completo incluindo definitionJson, packageBytes, etc.
No modo federado, o ID pode resolver um template global ou um relatório local
do tenant atual.
| Status | Erro | Quando |
|---|---|---|
404 | not_found | ID não encontrado |
Criar — POST /api/v1/reports#
Permissão: canInsert
Body:
{
"name": "My Report",
"namespace": "tenant",
"description": "Optional description",
"definitionJson": "{ ... }",
"packageBytes": "base64encoded..."
}
| Campo | Obrigatório | Descrição |
|---|---|---|
name | Sim | Nome do relatório (não vazio) |
namespace |
Não | tenant por padrão; use global para criar template compartilhado |
description | Não | Descrição |
definitionJson | Não | JSON inline da definição |
packageBytes | Não | Base64 do pacote .sulfite |
Resposta 201: Metadados do relatório criado (id, name, description, createdAt, updatedAt, storageKind).
| Status | Erro | Quando |
|---|---|---|
400 |
validation_error |
name ausente ou vazio |
403 | forbidden | Sem canInsert |
403 |
forbidden |
"namespace": "global" sem can_edit_global |
402 | quota_exceeded | Quota local do tenant excedida |
Valores desconhecidos de namespace são normalizados para tenant.
Templates globais não consomem reports.count nem storage.bytes
dos tenants.
Criar template global#
curl -X POST http://localhost:8080/api/v1/reports \
-H "Authorization: Bearer $OPERATOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Invoice Template",
"namespace": "global",
"definitionJson": "{...}"
}'
Atualizar — PUT /api/v1/reports/:id#
Permissão: canEdit
Body: Mesmos campos do POST (todos opcionais). Se name for fornecido, não pode ser vazio.
O namespace não pode ser alterado depois da criação.
Atualizar um relatório global exige can_edit_global.
Resposta 200: Metadados atualizados.
| Status | Erro | Quando |
|---|---|---|
400 | validation_error | name vazio |
403 |
forbidden |
Relatório global sem can_edit_global |
404 | not_found | ID não encontrado |
422 |
namespace_immutable |
Tentativa de trocar namespace |
402 |
quota_exceeded |
Novo pacote excede storage.bytes local |
Excluir — DELETE /api/v1/reports/:id#
Permissão: canDelete
Excluir um relatório global exige can_edit_global.
Resposta 204: Sem body.
| Status | Erro | Quando |
|---|---|---|
403 |
forbidden |
Relatório global sem can_edit_global |
404 | not_found | ID não encontrado |
Exemplo: fluxo completo#
# Criar
curl -X POST http://localhost:8080/api/v1/reports \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Vendas Mensal", "namespace": "tenant", "definitionJson": "{...}"}'
# Listar
curl http://localhost:8080/api/v1/reports \
-H "Authorization: Bearer $TOKEN"
# Buscar
curl "http://localhost:8080/api/v1/reports?q=vendas" \
-H "Authorization: Bearer $TOKEN"
# Atualizar
curl -X PUT http://localhost:8080/api/v1/reports/$ID \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"description": "Atualizado"}'
# Excluir
curl -X DELETE http://localhost:8080/api/v1/reports/$ID \
-H "Authorization: Bearer $TOKEN"