Skip to content

LiveReportArtefact

LiveReportArtefact manifests define production-ready web applications that serve multiple ReportArtefacts as navigable pages with support for dynamic query parameter substitution.

The smallest well-formed LiveReportArtefact sets the required spec.title and the mandatory root route / with the deliverable it serves.

apiVersion: bino.bi/v1alpha1
kind: LiveReportArtefact
metadata:
  name: sales-dashboard
spec:
  title: "Sales Dashboard"
  routes:
    "/":
      artefact: overview-report

All attributes are listed in the Attribute Reference below.

Each route serves either an artefact or one or more layoutPages (see spec.routes and Parameterized LayoutPages in routes), and the application becomes installable only when spec.pwa is set.

Human-readable title of the live report application.

Optional description of the application.

Optional. When present, bino serve serves the application as an installable Progressive Web App: it generates a web app manifest and a service worker, and injects the manifest link, the service-worker registration, and - when configured - a theme-color meta tag and an apple-touch-icon link into every page. Titled non-root routes are additionally exposed as app shortcuts (the jump list on the installed app’s icon). When spec.pwa is absent, serving behavior is completely unchanged - no extra tags, routes, or defaults.

  • name - full application name shown during installation and on splash screens. Defaults to spec.title.
  • shortName - short name shown under the home screen icon. Defaults to name.
  • description - description shown in install prompts. Defaults to spec.description.
  • themeColor - theme color applied to the browser UI around the installed app, e.g. "#0B5FFF".
  • backgroundColor - background color of the splash screen shown while the installed app loads, e.g. "#FFFFFF".
  • display - display mode of the installed app. One of standalone (default), fullscreen, minimal-ui, browser.
  • icons (required) - installable app icons, see below.

Icons offered to the operating system for the installed app. At least one icon is required; include a 512x512 icon for best results.

Each icon references an Asset manifest:

  • asset (required) - metadata.name of an Asset with spec.type: image and a source.localPath. Icons are served from the local file; remote or inline asset sources are rejected.
  • sizes (required) - pixel dimensions as WIDTHxHEIGHT, e.g. 512x512.
  • purpose - any (default) for a regular icon, or maskable for an icon designed with a safe zone so the OS may apply an adaptive mask.

Example:

---
apiVersion: bino.bi/v1alpha1
kind: Asset
metadata:
  name: app-icon-192
spec:
  type: image
  mediaType: image/png
  source:
    localPath: ./assets/icon-192.png
---
apiVersion: bino.bi/v1alpha1
kind: Asset
metadata:
  name: app-icon-512
spec:
  type: image
  mediaType: image/png
  source:
    localPath: ./assets/icon-512.png
---
apiVersion: bino.bi/v1alpha1
kind: Asset
metadata:
  name: app-icon-maskable
spec:
  type: image
  mediaType: image/png
  source:
    localPath: ./assets/icon-maskable.png
---
apiVersion: bino.bi/v1alpha1
kind: LiveReportArtefact
metadata:
  name: sales-dashboard
spec:
  title: "Sales Dashboard"
  pwa:
    shortName: Sales
    themeColor: "#0B5FFF"
    backgroundColor: "#FFFFFF"
    icons:
      - asset: app-icon-192
        sizes: 192x192
      - asset: app-icon-512
        sizes: 512x512
      - asset: app-icon-maskable
        sizes: 512x512
        purpose: maskable
  routes:
    "/":
      artefact: overview-report

Map of URL paths to route configurations. The root route / is mandatory.

Each route must specify either artefact or layoutPages (but not both):

  • artefact - name of a ReportArtefact to render for this route.
  • layoutPages - a single LayoutPage name, or an array whose entries are either a name, a glob pattern matching LayoutPage names, or an object with page and params, rendered directly (without a ReportArtefact wrapper).
  • title - optional page title override.
  • queryParams - array of query parameters allowed for this route.

Routes are accessible at their defined paths, e.g., /sales renders sales-report.

Using artefact:

routes:
  "/":
    artefact: overview-report

Using layoutPages (single page):

routes:
  "/":
    layoutPages: overview-page

Using layoutPages (multiple pages):

routes:
  "/":
    layoutPages:
      - page-1
      - page-2
      - page-3

String entries in the array may also be glob patterns (*, ?, […]) that match LayoutPage names, e.g. - "sales-*". A glob entry expands to every matching page in name order; it cannot carry params.

The layoutPages option is useful when you want to serve individual LayoutPage documents directly without defining a full ReportArtefact.

