Skip to the lesson
CivOps AI Academy · M23Dashboards and Reporting: Every Number from One Metric Registry
0%

Chapter 1 · Purpose, scope and standards

One registry, one number

Most reporting tools let anyone calculate a figure inside a chart. This module does the opposite: dashboards, reports and alerts can show only numbers defined once, in the data fabric's metric registry, so the same figure means the same thing on every screen.

20 min8 dash_ tables9 capabilities4 standards

By the end of this chapter you can

  • Explain why a figure is defined once in a registry and read everywhere, instead of calculated in each chart.
  • Say what the module covers, and what stays with the data fabric.
  • Name the module's two pitfalls and the four standards it applies.

Why a figure is defined once

Business intelligence tools such as Microsoft Power BI, Tableau, Looker, Metabase, Grafana, Domo, Qlik Sense and Klipfolio let a builder drag a field onto a chart and calculate a figure there. That freedom is their strength. It is also how two reports come to show different answers for the same week: each chart keeps its own copy of the formula, and the copies drift apart.

This module gives every role the numbers it decides with from one source. A dashboard panel names a metric that is registered in the data fabric, and the platform reads the figure from the registry. The panel cannot hold a typed number or a figure calculated on the screen. The result is that the screen, the emailed report and the alert all show the same number, and any number can be followed back to its definition and its data.

One definition, many readersLeft: two reports each calculate scrap rate in their own chart and show 3.5 and 3.3 for the same week. Right: one registry definition feeds the screen, the report and the alert, which all show 3.3. CALCULATED IN EACH CHARTReport Aaverage of the two line rates: 3.5Report Btotal scrap ÷ total units: 3.3Same figure, same week, two answersEach copy of a definition drifts apart.DEFINED ONCE IN THE REGISTRYMetric registryscrap_rate · one formula · version 1Screen3.3Report3.3Alert3.3Every reader gets the same number
Defined once, read everywhere. Two reports that calculate scrap rate in their own charts give 3.5 and 3.3 for the same week. With one definition in the registry, the screen, the report and the alert all give 3.3.

What the module covers

The module builds dashboards and panels on registered metrics and dimensions, shares them by role through the Role and Exposure Matrix, adds filters, drill-down and time comparison, sends scheduled reports, raises alerts that a person acknowledges, and shows where any number comes from. It also embeds the same views on the three surfaces: operator at the machine, supervisor on the floor and manager in the office.

The edge of Dashboards and reportingInside: metric-bound panels, role dashboards, filters and drill-down, period comparisons, sharing by role, reports and alerts, lineage and no-data coverage. Outside, owned by the data fabric: metric definitions, ad-hoc SQL on tables (refused), and the warehouse and ETL. INSIDE DASHBOARDS (M23)Metric-bound panelsRole dashboardsFilters and drill-downPeriod comparisonsSharing by roleReports and alertsLineageNo-data coverageOUTSIDE, WITH ITS OWNERMetric definitionsdata fabric metric registryAd-hoc SQL on tablesrefused: numbers comefrom the fabricWarehouse and ETLdata fabric
The edge of the module. Defining and calculating metrics belongs to the data fabric. The dashboards refuse ad-hoc SQL against operational tables, so a number can only come from the fabric.
CapabilityWhat it doesTier
Metric-bound panelsEvery panel names a registered metric and its dimensions. It cannot hold a typed or computed-on-screen number.MVP
Dashboards and layoutDashboards per role and surface; versioned layouts; drafts and publish.MVP
Filters and drill-downSite, line, product and period filters; drill to the records behind a number.MVP
ComparisonsPeriod over period, and target against actual, with the target's owner and source.STD
Sharing and accessShared by role through the Role and Exposure Matrix; row-level security on every query.MVP
Scheduled reportsPDF or CSV snapshots on a schedule, with a delivery log.STD
AlertsThreshold and anomaly alerts on a metric, with acknowledgement and escalation.STD
LineageFrom any value to its metric definition, version and source data.MVP
Coverage reportingShows which panels have data behind them. A panel with no data says "no data", never zero.MVP

MVP capabilities are the must-haves before a business can cancel its old tool with confidence. STD capabilities match what mainstream tools offer.

Two pitfalls to design out

