<aside>
Freelance Engagement ยท Mar 2026 ยท B2B SaaS
Client details anonymised under NDA. All company IDs and names replaced with alphanumeric identifiers.
</aside>
โ The Ask
A B2B SaaS client expanding into a new customer segment had no analytics infrastructure to measure whether the expansion was working. I was brought in to build it from scratch.
๐ What I Analysed
Revenue concentration using Pareto analysis, a multi-signal churn risk scoring model across 655 active accounts, feature adoption across 838,790 product events, and customer segmentation by industry, geography, and company size.
๐ What I Delivered
A formal Business Intelligence Report with five strategic recommendations mapped to product, growth, and customer success teams โ presented to client leadership at the close of the engagement.
โ๏ธ What I Built
A three-layer dbt pipeline on Snowflake. 6 staging models cleaning raw data from three source systems, 8 mart models applying business logic with 185 automated data quality tests across all 14
๐ก What I Found
Revenue distribution is healthier than the 80/20 benchmark (59.8/40.2). Enterprise and Growth each drive ~30% of MRR through opposite mechanisms. Payment failure is the strongest single predictor of churn. API usage in Enterprise creates natural switching costs.
๐ง Stack
Snowflake dbt Core SQL Postgresql
Python Git Jinja
What was the brief
In 2025, NTFC expanded beyond its enterprise-only motion and launched a self-serve Growth tier targeting small to mid-size European tech companies. Twelve months in, leadership had no reliable way to assess whether the expansion was working. Revenue was coming in, but there was no unified view across product usage, billing health, and support load. Basic questions like which accounts were at risk, how Growth customers engaged versus Enterprise, and how the new tier was affecting overall MRR concentration remained unanswered.
I was brought in to build the analytics foundation from scratch, modelling raw data from three source systems into a clean dbt pipeline on Snowflake, building the core metrics needed to evaluate the Growth tier expansion, and packaging findings into a formal BI report with recommendations for product, growth, and customer success teams.
How the pipeline works
The pipeline follows a three-layer architecture: raw data lands in Snowflake exactly as received, staging models clean and type every column without applying any business logic, and mart models join, aggregate, and apply business rules to produce analysis-ready tables.

*dbt lineage graph: data flows left to right from raw sources through staging to mart models*
Models
| Model | Type | Rows | What it answers |
|---|---|---|---|
| stg_companies | Staging view | 800 | Cleaned company accounts with typed dates and derived employee count |
| stg_subscriptions | Staging view | 905 | Subscription periods with decimal MRR and multi-format date parsing |
| stg_users | Staging view | 16050 | User seats with boolean flags correctly typed |
| stg_events | Staging view | 838790 | Product usage events รขโฌโ largest table in the pipeline |
| stg_invoices | Staging view | 1411 | Invoices with COALESCE handling for mixed date formats |
| stg_support_tickets | Staging view | 3676 | Support tickets with nullable resolution and CSAT metrics |
| dim_companies | Mart table | 800 | One row per company enriched with current plan MRR and ARR |
| dim_users | Mart table | 16050 | Users with company context and days since last login |
| fct_subscriptions | Mart table | 905 | Revenue table with churn flags and subscription length |
| fct_events | Mart table | 838790 | Events joined with user and company context |
| fct_invoices | Mart table | 1411 | Billing records with tax calculations and days to pay |
| fct_mrr_monthly | Mart table | 905 | MRR by month with window functions for plan totals and cumulative growth |
| churn_risk | Mart table | 655 | Multi-signal churn scoring across all active paying accounts |
| feature_adoption | Mart table | Aggregated | Feature usage by month plan industry country and platform |

*STAGING schema โ six views, one per source table*