I team di marketing hanno accesso a più dati che mai, eppure le decisioni rimangono basate su ipotesi. Report assemblati su fogli di calcolo, metriche che cambiano da una dashboard all'altra, tre risposte diverse alla domanda "qual è il vero CAC?". Il problema non è la scarsità di dati — è la perdita lungo il percorso dalla fonte all'insight. L'architettura dbt + BigQuery elimina questa perdita: con lo source mapping raccogli i dati grezzi, con il modeling layer li trasformi in logica aziendale, con il semantic layer crei un linguaggio comune per il team, e con gli exposures li rendi disponibili in produzione.

Source Mapping: dai Dati Grezzi alla Fonte Affidabile

Lo source mapping è il primo strato di dbt — la trasformazione iniziale dopo aver importato i dati di marketing in BigQuery. Gli event grezzi provenienti da Google Ads API, Meta Ads, Shopify vengono standardizzati nel livello staging. Nel modello stg_google_ads__campaign_performance ci sono 127 colonne, ma ne usi 12. Lo source mapping seleziona queste 12, converte i timestamp in UTC, trasforma il campaign_id in stringa, gestisce i null e crea una tabella pulita.

In BigQuery, le sorgenti si definiscono nel file sources.yml. Qui configuri i freshness check — se i dati da Google Ads non arrivano entro 2 ore, la dbt run fallisce. È un contratto imposto: il data pipeline diventa affidabile. Invece di scrivere select diretto dalla raw table, usi la macro {{ source('google_ads', 'campaign_stats') }} — nel grafo di lineage dbt mostri quale raw table alimenta quale modello.

sources:
  - name: google_ads
    database: production
    schema: raw_google_ads
    tables:
      - name: campaign_stats
        freshness:
          warn_after: {count: 2, period: hour}
          error_after: {count: 6, period: hour}
        columns:
          - name: campaign_id
            tests:
              - not_null
              - unique

Modeling Layer: Trasformare la Logica Aziendale in Codice

Dopo lo staging arrivano i livelli intermediate e mart — qui applichi la logica aziendale ai dati di marketing. Nel modello int_campaign_attribution calcoli l'attribuzione first-touch e last-touch. In fct_customer_lifetime_value analizzi l'LTV per cohort. Questi modelli usano la materializzazione incremental di dbt — ogni run elabora solo gli ultimi 3 giorni, i vecchi record rimangono intatti. Se la tabella customer_event in BigQuery ha 40 milioni di righe, dbt con la strategia incremental mantiene il tempo di esecuzione sotto i 2 minuti.

Nel livello mart crei tabelle specializzate per ogni business unit: mart_paid_media__daily_performance, mart_crm__email_engagement, mart_finance__revenue_attribution. Questi si collegano direttamente a Looker Studio, Tableau, Amplitude — ognuno estrae la metrica dal suo dominio dalla stessa fonte. Il calcolo del CAC non è più un dibattito: la formula paid_media_spend / new_customers è definita nel modello dbt, passa dalla code review, è testata e versionata in Git.

-- models/marts/paid_media/mart_paid_media__daily_performance.sql
{{ config(materialized='incremental', unique_key='date_campaign_id') }}

with campaign_spend as (
  select
    date,
    campaign_id,
    sum(cost_micros) / 1e6 as spend
  from {{ ref('stg_google_ads__campaign_performance') }}
  {% if is_incremental() %}
    where date >= date_sub(current_date(), interval 3 day)
  {% endif %}
  group by 1, 2
),

conversions as (
  select
    date(timestamp) as date,
    campaign_id,
    count(distinct user_id) as conversions
  from {{ ref('stg_ga4__conversions') }}
  {% if is_incremental() %}
    where date(timestamp) >= date_sub(current_date(), interval 3 day)
  {% endif %}
  group by 1, 2
)

select
  c.date,
  c.campaign_id,
  c.spend,
  coalesce(cv.conversions, 0) as conversions,
  safe_divide(c.spend, nullif(cv.conversions, 0)) as cpa
from campaign_spend c
left join conversions cv using (date, campaign_id)

Semantic Layer: Creare un Linguaggio Comune

Il semantic layer è una feature introdotta in dbt 1.6 — le metriche le definisci come codice e ogni strumento le utilizza. La metrica revenue non è sum(order_total), ma sum(case when payment_status = 'completed' then order_total end). Scompare la domanda "gli ordini annullati sono inclusi?". La definizione della metrica è su GitHub. Marketing, finance e product usano la stessa metrica revenue — solo con dimensioni diverse.

