Section C · Serving, quality & governance

Self-Serve & Internal Enablement

A data platform succeeds or fails on whether people can find, trust, and use its data without asking the DPE team for help. This chapter is about the enablement layer — the catalog, the dataset tiers, the access patterns per persona, and the onboarding paths — that turns a warehouse full of tables into a self-serve product. The alternative is a ticket queue that buckles the moment GridDP grows past a handful of analysts.

The ticket-queue anti-pattern

Picture GridDP's first year. There are three data engineers and a dozen analysts. When Finance wants take-rate by region, they Slack the DPE team; someone writes the SQL, pastes a screenshot, and moves on. When Supply ops wants fill-rate by GPU model, same thing. It works — barely — because the data team can hold every table in its collective head.

Now apply the scale numbers from Start Here: tens to low hundreds of internal users across the six consumer groups in that chapter — Product & growth, Finance & execs, Supply ops, Trust & safety, ML & DS, and the AI/NL interfaces. Each of them has questions every day. If every question routes through the data team, the team is the platform — a human API with a queue depth that grows linearly with headcount and a latency measured in days.

ANTI-PATTERN: the DPE team as a human query API ┌─────────┐ "GMV by region?" ┌──────────────┐ │ Finance │ ───────────────────▶ │ │ ├─────────┤ "fill rate?" │ DPE team │ queue │ Supply │ ───────────────────▶ │ (3 people) │ ▒▒▒▒▒▒▒▒ ← grows ├─────────┤ "churn cohort?" │ │ ▒▒▒▒▒▒▒▒ without │ Product │ ───────────────────▶ │ writes SQL │ ▒▒▒▒▒▒▒▒ bound ├─────────┤ "fraud rate?" │ by hand │ │ T&S │ ───────────────────▶ │ │ ⏱ latency: days └─────────┘ └──────────────┘ 😵 single point of failure SELF-SERVE: the platform answers, the team builds the platform ┌─────────┐ ┌──────────────────────────────┐ │ Finance │ ──▶ catalog ───┐ │ certified datasets + semantic│ ├─────────┤ (find) │ │ layer (ch.08) + golden paths │ │ Supply │ ──▶ semantic ──┼────▶│ │ ⏱ latency: minutes ├─────────┤ layer │ │ DPE team builds & curates │ 📈 scales w/ users │ Product │ ──▶ BI / NL ───┘ │ this, doesn't answer each Q │ ├─────────┤ └──────────────────────────────┘ │ T&S │ ▲ └─────────┘ │ team's queue holds only │ NEW datasets & edge cases
The load-bearing reframe

The DPE team's job is not to answer data questions; it is to build the system that lets others answer their own. Every recurring question that still lands in the team's queue is a bug in the platform — a missing dataset, an undiscoverable table, or an un-modeled metric. Self-serve is not a nice-to-have; it is the only architecture that scales sub-linearly with the number of consumers.

Self-serve does not mean "throw everyone raw SQL access and wish them luck." Uncurated access produces the opposite failure: five analysts compute "active rentals" five different ways and walk into the same meeting with five GMV numbers. Real self-serve is a curated product — discoverable data (the catalog), trustworthy data (tiers and contracts), and consistent metrics (the semantic layer from chapter 08). The rest of this chapter builds those pieces.

Data catalog & discovery

The first wall a new analyst hits is not "I can't query the data" — it's "I can't find the data, and when I find a table I don't know whether to trust it." GridDP has thousands of tables across the lakehouse, the warehouse, and the ClickHouse telemetry store. Which one holds the canonical rental record? Is rentals_v2_final or fct_rental the one Finance uses? When was it last refreshed? Who owns it? Without answers, every analyst rediscovers the data model by trial and error — and half of them give up and Slack the data team, recreating the ticket queue.

A data catalog is the search-and-trust layer over the platform's metadata. Good discovery surfaces, for every dataset:

  • Search & schemas — full-text search over table and column names, types, and descriptions, so "find me the bid table" actually works.
  • Ownership — the team and on-call human responsible (tied to the domains from Start Here).
  • Popularity & usage — how many people query it and how often; a proxy for "is this the real one."
  • Freshness — last successful load and the expected cadence, so a stale table is visibly stale.
  • Sample values & profiling — what the data actually looks like, null rates, distinct counts.
  • Lineage — upstream sources and downstream consumers, so you can trace a number back to the source system and forward to every dashboard it feeds.
  • Tier / certification — the trust badge (next section).