PitfallHow it showsWhat the module does
Calculating a KPI in the chartTwo reports give two answers for one figure, and nobody knows which is right.The panel stores only a metric key. The formula lives once in the registry, with an owner and a version.
Showing zero when there is no dataA line that did not run, or a site with no records, reads as a perfect score.No rows for the filter and period means "no data" with the reason. Only a stored 0 is shown as 0.

Four standards the module applies

StandardUse in this module
ISO 22400-2Definitions of manufacturing KPIs shown on operations dashboards [1].
IBCSConsistent notation for business charts and variance displays [2].
ISO 8601Dates, times and periods in filters and exports [3].
W3C WCAG 2.2 AAAccessible charts: contrast, text alternatives and keyboard use [4].
Exercise · Find a figure with two definitions15 minutes

You need: The reporting tool or spreadsheets your business uses today, and the person who owns the main report

Do this on your own business's reports. Use roles, never names, and keep any export in a private folder outside the repository.

Outcome: A list of the report's figures sorted by where each is calculated, one pair of figures that disagree (or a note that you found none), and one example of zero shown for no data.

Knowledge check

A report shows scrap rate calculated in the chart, and a second report shows it calculated differently. What is the lasting fix?

Knowledge check

A line did not run last week and the source has no rows for it. What should its panel show?

References

  1. ISO 22400-2:2014 Key performance indicators for manufacturing operations management. https://www.iso.org/standard/54497.html
  2. International Business Communication Standards (IBCS). https://www.ibcs.com/standards/
  3. ISO 8601 date and time format. https://www.iso.org/iso-8601-date-and-time-format.html
  4. W3C Web Content Accessibility Guidelines (WCAG) 2.2. https://www.w3.org/TR/WCAG22/

Chapter 2 · The data model

Tables, panels and versions

Eight dash_ tables hold dashboards, panels, shares, report schedules and alerts. They point at a small registry of metrics and at the spine's people, roles and files, and a set of database rules keeps every number honest.

25 min8 dash_ tables5 registry tables7 chart types

By the end of this chapter you can

  • Name the eight dash_ tables, the registry tables they read and the spine tables they use.
  • Read the column tables: types, required columns and allowed values.
  • Explain draft, publish and immutable versions, and the rules the database enforces.

The tables and what they point at

Every table in the module starts with the standard columns that every spine table has: id, tenant_id, created_at, created_by, updated_at, updated_by, row_version, archived_at and ext. The module has no people table, role list or file store of its own. It points at core_person, core_job_role, core_org_unit, core_attachment and core_action_item.

The eight dash_ tablesDashboard versions, panels, shares and report schedules point at dash_dashboard; report deliveries point at schedules; panels and alert rules name a metric in the registry; alert events point at alert rules; the spine tables supply people, roles, org units, attachments and action items. dash_dashboard_versionimmutable layoutdash_dashboardkey, surface, statusdash_panelmetric_key names aregistered metricfab_metricthe registry, ownedby the data fabricdash_report_schedulecron, format, recipientsdash_dashboard_sharerole, org unit or persondash_alert_rulemetric_key, kind, valuedash_report_deliverysent, failed, skippeddash_alert_eventopen, acknowledgedSPINE TABLEScore_personcore_job_rolecore_org_unitcore_attachmentcore_action_itemArrows run from the table that holds the key to the table it names.
The eight dash_ tables. Panels and alert rules name a metric in the registry by its code. The registry is owned by the data fabric, not by the dashboards.
TableWhat a row is
dash_dashboardA dashboard for a role and a surface.
dash_dashboard_versionAn immutable published layout.
dash_panelA panel bound to a registered metric.
dash_dashboard_shareWho may see a dashboard: a job role, an org unit or a person.
dash_report_scheduleA scheduled snapshot of a dashboard, as PDF or CSV.
dash_report_deliveryOne scheduled report sent, failed or skipped.
dash_alert_ruleA threshold or anomaly rule on a metric.
dash_alert_eventAn alert raised, and how it was handled.

Column reference

These are the columns your AI coding agent builds from. Required means not null; allowed values are check constraints, which the database tests on every row. A foreign key is a column whose value must match the id of a row in another table. jsonb is a column type that holds structured data written like {"site": "S1"}, which Postgres can search inside.