Array of query parameters allowed for this specific route.

Each parameter has:

  • name (required) - parameter name, used as ${name} in documents.
  • type - input type for the serve UI. One of: string (default), number, number_range, select, date, date_time. The server also checks request values against the type, see Parameter types.
  • default - default value if parameter is not provided.
  • optional - if true, the parameter is optional even without a default value. The parameter will be empty if not provided.
  • description - human-readable description.
  • options - configuration for select, number, and number_range types: items for a static option list (each item requires a value, its label defaults to that value), dataset with valueColumn and labelColumn for options loaded from a DataSet, and min, max, step for numeric inputs.

Important: If a parameter has no default and optional is not true, the server returns HTTP 400 with a JSON error listing the missing parameters.

Type Input control Description
string Text input Default type. Free-text input.
number Number input Numeric input with optional min/max/step.
number_range Dual range slider For min/max range filtering. Creates two parameters: {name} and {name}_max.
select Dropdown Selection from predefined options (static or from a DataSet).
date Date picker Date selection (YYYY-MM-DD format).
date_time DateTime picker Date and time selection (YYYY-MM-DDTHH:MM, seconds optional, or RFC 3339).

The server checks each request value against the declared type and options. A number or number_range value must be a decimal number within min and max, a select value must be one of the static items, a date must be YYYY-MM-DD, and a date_time must be YYYY-MM-DDTHH:MM (seconds optional) or RFC 3339. A value that does not match is not used: the page shows the parameter form with the field highlighted instead of the report. An empty value for one of these types counts as not sent, so the default applies. string values and the values of a select that has no static items or sets options.dataset are not checked.

The options object supports different settings depending on the parameter type:

For select type:

queryParams:
  - name: REGION
    type: select
    description: "Select region"
    options:
      items:
        - value: "EU"
          label: "Europe"
        - value: "US"
          label: "United States"
        - value: "APAC"
          label: "Asia Pacific"

For select parameters with static items, you can access both the value and label:

  • ${REGION} - the value (e.g., "EU")
  • ${REGION_LABEL} - the label (e.g., "Europe")

This is useful for displaying human-readable text while using the value for data filtering.

For select with DataSet:

queryParams:
  - name: CATEGORY
    type: select
    description: "Select category"
    options:
      dataset: category_list
      valueColumn: category_id
      labelColumn: category_name

The referenced DataSet should return rows with the specified columns. If labelColumn is omitted, valueColumn is used for both.

For number and number_range types:

queryParams:
  - name: YEAR
    type: number
    default: "2024"
    options:
      min: 2000
      max: 2030
      step: 1
  - name: PRICE
    type: number_range
    description: "Price range filter"
    options:
      min: 0
      max: 10000
      step: 100

Query parameters are substituted into your report documents using the same ${VAR} syntax as environment variables. This allows dynamic filtering of data.

Example DataSet using a query parameter:

apiVersion: bino.bi/v1alpha1
kind: DataSet
metadata:
  name: filtered_sales
spec:
  query: |
    SELECT * FROM sales
    WHERE year = ${YEAR}
    AND region = '${REGION}'

When accessed with ?YEAR=2024&REGION=EU, the query becomes:

SELECT * FROM sales
WHERE year = 2024
AND region = 'EU'

When a route must deliver only some rows, filter in the DataSet query as filtered_sales does. Do not use a component filter for this: it runs in the browser, so every row of the component’s dataset reaches the viewer. Filtering in the DataSet limits the rows per viewer only when a layer in front of bino serve, for example a proxy, sets the parameters and the viewer cannot change them. See Data sent to the browser.

For select parameters with static items, use ${PARAM_LABEL} to show the human-readable label:

apiVersion: bino.bi/v1alpha1
kind: LayoutPage
metadata:
  name: sales-page
spec:
  children:
    - kind: Text
      spec:
        # Shows "Sales Report for Europe" instead of "Sales Report for EU"
        value: "Sales Report for ${REGION_LABEL}"
---
apiVersion: bino.bi/v1alpha1
kind: ReportArtefact
metadata:
  name: main-report
spec:
  filename: main.pdf
  title: "Main Report"
---
apiVersion: bino.bi/v1alpha1
kind: LiveReportArtefact
metadata:
  name: dashboard
spec:
  title: "Dashboard"
  routes:
    "/":
      artefact: main-report

Serve with:

bino serve --live dashboard
---
apiVersion: bino.bi/v1alpha1
kind: ReportArtefact
metadata:
  name: overview
