> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# How report generation works

> The path a Reporter report takes: the request, extraction against the configured data sources, the render, the file in object storage, and the download.

Report generation has two halves. The **manager** accepts your request, checks it, and hands it to a queue. The **worker** extracts the data, renders the template, and writes the file. Reporter answers your request as soon as the first half completes, so you poll or listen for the second.

Both halves ship in one binary. A deployment runs the API surface, the worker surface, or both, and a queue carries the work between them.

This page follows one report along that path.

## The path end to end

***

<Steps>
  <Step title="Request">
    You call [Create a report](/en/reference/reporter/create-report) with a template identifier and the row filters you want. Reporter validates the request and stores the report as `Processing`.
  </Step>

  <Step title="Extraction">
    The worker queries each data source the template names, one section per data source, and keeps only the fields in the template's field map.
  </Step>

  <Step title="Render">
    The extracted rows become the context for the template. Reporter renders the document in the template's output format.
  </Step>

  <Step title="Storage">
    Reporter writes the rendered file to the configured object storage bucket and records the terminal status of the report.
  </Step>

  <Step title="Download">
    You call [Download a report](/en/reference/reporter/download-report) and receive the file with its content type and filename.
  </Step>
</Steps>

## What the manager does

***

The manager owns everything that happens before the queue. It runs four checks in order, and any one of them can reject the request outright.

**It applies idempotency.** Send an `X-Idempotency` header to name the request yourself. Without one, Reporter derives the key from the request body. A repeat of an in-flight request is rejected as a duplicate. A repeat of a completed request returns the original report and marks the response with `X-Idempotency-Replayed: true`. The window is 30 seconds.

**It resolves the template.** Reporter loads the field map, the output format, and the description that belongs to the template identifier. An unknown identifier fails here.

**It validates your filters.** Every field you filter on is checked against the live schema of its data source. A wrong field name fails the request instead of producing an empty report.

**It records the report and queues the work.** The report is stored as `Processing` and the response returns immediately with that status. Reporter then publishes the generation command for the worker.

The report keeps its own copy of the output format and the template description. That snapshot is what makes an old report reproducible after the template moves on.

## What the worker does

***

The worker consumes the command and owns the rest of the path.

A queue can deliver the same command twice. The worker therefore reads the report before it starts a run: a report that already settled as `Finished` or `Error` is left as it is, rather than generated again.

It then loads the template file from object storage and extracts data. **Each data source is one section.** A section that fails does not stop the others. The worker collects the outcome of every section and only then decides the status of the report.

When every section fails, Reporter records the failure and skips the render. No misleading file reaches the bucket.

The render step turns the surviving sections into the document. When the output format is PDF, Reporter renders HTML first and converts it through a headless browser pool. The finished bytes go to the bucket, the terminal status goes to the report record, and a terminal event goes to the event stream.

## Report states

***

A report reaches one of four states.

| State        | Meaning                                                       | Artifact          |
| ------------ | ------------------------------------------------------------- | ----------------- |
| `Processing` | Accepted and queued, or in extraction                         | Not yet           |
| `Finished`   | Every section returned data                                   | Ready to download |
| `Partial`    | Some sections failed, others returned data                    | Incomplete        |
| `Error`      | Every section failed, or the request never reached the worker | None              |

Poll [Check report status](/en/reference/reporter/check-report-status) or consume the terminal event. A `Partial` report carries a per-section outcome in its metadata, which names the data sources that did not answer: fix those data sources, then generate the report again. [Download a report](/en/reference/reporter/download-report) serves the artifact once the report is `Finished`.

## Time limits on the path

***

Each stage carries its own limit, and an operator sets them per deployment.

| Limit                  | Default     | Applies to                        |
| ---------------------- | ----------- | --------------------------------- |
| Idempotency window     | 30 seconds  | Repeat detection on the request   |
| Extraction timeout     | 300 seconds | One extraction run                |
| Extraction concurrency | 4           | Parallel queries inside one run   |
| PDF conversion timeout | 90 seconds  | One HTML-to-PDF conversion        |
| PDF worker pool        | 2           | Concurrent conversions per worker |

Volume limits bound the same run: 10 data sources, 50 tables per data source, 200 fields per table, and 100 MiB of extracted result. See [Environment variables](/en/reporter/reporter-environment-variables) for the settings behind each one.

## Where deadlines fit

***

A deadline is a due date with a recurrence rule, and it can name the template that satisfies it. It sits beside the generation path rather than on it.

A deadline never starts a report. You generate the report through the request path above, then mark the deadline delivered. Reporter recomputes a deadline on read. A recurring obligation that carries a delivery mark rolls forward to its next due date on the first read after the current date passes, and that roll-forward clears the mark. The notifications operation returns the deadlines inside their alert window when you ask for them. See [Managing deadlines](/en/reporter/managing-deadlines).

## Storage and download

***

Rendered files live in one S3-compatible bucket, under the `reports/` prefix. Reporter stores each file under the template identifier and names it after the report, so files stay grouped by the template that produced them.

Download returns the bytes with the content type of the output format and a filename built from the report identifier. The download works after the template is deleted, because the report holds its own format snapshot.

A report is created once and then retained. Its filters, its status, and its file describe exactly the request that produced them, which is what makes an old report evidence of what you reported at the time.

<Note>
  Reporter keeps rendered files in the bucket. Set retention with a lifecycle policy on the bucket itself.
</Note>

## Next steps

***

<CardGroup cols={2}>
  <Card title="Reporter template engine" icon="gears" href="/en/reporter/reporter-template-engine">
    The field map, the data context, and the two kinds of filter.
  </Card>

  <Card title="Using Reporter" icon="play" href="/en/reporter/using-reporter">
    Upload a template, generate a report, and download the result.
  </Card>

  <Card title="Managing deadlines" icon="calendar-check" href="/en/reporter/managing-deadlines">
    Track a regulatory obligation and mark it delivered.
  </Card>

  <Card title="Reporter architecture" icon="sitemap" href="/en/reporter/reporter-architecture">
    One binary, two surfaces, and the stores they share.
  </Card>
</CardGroup>