Nel lavoro di Roibase sulla strategia di dati first-party e misurazione il semantic layer è un passaggio obbligatorio. Quando unisci customer event da diversi touch point, senza definizioni di metriche standardizzate ogni analisi dà risultati diversi. In dbt il file metrics.yml definisce le metriche, che vengono esposte ai BI tool via API — Looker, Hex, Mode leggono dal semantic layer, il numero appare uguale ovunque.

# models/metrics/metrics.yml
metrics:
  - name: marketing_qualified_leads
    label: Marketing Qualified Leads
    model: ref('fct_leads')
    calculation_method: count_distinct
    expression: lead_id
    timestamp: created_at
    time_grains: [day, week, month]
    dimensions:
      - utm_source
      - utm_campaign
      - landing_page
    filters:
      - field: lead_status
        operator: '='
        value: "'MQL'"

Exposures: Mettere in Produzione

Gli exposures traccia il dipendente downstream — definisci quale dashboard alimenta quale modello dbt. Hai una dashboard Looker "Weekly Campaign Performance" che estrae dati da mart_paid_media__daily_performance. Nel file exposures.yml registri questa dipendenza. Ora, se apportiamo una breaking change a mart_paid_media__daily_performance, dbt ti avverte: "Questo modello alimenta 3 dashboard, fai un impact analysis."

Gli exposures appaiono anche nella documentazione — nei dbt docs, quando clicchi su un modello, vedi "Used in 5 dashboards, 2 reverse ETL jobs, 1 ML pipeline". La lineage si estende fino al livello BI. Sai esattamente quale dashboard viene da quale SQL. Il tempo di debug scende perché individuate il dashboard problematico e risalite al modello sorgente.

Tipo di ExposureUtilizzoMetodo di Tracciamento
DashboardLooker, Tableau, MetabaseURL + model ref
Reverse ETLCensus, HightouchJob ID + source table
ML PipelineVertex AI, SageMakerModel name + feature table
Operational ToolBraze, Iterable segmentationSegment ID + dbt model

Pipeline Orchestration: il Ritmo di Ogni Livello

Orchestri il pipeline con dbt Cloud Scheduler o Airflow. Alle 6:00 del mattino i dati grezzi vengono caricati in BigQuery (Fivetran, Stitch, Airbyte), alle 6:30 parte dbt run. I modelli staging completano in 5 minuti, gli intermediate in 10, i mart in 15. Alle 7:00 il semantic layer è esposto, alle 7:15 le dashboard Looker si aggiornano. Quando il team arriva in ufficio alle 9:00 ha già i dati di ieri — niente delay di 3 ore.

Ogni run esegue la test suite: not_null, unique, accepted_values, relationships. Se in stg_google_ads__campaign_performance il campaign_id non è unico, dbt run fallisce. Un alert arriva su Slack. Il gate di qualità dei dati è enforcement a livello di codice. I dati rotti non raggiungono la produzione.

# dbt_project.yml on-run-end hooks
on-run-end:
  - "{{ log_dbt_results() }}"
  - "{{ send_slack_notification() }}"
  - "{{ update_looker_cache() }}"

Trade-off: Complessità vs Governance

Lo stack dbt + BigQuery introduce complessità. Nel team di analyst la competenza SQL diventa obbligatoria — "faccio un pivot in Excel" non basta più. Git workflow, code review, CI/CD pipeline sono concetti da imparare. Su team piccoli questo overhead può essere costoso. Ma il trade-off è netto: guadagni governance. Invece di formula persa in un foglio, hai codice sotto version control. "Da dove viene questo numero?" si risponde con Git blame in 10 secondi.

Il costo di BigQuery è un altro trade-off. I full table scan sono cari — la strategia di partition e cluster è obbligatoria. Nei modelli dbt incremental, i config partition_by e cluster_by sono critici. Una pipeline che elabora 100 GB al mese su BigQuery genera ~$50 di slot cost + $5 di storage. È un managed service, niente overhead infra, ma se non ottimizzi le query la fattura sale.

Connettere i dati di marketing al decision-making non è più risolvibile con fogli di calcolo e BI tool. Lo stack dbt + BigQuery codifica ogni livello dalla fonte all'exposure. Lo source mapping rende i dati grezzi affidabili, il modeling layer applica la logica aziendale, il semantic layer crea il linguaggio comune, gli exposures li mettono in produzione. Code review, test, version control — il data pipeline è ora gestito con la disciplina dello sviluppo software.