spec:
  filename: overview.pdf
  title: "Overview"
---
apiVersion: bino.bi/v1alpha1
kind: ReportArtefact
metadata:
  name: sales
spec:
  filename: sales.pdf
  title: "Sales Detail"
---
apiVersion: bino.bi/v1alpha1
kind: ReportArtefact
metadata:
  name: regions
spec:
  filename: regions.pdf
  title: "Regional Analysis"
---
apiVersion: bino.bi/v1alpha1
kind: LiveReportArtefact
metadata:
  name: sales-app
spec:
  title: "Sales Application"
  routes:
    "/":
      artefact: overview
      queryParams:
        - name: YEAR
          default: "2024"
          description: "Reporting year"
    "/sales":
      artefact: sales
      title: "Sales Details"
    "/regions":
      artefact: regions
      title: "Regions"
---
apiVersion: bino.bi/v1alpha1
kind: DataSet
metadata:
  name: year_sales
spec:
  query: |
    SELECT * FROM raw_sales
    WHERE extract(year from sale_date) = ${YEAR:2024}
---
apiVersion: bino.bi/v1alpha1
kind: DataSet
metadata:
  name: department_list
spec:
  query: |
    SELECT DISTINCT department_id, department_name FROM departments ORDER BY department_name
---
apiVersion: bino.bi/v1alpha1
kind: LiveReportArtefact
metadata:
  name: dynamic-report
spec:
  title: "Dynamic Report"
  routes:
    "/":
      artefact: main-report
      queryParams:
        - name: YEAR
          type: number
          default: "2024"
          description: "Year for analysis"
          options:
            min: 2000
            max: 2030
        - name: DEPARTMENT
          type: select
          description: "Department (required)"
          options:
            dataset: department_list
            valueColumn: department_id
            labelColumn: department_name
        - name: START_DATE
          type: date
          description: "Start date for report period"
        - name: AMOUNT_RANGE
          type: number_range
          description: "Filter by amount"
          options:
            min: 0
            step: 100

Access patterns:

  • / - uses default YEAR=2024, but requires DEPARTMENT
  • /?DEPARTMENT=sales - works, uses default YEAR
  • /?YEAR=2023&DEPARTMENT=marketing - overrides YEAR
  • /?YEAR=2023 - returns HTTP 400: missing DEPARTMENT

LiveReportArtefact applications include built-in navigation. When navigating between routes:

  1. The browser URL updates via History API.
  2. Only the report content is fetched and swapped.
  3. Assets (CSS, fonts, scripts) are not reloaded.

This provides a smooth single-page application experience while maintaining proper URL routing.

When using layoutPages in a route, you can pass parameters to LayoutPages that define them. This combines the power of LayoutPage parameters with dynamic query parameters.

apiVersion: bino.bi/v1alpha1
kind: LiveReportArtefact
metadata:
  name: regional-dashboard
spec:
  title: "Regional Dashboard"
  routes:
    "/regional":
      layoutPages:
        - page: regional-sales
          params:
            REGION: ${REGION} # From query params
            YEAR: ${YEAR}
      queryParams:
        - name: REGION
          type: select
          default: "EU"
          options:
            items:
              - value: "EU"
                label: "Europe"
              - value: "US"
                label: "North America"
              - value: "APAC"
                label: "Asia Pacific"
        - name: YEAR
          type: number
          default: "2024"
          options:
            min: 2020
            max: 2030

When users visit /regional?REGION=US&YEAR=2023, the query params flow into the LayoutPage params, rendering the page with those values.

You can mix static values with dynamic query param references:

routes:
  "/comparison":
    layoutPages:
      # First page: current year, user-selected region
      - page: regional-sales
        params:
          REGION: ${REGION}
          YEAR: "2024" # Static value
          LABEL: "Current Year"

      # Second page: previous year, same region
      - page: regional-sales
        params:
          REGION: ${REGION} # Same as user selected
          YEAR: "2023" # Static: previous year
          LABEL: "Previous Year"
    queryParams:
      - name: REGION
        type: select
        default: "EU"

This creates a comparison view showing two years side by side.

Include the same LayoutPage multiple times with different parameter combinations:

routes:
  "/all-regions":
    layoutPages:
      - page: regional-sales
        params:
          REGION: EU
          YEAR: ${YEAR}
      - page: regional-sales
        params:
          REGION: US
          YEAR: ${YEAR}
      - page: regional-sales
        params:
          REGION: APAC
          YEAR: ${YEAR}
    queryParams:
      - name: YEAR
        type: number
        default: "2024"

