Step 1 — Copy the Project

cp -r db/dbt db/dbt-2

This gives you an exact copy of the full Northwind dbt project. Now we’ll strip it down to the bare minimum.

Step 2 — What to Remove vs. Keep

db/dbt-2/
  models/
    staging/
      stg_orders.sql      ← keep & simplify
      stg_customers.sql  ← keep & simplify
      stg_order_details.sql ← delete
      stg_products.sql     ← delete
      stg_employees.sql    ← delete
      _staging.yml         ← update (2 models only)
    marts/
      dim_customer.sql   ← keep & simplify
      dim_product.sql    ← delete
      dim_employee.sql   ← delete
      dim_time.sql       ← delete
      fact_sales.sql     ← delete
      fact_order_summary.sql ← new (replaces fact_sales)
      vw_sales_detail.sql  ← delete
      vw_monthly_sales.sql ← delete
      vw_customer_revenue.sql ← new (replaces both views)
      _marts.yml          ← update (3 models only)
  dbt_project.yml         ← update project name
  profiles.yml            ← no change needed
  Dockerfile              ← no change needed

Red strikethrough = delete. Green = keep/create. Yellow = modify.

Full (db/dbt)Simplified (db/dbt-2)
Staging5 models2 models
Dimensions4 tables1 table
Facts1 table (per line item)1 table (per order)
Views21
Total12 objects5 objects

Step 3 — Simplified File Contents

config dbt_project.yml
name: 'northwind_simple'   # changed from 'northwind'
version: '1.0.0'

profile: 'northwind_clickhouse'  # same profile — same DB connection

models:
  northwind_simple:
    staging:
      +materialized: view
    marts:
      +materialized: table
staging models/staging/stg_orders.sql
-- Thin wrapper: rename PascalCase columns to snake_case
SELECT
    OrderID     AS order_id,
    CustomerID  AS customer_id,
    toDate(OrderDate) AS order_date,
    Freight     AS freight
FROM {{ source('northwind_oltp', 'Orders') }}
staging models/staging/stg_customers.sql
SELECT
    CustomerID   AS customer_id,
    CompanyName  AS company_name,
    Country      AS country
FROM {{ source('northwind_oltp', 'Customers') }}
dimension models/marts/dim_customer.sql
-- One row per customer, surrogate key
SELECT
    row_number() OVER (ORDER BY customer_id) AS customer_key,
    customer_id,
    company_name,
    country
FROM {{ ref('stg_customers') }}
fact models/marts/fact_order_summary.sql
-- One row per ORDER (not per line item — much simpler)
SELECT
    row_number() OVER (ORDER BY o.order_date, o.order_id) AS order_key,
    o.order_date,
    coalesce(dc.customer_key, 0) AS customer_key,
    toDecimal64(o.freight, 2) AS freight
FROM {{ ref('stg_orders') }} o
LEFT JOIN {{ ref('dim_customer') }} dc
    ON o.customer_id = dc.customer_id
WHERE o.order_date IS NOT NULL
view models/marts/vw_customer_revenue.sql
-- Revenue summary per customer — ready for dashboards
SELECT
    dc.company_name,
    dc.country,
    count(*)                        AS total_orders,
    round(sum(f.freight), 2)        AS total_freight,
    round(avg(f.freight), 2)        AS avg_freight
FROM {{ ref('fact_order_summary') }} f
LEFT JOIN {{ ref('dim_customer') }} dc
    ON f.customer_key = dc.customer_key
GROUP BY dc.company_name, dc.country
ORDER BY total_freight DESC

Simplified DAG

stg_customers
─▸
dim_customer
─▸
fact_order_summary
─▸
vw_customer_revenue
stg_orders
──────────────────▸
fact_order_summary

Same pattern as the full project: stagingdimensionfactview. Just fewer models.

Remember: This is a disposable learning exercise. The original db/dbt remains untouched. We’ll delete db/dbt-2 after verifying it works.