RUN_MODE selects which surfaces a process serves. The same image runs as the API, as the report worker, or as both. Four dependencies sit behind them.
Reporter reads your databases through an extraction engine that runs inside the worker process. There is no separate extraction service to deploy.
What you deploy
Run modes
RUN_MODE=api serves every REST operation, plus /health, /readyz, and /version, on the address in SERVER_ADDRESS. RUN_MODE=worker consumes the report command queue and serves /health and /readyz on HEALTH_PORT. RUN_MODE=all runs both surfaces in one process.
Use all for local development. In production, deploy the two surfaces separately, so report generation scales on its own.
MongoDB
Both surfaces use the same MongoDB deployment. The API surface writes templates, reports, and deadlines. The worker updates a report as it completes.
MONGO_HOST and MONGO_NAME are required at startup.
RabbitMQ
Two separate concerns share one broker.
The report command queue
This queue carries work from the API surface to the worker.RABBITMQ_EXCHANGE, RABBITMQ_GENERATE_REPORT_QUEUE, and RABBITMQ_GENERATE_REPORT_KEY name the exchange, the queue, and the routing key. The API surface publishes, so it needs all three plus its broker connection: RABBITMQ_HOST, RABBITMQ_PORT_AMQP, RABBITMQ_DEFAULT_USER, and RABBITMQ_DEFAULT_PASS. The worker consumes from the queue and needs that same connection plus RABBITMQ_GENERATE_REPORT_QUEUE. The broker objects must exist before either service starts.
The channel is internal to Reporter. To learn that a report finished, subscribe to the business events below, or poll the report.
A worker that fails a message retries it up to five times with backoff, and then rejects it without requeue. Bind a dead-letter exchange to the command queue, so a rejected report lands somewhere you can inspect.
The events exchange
Business events (template.*, report.*, deadline.*, regulatory.*) go to an exchange you name in RABBITMQ_REPORT_EVENTS_EXCHANGE. The value is operator-configured. The reference value is reporter.events.
Set that exchange, STREAMING_BROKERS, and STREAMING_CLOUDEVENTS_SOURCE whenever STREAMING_ENABLED=true. With streaming off, both surfaces start normally and publish nothing.
Object storage
Reporter uses one S3-compatible bucket, named in
OBJECT_STORAGE_BUCKET. It holds two kinds of object, each under its own prefix:
- the template source, as
templates/<templateId>.tpl - the rendered report, as
reports/<templateId>/<reportId>.<format>
OBJECT_STORAGE_USE_PATH_STYLE=true is what MinIO and SeaweedFS expect, and OBJECT_STORAGE_DISABLE_SSL stays false outside local development.
Report retention
Reporter keeps report files and regulatory filings forever. It has no delete endpoint and no retention setting, so the bucket grows with your report volume. The only way a file expires is an object-storage lifecycle rule that you configure. Such a rule also deletes approved regulatory filings, which are the institution’s regulatory record. The saved rows that a regulatory correction re-renders the draft from are also stored underreports/, so an expiry rule can make an older draft impossible to correct.
Redis or Valkey
REDIS_HOST is required on the API surface. Redis backs the idempotency lock on report creation and the datasource schema cache.
Idempotency state lives in Redis, not in process memory, so API replicas share it. The same report request sent twice, to two replicas, creates one report.
Data sources
Reporter reads reporting data from PostgreSQL and MongoDB data sources in its persisted registry. Create and manage them through the data-source API. An optional
DATASOURCE_{NAME}_* block seeds a user-managed registry entry at Manager startup. It seeds the entry only when that configName is absent. Later API edits and deletions take precedence over the environment.
Both Manager and worker require the same persistent DATASOURCE_CRED_ENC_KEY to protect the registry credentials. Keep it unchanged across restarts and deployments so they can continue decrypting stored credentials. Reporter also starts with none configured, and serves templates, deadlines, and metrics.
Sizing the worker
RABBITMQ_NUMBERS_OF_WORKERS sets how many report jobs one worker process runs in parallel. For horizontal scale, add worker replicas and drive them from the depth of the command queue.
PDF output renders through a headless-browser pool: PDF_POOL_WORKERS concurrent renders, which defaults to 2, each bounded by PDF_TIMEOUT_SECONDS, which defaults to 90. Size worker memory against that pool, not only against the rows a report reads. The other output formats do not use it.
Every report also carries extraction limits. They are 10 data sources, 20 tables per data source, and 50 fields per table. They also cover 4 data sources read at a time, a 300-second deadline, and a 256 MiB cap on extracted data. The ENGINE_* variables change them. Each table also returns at most 150,000 rows and each query times out after 300 seconds, unless the data source sets its own values.
Deployment mode and TLS
DEPLOYMENT_MODE declares the flavor of the deployment: local, byoc, or saas. It tags the /readyz response, and in saas it enforces TLS.
Leave ALLOW_INSECURE_TLS unset in production. It bypasses those checks, and the local development stack is the only place for it.
Startup checks
Reporter validates its configuration before it serves anything. Each check below stops the process, and the error names every variable at fault.
A dependency that is down at boot does not produce a silently broken pod.
/health answers 503 until the startup self-probe succeeds. The kubelet then restarts the pod instead of sending it traffic.Rolling updates
On
SIGTERM, both surfaces enter a drain. The /readyz probe answers 503 from the moment the signal arrives, before the servers begin shutdown. In-flight requests and in-flight messages finish. Kubernetes removes the pod from Service endpoints while it still works.
Set the termination grace period above your longest report render. See the health and readiness reference for what the probes report during a drain.
Next steps
Environment variables
Every Reporter variable, by category.
BYOC configuration
The configuration blocks every Lerian product shares.
Health and readiness
The probe contract and what each response means.
Connect Reporter to Midaz
Point Reporter at a Midaz database and render your first report.