This shows all three regions on a single page, with the year controlled by the query parameter.

---
# Define a parameterized LayoutPage
apiVersion: bino.bi/v1alpha1
kind: LayoutPage
metadata:
  name: department-kpis
  params:
    - name: DEPARTMENT
      type: string
      required: true
    - name: YEAR
      type: number
      default: "2024"
    - name: SHOW_FORECAST
      type: boolean
      default: "false"
spec:
  titleBusinessUnit: "${DEPARTMENT} KPIs"
  pageLayout: 2x2
  children:
    - kind: Text
      spec:
        value: "${DEPARTMENT} Performance - ${YEAR}"
    - kind: ChartStructure
      spec:
        dataset: department-data
        chartTitle: "Revenue"
    - kind: Table
      spec:
        dataset: department-data

---
# Use it in a LiveReportArtefact
apiVersion: bino.bi/v1alpha1
kind: LiveReportArtefact
metadata:
  name: department-dashboard
spec:
  title: "Department Dashboard"
  routes:
    # Single department view
    "/":
      layoutPages:
        - page: department-kpis
          params:
            DEPARTMENT: ${DEPARTMENT}
            YEAR: ${YEAR}
            SHOW_FORECAST: ${SHOW_FORECAST:false}
      queryParams:
        - name: DEPARTMENT
          type: select
          description: "Select department"
          options:
            dataset: department_list
            valueColumn: dept_id
            labelColumn: dept_name
        - name: YEAR
          type: number
          default: "2024"
          options:
            min: 2020
            max: 2030
        - name: SHOW_FORECAST
          type: select
          default: "false"
          options:
            items:
              - value: "true"
                label: "Yes"
              - value: "false"
                label: "No"

    # All departments view
    "/all":
      layoutPages:
        - page: department-kpis
          params:
            DEPARTMENT: "Sales"
            YEAR: ${YEAR}
        - page: department-kpis
          params:
            DEPARTMENT: "Marketing"
            YEAR: ${YEAR}
        - page: department-kpis
          params:
            DEPARTMENT: "Engineering"
            YEAR: ${YEAR}
      queryParams:
        - name: YEAR
          type: number
          default: "2024"

Access patterns:

  • /?DEPARTMENT=Sales - Shows Sales department for 2024
  • /?DEPARTMENT=Marketing&YEAR=2023 - Shows Marketing for 2023
  • /all - Shows all departments for 2024
  • /all?YEAR=2022 - Shows all departments for 2022

The CLI validates LiveReportArtefact manifests at load time:

  • Root route / must be present.
  • All route paths must start with /.
  • The paths /manifest.webmanifest and /sw.js are reserved for PWA serving and are rejected as route paths - even when spec.pwa is not set.
  • All referenced artefact names must correspond to existing ReportArtefact manifests.
  • All referenced LayoutPages in layoutPages must exist.
  • Query parameter names must be unique within each route.
  • Every spec.pwa.icons[].asset must name an existing Asset manifest with spec.type: image and a source.localPath.

Validation errors are reported before the server starts.

