LiveReportArtefact
LiveReportArtefact manifests define production-ready web applications that serve multiple ReportArtefacts as navigable pages with support for dynamic query parameter substitution.
Minimal definition
Section titled “Minimal definition”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-reportAll 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.
Fields
Section titled “Fields”spec.title (required)
Section titled “spec.title (required)”Human-readable title of the live report application.
spec.description
Section titled “spec.description”Optional description of the application.
spec.pwa
Section titled “spec.pwa”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 tospec.title.shortName– short name shown under the home screen icon. Defaults toname.description– description shown in install prompts. Defaults tospec.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 ofstandalone(default),fullscreen,minimal-ui,browser.icons(required) – installable app icons, see below.
spec.pwa.icons
Section titled “spec.pwa.icons”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.nameof anAssetwithspec.type: imageand asource.localPath. Icons are served from the local file; remote or inline asset sources are rejected.sizes(required) – pixel dimensions asWIDTHxHEIGHT, e.g.512x512.purpose–any(default) for a regular icon, ormaskablefor 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-reportspec.routes (required)
Section titled “spec.routes (required)”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 aReportArtefactto render for this route.layoutPages– a singleLayoutPagename, or an array whose entries are either a name, a glob pattern matchingLayoutPagenames, or an object withpageandparams, 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-reportUsing layoutPages (single page):
routes:
"/":
layoutPages: overview-pageUsing layoutPages (multiple pages):
routes:
"/":
layoutPages:
- page-1
- page-2
- page-3String 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.
spec.routes[path].queryParams
Section titled “spec.routes[path].queryParams”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.default– default value if parameter is not provided.optional– iftrue, the parameter is optional even without a default value. The parameter will be empty if not provided.description– human-readable description.options– configuration forselect,number, andnumber_rangetypes:itemsfor a static option list (each item requires avalue, itslabeldefaults to that value),datasetwithvalueColumnandlabelColumnfor options loaded from aDataSet, andmin,max,stepfor 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.
Parameter types
Section titled “Parameter types”| 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 (ISO 8601 format). |
Options configuration
Section titled “Options configuration”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_nameThe 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: 100Query parameter substitution
Section titled “Query parameter substitution”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:
type: query
query: |
SELECT * FROM sales
WHERE year = ${YEAR}
AND region = '${REGION}'When accessed with ?YEAR=2024®ION=EU, the query becomes:
SELECT * FROM sales
WHERE year = 2024
AND region = 'EU'Using labels in display text
Section titled “Using labels in display text”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}"Minimal example
Section titled “Minimal example”---
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-reportServe with:
bino serve --live dashboardMulti-page application
Section titled “Multi-page application”---
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"Dynamic reports with query params
Section titled “Dynamic reports with query params”---
apiVersion: bino.bi/v1alpha1
kind: DataSet
metadata:
name: year_sales
spec:
type: query
query: |
SELECT * FROM raw_sales
WHERE extract(year from sale_date) = ${YEAR:2024}
---
apiVersion: bino.bi/v1alpha1
kind: DataSet
metadata:
name: department_list
spec:
type: query
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: 100Access 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
Navigation
Section titled “Navigation”LiveReportArtefact applications include built-in navigation. When navigating between routes:
- The browser URL updates via History API.
- Only the report content is fetched and swapped.
- Assets (CSS, fonts, scripts) are not reloaded.
This provides a smooth single-page application experience while maintaining proper URL routing.
Parameterized LayoutPages in routes
Section titled “Parameterized LayoutPages in routes”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.
Basic usage
Section titled “Basic usage”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: 2030When users visit /regional?REGION=US&YEAR=2023, the query params flow into the LayoutPage params, rendering the page with those values.
Combining static and dynamic params
Section titled “Combining static and dynamic params”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.
Multiple parameterized pages
Section titled “Multiple parameterized pages”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.
Complete example
Section titled “Complete example”---
# 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
Validation
Section titled “Validation”The CLI validates LiveReportArtefact manifests at load time:
- Root route
/must be present. - All route paths must start with
/. - The paths
/manifest.webmanifestand/sw.jsare reserved for PWA serving and are rejected as route paths — even whenspec.pwais not set. - All referenced
artefactnames must correspond to existingReportArtefactmanifests. - All referenced LayoutPages in
layoutPagesmust exist. - Query parameter names must be unique within each route.
- Every
spec.pwa.icons[].assetmust name an existingAssetmanifest withspec.type: imageand asource.localPath.
Validation errors are reported before the server starts.
Attribute Reference
Section titled “Attribute Reference”Common Metadata
Section titled “Common Metadata”| 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. |
Spec Attributes
Section titled “Spec Attributes”| 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.