---
id: CAP-PFM-QRY-011
title: Maintain a shared report library
feature: FEAT-PFM-QRY-04
product_area: platform
module: queries
revision: 1
status: draft
product_intent: confirmed
implementation_evidence: observed
supersedes:
  - CAP-RPT-CAT-001
  - CAP-RPT-CAT-002
  - CAP-RPT-CAT-003
  - CAP-RPT-CAT-004
  - CAP-RPT-CAT-005
  - CAP-RPT-CAT-006
  - CAP-RPT-CAT-007
  - CAP-RPT-CAT-008
  - CAP-RPT-CAT-009
  - CAP-RPT-CAT-010
  - CAP-RPT-CAT-011
  - CAP-RPT-CAT-012
  - CAP-RPT-CAT-013
  - CAP-RPT-QRY-002
  - CAP-RPT-QRY-003
  - CAP-RPT-QRY-004
  - CAP-RPT-QRY-006
  - CAP-RPT-QRY-007
  - CAP-RPT-SUB-006
  - CAP-RPT-SUB-007
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - 'services-platform:docs/milestones/plans/RPT-M1-plan.md#A3'
  - 'services-platform:docs/milestones/plans/RPT-M1-plan.md#A4'
  - 'services-platform:docs/milestones/plans/RPT-M1-plan.md#D3'
  - 'services-platform:docs/milestones/plans/RPT-M1-plan.md#D4'
  - 'services-platform:docs/milestones/plans/RPT-M1-plan.md#D5'
  - 'services-platform:docs/milestones/plans/RPT-M1-plan.md#D9'
purpose: Keep reports discoverable and maintainable with controlled audiences and dependencies on saved questions.
outcomes:
  - Staff find built-in and customer reports in one catalog.
  - Layout sharing preserves execution access checks.
  - Catalog filtering excludes reports without accessible base sources.
concepts:
  - CON-PFM-QRY-003
actors:
  - ACT-PFM-013
  - ACT-PFM-014
  - ACT-PFM-007
  - ACT-PFM-015
surfaces:
  - console
  - api
preconditions: []
postconditions: []
permissions:
  - key: platform.reports.read
    where_checked: api
    scope: tenant
  - key: platform.reports.use
    where_checked: api
    scope: tenant
  - key: platform.reports.share
    where_checked: service
    scope: record
  - key: platform.reports.manage
    where_checked: service
    scope: record
  - key: platform.saved-queries.read and the dataset's query key (to read a report's data)
    where_checked: service
    scope: tenant
