Case Study
How a B2B SaaS Company Unified Its Data Across HubSpot, Stripe, and Everything Else, and Put an AI Analyst in Slack.
At a B2B SaaS company, every team pulled its own numbers from its own tool, and the numbers never matched. We unified HubSpot, Stripe, and the rest into one governed warehouse and added an AI data intelligence layer for Slack and the AI tools their teams already use, so there is one answer and everyone can ask for it.
- To answer a business question in Slack, down from hours
- <5 Sec
- Governed data layer across HubSpot, Stripe, and the rest of the stack
- 1
- Metrics defined once and read by every dashboard and answer
- 200
The Challenge
Every Tool Had Its Own Numbers, and Nobody Could Say Which Were Right.
Bring the data together once, give every customer one record and every metric one definition, and write the rules down where they can be checked. Then let people ask where they already work, in Slack, with the guardrails built into the system rather than a memo.
The Business Context
The business is a venture-backed B2B SaaS company that grew faster than its reporting. Sales ran in HubSpot, billing in Stripe, and product usage, sales calls, and marketing attribution in three more tools, with the product’s own usage data in the application itself. Every team depended on numbers put together from these systems by hand.
None of the tools agreed on who a customer was or what they paid. Sales could not match what it had closed to what billing had invoiced, marketing could not follow a lead from first touch to paid, and customer success had no dependable list of renewals coming up. Finance kept the real revenue numbers in a monthly workbook, so every question meant exporting files and joining them in a spreadsheet. Leadership read three sets of numbers that disagreed, and last quarter’s board figures could not be produced twice. Personal data sat unprotected, and there was no record of who had looked at it.
- Leadership read three sets of numbers that disagreed, and last quarter’s board figures could not be produced twice.
- Sales could not match what it had closed in HubSpot to what Stripe had invoiced, and pipeline coverage was rebuilt in a spreadsheet every quarter.
- Marketing could not follow a lead from first touch through sign-up to paid, and nobody trusted the attribution.
- Customer success had no dependable list of renewals coming up, and churn meant something different on every dashboard.
- Finance typed the monthly revenue workbook in by hand, so the close took days and could not be reproduced.
- Personal data sat unprotected, and there was no record of who had looked at it.
What We Delivered
We were the external engineering team. We built one governed warehouse on the company’s own Google Cloud account, defined every metric once, moved reporting to Hex, and put an AI data intelligence layer in Slack so anyone can ask a question and trust the answer. Personal data is protected by default, and the whole setup is written down as code. The company owns all of it.
The Solution
Six Problems, and What We Built for Each.
01 / 06
Every tool, its own numbers
- HubSpot & Stripe
- Gong & Dreamdata
- PostHog
- Product usage data
Each tool knew part of the customer, and nothing joined them up The Problem
Every Tool Knew Part of the Customer
Deals in HubSpot, payments in Stripe, usage, calls, and marketing in three more tools. Nobody could follow a customer from first touch to renewal, and what sales closed never matched what billing invoiced.
One warehouse
- HubSpot & Stripedeals & payments
- Gong & Dreamdatacalls & attribution
- PostHogproduct analytics
- Product usage dataas it changes
What We Built
One Warehouse, Where Every Customer Has One Record
Everything lands in one warehouse, and one record ties a company’s deals, invoices, calls, and usage together. A customer can be followed from first touch to renewal, and the numbers line up.
How We Built It
Deals, Contacts, and CompaniesHubSpotLanded through a managed Fivetran connector
Subscriptions, Invoices, and PaymentsStripeLanded the same way, and tied to the HubSpot company through a documented join order
Sales CallsGongCalls, participants, and transcripts, through a purpose-built dlt pipeline
Product Analytics and AttributionPostHogPostHog through its native export, and Dreamdata for marketing attribution
Product Usage Data, as It ChangesPostgreSQLUsers, organisations, and trials, replicated by change data capture into a buffer no person reads
Everything lands in BigQuery. Airflow runs every load on a schedule and alerts the team in Slack when a run is missed or late.
02 / 06
Spreadsheets everywhere, most figures typed in by hand each month The Problem
The Board Numbers Could Not Be Produced Twice
Finance kept the real revenue figures in a monthly workbook, typed in by hand. The dashboard app showed something different, closed quarters could change after the fact, and nobody could reproduce what the board had seen last quarter.
- Stripe export
- HubSpot export
Monthly revenue, built in the warehouse
- New
- Expansion
- Churn
Checked against Finance’s close each month
What We Built
Revenue Built in the Warehouse, Checked against Finance, and Locked
Every rule Finance applied by hand is written down and rebuilt in the warehouse. The result is checked against Finance’s close each month, history is kept, and a closed quarter stays closed, so the board reads the same number twice.
How We Built It
- 01
Every Rule, Written DownMore than 110 numbered decisions, each with an owner, such as “a late renewal is not churn”
Rebuilt as Tested ModelsdbtAround 500 dbt models, built and tested on every run
- 03
Calibrated to Finance’s CloseWarehouse revenue is compared with Finance’s figure each month, and the differences are documented
- 04
Targets from Finance’s Own SheetThe budget sheet Finance already maintains is read in place as a BigQuery external table, so targets are never retyped
Every change is a reviewed pull request with its development build and a query that shows the change does what it says. Merging is the release.
03 / 06
“Churn” means…
- Finance
- Sales
- Marketing
The Problem
The Same Word Meant a Different Number in Each Team
Churn, active user, and a qualified lead each meant something different in the dashboard app, Finance’s workbook, and a definitions document. When they disagreed, there was no agreed way to settle it.
“Churn” means…
- Finance
- Sales
- Marketing
What We Built
One Definition, Written Once and Read Everywhere
Each of 200 metrics is defined once, by a named owner. Every dashboard, every Slack answer, and every self-built view reads that one definition, so they cannot drift apart.
How We Built It