dash_dashboard

ColumnTypeRequiredAllowed values or note
keytextyesUnique per business, for example line-1-operator.
titletextyes
surfacetextyesoperator, supervisor, manager
owner_iduuidyesForeign key to core_person.
statustextyesdraft, published, archived
published_version_iduuidnoMust name a version of this same dashboard.

dash_dashboard_version

ColumnTypeRequiredAllowed values or note
dashboard_iduuidyesForeign key to dash_dashboard.
version_nointyesUnique per dashboard.
layoutjsonbyesThe panels as published. Holds no value, number or formula of its own.
published_attimestampnoISO 8601 in UTC.
published_byuuidnoForeign key to core_person.

dash_panel

ColumnTypeRequiredAllowed values or note
dashboard_iduuidyesForeign key to dash_dashboard.
titletextyes
metric_keytextyesThe code of an approved metric in the registry. Not a foreign key: a rule checks it.
dimensionsjsonbnoA filter of dimension codes and values, and an optional group_by.
charttextyesnumber, line, bar, table, gauge, heatmap, pareto
default_periodtextyesAn ISO 8601 duration of the form PnD or PnW, such as P7D.
target_metric_keytextnoUsed only when the target is itself a registered metric.
seqintyesOrder on the dashboard.

dash_dashboard_share

ColumnTypeRequiredAllowed values or note
dashboard_iduuidyesForeign key to dash_dashboard.
job_role_iduuidnoForeign key to core_job_role.
org_unit_iduuidnoForeign key to core_org_unit.
person_iduuidnoForeign key to core_person. Exactly one of the three targets must be set.

dash_report_schedule

ColumnTypeRequiredAllowed values or note
dashboard_iduuidyesForeign key to dash_dashboard.
crontextyesFive fields: minute, hour, day of month, month, day of week.
formattextyespdf, csv
recipientsjsonbyesA list of core_person ids, never typed email addresses.
filtersjsonbnoDimension codes and values that narrow every panel.
activeboolyes

dash_report_delivery

ColumnTypeRequiredAllowed values or note
report_schedule_iduuidyesForeign key to dash_report_schedule.
attimestampyes
statustextyessent, failed, skipped_no_data
attachment_iduuidnoForeign key to core_attachment. Empty when skipped_no_data.
errortextnoThe error text of a failed delivery.

dash_alert_rule

ColumnTypeRequiredAllowed values or note
metric_keytextyesThe code of an approved metric.
dimensionsjsonbnoDimension codes and values the rule watches.
kindtextyesthreshold, anomaly
operatortextyesgt, lt, outside_band
valuenumericnoThe limit, or the width of the band.
severitytextyesinfo, warning, critical
owner_iduuidyesForeign key to core_person.
activeboolyes

dash_alert_event

ColumnTypeRequiredAllowed values or note
alert_rule_iduuidyesForeign key to dash_alert_rule.
raised_attimestampyes
observed_valuenumericnoThe value that broke the rule.
statustextyesopen, acknowledged, resolved
acknowledged_byuuidnoForeign key to core_person. Always the signed-in person.
acknowledged_attimestampno
action_item_iduuidnoForeign key to core_action_item.

The registry tables the dashboards read

The data fabric owns these. The course builds the five it needs, each with the standard columns and row-level security. Keep numerator, denominator and value as exact decimals (numeric), never floating point, so a rate adds up the same way every time.

TableColumns
fab_entity_registrytable_name (unique), module_code, entity_kind (master, transaction, event, timeseries, aggregate, metadata, academy), description, classification (public, internal, confidential, restricted), contains_pii, contains_health.
fab_dimensioncode (unique), name, source_entity_id, hierarchy (jsonb), status (active, deprecated).
fab_metriccode (unique), name, definition, formula, standard_ref, uom_id, grain (event, shift, day, week, month, order, lot, asset, person), direction (higher_better, lower_better, on_target), target (number), owner_module, status (draft, approved, deprecated).
fab_metric_inputmetric_id, entity_id, role (numerator, denominator, filter, dimension, source).
fab_metric_valuemetric_id, grain, period_start, period_end, dimension_key (jsonb), value, numerator, denominator, computed_at, quality_score. Append-only: a correction is a new row with a later computed_at. Every dimension_key includes the site code, because operator and supervisor reads are limited to their own site by it.