rules:
  - id: BR-CAP-PFM-QRY-011-01
    proved_by: [ATS-PFM-QRY-011-01, TST-PFM-QRY-233, TST-PFM-QRY-335]
    statement: >-
      A report’s audience includes its owner, selected-role holders, the workspace for organization sharing,
      and report managers, with other readers receiving a not-found response.
    kind: permission
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/reports.e2e.spec.js#answers a colleague’s read of a private
      report as 404, exactly as an id nobody holds
    origin: none
  - id: BR-CAP-PFM-QRY-011-02
    proved_by: [ATS-PFM-QRY-011-02, TST-PFM-QRY-050, TST-PFM-QRY-231]
    statement: >-
      Report reading requires read permission, whereas every write requires use permission, preventing Read
      Only users from creating, copying, saving, sharing or deleting reports.
    kind: permission
    enforced_at:
      - api
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/read-tier.e2e.spec.js#is refused creating a report, which
      includes copying one, with 403
    origin: 'services-platform:docs/milestones/plans/RPT-M1-plan.md#D5'
  - id: BR-CAP-PFM-QRY-011-03
    proved_by: [ATS-PFM-QRY-007-13, ATS-PFM-QRY-011-03, TST-PFM-QRY-074, TST-PFM-QRY-231]
    statement: >-
      Stored-report catalog reads check source-query visibility and base-dataset access for every reader,
      including managers, without validating the full definition or every joined dataset.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: 'services-platform:modules/queries/services/reports/report-library.ts:readableReports'
    origin: 'services-platform:docs/milestones/plans/RPT-M1-plan.md#D3'
  - id: BR-CAP-PFM-QRY-011-04
    proved_by: [ATS-PFM-QRY-006-18, ATS-PFM-QRY-011-04, ATS-PFM-QRY-011-14, ATS-PFM-QRY-011-15, ATS-PFM-QRY-012-11, TST-PFM-QRY-023, TST-PFM-QRY-233]
    statement: >-
      A report cannot have a wider audience than its saved query, and selected report roles must be contained
      in the query’s roles, with the narrower source identified on refusal.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/reports.e2e.spec.js#refuses a report shared wider than its
      saved query as 409 ReportSharedWiderThanQuery, naming the query
    origin: 'services-platform:docs/milestones/plans/RPT-M1-plan.md#A3'
  - id: BR-CAP-PFM-QRY-011-05
    proved_by: [ATS-PFM-QRY-011-05, TST-PFM-QRY-233, TST-PFM-QRY-411]
    statement: >-
      Owners and managers maintain reports; owners need share permission for audience changes, managers use
      manage permission, and an unchanged audience needs neither sharing grant.
    kind: permission
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/reports.e2e.spec.js#refuses sharing without
      platform.reports.share as 403
    origin: none
  - id: BR-CAP-PFM-QRY-011-06
    proved_by: [ATS-PFM-QRY-011-06, TST-PFM-QRY-068, TST-PFM-QRY-411]
    statement: >-
      Rhythm staff working under a workspace grant receive report-management powers over private and shared
      reports, while data-readability filtering still applies.
    kind: permission
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/queries/tests/unit/services/reports/report-access.spec.ts#gives staff every
      write power over a colleague’s private report, as a manager has
    origin: 'services-platform:docs/milestones/plans/RPT-M1-plan.md#D4'
  - id: BR-CAP-PFM-QRY-011-07
    proved_by: [ATS-PFM-QRY-011-07, TST-PFM-QRY-335, TST-PFM-QRY-411]
    statement: >-
      An authorized report-use holder can copy a visible report into a new private report they own; Read Only
      readers cannot create copies.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/queries/tests/integration/services/reports/report-library.integration.spec.js#lets
      a colleague copy an organization report it can see, the copy its own and private
    origin: none
  - id: BR-CAP-PFM-QRY-011-08
    proved_by: [ATS-PFM-QRY-011-08, TST-PFM-QRY-233]
    statement: >-
      Creating or saving a report requires a visible saved-query source, rejecting unseen sources as
      unavailable.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/reports.e2e.spec.js#refuses a saved query the caller may not
      see as 400 naming saved_query_id
    origin: none
  - id: BR-CAP-PFM-QRY-011-09
    proved_by: [ATS-PFM-QRY-011-09, TST-PFM-QRY-322, TST-PFM-QRY-359]
    statement: >-
      Reports have owner-unique case-insensitive names of one to 120 characters, descriptions of at most one
      thousand characters, one of four kinds and exact stored layouts bounded by 512 KiB.
    kind: validation
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/queries/tests/integration/services/persistence/reports.integration.spec.js#refuses
      a second report of the owner whose name differs only in case, storing nothing
    origin: none
  - id: BR-CAP-PFM-QRY-011-10
    proved_by: [ATS-PFM-QRY-011-10, TST-PFM-QRY-055, TST-PFM-QRY-233]
    statement: >-
      Saves carry the read version in their body and deletes supply it as a parameter, rejecting missing
      versions and conflicting stale changes.
    kind: validation
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/reports.e2e.spec.js#refuses a replacement that states no
      version as 400 MissingVersion
    origin: 'services-platform:docs/milestones/plans/RPT-M1-plan.md#RPT-M1-S08'
  - id: BR-CAP-PFM-QRY-011-11
    proved_by: [ATS-PFM-QRY-011-11, TST-PFM-QRY-127, TST-PFM-QRY-233]
    statement: >-
      Report reads flag source definitions changed since the report was saved, and another report save records
      the latest source versions.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/reports.e2e.spec.js#answers saved_query_changed once the
      saved query has been edited since the report was saved
    origin: none
  - id: BR-CAP-PFM-QRY-011-12
    proved_by: [ATS-PFM-QRY-011-12, ATS-PFM-QRY-011-16, ATS-PFM-QRY-011-17, ATS-PFM-QRY-013-12, ATS-PFM-QRY-015-18, TST-PFM-QRY-057, TST-PFM-QRY-069, TST-PFM-QRY-230]
    statement: >-
      Report deletion releases its saved-query dependency without deleting the query and pauses dependent
      schedules atomically.
    kind: lifecycle
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/query-schedules.e2e.spec.js#pauses the schedule
      report_deleted, its report gone
    origin: 'services-platform:docs/milestones/plans/RPT-M1-plan.md#D9'
  - id: BR-CAP-PFM-QRY-011-13
    proved_by: []
    statement: >-
      The catalog returns newest-updated reports without layouts in pages of at most one hundred, filtered by
      scope, name, kind or source query.
    kind: policy
    enforced_at:
      - api
      - service
    must_prove: false
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/reports.e2e.spec.js#answers each item without its
      definition, with its owner’s name
    origin: none
  - id: BR-CAP-PFM-QRY-011-14
    proved_by: []
    statement: >-
      Rhythm’s built-in reports ship in the console rather than stored records, and stored reports have no
      system-sharing audience.
    kind: policy
    enforced_at:
      - console
    must_prove: false
    provenance: documented
    source: 'services-platform:docs/queries/reports.md#Reports'
    origin: none