A Semantic LayerMetricFlowEach metric is defined once: certified MRR and ARR, new, expansion, and churn ARR, pipeline, bookings, retention, and product usage
- 02
A Metric RegisterEvery metric carries an owner, a citation, and a status: certified, divergent, unconfirmed, or not implemented. An unimplemented metric is never served
- 03
Guardrails in the DefinitionBalances such as ARR are read at period end, never summed; a table that needs a filter refuses to run without it
CI fails the build if a metric has no status, a column does not exist, or a citation does not resolve. The manifest reaches every consumer within seconds of a green build.
04 / 06
What was net new ARR last quarter, by segment?
Someone writes a query, checks it, and sends the result back
One of around 70 recurring questions
The Problem
Every Question Waited for Someone to Pull the Numbers
Around 70 recurring questions from revenue operations alone, each waiting for a person to write and check a query. A simple question could take hours, and the people who could answer it had a queue.
What was net new ARR last quarter, by segment?
Here is net new ARR for last quarter, by segment.Certified
From the governed metricsAsked by a verified member
What We Built
Ask in Slack, and Get an Answer You Can Trust
Slack is where this team works, so the analyst works there too. Anyone can ask in plain words, and each answer carries a label, Certified, Provisional, Directional, or Declined, worked out from where the figures came from, not by the AI’s own say-so.
How We Built It
A Read-Only AI AnalystClaudeBuilt on Claude Managed Agents, answering in approved channels and direct messages
- 02
Trusted Sources, in a Fixed OrderThe governed metrics first, then definitions and context, then guarded SQL only when the first two cannot answer
- 03
Every Figure Traced to a Tool CallA checker catches any number not backed by a result in the same turn, and the agent gets one turn to repair it
One MCP Gateway on Cloud RunMCPGoverned metrics and guarded SQL behind one gate, also switched on as a company connector in Claude
Every Asker Verified, Every Query GuardedGoogle BigQueryOnly full workspace members, each with a signed token per conversation. SQL is read-only, capped, and refuses PII columns; BigQuery IAM is the real boundary
The same agent is available in Claude, and a monitoring dashboard reports usage, reliability, speed, cost, and feedback from the agent’s own telemetry.
05 / 06
Customer records
Name
Email
Plan
Usage
Anyone with access saw everything, and nothing recorded who read what The Problem
Personal Data, and No Record of Who Had Seen It
Names, emails, and other personal details sat unprotected across the data, the product held customer content under contract, and we, as the outside engineering team, needed to work on live data. There was no record of who had looked at what.
Customer records
Name
masked
Email
masked
Plan
Usage
Access window: 24 hours at mostWritten reasonOne approvalAlert on start
What We Built
Protected by Default, with Short, Approved Access That Leaves a Trail
Personal details are hidden from everyone by default, our own engineers included. Seeing them needs a written reason and one approval, lasts at most 24 hours, and sends an alert the moment it starts. Customer content never enters the warehouse.
How We Built It
Policy Tags from BirthGoogle BigQueryA personal-data column is tagged in the same reviewed change that creates it, and a build without the tags fails
Time-Boxed AccessGoogle CloudPrivileged Access Manager grants of at most 24 hours, with a reason, one approval, and an alert if data is copied out
Every Grant Defined as CodeTerraformDatasets, access groups, and entitlements live in Terraform and are applied only from CI. Nobody is granted access as an individual
Customer content never enters the warehouse: no message bodies, prompts, or document text. Customers whose contracts exclude analytics stay excluded on every build.
06 / 06
“What did we report to the board last quarter?”
“Which renewals are due next month?”
“Can I get a pipeline view for my team?”
The Problem
Reports Were Rebuilt by Hand, and Every New Chart Was a Request
The board summary, pipeline coverage, and the renewal list were put together again each period. A manager who wanted a view for their own team asked for it and waited.
One set of definitions, three ways in
- Reporting · Hex dashboards
- Analytics · the AI analyst in Slack
- Your own dashboards · Claude, through MCP
What We Built
Reports in Hex, Answers in Slack, and Dashboards Anyone Can Build
Three ways in, all reading the same definitions. The standing reports live in Hex. Questions a report cannot answer go to the AI analyst in Slack. And anyone can build their own dashboard in Claude on the same metrics, without asking.
How We Built It
The Reporting LayerHexHex reads governed metrics from MetricFlow and data from the warehouse, so a chart and a Slack answer agree
The Analytics LayerSlackThe AI analyst answers the questions a dashboard cannot, in the channels the team already reads
Dashboards through MCPMCPThe MCP gateway is a company connector in Claude, so a sales manager builds a pipeline tracker and customer success builds a renewals board