A panel is a question, not a number

A panel row says which metric to ask for, how to slice it, how to draw it and over which period. It never says what the answer is.

A dash_panel row: a metric code and a question, no value
{
  "dashboard": "line-1-operator",
  "title": "Scrap rate, last 7 days",
  "metric_key": "scrap_rate",
  "dimensions": { "filter": { "site": "S1", "line": "L1" } },
  "chart": "number",
  "default_period": "P7D",
  "target_metric_key": null,
  "seq": 1
}
ChartUse it to
numberShow one figure, with its target and the previous period.
lineShow a trend over days.
barCompare the members of one dimension, such as lines.
tableShow exact values. It also serves as the text alternative of the other charts.
gaugeShow one value against its target.
heatmapShow two dimensions at once, such as line and day.
paretoRank causes by size, with the running share.

Draft, publish, version

A builder edits a dashboard as a draft. Publishing writes the next row in dash_dashboard_version from the saved panels, sets published_version_id, and records a dash.dashboard.published event. Viewers read only the published version, so editing a panel changes nothing for them until the next publish. A published layout never changes: a change is a new version, and the older ones remain as the record of what readers saw.

Draft, publish and versionsA dashboard is drafted, published and archived. Each publish adds an immutable version; the dashboard's published_version_id names the one viewers read. Editing panels changes nothing for viewers until the next publish. draftpanels are edited herepublishedviewers read a versionarchivedhidden, history keptVersion 1layout never changesVersion 2layout never changesVersion 3made at next publishpublished_version_idViewers neversee a draft.Panel editschange nothingfor viewersuntil thenext publish.
Drafts change; versions do not. The dashboard points at the version viewers read. The next publish adds a version and moves the pointer.

The module publishes dash.dashboard.published, dash.alert.raised and dash.alert.acknowledged. It consumes fab.metric.version_published, so the owners of dashboards that use a metric are told when its meaning changes, and fab.quality.score_dropped. A metric's version is its row_version, and ISO 8601 [2] fixes how every date and period is written. A metric may carry a reference to a standard such as ISO 22400-2 in standard_ref [3].

Exercise · Write one figure as a metric and a panel15 minutes

You need: One figure from your own main report (from the previous exercise) and a text editor

Do this on paper or in a text file. Nothing is built yet.

Outcome: A one-page metric definition and a panel row that names it, with no value or formula in the panel.

Knowledge check

What makes sure a panel cannot hold its own number?

Knowledge check

A published dashboard needs a change to one panel. What happens?

References

  1. PostgreSQL documentation: Row security policies. https://www.postgresql.org/docs/current/ddl-rowsecurity.html
  2. ISO 8601 date and time format. https://www.iso.org/iso-8601-date-and-time-format.html
  3. ISO 22400-2:2014 Key performance indicators for manufacturing operations management. https://www.iso.org/standard/54497.html

Chapter 3 · Roles, rules and lineage

Who sees what, and how a number is read

The same dashboard can be shared with a role and still show a person only their site's rows. One read function answers every question, ratios are added the right way, a missing value says no data, and any number opens to its records and its definition.

30 min8 roles1 read function3 surfaces

By the end of this chapter you can

  • Say who may define, build, view, schedule and acknowledge, and how sharing differs from row-level security.
  • Add up a ratio correctly, show no data instead of zero, and write a period and a comparison.
  • Open a number to its records and its metric definition, and make a chart accessible and consistent.

Roles and surfaces

Roles are jobs, not names. Five are people; three are not and have credentials of their own, which you set in your host's environment settings and never paste into a chat or a file.

RoleDoes
Metric stewardRegisters, approves, changes and retires metrics in the fabric, and registers the source table of each figure. Cannot edit a dashboard.
Dashboard builderDrafts, publishes and shares dashboards, schedules reports and creates alert rules. Cannot approve a metric.
OperatorReads dashboards shared with them, on the operator surface (phone, at the machine).
SupervisorReads dashboards, acknowledges alerts and creates action items, for their own site.
ManagerReads dashboards for every site, acknowledges alerts, sees the delivery log and the health measures.
Report serviceNot a person. Runs the scheduled reports and writes the delivery log.
Alert serviceNot a person. Evaluates alert rules, escalates, and reacts to registry events.
Metric jobNot a person. Computes the values of your own figures. Reads no dash_ table.

