Documentazione Automatica in dbt: Descrizioni YAML, Data Lineage e dbt Catalog
dbt genera automaticamente documentazione e lineage graph dal codice: come aggiungere descrizioni YAML a modelli e colonne, il DAG interattivo che mostra le dipendenze, column-level lineage per tracciare ogni campo dalla sorgente al report finale.
Il Problema della Documentazione nei Data Warehouse
Ogni data team conosce il problema: il warehouse cresce, arrivano nuovi analisti, e nessuno
sa più cosa contiene la tabella fct_orders_v2_final o da dove viene
la colonna adjusted_revenue. La documentazione esiste in Confluence, ma è
disallineata dal codice reale da mesi.
dbt risolve questo problema alla radice: la documentazione è codice, vive
nello stesso repository dei modelli, si aggiorna con ogni dbt run e genera
automaticamente un catalogo interattivo con lineage graph. Non è una best practice
aggiuntiva - è parte integrante del workflow.
Descrizioni YAML: Il Contratto Dati Dichiarativo
Il punto di partenza è il file schema.yml nella directory del modello.
Ogni modello e ogni colonna può avere una descrizione in testo libero (o Markdown):
# models/marts/finance/schema.yml
version: 2
models:
- name: fct_orders
description: >
Fatto degli ordini completati, granularità ordine. Ogni riga rappresenta
un ordine con stato 'completed', arricchito con informazioni cliente, prodotto
e canale di acquisizione. Aggiornato quotidianamente alle 06:00 UTC.
**Fonte dati:** `stg_orders` (sorgente transazionale) + `dim_customers` + `dim_products`
**Owner:** team Finance Analytics
**SLA:** dati aggiornati entro le 07:00 UTC
meta:
owner: "finance-analytics@company.com"
freshness_expected_hours: 25
pii_columns: ["customer_email", "billing_address"]
columns:
- name: order_id
description: >
Identificatore univoco dell'ordine. Corrisponde all'`order_id` nel
sistema transazionale. Formato: stringa UUID v4.
- name: customer_id
description: >
Chiave esterna verso `dim_customers`. Ogni ordine appartiene
a esattamente un cliente.
- name: order_date
description: >
Data (senza ora) in cui l'ordine è stato completato.
Usare questa colonna per aggregazioni temporali, non `created_at`.
- name: gross_revenue
description: >
Ricavo lordo dell'ordine in EUR, prima di sconti e rimborsi.
Formula: `SUM(line_quantity * unit_price)`.
- name: net_revenue
description: >
Ricavo netto in EUR, dopo sconti applicati.
Formula: `gross_revenue * (1 - discount_pct)`.
- name: acquisition_channel
description: >
Canale tramite cui il cliente ha effettuato l'acquisto.
Valori possibili: `organic`, `paid_search`, `email`, `referral`, `social`, `direct`.
Derivato dalla sessione di acquisto tramite `dim_sessions`.
Descrizioni con doc() per Contenuti Riutilizzabili
Per descrizioni lunghe o condivise tra modelli, dbt supporta i doc block:
file Markdown nella directory models/ che possono essere referenziati tramite
la funzione doc():
-- models/docs/revenue_metrics.md
{% docs gross_revenue %}
Ricavo lordo dell'ordine in EUR, prima di sconti e rimborsi.
**Formula:** `SUM(line_quantity * unit_price)`
**Note contabili:** questo valore include l'IVA per i clienti IT/EU.
Per il ricavo netto IVA, usare `net_revenue_ex_vat`.
**Frequenza di aggiornamento:** giornaliera (06:00 UTC).
{% enddocs %}
{% docs customer_tier %}
Segmento di appartenenza del cliente al momento dell'ordine (SCD-2 snapshot).
| Valore | Soglia annuale | Benefici |
|----------|---------------|----------|
| standard | < 1.000 EUR | nessuno |
| silver | 1.000-5.000 EUR | spedizione gratuita |
| gold | 5.000-20.000 EUR | 5% sconto + spedizione |
| platinum | > 20.000 EUR | 10% sconto + account manager |
{% enddocs %}
# Uso nel schema.yml
columns:
- name: gross_revenue
description: "{{ doc('gross_revenue') }}" # referenza al doc block
- name: customer_tier
description: "{{ doc('customer_tier') }}"
Generare il Catalogo: dbt docs generate e serve
Il catalogo dbt è un'applicazione web statica generata dai metadati del progetto e dal warehouse. Due comandi per usarlo:
-- 1. Genera il catalogo (interroga il warehouse per schema e statistiche)
dbt docs generate
-- 2. Avvia un server locale per navigare il catalogo
dbt docs serve
-- Apre automaticamente http://localhost:8080
-- In CI/CD: genera il catalogo e pubblica gli artifact
dbt docs generate --no-compile -- più veloce se già compilato
-- Output dei file generati in target/:
-- target/catalog.json -- metadati di tabelle e colonne
-- target/manifest.json -- DAG del progetto, modelli, test
-- target/sources.json -- metadati sorgenti
-- target/index.html -- l'applicazione web statica
Il catalogo generato contiene:
- Tutte le descrizioni di modelli e colonne scritte in YAML
- Schema effettivo delle tabelle (tipi colonne, dimensioni)
- Test configurati per ogni modello
- Il lineage graph interattivo (DAG)
- Statistiche di row count e dimensioni tabelle (dove supportato)
Il DAG Interattivo: Capire le Dipendenze
La feature più potente del catalogo dbt è il lineage graph:
una visualizzazione interattiva del DAG completo del progetto. Ogni nodo è
un modello, ogni arco è una dipendenza creata da ref() o source().
Dalla UI è possibile:
- Filtrare per layer (staging, intermediate, marts) usando i selettori dbt standard
- Espandere/collassare sotto-grafi
- Cliccare su un nodo per vedere descrizione, colonne, test e SQL compilato
- Vedere il lineage upstream (da dove arriva questo modello) e downstream (chi dipende da questo)
Selettori per Navigare il Lineage
-- Nella barra di ricerca del catalogo, puoi usare i selettori dbt:
-- Tutti i modelli che dipendono da stg_orders (downstream)
+stg_orders
-- stg_orders e tutti i suoi upstream (sorgenti incluse)
stg_orders+
-- Tutti i modelli in marts/ e il loro upstream immediato
+tag:marts
-- Solo i modelli con un certo owner nei meta
exposure:finance_dashboard
-- CLI equivalente (per capire il subset visivamente):
dbt ls --select +fct_orders+ -- mostra upstream E downstream di fct_orders
Column-Level Lineage: Tracciare un Campo dalla Sorgente al Report
Il column-level lineage (disponibile in dbt Cloud e con alcuni metadati
aggiuntivi in dbt Core) traccia ogni colonna attraverso i modelli: da quale colonna sorgente
deriva net_revenue nel report finale? dbt Cloud Explorer mostra questo
automaticamente analizzando le SELECT.
# Per abilitare il column-level lineage in dbt Core,
# aggiungi le dipendenze colonne nei meta (opzionale ma utile):
models:
- name: fct_orders
columns:
- name: net_revenue
description: "Ricavo netto dopo sconti"
meta:
derived_from:
- model: stg_orders
column: total_amount
- model: stg_orders
column: discount_pct
formula: "total_amount * (1 - discount_pct)"
In dbt Cloud Enterprise, il column-level lineage è automatico: il sistema analizza
il SQL compilato di ogni modello e costruisce il grafo di dipendenze a livello di colonna.
Utile per l'impact analysis: se cambia la definizione di discount_pct nella sorgente,
quali report finali sono impattati?
Exposures: Documentare i Consumer del Warehouse
Le exposure documentano chi usa i modelli dbt - dashboard Tableau, report Power BI, notebook Python, API. Appaiono nel lineage graph come nodi finali e permettono di capire l'impatto di un cambiamento:
# models/exposures.yml
version: 2
exposures:
- name: finance_weekly_report
label: "Report Finanziario Settimanale"
type: dashboard # dashboard | ml | notebook | analysis | application
maturity: high # low | medium | high
url: https://tableau.company.com/views/FinanceWeekly
description: >
Dashboard Tableau aggiornata ogni lunedì mattina con KPI finanziari
della settimana precedente. Usata dal CFO e dal team Finance per il report
settimanale al board.
owner:
name: Finance Analytics Team
email: finance-analytics@company.com
depends_on:
- ref('fct_orders')
- ref('fct_order_line_items')
- ref('dim_customers')
- ref('dim_products')
- name: ml_churn_model
label: "Modello ML Churn Prediction"
type: ml
maturity: medium
description: >
Feature store per il modello di churn prediction. Addestrato settimanalmente,
serve dati degli ultimi 90 giorni di comportamento cliente.
owner:
name: Data Science Team
email: datascience@company.com
depends_on:
- ref('fct_customer_events_90d')
- ref('dim_customers')
Sources: Documentare le Sorgenti Esterne
Le sorgenti raw del warehouse meritano la stessa cura documentativa dei modelli dbt.
Il file sources.yml permette di documentarle e di attivare i freshness check:
# models/staging/sources.yml
version: 2
sources:
- name: raw
description: >
Schema raw: dati grezzi caricati dai sistemi transazionali tramite Fivetran.
Nessuna trasformazione applicata. Schema di appoggio - non usare direttamente
nei report, usare i modelli staging/ come interfaccia stabile.
database: analytics_db
schema: raw
loaded_at_field: _fivetran_synced # colonna di timestamp per il freshness check
freshness:
warn_after: {count: 12, period: hour}
error_after: {count: 24, period: hour}
tables:
- name: orders
description: "Ordini dal CRM, sincronizzati ogni 15 minuti."
columns:
- name: id
description: "Primary key del sistema sorgente."
- name: customer_id
description: "FK verso la tabella customers."
- name: status
description: "Status dal CRM: created|paid|shipped|delivered|cancelled."
- name: _fivetran_synced
description: "Timestamp dell'ultima sincronizzazione Fivetran."
- name: customers
description: "Anagrafica clienti dal CRM."
freshness:
warn_after: {count: 24, period: hour} # override per questa tabella
-- Verificare la freshness delle sorgenti:
dbt source freshness
-- Output esempio:
-- Found 3 sources, 7 tables
-- Checking freshness of 7 sources (7 checks)
-- OK freshness of raw.orders ..................... [ok in 0.34s]
-- WARN freshness of raw.customers ............... [warn in 0.41s]
-- ERROR freshness of raw.events ................. [error in 0.29s]
Meta: Metadati Custom per Governance
Il campo meta in YAML permette di aggiungere metadati strutturati custom
che appaiono nel catalogo e possono essere usati da tool di governance esterni:
models:
- name: fct_orders
meta:
owner: "finance-analytics@company.com"
team: "Finance Analytics"
tier: "gold" # bronze/silver/gold (data quality tier)
sla_hours: 25 # ore massime dall'ultimo aggiornamento
pii: false # contiene PII?
gdpr_relevant: true # rilevante per GDPR?
retention_days: 365 # giorni di retention
business_glossary_link: "https://wiki.company.com/glossary/orders"
downstream_systems:
- "Tableau Finance Dashboard"
- "Looker Revenue Report"
- "ML Churn Feature Store"
Pubblicare il Catalogo in Produzione
In dbt Core, il catalogo generato è una cartella di file statici che puoi hostare su qualsiasi static file server. Ecco un pattern comune con GitHub Actions + GitHub Pages:
# .github/workflows/dbt-docs.yml
name: Publish dbt Docs
on:
push:
branches: [main]
jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dbt
run: pip install dbt-snowflake==1.8.0
- name: dbt deps
run: dbt deps
env:
DBT_PROFILES_DIR: .
- name: dbt docs generate
run: dbt docs generate --target prod
env:
SNOWFLAKE_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
SNOWFLAKE_PASSWORD: ${{ secrets.SNOWFLAKE_PASSWORD }}
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./target
destination_dir: docs
dbt Cloud: Documentazione Integrata
In dbt Cloud, il catalogo viene generato automaticamente dopo ogni job di produzione e accessibile tramite il menu “Explore”. dbt Cloud Enterprise aggiunge column-level lineage automatico, ricerca full-text nelle descrizioni, e integrazione con tool di catalogo esterni (Alation, Collibra, Atlan).
Best Practices per la Documentazione dbt
Avere la possibilità di documentare non significa che la documentazione sia automaticamente buona. Ecco le pratiche che distinguono un catalogo utile da un catalogo abbandonato:
Scrivi Descrizioni Operative, Non Ovvie
# EVITA: descrizioni ridondanti che ripetono il nome della colonna
columns:
- name: order_id
description: "L'ID dell'ordine." # inutile
# PREFERISCI: descrizioni operative con contesto, formato, vincoli
columns:
- name: order_id
description: >
Identificatore univoco dell'ordine. UUID v4 generato dal sistema CRM.
Usare questo campo come chiave di join con i sistemi transazionali.
Non corrisponde all'order_number visibile all'utente (quello è in `order_number`).
- name: gross_revenue
description: >
Ricavo lordo dell'ordine in EUR, centesimi di precisione.
Include IVA per ordini EU, esclusa per ordini US.
Per ricavo netto usare `net_revenue`. Per ricavo ex-IVA usare `net_revenue_ex_vat`.
Non include spese di spedizione (vedi `shipping_amount`).
Documenta le Anomalie Note e le Limitazioni
models:
- name: fct_orders
description: >
**NOTA (2024-03-15):** Gli ordini precedenti al 2022-01-01 hanno `acquisition_channel`
sempre NULL: il tracking non era presente prima di quella data.
Non filtrare su NULL in analisi pre-2022 o i risultati saranno distort.
**LIMITAZIONE NOTA:** I rimborsi parziali non riducono `gross_revenue` in questo modello
(feature pianificata per Q3 2024). Per analisi rimborsi usare `fct_refunds`.
**DIPENDENZA CRITICA:** Questo modello dipende da `snap_customers` (snapshot SCD-2).
Se lo snapshot non è aggiornato, la segmentazione cliente potrebbe essere
basata su dati del giorno precedente.
Automazione: Generare Bozze di Documentazione
-- dbt Cloud e alcuni tool (dbt-osmosis, dbt-coverage) permettono di
-- generare automaticamente bozze di schema.yml per modelli non documentati
-- Installa dbt-osmosis per propagare automaticamente le descrizioni
-- dalle sorgenti fino ai modelli downstream:
pip install dbt-osmosis
-- Genera schema.yml per tutti i modelli privi di documentazione:
dbt-osmosis yaml generate --select path:models/staging/
-- Propaga le descrizioni dai modelli upstream ai downstream:
dbt-osmosis yaml refactor --select path:models/marts/
-- dbt-coverage: verifica la percentuale di documentazione nel progetto
pip install dbt-coverage
dbt-coverage compute doc --cov-report coverage.json
dbt-coverage check doc --cov-report coverage.json --min-coverage 80
Conclusioni e Prossimi Passi
La documentazione dbt non è documentazione nel senso tradizionale: è un contratto vivente che si evolve col codice, genera automaticamente un catalogo navigabile, e permette a ogni membro del team di capire da dove vengono i dati e come sono stati trasformati.
Investire nella qualità delle descrizioni YAML, nelle exposure e nella documentazione delle sorgenti ripaga in proporzione alla dimensione del team e alla complessità del warehouse.
Il prossimo modulo affronta un confronto pratico molto richiesto: dbt Core vs dbt Cloud. Quando il self-hosting è sufficiente e quando il managed service vale il costo.

Commenti
Caricamento commenti...
Accedi per commentare