All three ask the semantic layer for the same named metric, so an official dashboard and a self-built one cannot drift.
All the Data, in One Place.
Before: Six Platforms, Each Holding Part of the Customer
HubSpotContacts, companies, and deals
StripeSubscriptions, invoices, and payments
PostHogProduct analytics events
GongSales calls and transcripts
DreamdataMarketing attributionProduct Usage DataUsers, organisations, and trials
Nothing joined them. Following one customer meant an export from each
After: One Place Holds All of It
Everything About a Customer, in One Place
Deals, payments, product usage, sales calls, and marketing attribution for the same company, side by side in one warehouse
HubSpotContacts, companies, and deals
StripeSubscriptions, invoices, and payments
PostHogProduct analytics events
GongSales calls and transcripts
DreamdataMarketing attributionProduct Usage DataUsers, organisations, and trials
- One Customer, One Record
- Follow a company from first touch to renewal without joining anything by hand
- One Number per Question
- Churn, pipeline, and revenue mean the same thing on every dashboard and in every answer
- Bookings Match Billing
- What sales closed and what finance invoiced reconcile in one place
- Last Quarter Still Adds Up
- History is kept, so what was reported before can be reproduced
Every platform lands here on a schedule. Nobody exports or pastes a file again
How the Pieces Fit Together
Before: Every Tool Had Its Own Numbers
- HubSpot & Stripe
Files exported and pasted into Finance’s workbook, joined by hand
A dashboard app reading the same two tools, rebuilt from scratch on every run
Two answers to the same question, and no agreed way to settle it
Connected to nothing
- PostHog
- Gong
- Dreamdata
- Product usage data
Only the CRM and billing reached anyone, and they reached two places that disagreed. Product usage, sales calls, and attribution needed a custom export every time, so nobody could follow a customer from first touch to renewal or match what sales closed to what billing invoiced.
Sets of Numbers3
After: One Set of Numbers, from Source to Answer