Two locks protect a dashboard. The first is sharing: a row in dash_dashboard_share names a job role, an org unit or a person, and a dashboard that is not shared with you never appears. The second is row-level security: every panel query runs with the reader's rights, so a reader gets only the rows of their site (a manager, every site). A dashboard can be shared with a person and still show them "no data" for rows they may not read.

Who sees which dashboardA grid of three practice dashboards against four people. Operator One sees line-1-operator. Supervisor One and Manager One see site-supervisor and plant-manager. Supervisor Two sees site-supervisor but, being at site S2, gets no data on it. Operator OneSupervisor OneSupervisor TwoManager Oneline-1-operatorsite-supervisorplant-managerShared with the person, and their site's rows are returnedShared, but the rows are site S1 only: the panels say no dataA blank cell means the dashboard is not shared with that person, so it never appears for them.
Sharing is one lock; row-level security is another. In the practice data, Supervisor Two at site S2 can open site-supervisor, but every panel on it asks for site S1 and gets no data.

The Postgres facts that decide how the access rights are written: an update or delete finds rows only through the role's read right, so a role that updates rows must also read them, and the changed row must still pass that read rule. An insert that returns its row needs the read right too. The rights written in the Role and Exposure Matrix must cover everything the later sessions ask a role to do, because the database rules are generated from it.

SurfaceScreens
Operator (phone)/dashboards (the dashboards you can read), /dashboards/view/[key] (one dashboard), /dashboards/number/[key]/[panel] (drill and lineage), /dashboards/metric/[code] (a definition, read only).
Supervisor/dashboards/alerts (acknowledge), /dashboards/reports (the reports listing).
Manager/dashboards/health (panels with data, acknowledgement time, delivery success).
Builder and steward only/dashboards/build (builder) and /fabric/metrics (steward).

One read function

Every screen, report and alert reads a number through one database function, read_metric(code, from, to, filter, group_by). It runs with the caller's rights, so row-level security applies to every call. It keeps, for each day, dimension and metric, the row with the latest computed_at (a correction replaces a value without editing it), combines rows by the metric's aggregation, and returns the value, numerator, denominator, the number of days with data and days in the period, with the previous period and the metric's target and version. The browser never calculates.

How rows combine matters. A rate is 100 times the sum of the numerators divided by the sum of the denominators. It is never the average of averages.

Ratio of sums against average of averagesBars to scale from 0 to 5 percent. Line L1 scrap rate 3.0, line L2 4.0, their average 3.5 which is wrong, and total scrap 31 over total units 950 which is 3.263, shown as 3.3. 0%1%2%3%4%5%Line L121 scrap of 700 units3.0Line L210 scrap of 250 units4.0Average of the two rates(3.0 + 4.0) ÷ 2: wrong3.5, wrongTotal scrap ÷ total units31 scrap of 950 units3.263, shown as 3.3Round once, at display. The average of two rates ignores that L1 made nearly three times the units.
Average of averages is wrong. Line L1 scrapped 21 of 700 units (3.0%) and line L2 10 of 250 (4.0%). The plant's rate is 31 of 950, which is 3.263% and is shown as 3.3. The average of 3.0 and 4.0 gives 3.5, which is not what the plant made.

Round once, at display, to one decimal place with exact halves going up, and compare the unrounded numbers. Totals, targets and variances are worked out before rounding.

No data, never zero

No value row for the filter and period means no data, with the reason. A stored 0 is shown as 0. If only some days have data, the panel says how many: "5 of 7 days". A filter that selects different members of the same dimension at once gives no data, because no row can be two members.

No data against zeroTwo rows of seven days from 9 to 15 March 2026. Line L1 has data every day. Line L2 has data on the five weekdays and no data on Saturday and Sunday, shown as no data rather than zero. Mon 9Tue 10Wed 11Thu 12Fri 13Sat 14Sun 15Line L1datadatadatadatadatadatadataLine L2datadatadatadatadatano datano dataLine L2 runs on weekdays only: the panel shows 5 of 7 days, and the two blank days are no data, not 0.A stored 0 is a real zero and is shown as 0. A missing row is shown as no data, with the reason.
A missing day is not a zero day. Line L2 runs on weekdays only, so its panel reports 5 of 7 days and the weekend as no data.