CATALOG ARCHITECTURE — harvest, store, serve ┌───────────────────────────────────────────────────────────────────┐ │ HARVESTERS (pull metadata; the platform pushes events too) │ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌──────────┐ ┌────────┐ │ │ │ warehouse │ │ lakehouse │ │ ClickHouse│ │ dbt │ │ BI │ │ │ │ INFO_SCHEMA│ │ Iceberg │ │ system │ │ manifest │ │ tool │ │ │ │ + query │ │ catalog │ │ tables │ │ + tests │ │ (dash, │ │ │ │ history │ │ + lineage│ │ │ │ + docs │ │ owners)│ │ │ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ └────┬─────┘ └───┬────┘ │ └─────────┼─────────────┼─────────────┼────────────┼───────────┼──────┘ └─────────────┴──────┬──────┴────────────┴───────────┘ ▼ ┌───────────────────────────┐ │ METADATA STORE (graph) │ entities: dataset, │ datasets · columns · │ column, owner, tier, │ lineage edges · owners · │ glossary term, dashboard │ tiers · glossary · usage │ └─────────────┬─────────────┘ ▼ ┌────────────────────────────────────┐ │ UI (search, browse, lineage map) │ ← humans │ API (programmatic, feeds NL/AI) │ ← agents (ch.13) └────────────────────────────────────┘

The catalog is itself a small data platform: harvesters crawl each store's system metadata (and the dbt manifest, and the BI tool's API) on a schedule or via push events, a metadata store (usually a graph, because lineage is a graph) holds the unified model, and a UI + API serve it to humans and — increasingly — to the NL/AI layer in chapter 13, which depends on rich catalog metadata to ground its answers.

Tooling, per reference stackCatalog choiceNotes
Stack A — open-source lakehouseDataHub or OpenMetadataSelf-hosted graph catalog; rich lineage, pluggable harvesters; you run it
Stack B — Databricks-centricUnity CatalogGovernance + discovery + lineage native to the platform; less cross-engine reach
Stack C — Snowflake-centricSnowflake HorizonBuilt-in discovery, lineage, tags, data-quality monitors over Snowflake objects
A catalog nobody curates is a phone book of strangers

Auto-harvested metadata gets you schemas, lineage, and usage for free — but descriptions, ownership, and tiers are human inputs. The failure mode is a catalog full of 4,000 tables with blank descriptions that no one trusts. The fix is to make curation a side effect of the workflow: descriptions live in dbt model YAML (so they ship with the code), ownership is inherited from the domain, and certification is a reviewed promotion (next section), not a field someone is supposed to remember to fill in.

Data contracts, operationalized

Chapter 01 introduced the data contract as the versioned agreement between a producing service and the platform — the API for what a source emits. Here we operationalize that idea and extend it one layer up: contracts also govern the datasets the platform publishes to its internal consumers. A contract is the seam that lets producer and consumer evolve independently, and the enforcement mechanism that keeps self-serve from turning into self-sabotage.

Four properties turn a contract from documentation into a load-bearing system:

  • Producer-owned schema. The team that emits the data owns the contract, checked into their repo next to the code that produces it. The platform is a consumer with rights, not the author.
  • CI enforcement. A schema change that violates the contract fails the producer's CI build — before it ships — not the platform's 3 a.m. pipeline. This is the whole point: the breaking change is caught where it's cheapest to fix.
  • An explicit breaking-change policy. Additive changes are free; removals and type changes require a major-version bump and advance notice, so downstream consumers can migrate.
  • The contract as the API boundary. Downstream code depends on the contract's guarantees (this field exists, is non-null, lands within 60s), not on the producer's internal table layout.
