How does it work with Neos
Report generation is asynchronous and should not be performed synchronously when calling the generation API in the report server. The generation is performed by the reporting service for a business cluster.
Report templates are stored in Neos cluster backend service as .mrt files.
Report Persistence Modes
The reporting service supports three report persistence modes with automatic mode selection based on configuration:
Mode Priority and Detection
In production (Helm deployment), the active mode is selected with the following priority order:
- S3 Mode (priority 1) - Enabled when
report.S3.configurationSecretis configured - Filesystem Mode (priority 2) - Enabled when
report.volumeis configured - Legacy Mode (priority 3) - Enabled otherwise (neither
report.S3.configurationSecretnorreport.volumeis configured)
Important
S3 mode is intended for business cluster versions 3.2 and later. Older business clusters can still run in an S3-configured environment by setting clusters[].reportLegacyMode: true (mono-tenant) or clusters[].versions[].reportLegacyMode: true (multi-tenant), which keeps their report flow on the legacy Pub/Sub payload path.
At runtime, the application detects S3 mode from AWS:BucketName and legacy mode from NeosReportLegacyMode=true.
When S3 is active, the reporting server can still force the legacy payload flow for specific requesters using NeosReportLegacyRequesterAppIds.
This list is rendered by Helm from reportLegacyMode flags and matches Dapr app IDs (backend and task-runner) of targeted legacy clusters/versions.
In production, these runtime settings are expected to be rendered/provided by Helm from the deployment configuration above.
S3 Mode
When it's active: report.S3.configurationSecret is configured in Helm.
The secret content is then projected into the process configuration, where AWS:BucketName becomes the runtime signal used by the application.
Reports are persisted directly in an AWS S3 bucket as objects with the following characteristics:
- Object location:
reports/<TenantId>/<GenerationId>in the configured bucket - Metadata: Report information (filename, tenant, user, report name) is stored as S3 object metadata
- Requirements: Only BucketName is required; AWS SDK handles authentication via IAM roles, environment variables, or credential profiles
- Optional parameters: ServiceUrl (for S3-compatible endpoints like MinIO), AccessKey/SecretKey (for explicit credentials), Region (for explicit region override)
- Advantages: Scalable, serverless storage; supports large files without size limits; supports multi-region access; ideal for cloud-native deployments
Filesystem Mode
When it's active: report.volume is configured in Helm (and no S3 configuration secret is configured).
Reports are persisted on a shared distributed filesystem with the following characteristics:
- Storage path:
/var/lib/neos/reports/<TenantId>/<GenerationId>in production,.neos/reports/<TenantId>/<GenerationId>in development - Metadata: Report information is stored in a companion
.metafile (JSON format) - Write safety: Report is written as
<GenerationId>.tmpand renamed to<GenerationId>when complete, preventing partial file retrieval - Requirements: Persistent volume mounted at
/var/lib/neos/reportsin Kubernetes deployments - Advantages: Familiar POSIX filesystem semantics; supports large files; suitable for on-premises deployments with shared storage
Legacy Mode
When it's active: Neither report.S3.configurationSecret nor report.volume is configured in Helm.
In this case, Helm renders NeosReportLegacyMode=true in application settings, and runtime mode detection falls back to legacy mode.
Reports are persisted in the cluster database via the reporting message:
- Storage location: Cluster database
$NeosFiledatatable - Transport: PDF is base64-encoded and embedded in the PubSub message payload
- File size limit: 4MB per report due to message payload constraints
- Deprecation notice: This mode is retained for backward compatibility with versions prior to
2.4.0and should not be used in new deployments - Use case: Legacy systems without persistent volumes or S3 access
Per-request Legacy Fallback in S3 Environments
When S3 mode is active, report persistence is normally done in S3. However, for compatibility with older business clusters, the reporting server can force legacy transport for selected requesters:
- Activation source:
clusters[].reportLegacyMode: true(mono-tenant) orclusters[].versions[].reportLegacyMode: true(multi-tenant) - Helm rendering: these flags generate
NeosReportLegacyRequesterAppIdsin report serverappsettings.json - Matching rule: if request
Interlocutors.ActualRequesterorInterlocutors.BusinessDataProvidermatches a configured app ID, report generation switches to legacy payload for that request - Result: PDF is base64-encoded in
ReportingGeneratedpayload, and consuming legacy backend persists it into$NeosFile
Generation Flow
When a client requests a report to be generated:
- Request initiation: Backend cluster sends a request to the reporting service using pub sub
- Report generation: Reporting service publishes its own event and manages its task queue
- Template & data retrieval: Reporting service uses service invocation to:
- Retrieve the template (
.mrtfile) from the cluster - Query the cluster's entity views needed to render the report as PDF
- Retrieve the template (
- Report persistence: Based on the active mode (S3, Filesystem, or Legacy), the generated report is saved:
- S3 Mode: Direct upload to S3 bucket with object metadata
- S3 Mode + per-request legacy fallback: Base64 payload is used for requesters listed in
NeosReportLegacyRequesterAppIds - Filesystem Mode: Written to shared filesystem with companion
.metafile - Legacy Mode: Base64-encoded and published to PubSub message
- Notification: Reporting service publishes a message with the report identifier to the message broker
- Client notification: Cluster subscribes to the message and notifies the requesting client via SignalR
- Download: When the client requests download/print:
- S3 Mode: Browser downloads from the reporting service which retrieves the report from S3 and serves it
- Filesystem Mode: Browser downloads from the reporting service which retrieves the report from the shared filesystem and serves it
- Legacy Mode: Browser downloads from the cluster backend which retrieves the report from the database and serves it
Flow diagram
sequenceDiagram
participant WB as Web browser
participant CB as Cluster backend
participant MB as Message broker (Dapr pub sub)
participant RS as Reporting server
participant NH as Notification Hub (SignalR)
participant S3 as AWS S3 (optional)
WB->>RS: Request report generation
RS->>MB: Publish event GenerateReport
MB->>RS: Subscribe event GenerateReport
rect rgb(18, 21, 230)
Note right of CB: GenerateReport
RS->>CB: Get report definition (mrt file) via DAPR service invocation
CB-->>RS: Return definition
RS->>CB: Get report data from entity views via DAPR service invocation
CB-->>RS: Return data
alt S3 Mode (report.S3.configurationSecret configured)
alt Requester in NeosReportLegacyRequesterAppIds
RS->>MB: Publish generated PDF file (base64 encoded)
else Standard S3 flow
RS->>S3: Upload report with object metadata
S3-->>RS: Confirm upload
RS->>MB: Publish generated PDF identifier (S3 location)
end
else Filesystem Mode (report.volume configured)
RS->>RS: Save report at `/var/lib/neos/reports/<TenantID>/<GUID>`
RS->>RS: Write `<GUID>.meta` with report metadata
RS->>MB: Publish generated PDF identifier (file path)
else Legacy Mode (no report.volume and no report.S3.configurationSecret)
RS->>MB: Publish generated PDF file (base64 encoded)
end
end
rect rgb(235, 52, 83)
Note right of WB: ReportingGenerated
MB->>CB: Subscribe event ReportingGenerated
opt Legacy Mode (global or per-request fallback)
CB->>CB: Store PDF from base64 to database
end
CB->>NH: Create notification (SignalR)
NH->>WB: Push notification for PDF download/print
end
rect rgb(238, 130, 238)
Note right of WB: Download/Print PDF
alt S3 Mode (Browser downloads from reporting service)
WB->>RS: Request PDF download/print
RS->>S3: Retrieve report from S3
S3-->>RS: Return PDF
RS-->>WB: Serve PDF
else Filesystem Mode (Browser downloads from reporting service)
WB->>RS: Request PDF download/print
RS->>RS: Retrieve report from `/var/lib/neos/reports/<TenantID>/<GUID>`
RS-->>WB: Serve PDF
else Legacy Mode (Browser downloads from cluster backend)
WB->>CB: Request PDF download/print
CB->>CB: Retrieve PDF from database
CB-->>WB: Serve PDF
end
end
Note: this diagram describes the Helm deployment contract used in production. At runtime, the application detects S3 mode from AWS:BucketName and legacy mode from NeosReportLegacyMode=true.