Periods, filters and comparisons

A period is written as an ISO 8601 duration or interval [1], and a time of day as a timestamp such as 2026-03-16T06:05:00Z [2]. Here P7D means the 7 whole days ending the day before the as-of date. With the as-of date 2026-03-16, the period is 2026-03-09/2026-03-15 and the previous period, the same length immediately before it, is 2026-03-02/2026-03-08. One clock function gives every date, so a test can say "today is 2026-03-16".

The period and the previous periodA calendar from 2 to 16 March 2026, one cell per day. The previous period is 2 to 8 March, the period P7D is 9 to 15 March, and the as-of date is 16 March. March 2026Mon 2Tue 3Wed 4Thu 5Fri 6Sat 7Sun 8Mon 9Tue 10Wed 11Thu 12Fri 13Sat 14Sun 15Mon 16Previous periodThe period (P7D)as of2026-03-02/2026-03-082026-03-09/2026-03-152026-03-16P7D means the 7 whole days ending the day before the as-of date.The previous period is the same length, immediately before it. Both are written as ISO 8601 intervals.
The period and the previous period, drawn to scale with one cell per day. Both are ISO 8601 intervals.

Filters (site, line, product, period) change the question a panel asks. They never change what a panel holds. A filter is intersected with the panel's own filter and with the reader's row-level scope. A target comes from the metric (its target, owner module and version), so the screen can show who owns the target and where it came from.

On the practice dataScrap rateScrap, units made
Period 2026-03-09/2026-03-153.331 of 950
Previous period 2026-03-02/2026-03-082.019 of 950
Varianceup 1.3 points3.263 minus 2.0, then rounded
Target (a practice value, not a recommended limit)3.0from the metric, with its owner

Drill and lineage

A number is a link. The first click shows the value rows behind it: period, dimension, numerator, denominator, when each was computed and the metric version it was computed on. The second shows the metric's definition page: code, definition, formula, standard reference, grain, direction, target with its owner module, status and version. The third shows the source: the entities the metric reads, linked to the owning module's screen where one exists.

From a number to its sourceA number on a panel leads to the panel, the metric definition, its inputs and the value rows. Two links open from the number: the drill to the rows behind it, and the lineage page with the definition, version and source. Number3.3 on a panelPaneldash_panelmetric_keyDefinitionfab_metricformula, versionInputsfab_metric_input,entity registryValue rowsfab_metric_valueappend-onlyDrill: the rows behind itperiod, dimension, numerator,denominator, computed_at, versionLineage: the definition and the sourcecode, formula, target, owner module, version,and the inputs, linked to the owning screenEvery number on a published dashboard links to its metric definition.
From a number to its source. The dashboards never read an operational table. The number comes from the fabric, and the fabric says where it came from.

When a metric's definition changes, the registry publishes fab.metric.version_published. The alert service finds every published layout that names the metric and gives each dashboard owner one action item. The published versions do not change; the lineage page shows value rows computed on the old version beside the current one.

Charts people can read

  • Text alternative. Each chart has the same numbers available as a table, so a screen reader or a printed copy loses nothing (WCAG 1.1.1) [4].
  • Contrast. Text is at least 4.5 to 1 against its background (1.4.3) [5], and chart lines and bars at least 3 to 1 (1.4.11).
  • Not by colour alone. Above or below target is written as a word as well as shown in a colour (1.4.1).
  • Keyboard. Filters, drill links and the table toggle work from the keyboard (2.1.1) [3].
  • Consistent notation. Following IBCS [6], use the same look for actual on every chart and a different but consistent look for the previous period and for the target; keep the same scale on charts that are compared; show a variance as a difference.
Exercise · Hand-check one figure15 minutes

You need: A figure from your own data that is a ratio, a calculator or spreadsheet, and the record counts behind it

Use your own numbers. The aim is to prove the ratio of sums by hand before any screen is built.

Outcome: A hand-worked combined rate, the average of averages beside it, the week-on-week variance, and one note saying which days read as no data.

Knowledge check