01
Every Source, Loaded on a Schedule
HubSpot, Stripe, PostHog, Gong, Dreamdata, and product usage data, each through its own pipeline
02
Loaded and Orchestrated
Fivetran for HubSpot and Stripe, dlt and native exports for the rest, Datastream for product usage data, with Airflow running every pipeline on a schedule and alerting in Slack
03
One Warehouse, One Record per Customer
Cleaned, matched, and joined in BigQuery, with personal details hidden by default

04
One Definition for Every Metric
200 governed metrics in MetricFlow, each with an owner and a status
05
One MCP Gateway, Two Tools
Governed metrics and guarded SQL, served over the Model Context Protocol behind one gate on Cloud Run. Every call is authenticated per person, audited, and capped, with PII columns refused
06
The AI Data Agent
Built on Claude Managed Agents. Reads the governed metrics first and guarded SQL last, and labels every answer Certified, Provisional, Directional, or Declined
07
Three Ways In
Reporting in Hex, reading governed metrics from MetricFlow and data from the warehouse; analytics through the AI analyst in Slack and Claude; and self-built dashboards in Claude through the MCP gateway
08
The People Asking
Finance, sales, marketing, customer success, and leadership, each answer attributed and audited
Production is built only by the scheduler, on infrastructure defined in Terraform. People read from it; nobody writes to it, and nobody reads the raw application data.
Sets of Numbers1
How the Data Is Governed, Protected, and Retained.
Governance on this platform covers three things. Protection means personal data is hidden from everyone by default, our own engineers included, access is granted to groups rather than to individuals, and customer content never enters the warehouse at all. Retention means nothing is kept longer than it is needed. Raw product usage data and developer sandboxes expire after 7 days, access grants and agent sessions end within 24 hours, the agent keeps usage counts but never the text of a question, and a person who asks to be erased is removed before the next write, with legal holds taking priority. Control means every dataset, group, grant, and entitlement is written in Terraform and applied only from CI, so a change to who can see what is a reviewed pull request, never a click in a console. The three lanes below show how a read is governed in practice.
Where Data Can Be ReadMasked by default at every tier a person can see
Raw Product Usage Data
Replicated from the application into a machine-only buffer that expires after 7 days. No person reads it
Landing
Each source as it was sent. Readable only inside an approved access window
Lake
Typed and deduplicated, with personal data masked for everyone
Warehouse
Business models, still masked. A model that is not signed off builds in a candidate dataset nobody reads
Dashboards, Slack & Claude
Read the governed models only, with every query attributed to the person who asked
PII MaskingBigQuery policy tags with always-null masking; tags come first, before any group is bound to a dataset
Tagged at Birth
A personal-data column is tagged in the same reviewed change that creates it. A production build without the tag configuration fails
Masked by Default
Anyone without a grant reads a tagged column as empty: names, addresses, phones, IP addresses, and raw email
The Tag Follows the Column
A tagged column can appear downstream only with the same tag. Renaming, hashing, or dropping the tag fails CI
Keys Stay Joinable
Join keys are never masked. People are matched across sources with a keyed email token, encrypted under a managed key, never a plain hash
Unmasked Only in a Window
Seeing the real value needs an approved access grant, below, and a dev build cannot run while one is held
Reading Sensitive DataGoogle Cloud Privileged Access Manager
Request
A written reason, for the shortest time that covers the task
One Approval
Recorded with the request, so the grant has an owner
Window Opens
At most 24 hours. An email goes out the moment it activates
Read in Place
An alert fires if the data is copied out, extracted, or written anywhere else
Expires
Access ends on its own, with who, why, and when on record
Customers whose contracts exclude their data from analytics are excluded on every build, and that exclusion fails closed.
Technologies Used
HubSpot
CRM: Contacts, Companies & Deals
Stripe
Payments: Subscriptions & Invoices
PostHog
Product Analytics
Gong
Sales Call Recordings

Dreamdata
Marketing Attribution
PostgreSQL
Product Usage Data, Replicated as It Changes
Google BigQuery
Cloud Data Warehouse
dbt
Data Modeling, Tests & Documentation

