Let business teams refresh data without dbt Cloud seats

By General Input

A simple screen where marketing and finance can see when each dataset last updated and hit Refresh now, with your data team looped in on Slack.

Integrations

  • dbt Cloud
  • Slack Bot

Type

App

Categories

  • Operations
  • Engineering

Build me an app that my marketing and finance analysts can open to refresh the data they depend on, without giving them dbt Cloud seats. The people using this are business users, not analytics engineers, so every label, status, and error message in the interface has to read in plain English. Never show raw job names, run status numbers, model names, or stack traces on the main screen.

The main screen is a list of datasets. Load the available dbt Cloud jobs with List Jobs, then show only the ones on an allowlist that an admin picks in settings. Each allowlisted job gets a friendly business name the admin sets, for example turning a job called daily_marketing_prod into Marketing Attribution. Each row shows the dataset name, the outcome of its last build, when that build finished in relative terms like Updated 2 hours ago, how long the build took, and a freshness badge that is green when the last successful build is inside the admin's staleness window for that dataset and red when it is older or the last build failed.

Get the per-row build history from List Runs filtered to each allowlisted job, ordered newest first, and use Retrieve Run when you need the full detail of a specific run. dbt Cloud returns run status as a number, so map it to plain language everywhere in the UI: 1 means Waiting to start, 2 means Getting ready, 3 means Building now, 10 means Up to date, 20 means Build failed, and 30 means Cancelled. Remember that dbt Cloud requires an account id in nearly every request path and wraps every response as an object with status and data, so read the payload out of data.

Every row has a Refresh now button. When someone presses it, ask them for a short reason in a small dialog, then call Trigger Job Run for that job. That endpoint is asynchronous: it enqueues a run and returns the new run id rather than waiting for the result, so the handler must then poll Retrieve Run for that id until is_complete is true. While it polls, the row shows live status moving through Waiting to start, Getting ready, Building now, and finally Up to date or Build failed. Keep the rest of the screen usable while a refresh is in flight, and let several datasets refresh at once.

As soon as a refresh is requested, post a note into the data team's Slack channel with Slack Bot Send a Message. The note names the person who asked, the friendly dataset name, and the reason they typed, for example: Priya in Finance asked to refresh Revenue Daily because the month-end deck needs today's numbers. The admin picks the channel in settings and can turn these notes off per dataset.

Rows whose last build failed get a Retry from failure button that calls Retry Failed Job, which resumes from the point of failure instead of rebuilding everything, and then polls the same way a fresh trigger does. Failed rows also open a detail drawer that explains what went wrong without requiring anyone to read logs. Populate the drawer with Retrieve Run Failure Details for the failed run, and use Retrieve Run Step to pull the specific step that broke along with its error text. Lead the drawer with a one-line plain summary of which stage failed, show the error text underneath for anyone who wants it, and include a Contact the data team action that posts the failure into the same Slack channel.

Bake in these guardrails. Never let a job be triggered while it is already queued or running: before triggering, check the job's most recent run and if its status is Waiting to start, Getting ready, or Building now, disable the button and show that a refresh is already underway, including who requested it if that request came from this app. Give the requester a rough sense of their place in the line by counting how many runs are currently queued or running across the account, and show something like Yours is second in line rather than exposing raw queue internals. If dbt Cloud returns an error, show a friendly message such as We could not start that refresh, the data team has been notified, and never surface a raw error payload to a business user.

Keep a per-user request history. Every viewer has a My requests view listing only their own past refreshes, each with the dataset, when they asked, the reason they gave, how long it took, and how it ended. Persist these records in the app so the history survives across sessions, and show a viewer's most recent request for a dataset inline on the main list.

Finally, add an admin settings screen where an admin picks which jobs appear in the allowlist, sets each one's friendly name and staleness window, chooses the Slack channel for refresh notes, and decides whether a reason is required before requesting a refresh and whether the retry button is available to all viewers or admins only.

Related prompts

Explore more prompts
A brand asset library your marketing team actually searchesTurn Mailjet email clicks into ranked HubSpot follow-upsClean out the Looker dashboards and Looks nobody opensLiveKit live operations console for room moderationWake up dormant Keap leads with a researched reasonLiveChat coverage board for planning next week's shiftsPhone routing control panel for LiveKit voice agentsLinkedIn Ads budget pacing dashboard for every client accountGive your team Looker numbers without buying more seatsPause marketing emails to escalated customers, then restore them