Morning data freshness board for your BigQuery tables

One grid of every table you track, when it last landed, and what broke, with stale tables pinned to the top and an agent that explains why.

App
Google BigQueryLinearSlack BotEngineeringOperationsResearch & MonitoringNotifications & Alerts
PromptCreate

Build me a data freshness board that my data team opens first thing every morning. The whole point is to answer one question fast: did last night's data land where it was supposed to? I want a single grid covering every table across the BigQuery datasets we track, and I want the broken things impossible to miss.

The main view is one table-per-row grid with these columns: table name (project.dataset.table), dataset, owner, last updated, row count, the freshness window we expect it to land inside, and a status. Anything past its window is stale and pins to the top of the board in red with the overdue amount spelled out ("4h late", "2 days late"). Everything healthy collapses into a section below that starts closed, with a count on it like "38 tables healthy". Sort the stale group by how badly overdue it is, worst first.

Build the grid with BigQuery handlers. Use List Projects to discover the projects the connected account can read, List Datasets to enumerate datasets in the projects we have chosen to track, and List Tables to enumerate the tables in each tracked dataset. Then call Get Table per table for lastModifiedTime and numRows, which are the last-updated and row-count columns. Cache the assembled board in app state and refresh it when someone opens the app or hits a Refresh button, rather than re-walking every table on every render, because a wide warehouse means a lot of metadata calls.

lastModifiedTime is cheap but it lies for tables written by streaming inserts, which get touched constantly whether or not new business data arrived. So let each table optionally declare a freshness timestamp column instead. When one is set, measure freshness with a Run Query (Synchronous) call that selects MAX of that column for the table, and use that value as last-updated rather than the metadata timestamp. Show in the row which measure is being used so nobody is confused about where the number came from.

