Architecture — Data Quality + Lineage
From API to static file. Every hop audited.
Two Fivetran connectors. Snowflake as the lakehouse. dbt-Snowflake shapes the gold layer. dbt-wizard run-time agents read the same gold marts. A Python snapshot writes static JSON to CloudFront.
11
raw tables
16
dbt models
76
dbt tests
1
warn
Stack powered by
Fivetran lands the data. Snowflake stores and serves it. dbt governs the transform.
End-to-end lineage
Spotify and MusicBrainz raw → Fivetran connectors → Snowflake raw schemas → dbt-Snowflake staging views → Snowflake gold marts → static JSON on CloudFront.
Source tables
11 raw tables in Snowflake — two schemas, raw_spotify and raw_mb. Landed by two Fivetran Connector SDK connectors on each sync.
raw_spotify — 8 tables
raw_spotify
recently_played
Rows
1,240
Cols
9
PK
played_at, track_id
raw_spotify
top_tracks_short_term
Rows
50
Cols
7
PK
track_id, time_range
raw_spotify
top_tracks_medium_term
Rows
50
Cols
7
PK
track_id, time_range
raw_spotify
top_tracks_long_term
Rows
50
Cols
7
PK
track_id, time_range
raw_spotify
top_artists_short_term
Rows
50
Cols
6
PK
artist_id, time_range
raw_spotify
top_artists_medium_term
Rows
50
Cols
6
PK
artist_id, time_range
raw_spotify
top_artists_long_term
Rows
50
Cols
6
PK
artist_id, time_range
raw_spotify
saved_albums
Rows
96
Cols
8
PK
album_id
raw_mb — 3 tables
raw_mb
artists
Rows
88
Cols
10
PK
mbid
raw_mb
releases
Rows
96
Cols
12
PK
mbid
raw_mb
recordings
Rows
1,180
Cols
8
PK
mbid
dbt model lineage
7 staging views clean and cast raw columns. 9 Snowflake tables materialize the gold marts — core dims, listening facts, and curation aggregates. dbt-Snowflake adapter throughout.
Staging
stg_spotify__recently_played
stg_spotify__saved_albums
stg_spotify__top_tracks
stg_spotify__top_artists
stg_mb__releases
stg_mb__artists
stg_mb__recordings
Marts / Core
dim_albums
dim_artists
dim_tracks
Marts / Listening
fct_plays
agg_top_tracks_by_window
agg_top_artists_by_window
Marts / Curation
canon_vs_listening
decade_distribution
discoveries
7
Views (staging)
9
Snowflake tables (gold)
4
Layers
Data quality
dbt tests run on every build. Failures block promotion to the next layer. One warn on an accepted_values test — no failing tests in production.
Last run: dbt build · all layers · 8m ago
staging
all passing- not_null_stg_spotify__recently_pla…
- unique_stg_mb__releases_mbid
- not_null_stg_mb__artists_mbid
core
1 warn- not_null_dim_albums_album_id
- unique_dim_albums_album_id
- accepted_values_dim_tracks_source_…
listening
all passing- not_null_fct_plays_played_at
- referential_fct_plays_track_id__di…
- not_null_fct_plays_duration_ms
curation
all passing- not_null_canon_vs_listening_album_…
- unique_decade_distribution_decade
- not_null_discoveries_first_played_…
Operations
Personal dataset at personal scale. ~$10–20/month all-in (Snowflake XS warehouse, S3, CloudFront). Warehouse auto-suspends after 60s of inactivity.
Est. monthly cost
$10–20
Snowflake credits + S3 + CloudFront
p95 query time
0.8s
Snowflake XS warehouse, gold layer
Last full refresh
14m ago
Fivetran → dbt → snapshot
dbt build time
~40s
all 16 models, auto-suspend on
·
Trust boundaries
What is public, what is private, and where each credential lives.
Spotify credentials
User-bound OAuth. The connector holds a refresh token in Fivetran's encrypted secret store — never committed to this repo, never in .tfvars.
MusicBrainz access
Public API, no credentials required. The connector enforces MB's 1 req/sec policy via a configurable rate_limit_sleep parameter.
dbt Snowflake role
The dbt runner connects via a dedicated Snowflake role scoped to the LINER_NOTES database. Raw schema is readable; only the staging and marts schemas allow writes.
CloudFront isolation
The SPA is served from an S3 bucket that has no access to Snowflake. CloudFront serves the static export; Snowflake credentials are never embedded in the frontend.
Terraform IAM policies, Fivetran connector configs, and dbt profiles are all kept outside version control. .tfvars and profiles.yml.example contain no real values — only placeholder comments showing required keys.
·
dbt-wizard run-time agents
Natural-language queries over the Snowflake gold layer. Ask a question — four dbt-wizard sub-agents (Explorer, Summary, Worker, Verification) generate SQL, run it against the marts, and return a structured answer. Humans and agents read the same gold layer.
Input
Plain-English question against the semantic model defined on dim_albums, fct_plays, and the curation marts.
dbt-wizard agents
Four sub-agents — Explorer, Summary, Worker, Verification — generate SQL, execute it against the Snowflake gold layer, and return structured results. Same tested mart columns the rest of the site reads.
Output
Narrated answer rendered on the /ask page. Same gold tables the rest of the site reads — no separate analytical copy.
dbt-wizard sub-agents sit between the Snowflake gold marts and the app — the same position as the build_snapshot.py script, but interactive. They read the tested, versioned mart columns rather than raw API payloads.