scenarios:
  - id: SC-CAP-PFM-QRY-011-01
    given: A reader lacks query access to the report’s base dataset.
    when: They request the report catalog.
    then: The report is omitted.
    provenance: test
    source: 'services-platform:modules/queries/tests/e2e/read-tier.e2e.spec.js#is not shown the report in the catalog'
  - id: SC-CAP-PFM-QRY-011-02
    given: Two clients hold the same report version.
    when: They submit successive changes against that version.
    then: The first succeeds and the stale change receives a conflict.
    provenance: test
    source: >-
      services-platform:modules/queries/tests/e2e/reports.e2e.spec.js#refuses a replacement at a version no
      longer in force as 409
edge_cases: []
constraints: []
depends_on:
  - CAP-PFM-QRY-006
  - CAP-PFM-QRY-007
related:
  - CAP-PFM-QRY-006
  - CAP-PFM-QRY-012
  - CAP-PFM-QRY-013
  - CAP-PFM-QRY-015
journeys:
  - JNY-PFM-QRY-001
open_questions: []
operations:
  - createReport
  - listReports
  - getReport
  - updateReport
  - deleteReport
tables:
  - reports.table.ts
  - report-shared-roles.table.ts
  - report-sources.table.ts
evidence:
  - 'Pinned reference: services-platform:docs/milestones/plans/RPT-M1-plan.md'
  - 'Pinned reference: services-platform:docs/queries/reports.md'
  - 'Pinned reference: services-platform:modules/queries/services/reports/report-library.ts'
  - 'Pinned reference: services-platform:modules/queries/tests/e2e/query-schedules.e2e.spec.js'
  - 'Pinned reference: services-platform:modules/queries/tests/e2e/read-tier.e2e.spec.js'
  - 'Pinned reference: services-platform:modules/queries/tests/e2e/reports.e2e.spec.js'
  - >-
    Pinned reference:
    services-platform:modules/queries/tests/integration/services/persistence/reports.integration.spec.js
  - >-
    Pinned reference:
    services-platform:modules/queries/tests/integration/services/reports/report-library.integration.spec.js
  - 'Pinned reference: services-platform:modules/queries/tests/unit/services/reports/report-access.spec.ts'
controls: [TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-DAT-005, TC-IAM-001, TC-IAM-003, TC-IAM-006, TC-LOG-001, TC-LOG-004, TC-LOG-005, TC-MON-002, TC-PI-001, TC-PI-003, TC-PI-005, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-TEN-004, TC-VEN-001, TC-VEN-002, TC-VEN-003]
exercised_by: [FAS-PFM-QRY-04-01, FAS-PFM-QRY-04-02, FAS-PFM-QRY-04-03, FAS-PFM-QRY-04-04, FAS-PFM-QRY-04-05, FAS-PFM-QRY-05-05]
suites: [TST-PFM-QRY-023, TST-PFM-QRY-050, TST-PFM-QRY-055, TST-PFM-QRY-057, TST-PFM-QRY-068, TST-PFM-QRY-069, TST-PFM-QRY-074, TST-PFM-QRY-127, TST-PFM-QRY-230, TST-PFM-QRY-231, TST-PFM-QRY-233, TST-PFM-QRY-322, TST-PFM-QRY-335, TST-PFM-QRY-359, TST-PFM-QRY-411]
---

# Maintain a shared report library

## Purpose

Keep reports discoverable and maintainable with controlled audiences and dependencies on saved questions.

## How It Works

Staff browse the report catalog and open a report they can see. Rhythm’s built-in entries and stored customer entries reach the catalog through different sources. A person with report use can save a private copy and choose an audience. Platform checks that the report does not exceed its saved query’s audience. Catalog readability checks consider the source and its base dataset, while actual execution still validates the query. A changed source can produce a warning that the saved presentation needs attention. Owners and managers maintain reports using versions to avoid overwriting another change. Deletion removes the report while retaining its query and exported files.

## Relationships

The report catalog links stored presentations with saved questions. Dashboard composition and rendered output use those records.