Clicking a row opens a detail panel for that table. The panel runs Run Query (Synchronous) against INFORMATION_SCHEMA.JOBS_BY_PROJECT (region-qualified for the dataset's location) to list the recent load and query jobs whose destination was this table, showing job id, type, who or what submitted it, start time, duration, rows written, and outcome. Below that, show a row count trend for the last 14 days from the same job history so the team can see a load that ran but landed far fewer rows than usual. Use List Jobs on the project and Get Job on individual job ids to surface failed and cancelled jobs, including the error message, since a job that errored is usually the actual explanation for a stale table.

Every stale row gets an Investigate button that kicks off a background agent for that table. The agent should: read the table's configured upstream dependencies and check whether those upstream tables are themselves fresh (Get Table, or the MAX-timestamp query where configured); pull the recent job history for the table with List Jobs, Get Job, and an INFORMATION_SCHEMA query; and then write a short plain-English diagnosis back into the app card for that table. The diagnosis should classify what happened into one of three buckets, in plain words: the pipeline failed (a job errored or was cancelled, quote the error), it ran late (the job is still running or started behind schedule), or it landed empty (the job succeeded but wrote zero or far fewer rows than the usual daily volume). If the real cause is an upstream table rather than this one, say so and name the upstream table, because pointing at the symptom is what makes these boards useless. Show a running state on the card while the agent works, then replace it with the diagnosis and a timestamp.

Once a diagnosis exists, two follow-up actions appear on that card. The first files it as a Linear issue with Create Issue, prefilled with the table name in the title and the diagnosis plus recent job details in the description, letting the user pick or default the team and assign it to the table owner where that maps to a Linear user. Store the created issue key on the card and link to it so nobody files the same thing twice. The second posts the same summary to our data channel with the Slack Bot Send a Message action, formatted as a short readable update: table, how late it is, the diagnosis, and the Linear issue link if one was filed.

Freshness windows and table owners are configured per table inside the app, not in SQL, so anyone on the team can adjust the expected cadence when a pipeline's schedule changes. Each tracked table stores: expected freshness window (a duration, plus an optional expected-by time of day for daily tables), owner name or email, optional freshness timestamp column, and an optional list of upstream tables it depends on. Include a settings view for choosing which projects and datasets are tracked, and let people edit a table's config inline from the grid too.

The board must remember which stale tables have already been acknowledged, so the same known-broken table does not shout at the team every single morning. An Acknowledge button on a stale row moves it into a muted "known issues" group below the active stale group, keeping its diagnosis and any linked Linear issue visible, along with who acknowledged it and when. The acknowledgement clears automatically the moment the table lands fresh again, so a table that breaks a second time comes back to the top in red rather than staying quietly muted forever.

A few implementation notes. BigQuery returns numRows, lastModifiedTime, and other numeric fields as strings, so parse them carefully. Jobs and queries must run in the dataset's location, so read the location from List Datasets and pass it through on query and job calls. Keep the default board build to metadata calls only, and reserve actual queries for the detail panel, the optional MAX-timestamp freshness measure, and the investigate agent, so opening the board every morning stays cheap. Show a last-refreshed timestamp on the board so people know how current the view itself is.

What does this prompt do?

  • Shows every table across the BigQuery datasets you track in a single grid: when it last updated, how many rows it holds, who owns it, and the freshness window you expect it to land inside.
  • Pins anything past its window to the top in red and collapses the healthy tables underneath, so the morning check takes seconds instead of a spelunking session.
  • Click any row to see the recent jobs that wrote to that table, any that failed or were cancelled, and how its row count has moved over the last 14 days.
  • Hit Investigate on a stale table and a background agent checks its upstream tables and recent errors, then writes a plain-English verdict you can file as a Linear issue or post to your data channel in Slack.

What do I need to use this?

  • A Google account with read access to the BigQuery projects and datasets you want to watch
  • A rough idea of how often each table should update, which you set per table inside the app
  • A Linear workspace, if you want to file issues straight from the board
  • A Slack workspace where the app can post to your data channel

How can I customize it?

  • Set the freshness window per table: hourly, every morning by 6am, weekly, or whatever your team has promised the business.
  • Point tables that arrive by streaming at a timestamp column, so freshness reflects the newest row rather than the last time the table was touched.
  • Choose which projects and datasets appear on the board, and name an owner for each table so a stale row always has someone attached.
  • Pick the Slack channel and the Linear team that the follow-up buttons post into.

FAQs

Does this change anything in our warehouse?
No. The board only reads table metadata and runs read-only queries to build the freshness view and the history panel. The only things it ever writes are a Linear issue or a Slack message, and only when someone clicks the button.
How does it decide a table is stale?
It compares when the table last updated against the freshness window you set for it. A table with a six hour window that has not updated in nine hours is stale and jumps to the top of the board in red.
What about tables that are fed by streaming data?
The last-updated timestamp can be misleading for streaming tables, so you can optionally point a table at one of its own timestamp columns instead. The board then uses the newest row in the table as the freshness measure.
Will it keep shouting about a table we already know is broken?
Only until you acknowledge it. Acknowledged tables move into a quiet known-issues section and stay there until the table lands fresh again, at which point the acknowledgement resets on its own.
Do we need to write SQL to set this up?
No. Freshness windows and table owners are edited inside the app, so anyone on the team can adjust the expected cadence for a table without touching code or asking an analyst.

Related templates

Share of voice dashboard for your brand and competitors

See how your brand's news coverage and sentiment stack up against four competitors, then let an assistant write the weekly report for you.

GDELT
Notion
Slack Bot
App
Approval war room for every social post awaiting sign-off

One screen showing every social post waiting on approval, sorted by deadline, so reviewers can approve or reject without leaving the page.

Hootsuite
Slack Bot
App
Turn champion job changes into new pipeline in Attio

Every Monday, find the past champions and closed-won contacts who changed jobs, update Attio, and get the moves worth chasing in Slack.

Boomerang
Attio
Slack Bot
Agentic Task
Collect social post requests and schedule them in Hootsuite

Staff submit what happened, your social manager edits the copy, picks the accounts and puts it on the calendar without a single spreadsheet.

Hootsuite
Slack Bot
General Input Database
App
Voice agent QA review board for your Hume EVI calls

Open one board each morning, see which voice calls went badly, replay the exact moment the caller got frustrated, and file the fix.

Hume
Linear
Slack Bot
App
Clear your Guru verification backlog in one weekly app

A personal queue of every overdue Guru card, sorted by how late it is, with one-click verify, reassign, comment, and an agent that drafts the refresh for you.

Guru
Slack Bot
App

Stop starting the day wondering whether the data landed.

Give your data team one board that answers it, explains what broke, and turns the answer into a ticket.