---
id: WF-PFM-QRY-007
title: Render a report to PDF or Excel
trigger: A person with report-use access requests a PDF or supported Excel rendering.
product_area: platform
module: queries
revision: 1
status: draft
design_intent: confirmed
implementation_evidence: observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
inference: []
implements:
  - CAP-PFM-QRY-013
moves:
  - STATE-PFM-QRY-006
crosses:
  - SVC-PFM-QRY-queries
idempotency: >-
  The render request retains its export identity and storage key; terminal status prevents
  restarting settled work on redelivery.
concurrency: >-
  Rendering uses its own queue and headless-browser worker limits. It does not share the interactive
  query-file generator.
hops:
  - 'n': 1
    actor_or_service: Start report export route
    action: >-
      Open the report, check the requested format for its kind and commit the queued export with
      queued work.
    anchor: 'services-platform:modules/queries/services/rendering/report-exports.ts'
    seam: queue
    on_failure: Refuse source or format problems before admission.
    left_inconsistent: No file request is created by those checks.
    observer: the person
    provenance: observed
    source: 'services-platform:modules/queries/services/rendering/report-exports.ts'
  - 'n': 2
    actor_or_service: Export dispatcher
    action: Dispatch the report export to the rendering queue and remove accepted queued-work entries.
    anchor: 'services-platform:modules/queries/services/exports/dispatch-query-exports.ts'
    seam: schedule
    on_failure: Leave unsuccessful publication for another dispatch pass.
    left_inconsistent: A render can remain queued or be redelivered after a publish/delete interruption.
    observer: dispatcher alarms
    provenance: observed
    source: 'services-platform:modules/queries/services/exports/dispatch-query-exports.ts'
  - 'n': 3
    actor_or_service: Report renderer
    action: >-
      Start unfinished rendering and check that the requester still has report-use access and can
      open the report.
    anchor: 'services-platform:modules/queries/services/rendering/render-report.ts'
    seam: queue
    on_failure: Settle source removal or lost access as access_lost.
    left_inconsistent: No browser starts for a refused source.
    observer: the person following the export
    provenance: observed
    source: 'services-platform:modules/queries/services/rendering/render-report.ts'
  - 'n': 4
    actor_or_service: Report renderer and interception host
    action: >-
      Open the print page without a browser session and intercept allowed Platform reads as the
      requester, rejecting other requests.
    anchor: 'services-platform:modules/queries/services/rendering/api-interception.ts'
    seam: sync
    on_failure: A refused in-page request fails rendering.
    left_inconsistent: The browser result is not accepted as a valid report after a refused request.
    observer: 'renderer logs (method, origin, path, never query strings or bodies)'
    provenance: observed
    source: 'services-platform:modules/queries/services/rendering/api-interception.ts'
  - 'n': 5
    actor_or_service: Print page (console)
    action: The print component loads source data and signals readiness or error on its document.
    anchor: 'react-console:components/reporting/print/print-page.tsx'
    seam: sync
    on_failure: Page errors or readiness timeout fail the render.
    left_inconsistent: There is no accepted printable file until readiness succeeds.
    observer: the person following the export
    provenance: observed
    source: 'react-console:lib/reporting/print/readiness.ts'
  - 'n': 6
    actor_or_service: Report renderer
    action: >-
      Produce a bounded PDF or validate the page’s Excel output, store under the request key and
      settle success.
    anchor: 'services-platform:modules/queries/services/rendering/render-report.ts'
    seam: sync
    on_failure: >-
      File-limit refusals settle without acceptance; infrastructure failures retry and become
      internal failure on the final receive.
    left_inconsistent: An upload followed by failed settlement can leave the object ahead of its running row.
    observer: the person; the renderer's dead-letter queue alarm
    provenance: observed
    source: 'services-platform:modules/queries/services/rendering/render-report.ts'
branches:
  - Status and downloads use the existing export-file operations.
waits:
  - The page has five minutes to signal readiness inside the six-minute renderer timeout.
evidence:
  - >-
    services-platform at ad3f6a6: modules/queries/services/rendering/*.ts;
    aws/logic/report-renderer.lambda.ts; aws/renderer/Dockerfile; rendering.settings.ts;
    docs/queries/report-rendering.md
  - >-
    react-console at baf6dae: app/print/[tenantId]/reports/[reportId]/page.tsx;
    components/reporting/print/*.tsx; lib/reporting/print/*.ts
controls: [TC-AVL-004, TC-AVL-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-DAT-005, TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-IAM-006, TC-LOG-001, TC-LOG-004, TC-LOG-005, TC-MON-001, TC-MON-002, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-SEC-001, TC-SEC-002, TC-SEC-003, TC-SEC-004, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-VEN-001, TC-VEN-002, TC-VEN-003]
---

# Render a report to PDF or Excel

## What It Does

A person with report-use access requests a PDF or supported Excel rendering. Status and downloads use the existing export-file operations.

## The Flow

```mermaid
sequenceDiagram
  participant C as Request or schedule
  participant H0 as Start report export route
  participant H1 as Export dispatcher
  participant H2 as Report renderer
  participant H3 as Report renderer and interception host
  participant H4 as Print page console
  participant H5 as Report renderer
  C-)H0: Open the report, check the requested format for its kind and commit the queued export with queued wo
  H0-)H1: Dispatch the report export to the rendering queue and remove accepted queued-work entries
  H1-)H2: Start unfinished rendering and check that the requester still has report-use access and can open the
  H2->>H3: Open the print page without a browser session and intercept allowed Platform reads as the requester,
  H3->>H4: The print component loads source data and signals readiness or error on its document
  H4->>H5: Produce a bounded PDF or validate the page’s Excel output, store under the request key and settle su
```

Open the report, check the requested format for its kind and commit the queued export with queued work. Dispatch the report export to the rendering queue and remove accepted queued-work entries. Start unfinished rendering and check that the requester still has report-use access and can open the report. Open the print page without a browser session and intercept allowed Platform reads as the requester, rejecting other requests. The print component loads source data and signals readiness or error on its document. Produce a bounded PDF or validate the page’s Excel output, store under the request key and settle success.

## When Something Fails

Refuse source or format problems before admission. No file request is created by those checks. Leave unsuccessful publication for another dispatch pass. A render can remain queued or be redelivered after a publish/delete interruption. Settle source removal or lost access as access_lost. No browser starts for a refused source. A refused in-page request fails rendering. The browser result is not accepted as a valid report after a refused request. Page errors or readiness timeout fail the render. There is no accepted printable file until readiness succeeds. File-limit refusals settle without acceptance; infrastructure failures retry and become internal failure on the final receive. An upload followed by failed settlement can leave the object ahead of its running row.

## Idempotency and Concurrency

The render request retains its export identity and storage key; terminal status prevents restarting settled work on redelivery. Rendering uses its own queue and headless-browser worker limits. It does not share the interactive query-file generator.