Line A scraps 20 of 500 units and line B scraps 30 of 1,500. What is the plant's scrap rate?

Knowledge check

A supervisor at site S2 opens a dashboard that is shared with the supervisor role, but every panel is filtered to site S1. What do they see?

References

  1. ISO 8601 date and time format. https://www.iso.org/iso-8601-date-and-time-format.html
  2. RFC 3339: Date and Time on the Internet: Timestamps. https://www.rfc-editor.org/rfc/rfc3339
  3. W3C Web Content Accessibility Guidelines (WCAG) 2.2. https://www.w3.org/TR/WCAG22/
  4. W3C: Understanding Success Criterion 1.1.1 Non-text Content. https://www.w3.org/WAI/WCAG22/Understanding/non-text-content.html
  5. W3C: Understanding Success Criterion 1.4.3 Contrast (Minimum). https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html
  6. International Business Communication Standards (IBCS). https://www.ibcs.com/standards/

Chapter 4 · Sending, raising and replacing

Reports, alerts and cut-over

The numbers leave the screen as scheduled reports and alerts, the module measures itself with four figures, and the old tool is retired only after every number has been compared side by side.

25 min3 delivery statuses4 measures6-step cut-over

By the end of this chapter you can

  • Describe a report run, its three delivery statuses and why an empty report never reads as zero.
  • Explain how an alert is raised, acknowledged, escalated and linked to an action.
  • Read the module's four measures and plan a side-by-side cut-over.

Scheduled reports

A dash_report_schedule row holds a five-field cron, a format (PDF or CSV), a list of recipients and the filters that narrow every panel. The report is built with the same read function as the screens, so it shows the same numbers. Recipients are people, never typed email addresses, and each must be able to read the dashboard and all the rows the filters select: the save route refuses a recipient who could not see it.

A scheduled report and its outcomesA schedule is due; the report run uses the same read function as the screens and ends in one of three delivery statuses: sent, skipped_no_data when every panel had no data, or failed, which is retried at the next run. Scheduledash_report_scheduleReport runsame read functionas the screenssentfile stored and shown to every recipient;emailed only when you switch email onskipped_no_dataevery panel had no data:no file is madefailederror text kept; tried again at thenext run as a new rowOne delivery per due time
A due report ends in one of three statuses. If every panel has no data, no file is made, so an empty report can never read as zero.
StatusMeaning
sentThe file is stored and shown to every recipient, and emailed only when you have switched email on.
skipped_no_dataEvery panel had no data. No file is made.
failedThe run failed. The error text is kept and the report is tried again at the next run as a new row.

Alerts

An alert rule watches one registered metric. A threshold rule fires when a day's value is greater than (gt) or less than (lt) the rule's value. An anomaly rule (outside_band) fires when the day is further from the mean of the previous 7 daily values than the rule's value times their standard deviation, which is a measure of how spread out the values are. With fewer than 7 previous values it does not fire and says "not enough history". A flat history makes the band zero wide, so write down the smallest band you will accept on real data.

From rule to acknowledged alertAn alert rule is checked each whole day. A breach raises one open event, which can be escalated once to a manager, is acknowledged by a person, linked to an action item, and resolved. Alert ruledash_alert_ruleDaily checkeach whole dayEvent: openraised once a dayAcknowledgedby a personResolvedwhen handledEscalationonce, after therule's minutes,to a managerAction itemcore_action_itemowner and due dateAcknowledgement time: median minutes from raised to acknowledged.
One breach, one event. An event is raised once per rule per day. An open event is escalated once, after the rule's minutes, to the manager of the owner's org unit, and a person acknowledges it.
Severity or statusMeaning
info, warning, criticalHow serious the rule's owner judges a breach to be, set on the rule.
openRaised and not yet seen by a person.
acknowledgedA signed-in person took it, and the time is recorded. They may link an action item.
resolvedThe cause was handled.

The module's four measures

The module measures itself with four figures. The first three come from its own tables, so none is typed in. They are module self-measures, worked out from the module's own dash_ tables and not read through the metric read function; they are not registered metrics, because the metric job cannot read a dash_ table and a dashboard that measured itself through its own panels would be circular.