data-contract: catalog metadata for a published dataset — fct_rental
dataset: marketplace.fct_rental
owner: marketplace-domain          # ties to the domain in 00-START-HERE
tier: certified                     # raw | staged | certified (see below)
domain: marketplace
description: >
  One row per rental (a client's instance lifecycle on a host).
  The canonical rental grain. Use this, not rentals_v2_final.
sla:
  freshness: "<= 30 min behind source"
  availability: 99.5%
  on_call: "#marketplace-data-oncall"
schema:
  rental_id:    { type: string,    required: true, unique: true }   # grain key
  account_id:   { type: string,    required: true }                 # FK -> dim_account
  machine_id:   { type: string,    required: true }                 # FK -> dim_machine
  started_at:   { type: timestamp, required: true }                 # event_time, UTC
  ended_at:     { type: timestamp, required: false }                # null = still active
  gpu_hours:    { type: decimal,   required: true, min: 0 }
  revenue_usd:  { type: decimal,   required: true, min: 0 }         # reconciles to ledger
governance:
  pii: false
  certified_metrics: [gmv, take_rate, active_rentals]               # served via semantic layer (ch.08)
breaking_change_policy: major-version-bump + 2-week notice
tests:                                                              # enforced in CI (ch.10)
  - not_null: [rental_id, account_id, started_at]
  - unique: [rental_id]
  - relationships: { account_id: dim_account.account_id }
Contracts only work if they have teeth

A contract that isn't enforced in CI is a wish. The mechanism that makes it real: the contract file is the single source of truth, a CI check on both the producer repo and the platform repo validates schema and tests against it, and a violation blocks the merge. Without that gate, contracts decay into stale YAML and you're back to discovering breakages in production. Chapter 10 wires the test execution and alerting; here, the discipline is "no published dataset without a contract, no merge that breaks one."

Dataset tiers & certification

Not every table deserves the same trust. The raw landing zone for the telemetry firehose and a Finance-reconciled GMV table are both "data," but depending on them carries wildly different risk. If the catalog treats them identically, analysts can't tell a battle-tested gold table from someone's abandoned scratch query. The answer is an explicit tier ladder — a visible trust signal that says how much weight a dataset can bear.

THE CERTIFICATION LADDER — trust increases as you climb ┌────────────────────────┐ │ ✅ CERTIFIED / GOLD │ exec dashboards, │ owned · SLA · tested · │ finance, board, ▲ │ contract · semantic- │ the NL/AI layer │ │ layer metrics │ ┌───────┴────┴────────────────────────┘ │ 🟡 STAGED / SILVER │ analyst day-to-day, │ cleaned, conformed, modeled, but │ dashboards w/ caveats ▲ │ no formal SLA owner │ ┌───────┴───┴──────────────────────────────────────┘ │ ⚠ RAW / BRONZE │ exploration only, │ source-faithful landing; use at your own risk; │ "is the data even │ may be late, malformed, or change without notice │ here?" questions └───────────────────────────────────────────────────┘ promotion = a reviewed PR: add owner, SLA, tests, contract, description → badge in catalog

Promotion up the ladder is a deliberate act, not a default. A table earns the certified badge by acquiring an owner, an SLA, a contract, passing tests, and a human description — reviewed in a PR, the same way code earns a release tag. The badge then renders in the catalog as a trust signal: an analyst searching for "rental revenue" sees the certified fct_rental at the top and knows it's safe to put in front of the CFO.

TierWhat it isGuaranteesWho can depend on it
Raw / BronzeSource-faithful landing zone (CDC output, raw events, raw telemetry)None. May be late, malformed, or re-keyed without notice.DPEs and DS for exploration only. Use at your own risk.
Staged / Silver 🟡Cleaned, deduped, conformed, modeled (dimensions & facts, ch. 06)Schema is stable; tested for nulls/uniqueness; best-effort freshness.Analysts for day-to-day work and dashboards that carry caveats.
Certified / GoldAn owned, contracted data product feeding the semantic layerNamed owner, freshness & availability SLA, CI-enforced contract, on-call.Anyone — exec dashboards, Finance, the board, and the NL/AI layer (ch. 13).
Tiers map cleanly onto the medallion you already built

If you followed the bronze/silver/gold medallion architecture in the transformation chapter, the tier ladder is the same layers wearing a trust badge. The new idea here isn't the layering — it's making the trust level visible in the catalog and gating it behind a certification review. A gold-layer table that nobody promoted is still just silver with ambitions.

How different personas access data

"Self-serve" means different things to a SQL analyst and a CFO. The platform has to meet each consumer group from Start Here on the interface they already live in — and crucially, route them all through the same certified datasets and the same semantic layer, so that five interfaces still produce one GMV number.

PERSONA → INTERFACE, all grounded on ONE certified core + semantic layer analysts ──▶ SQL / warehouse ──┐ DS ──▶ notebooks ────────┤ PMs/execs──▶ BI dashboards ────┼──▶ ┌─────────────────────────────┐ ops ──▶ reverse-ETL ──────┤ │ SEMANTIC LAYER (ch.08) │ everyone ──▶ NL / AI (ch.13) ──┘ │ certified metrics + dims │ └──────────────┬──────────────┘ ▼ ┌─────────────────────────────┐ │ CERTIFIED / GOLD datasets │ └─────────────────────────────┘ one definition of GMV, served five different ways ─ never five definitions
Persona (consumer group)Primary interfaceWhat they need from itGrounded on
Analysts (Product, Finance, Supply)SQL / warehouse consoleAd-hoc querying, joins, full SQL power over modeled tablesStaged + certified marts
ML & data scienceNotebooks (Python/Spark)Feature engineering, training data, exploration at scaleRaw → certified + feature store (ch. 12)
PMs & execsBI dashboardsGoverned dashboards, no SQL, one trustworthy number per metricSemantic layer metrics
Supply / revenue opsReverse-ETLCertified metrics pushed back into operational tools (CRM, Sheets)Certified datasets only
Trust & safety / riskSQL + low-latency viewsFresh signals, audited access to sensitive data (ch. 11)Certified + restricted domains
Everyone (incl. non-technical)NL / AI in Slack (ch. 13)"What was GMV last week?" answered correctly in plain languageSemantic layer + catalog metadata

The design rule across the whole table: the interface varies, the source of truth does not. Reverse-ETL must read the certified metric, not re-derive it; the BI tool must hit the semantic layer, not hand-rolled SQL; the NL/AI bot must resolve "GMV" through the same metric definition the CFO's dashboard uses. The moment any interface computes its own version of a governed metric, the platform has forked its truth — exactly the failure self-serve was meant to prevent.

Onboarding internal users

A self-serve platform that takes a new analyst two weeks to figure out is not self-serve. The metric that captures this is time-to-first-query — how long from "new hire's first day" to "ran a useful query against a certified dataset, alone." Treating the platform as a product (the mindset from the DPE-role chapter) means optimizing that onboarding funnel as deliberately as the product team optimizes signup.

The enablement toolkit that drives time-to-first-query down:

  • Golden paths — one blessed, documented way to do each common task: "how to build a dashboard," "how to add a dbt model," "how to query telemetry." Not ten options; one paved road that works.
  • Starter templates — a dbt model scaffold, a notebook template pre-wired to the warehouse, a dashboard skeleton. New work starts from a known-good shape, not a blank page.
  • Docs-as-code — documentation lives in the repo next to the code and ships with it, so it can't rot independently. Dataset descriptions in dbt YAML flow straight into the catalog.
  • A "Datasets 101" guide — the canonical model, the tiers, the certified marts, and the three fact grains from Start Here, in one onboarding doc every new user reads.
  • Office hours — a recurring, low-friction channel for the questions the docs don't cover. The trick is to treat each office-hours question as a signal: a recurring one means a missing golden path or dataset, and gets fixed at the source.
Platform-as-product, applied

The product mindset means the DPE team's users are internal, but treated like customers: they have a funnel (discover → understand → query → trust), they churn (give up and Slack the team), and they have a satisfaction score. Office hours, golden paths, and starter templates aren't overhead — they're the platform's onboarding flow and docs. A platform team that ships a powerful warehouse but no paved paths has built a product with no UX, and its adoption metrics will say so.

Federated ownership vs central platform

As the platform grows, one question gets sharper: who owns which datasets? The centralized model — one DPE team owns every pipeline and every table — is the ticket queue's cousin. It works early, then the central team becomes the bottleneck for every new dataset, because they're the only ones who can build one. The federated answer is data mesh: the domain teams own their data as products, and the central platform team provides the paved roads — the ingestion framework, the catalog, the semantic layer, the CI for contracts — on which domains build.

WHO OWNS WHAT — central paved roads, domain-owned products ┌─────────────────────────────────────────────────────────────────┐ │ CENTRAL PLATFORM TEAM (DPE) — the paved roads │ │ ingestion framework · catalog · semantic layer · contract CI · │ │ storage & compute · tier/certification process · access control │ └───────────┬───────────────┬───────────────┬──────────────────────┘ │ build on │ build on │ build on ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ │marketplace│ │ billing │ │ supply │ ... 6 domains │ domain │ │ & finance│ │ / fleet │ │ owns: │ │ owns: │ │ owns: │ │ fct_rental│ │ fct_meter │ │ fleet_ │ │ fct_bid_event │ │ dim_ │ │ health │ │ (products)│ │ invoice │ │ (products)│ └───────────┘ └───────────┘ └───────────┘ central owns the ROADS; domains own the PRODUCTS that ride on them

Mesh is a powerful organizing principle — but it has a real cost, and at GridDP's scale (tens to low hundreds of users, six domains, a data team of a handful), full federation can hurt more than it helps. Each domain owning a data product requires that domain to have someone who can build and operate one; spread that thin and you get six half-maintained pipelines instead of one good central one.

When mesh helps vs hurts at this scale

Helps when a domain has both deep data expertise and a backlog the central team can't service — e.g. the ML team owning feature datasets, or billing owning the ledger-reconciled marts, because nobody understands them better. Hurts when you federate ownership to teams without data capacity, fragmenting standards and re-creating the swamp. The pragmatic path at GridDP: the central team owns the roads and the shared core (the canonical model, the cross-domain marts), while a few capable domains own their own products. Federate the willing and able; don't mandate mesh org-wide because a blog post said to.

Measuring enablement

Enablement is a product, so you measure it like one. These metrics tell the DPE team whether the platform is actually getting more self-serve over time — or whether the ticket queue is quietly creeping back.

MetricWhat it measuresHealthy direction
Time-to-first-queryNew user's day-1 to first useful self-serve query↓ Down (hours, not weeks)
% questions answered self-serveShare of data questions resolved without the DPE team writing SQL↑ Up (toward 80%+)
Catalog coverage% of datasets with owner, description, and tier filled in↑ Up (toward 100% for certified)
Certified-dataset adoptionShare of queries / dashboards hitting certified vs raw tables↑ Up (trust concentrates on gold)
Ticket-volume trendAd-hoc data requests landing in the team's queue over time↓ Down per-user (and recurring ones → fixed)
Active self-serve usersDistinct humans querying / building each week↑ Up (breadth of adoption)
Watch the per-user trend, not the absolute

Raw ticket volume can rise while the platform is improving — more users simply ask more questions. The signal that matters is ticket volume per active user trending down, and the share of tickets that are genuinely novel (a new dataset request) versus recurring (a question the platform should already answer). A flat per-user trend with mostly-recurring tickets is the alarm: self-serve has stalled, and the team is sliding back into being the query API.

Takeaway

  • The ticket queue — the DPE team as a human query API — does not scale past a handful of analysts; self-serve is the only architecture that grows sub-linearly with GridDP's tens-to-low-hundreds of users.
  • Self-serve is a curated product: discoverable data (catalog), trustworthy data (tiers, certification, contracts), and consistent metrics (the semantic layer from ch. 08) — not raw SQL access for all.
  • The catalog harvests metadata from every store into a graph and serves search, lineage, ownership, freshness, and trust badges to humans and the NL/AI layer alike.
  • Data contracts, enforced in producer CI with an explicit breaking-change policy, are the API boundary that lets producers and consumers evolve independently.
  • Tiers (raw → staged → certified) make trust visible; certification is a reviewed promotion, not a default. Meet each persona on its own interface, but ground them all on one certified core.
  • Federate ownership to the willing and able domains; keep the central team owning the paved roads and shared core. Don't mandate mesh org-wide at this scale.
  • Measure enablement like a product: time-to-first-query, % self-serve, catalog coverage, certified adoption, and the per-user ticket trend.

Self-serve only works if the data underneath is actually correct — and stays correct. Next we make trust enforceable rather than aspirational: tests, freshness, anomaly detection, and incident response. → Data Quality & Observability