Your next report should start with a useful model already in place.
We refactor existing dbt™ projects and build new SQL models around the work your teams need to understand. Explicit grain, shared definitions, and traceable transformations give new analysis a dependable starting point.
Model the business, layer by layer.
We separate source cleanup from business logic and reporting. Staging models standardize the inputs; intermediate models handle shared transformations; marts organize data for use.
Explicit grain and relationships keep joins from quietly changing what a number means.
5 source events↓2 completed work items↓15-minute mean duration
MODEL EXPLORER
mart.work_item_cycle2026-10-26 UTC
Count the work at the right grain.
One row per completed work item. Duration runs from the first accepted start to terminal completion.
Completed items · all timestamps UTC
Work item
Started
Completed
Minutes
W-101
09:00
09:12
12
W-102
09:05
09:23
18
Measure
(12 + 18) / 2 = 15 minutes
Exclusions
Open, canceled, missing-start or invalid-duration items
Owner role
Operations
Two work items, five source events. The event count is not the metric denominator.
Test the definition and its boundaries.
Model changes run through CI before release. Production data checks run separately as records arrive.
✓Unique work_item_id2 / 2
✓Relationships to source items2 / 2
✓Duration ≥ 0 minutes2 / 2
✓Duplicate event fixturepass
✓Out-of-order update fixturepass
We test the business rules and check source totals before a model change reaches your reports.
Follow the calculation to its sources.
Source cleanup, event resolution, and the reporting grain each have a distinct job.
source.events5 events · 2 work items
↓
stg_work_eventsSource IDs · UTC timestamps
↓
int_work_lifecycleResolve event order · calculate duration
↓
work_item_cycle2 rows · one row per completed item
→dbt
Reuse SQL with Jinja macros.
We use Jinja macros to package repeated SQL with clear inputs, then test the models that call them. Shared datasets belong in shared models. New reports can build on established logic instead of another copy of the same calculation.
Scale with incremental models.
Use incremental builds where a full rebuild adds little value. We define update keys, late-arrival windows, and backfill paths, then compare the results with a full build. We inspect query plans for repeated scans and expensive joins, and choose materializations to suit the workload.
Test the logic before release.
Tests for unique keys and valid relationships catch structural issues. Cases cover duplicate events, out-of-order updates, and invalid durations. Model changes run through CI before release; production checks keep validating the data as it arrives.
Make definitions part of the model.
A metric’s calculation, grain, exclusions, and owner belong alongside its code. We connect that documentation to lineage and review changes with the teams using the result.
Control access at the right layer.
Reporting models should expose the fields each team needs. We exclude unnecessary personal data, separate restricted attributes, and apply permissions in the warehouse. Access rules become part of the model’s design and review, with ownership clear when requirements change.
What does your data need to do next?
Tell us what is changing, where the current system gets in the way, and what your team needs to decide.