MetricFlow
Semantic Layer & Governed Metrics
Fivetran
HubSpot & Stripe Ingestion
dlt
Custom Ingestion Pipelines
Apache Airflow
Pipeline Orchestration on Cloud Composer
Google Cloud
Cloud Platform: Datastream, Cloud Run & Privileged Access Manager
Terraform
Infrastructure as Code
MCP
Model Context Protocol Gateway: Governed Metrics & Guarded SQL
Claude
AI Analyst, Claude in Slack & Cloud Coding Agents
Slack
Where the Team Lives: the Analyst, Alerts & Maintenance
Linear
Issue Tracking for Fixes
Hex
Reporting Layer: Dashboards
GitHub
Pull Requests, CI & Releases
Python
Pipelines & the MCP Gateway
Next.js
Agent Monitoring Dashboard
How the System Was Built
- 01
Bring Every Source into One Place
Sales, billing, product usage, sales calls, marketing attribution, and Finance’s own budget sheet all land in one warehouse on a schedule. Nothing is exported or retyped, and the team hears in Slack if a load is missed or late.
Technical Detail: Bring Every Source into One Place
HubSpot and Stripe land through Fivetran. Gong’s calls and Dreamdata’s attribution come through purpose-built pipelines. PostHog uses its native export, and Finance’s budget sheet is read in place as a BigQuery external table. The application Postgres database is replicated by Datastream change data capture into a machine-only buffer tier with 7-day partition expiry. Gong is loaded by a dlt pipeline with a deliberate transcript lag and reconciliation after each load. Every loader goes through one operational contract library: a run lock, a run ledger as the state of record, per-resource reconciliation, schema quarantine for unknown columns, a bounded retry policy, and tombstones for erased subjects. Airflow 3 on Cloud Composer 3 runs 19 production DAGs, with Slack job alerts and a watchdog for missed, queued, overdue, and recovered runs. Every DAG that moves data ships paused, and a person switches it on.
- 02
Write the Rules Down, Then Rebuild Them
The old dashboard app and the spreadsheets held years of judgment calls that lived in people’s heads. Each one was written down as a numbered decision with a named owner, then rebuilt where it can be tested on every run. Only then was the old app retired, after its hand-entered data had been saved.
Technical Detail: Write the Rules Down, Then Rebuild Them
Three dbt Core projects in one repository hold around 500 models: landing, generated from a per-column policy file; a typed and deduplicated lake, one dataset per source; and the warehouse, from staging through intermediate to domain marts for finance, sales, marketing, customer success, product, reference, and a customer data platform. More than 110 decision records cover rules such as “one-off invoices are not MRR” and “the finance month boundary is Pacific.” A model that has not been signed off builds in a candidate dataset that no dashboard or agent reads; promotion is one pull request that records the sign-off.
- 03
Give Every Customer One Record
HubSpot, Stripe, and the product each knew a customer by a different name. The warehouse ties them together into one record, following a documented order of precedence, so a company’s deals, invoices, calls, and usage finally line up.
Technical Detail: Give Every Customer One Record
The HubSpot-to-Stripe join ladder starts with the primary association and falls back in a documented order. People are joined across sources with a keyed email token produced by deterministic encryption under a KMS-wrapped keyset, so raw email never leaves staging. Join keys are never masked, and a check fails any tagged key. Quota comes from the commission tool’s own export as a versioned seed, refreshed by pull request, so it can finally be lined up with pipeline.
- 04
Define Each Metric Once, and Let Finance Keep the Final Say on Revenue
Two hundred metrics are defined once, each with a named owner, and every dashboard and every answer reads the same definition. Revenue is checked against Finance’s monthly close, and once a quarter is closed it stays closed.
Technical Detail: Define Each Metric Once, and Let Finance Keep the Final Say on Revenue
MetricFlow semantic models define certified MRR and ARR, new, expansion, downgrade, and churn ARR, net new ARR, logo counts, ARPC, pipeline created, bookings, won deals, gross and net revenue retention, and product usage measures. A metric register gives each metric an owner, a definition, a citation, and a reconciliation status. Additivity is declared, so flows sum over a quarter while balances are read at the period’s last month. Tables that need a filter refuse to run without it. CI fails if a metric has no status, a column is missing, or a citation does not resolve. The manifest is published after every green production build and hot-reloaded by the MCP gateway, so the agent and Claude read the new definition within seconds, and Hex reads the same MetricFlow definitions directly.
- 05
Put the AI Analyst Where People Already Ask
Slack is this team’s home. They move fast and decisions happen there, so the analyst had to be there too, not in another tab. Anyone can ask a question in plain words and get an answer in seconds, with a label that says how far it can be trusted. The label comes from where the figures came from, not from the AI’s own confidence.
Technical Detail: Put the AI Analyst Where People Already Ask
A read-only data agent answers in Slack and in Claude. The Slack bot runs on Claude Managed Agents as a Cloud Run worker pool. It calls the MCP gateway’s governed metrics tool first, knowledge vaults of definitions second, and its guarded SQL tool last, and labels every answer Certified, Provisional, Directional, or Declined. Every figure needs a tool call in the same turn; a checker catches numbers that are not on the answer card or in a tool result, and the agent gets one turn to repair them. The SQL guard allows a single SELECT over allowlisted datasets, refuses PII columns and candidate datasets, and caps billed bytes and rows. BigQuery IAM on the service account is the real boundary. Each asker is verified as a full workspace member, and a signed token per thread and user, scoped to one server and expiring within 24 hours, puts the verified asker on every audit line. Evals include must-refuse cases, and a Next.js dashboard reports usage, reliability, speed, cost, and feedback from the agent’s own telemetry.
- 06
Three Ways In: Reports, Answers, and Dashboards Anyone Can Build
The standing reports live in Hex. Questions a report cannot answer go to the AI analyst in Slack. And anyone can build their own dashboard in Claude on the same metrics, so a sales manager has a pipeline tracker and customer success has a renewals board without asking the data team. All three read the same definitions, so they cannot disagree.
Technical Detail: Three Ways In: Reports, Answers, and Dashboards Anyone Can Build
Hex is the reporting layer: a revenue dashboard that replaced the old app and a Finance OKR dashboard, built to a written house style. Hex reads governed metrics from MetricFlow and data from the warehouse, not through MCP. The AI analyst in Slack is the analytics layer. The third layer is self-serve: the MCP gateway behind the Slack agent is switched on as a company connector in Claude, so far used to build Claude dashboards. The guardrails live in the gateway and in IAM, not in the prompt, so a user-built dashboard inherits the same PII refusals, row and byte caps, and candidate exclusions as the agent. Every connector call is authenticated per user and audited. Because both the official Hex dashboards and the self-built ones ask the semantic layer for the same named metric, they cannot drift. The data platform owns definitions, quality, and access; the business builds its own views.
- 07
Protect Personal Data by Default, and Make Any Exception Short and Visible
Names, emails, and other personal details are hidden from everyone by default, our own engineers included. Seeing them needs a written reason and one approval, lasts at most 24 hours, and raises an alert if anything is copied out. Customer content never enters the warehouse at all.
Technical Detail: Protect Personal Data by Default, and Make Any Exception Short and Visible
BigQuery policy tags with always-null masking cover three classes: redacted PII, the restricted email token, and restricted customer content. A column is tagged in the same reviewed diff that creates it, a deny-by-default check keeps the tag on every downstream column, and a build without tag configuration fails. Two Privileged Access Manager entitlements cover landing reads and PII unmasking, with an activation email and a separate copy-out alert. A per-column landing policy gives every application column one action, from keep to drop, and JSON fields are readable only through an allowlist of paths. Organisations whose contracts exclude analytics have every content-derived value nulled on every build, with the exclusion list hash-pinned in both repositories.
- 08
Write the Whole Setup Down, So It Can Be Rebuilt and Nothing Goes Live Unreviewed
Every part of the platform, including who can see what, is written down as code and applied only after review. A change ships by merging it, and there are no passwords or key files sitting anywhere.
Technical Detail: Write the Whole Setup Down, So It Can Be Rebuilt and Nothing Goes Live Unreviewed
Terraform defines the four Google Cloud projects, every BigQuery dataset and grant, the Privileged Access Manager entitlements, Cloud Run services, and Cloud Composer, and is applied only from CI. Trunk-based development with CI and one approval; merging moves the dbt image’s production tag and the next scheduled run builds it. Personal credentials in development and Workload Identity Federation in CI, with no service-account keys. Per-developer sandboxes read the production lake and write only to their own datasets, with a query cap. Offline checks cover SQL style, naming, policy tags, masked keys, the semantic contract, and declared freshness, with no cloud access. Every repository carries an AGENTS.md that Claude, Cursor, and Codex read, so coding agents follow the same rules people do.
- 09
Keep It Running from Where the Team Already Works
The platform is looked after from a Slack channel, because that is where this team works and how fast it moves. A late load, a definition that needs a change, or a new field that needs protecting is raised there, tracked in Linear, and handled by Claude or a cloud coding agent for the small fixes, with a person reviewing every change before it goes live.
Technical Detail: Keep It Running from Where the Team Already Works
Airflow job alerts and the watchdog post to the same channel, so a failure is seen where the fix is discussed. Linear holds the issue. Claude in Slack answers questions about the platform from the repositories’ own documentation, and cloud coding agents open the pull request for small changes such as a new metric status, a tag, or a seed refresh. Every change still goes through CI and one approval; merging is the release.
The Results
One Set of Numbers. Answers Anyone Can Ask For.
What Was Delivered
Sales, billing, product usage, sales calls, and marketing attribution are joined in one warehouse, with one record per customer and one definition per metric. Revenue is checked against Finance’s close every month. The standing reports run in Hex, anyone can ask the AI analyst in Slack or Claude and get a labelled answer, and anyone can build their own dashboard on the same metrics. Personal data is protected by default, and the whole setup is written down as code.
What Changed in the Working Month
The old dashboard app was retired after its rules were written down, rebuilt, and checked against it, and after its hand-entered data was saved. The renewal list, Finance’s monthly revenue movements, pipeline coverage, and the board summary are repeatable reports instead of spreadsheets rebuilt by hand. The Slack analyst has been live since autumn 2026, and the project owner reports that a business question that used to wait hours for someone to pull the numbers is now answered in under five seconds.
This account describes the engineering, not the business. The move from hours to under five seconds for an answer is reported by the project owner; no measurement period or independent validation was supplied. No revenue figures or other business results are claimed. The platform figures, 19 production pipelines, around 500 models, 200 governed metrics, and more than 110 decision records, come from the delivered repositories.
What Changed for the People Doing the Work
- Finance
- Keeps the final say on reported revenue, and checks the warehouse figure against the close each month instead of retyping it. Monthly movements come from the platform, and a closed quarter stays closed.
- Revenue Operations & Sales
- Ask the recurring questions in Slack instead of waiting for someone to pull the numbers. What sales closed and what billing invoiced now match.
- Marketing & Growth
- Follow an account from first touch through sign-up to paid in one place, with one definition of a qualified lead and an active user.
- Customer Success
- Has a dependable list of renewals coming up, and kept its renewal forecasts when the old app was retired.
- Leadership & the Board
- Read the same numbers on every dashboard and in every Slack answer, with history kept, so last quarter can be looked up rather than reconstructed.
- Engineers
- Work on live data with personal details hidden by default, and short, approved windows for anything sensitive. Small fixes are raised in Slack, tracked in Linear, drafted by a cloud coding agent, and reviewed before they go live.
What This Project Reinforced
Write the Rules Down before You Build
The old app and the spreadsheets held years of judgment calls. Getting each one written down with a named owner was most of the real work, and it is what made the numbers trustworthy.
Decide Whose Number Wins When Two Disagree
Finance’s close decides reported revenue, and the metric definitions decide what a word means. When they disagree, the owner decides, and the gap is written down rather than quietly patched.
Put the Guardrails in the System, Not in a Memo
A rule that lives only in a document eventually gets broken. Labels worked out by the system, access that expires on its own, and a build that refuses to run without its protections held up where instructions would not.
Let People Ask Where They Already Work
This team runs on Slack and moves fast. An analyst, alerts, and upkeep inside Slack get used every day; a separate portal would not have been.
Self-Serve Only Works Once the Data Is Governed
The Slack analyst and the self-built dashboards were only safe to switch on because the definitions, the protection of personal data, and the access rules were already in place.