Attribute Type Required Default Description
apiVersion string yes - Must be bino.bi/v1alpha1.
kind string yes - Must be LiveReportArtefact.
metadata.name string yes - Unique identifier, used with bino serve --live <name>.
metadata.labels object no - Key-value pairs for categorization and constraint matching.
metadata.annotations object no - Arbitrary key-value metadata, not used by the system.
metadata.description string no - Free-form description.
metadata.constraints array no - Conditional inclusion rules. See Constraints.
Attribute Type Required Default Description Sample
spec.title string yes - Human-readable title of the live report application. Must not be empty. title: "Sales Dashboard"
spec.description string no - Description of the application. Also the fallback for spec.pwa.description. description: "Interactive sales reporting application"
spec.pwa object no - Progressive Web App configuration. When present, bino serve adds a web app manifest, a service worker, and the related tags; when absent, serving behavior is unchanged. See spec.pwa. pwa: { shortName: Sales, icons: [...] }
spec.pwa.name string no spec.title Full application name shown during installation and on splash screens. name: "Sales Dashboard"
spec.pwa.shortName string no pwa.name Short name shown under the home screen icon. shortName: Sales
spec.pwa.description string no spec.description Description shown in install prompts. description: "Sales KPIs on the go"
spec.pwa.themeColor string no - Theme color applied to the browser UI around the installed app. themeColor: "#0B5FFF"
spec.pwa.backgroundColor string no - Background color of the splash screen shown while the installed app loads. backgroundColor: "#FFFFFF"
spec.pwa.display string no standalone Display mode of the installed app. Values: standalone, fullscreen, minimal-ui, browser. display: fullscreen
spec.pwa.icons array yes (within pwa) - Icons offered to the operating system, at least one. A 512x512 icon is recommended. See spec.pwa.icons. icons: [{ asset: app-icon, sizes: 512x512 }]
spec.pwa.icons[].asset string yes - metadata.name of an Asset with spec.type: image and a source.localPath. Remote or inline asset sources are rejected. asset: app-icon-512
spec.pwa.icons[].sizes string yes - Pixel dimensions as WIDTHxHEIGHT. sizes: 512x512
spec.pwa.icons[].purpose string no any Icon purpose. Values: any for a regular icon, maskable for an icon with a safe zone the OS may mask. purpose: maskable
spec.routes object yes - Map of URL paths to route configurations. The key / is mandatory; every path must start with /; /manifest.webmanifest and /sw.js are reserved. See spec.routes. routes: { "/": { artefact: overview-report } }
spec.routes[path] object - - One route. Must set exactly one of artefact or layoutPages. "/sales": { artefact: sales-report, title: "Sales Analysis" }
spec.routes[path].artefact string one of artefact / layoutPages - metadata.name of the ReportArtefact rendered for this route. Cannot be combined with layoutPages. artefact: overview-report
spec.routes[path].layoutPages string or array one of artefact / layoutPages - One or more LayoutPage documents rendered directly, without a ReportArtefact wrapper. Cannot be combined with artefact. layoutPages: overview-page
spec.routes[path].layoutPages[] string or object - - Array entry: a LayoutPage name, a glob pattern matching names, or the object form below. - summary-page
spec.routes[path].layoutPages[].page string yes (in object form) - Exact LayoutPage name, no glob pattern. See Parameterized LayoutPages in routes. page: regional-sales
spec.routes[path].layoutPages[].params object of strings no - Parameter values passed to the LayoutPage; keys must match its metadata.params. Values may be static or ${QUERY_PARAM} references. params: { REGION: "${REGION}" }
spec.routes[path].title string no - Page title override for this route. Titled non-root routes also become PWA app shortcuts. title: "Regional Breakdown"
spec.routes[path].queryParams array no - Query parameters allowed for this route, substituted as ${VAR} in the documents. Names must be unique per route. See spec.routes[path].queryParams. queryParams: [{ name: YEAR, default: "2024" }]
spec.routes[path].queryParams[].name string yes - Parameter name, used as ${name} in documents. Must match ^[A-Za-z_][A-Za-z0-9_]*$. name: REGION
spec.routes[path].queryParams[].type string no string Input control in the serve UI. Values: string, number, number_range, select, date, date_time. See Parameter types. type: select
spec.routes[path].queryParams[].default string no - Default value when the parameter is not provided. Without a default and without optional: true the request returns HTTP 400. default: "2024"
spec.routes[path].queryParams[].optional boolean no false If true, the parameter may be missing without a default; it is then empty. optional: true
spec.routes[path].queryParams[].description string no - Human-readable description of what the parameter controls. description: "Year to display"
spec.routes[path].queryParams[].options object no - Input configuration for select, number, and number_range. See Options configuration. options: { min: 2000, max: 2030 }
spec.routes[path].queryParams[].options.items array no - Static option list for select. items: [{ value: "EU", label: "Europe" }]
spec.routes[path].queryParams[].options.items[].value string yes - Value submitted when the option is selected, available as ${NAME}. value: "EU"
spec.routes[path].queryParams[].options.items[].label string no the item’s value Human-readable label, available as ${NAME_LABEL}. label: "Europe"
spec.routes[path].queryParams[].options.dataset string no - Name of a DataSet the select options are loaded from. dataset: category_list
spec.routes[path].queryParams[].options.valueColumn string no - Dataset column used as the option value. valueColumn: category_id
spec.routes[path].queryParams[].options.labelColumn string no valueColumn Dataset column used as the option label. labelColumn: category_name
spec.routes[path].queryParams[].options.min number no - Minimum value for number and number_range. min: 2000
spec.routes[path].queryParams[].options.max number no - Maximum value for number and number_range. max: 2030
spec.routes[path].queryParams[].options.step number no - Step increment for number and number_range. step: 100

See ReportArtefact for the PDF deliverable served by a route, and bino serve for running the application.