MeasureDefinitionPractice data
Panels with dataPanels whose metric has data in the period, divided by all panels of the latest published versions the reader can read. Read as the dashboard builder, who can read every dashboard.9 of 10, 90.0%
Alert acknowledgement timeThe median minutes from raised to acknowledged. The median is the middle value, or the mean of the two middle values.60 minutes
Report delivery successThe due times that have a sent delivery, divided by the due times in the period. A run considers the due times in the 24 hours up to its clock, so those are the due times inside the look-backs of the runs made in the period; a due time older than that is never back-filled. No table stores runs: they are inferred from the delivery rows, one run per distinct delivery time, so a run that found nothing due, or a missed run, leaves no trace.2 of 3, 66.7%
Retired BI seatsPaid licences cancelled after the cut-over, counted from the vendor's own seat list.recorded in the cut-over notes

Retired BI seats is counted outside the dashboards. A seat count typed into a panel would break the rule this module teaches.

Replace the old tool

List the old tool's most-used reports, define each figure once in the registry, rebuild those reports as dashboards, and run both side by side for a period. Compare every number before cancelling any seat.

From the old tool to the registrySix steps: list the old reports, rebuild them on registered metrics, run both side by side, explain every difference, cut over on a set date, and cancel the seats with the saving recorded. List the old reportsthe five most used, withseats and costRebuild on the registryeach figure defined onceRun side by sideold tool stays theone people useExplain every differencea gap you cannot explainmeans not readyCut over on a set daterollback plan written firstCancel the seatsrecord the savingThe old tool keeps its history, read only, after the cut-over date.
Six steps from the old tool to the registry. The side-by-side run is the safety net, and a difference you cannot explain means you are not ready.
  • Explain every difference. Typical causes: the old chart's own formula against the registered definition, the day boundary or time zone, a filter, rounding, the refresh time, and zero shown by the old tool where the source had no data. A figure where the platform says "no data" and the old tool says 0 is a finding about the old tool.
  • Decide with the figure's owner. If the old formula is right, change the definition in the registry once, as the metric steward, never in a chart.
  • Write a rollback plan first. Name who tells the readers, the date after which the old reports are no longer used for decisions, who keeps the old tool read only, and who decides to roll back.
  • Cancel with the facts. Check the vendor's notice period and how long you can still export after cancelling. Write the saving against the Retired BI seats measure.
Exercise · Plan a side-by-side comparison15 minutes

You need: Your list of the five most-used reports, the old tool's own exports for one period, and the vendor's cancellation terms

Do this before you build anything. The old tool's exports stay in a private folder outside the repository.

Outcome: A comparison table ready to fill in, a cut-over date with a rollback plan, and the cancellation notice date written next to it.

Knowledge check

Every panel on a scheduled report has no data for the period. What should the delivery do?

Knowledge check

During the side-by-side week, one figure differs between the old tool and the registry. What is the right next step?

References

  1. ISO 22400-2:2014 Key performance indicators for manufacturing operations management. https://www.iso.org/standard/54497.html
  2. International Business Communication Standards (IBCS). https://www.ibcs.com/standards/
  3. ISO 8601 date and time format. https://www.iso.org/iso-8601-date-and-time-format.html

Chapter 5 · 12 questions · 80% passes

Final assessment

Twelve questions across the element. Score 80% (10 of 12) to pass. Your LMS records your score and each answer; you can review the chapters and try again.

15 min12 questions≈ 15 minutesRetake allowed

Choose one answer for each question, then submit. You will see the right answer and why for every question.

1. Where may a number shown on a dashboard panel come from?
2. No rows exist for a line last week. What does its panel show?
3. Two reports show different scrap rates for the same week. What is the lasting fix?
4. What does a dash_panel row hold?
5. A published dashboard version needs a different layout. What happens?
6. Line A scraps 10 of 500 units and line B scraps 60 of 1,500 units. What is the combined scrap rate?
7. A supervisor at site S2 opens a dashboard shared with the supervisor role whose panels are all filtered to site S1. What do they see?
8. With the as-of date 2026-03-16, what does the period P7D cover?
9. Why is a metric value never edited in place?
10. A scheduled report is due and every panel has no data. What should the delivery record?
11. What does the alert acknowledgement time measure?
12. During the side-by-side run one figure differs between the old tool and the new dashboard. What is the right move?