The Data Model: Why I Put My Music Catalog in Salesforce

Matt/ April 21, 2026/ AI, Development, Integration, Music, Personal, Projects, Salesforce/ 0 comments

After the intro post, a few people asked the same question: why Salesforce?

Fair question. Salesforce is enterprise CRM software. It costs money, has a steep learning curve, and comes with the kind of bureaucratic reputation that makes developers wince. It is not, on the surface, an obvious choice for a solo musician trying to get their songs on playlists.

Here’s why it made sense anyway – and why the data model that came out of it turned out to be the foundation for everything else in this project.


Why Not a Spreadsheet

I started with spreadsheets. Most musicians do. You’ve got a tab for playlists, a tab for submissions, maybe a tab for tracks. It works until it doesn’t.

The problem isn’t storage, it’s relationships. A track can appear on multiple releases. A release can have multiple tracks. A playlist can receive multiple submissions for the same track at different times. A submission has a status that changes. When you start asking questions like “which playlists have accepted my music before?” or “which of my tracks has the best shot at this playlist?”, spreadsheets collapse. You end up copy-pasting data across tabs and losing confidence in which version is correct.

What you actually need is a relational database with a UI that doesn’t require writing SQL. Salesforce is exactly that – and it comes with bulk APIs, a workflow engine, and Agentforce – an agentic AI layer that I had plans for.


The Five Core Objects

The data model has five custom objects:

Release__c – an album or single. Holds metadata like release date, genre, Spotify URL, and Apple Music URL. This is the commercial unit – the thing that gets pitched to press and submitted to DSPs.

Track__c – an individual song from my own catalog. Holds the audio feature scores, composite scores, and submission metrics. A track is the atomic unit of the submission pipeline – you submit tracks to playlists, not releases.

Release_Track__c – the junction between Release and Track. A track can appear on multiple releases (a single and then an album, for example), and a release obviously has multiple tracks. This junction object is a Master-Detail on both sides, which means it’s tightly coupled – delete the release or the track and the junction record goes with it.

Playlist__c – a Spotify playlist. Auto-number name (PL-00001, PL-00002). Holds metadata synced from Spotify: follower count, track count, whether it’s active, the platform. This is where the playlist profile scores live once snapshots are built – more on that in a later post.

Playlist_Submission__c – a track submitted to a playlist. Master-Detail on Playlist__c. Records the submission date, method, status (Draft → Submitted → Successful/Unsuccessful), and any notes. This is the object that ultimately answers the question this whole project is trying to answer: did the curator say yes?


The Junction Table Pattern

Release_Track__c is worth pausing on because it’s a pattern that trips people up.

The naive data model puts tracks directly on releases – a Master-Detail with Release as parent. That works until a track appears on more than one release, at which point you either duplicate the track record or break your model.

The junction table solves this cleanly. Release__c and Track__c are independent objects. Release_Track__c sits between them and holds the relationship. One track, one record – no duplication, no broken lookups. Each release-track combination gets its own junction record, which also turns out to be the right place to store release-specific metadata like track number and Spotify popularity (which can differ between a single release and an album release).

This pattern is standard in relational databases and has a name in Salesforce – junction object – but it’s not the first thing that comes to mind when you’re setting up a data model from scratch.


What the Model Enables

This data model matters beyond basic record-keeping because it creates the right foundation for the Music Intelligence Engine.

Track__c is where the audio feature scores live. Playlist__c is where the playlist profile lives. Playlist_Submission__c is the ground truth on what actually worked.

When you eventually want to ask “given this track’s audio profile and this playlist’s profile, how well do they fit – and should I submit?”, you need all three of those objects to be clean, relational, and queryable. The data model has grown considerably since these initial five core objects – but every layer that came after was only possible because the foundation was right.

That’s why Salesforce.


One more thing worth noting: while I was building this, Spotify quietly deprecated their Audio Features API – the endpoint that used to return energy, danceability, valence, and a dozen other musical characteristics for any track. That’s the moment this project stopped being a submission tracker and became something I hadn’t planned to build. More on that next.

Share this Post

About Matt

Matt McGuire is a Salesforce architect, AI builder, and punk musician based in Toronto. Canada's #1 certified Salesforce professional, 42× certified across architecture, development, AI, and a wide range of platform products. He's been building on Salesforce for 17 years and currently spends most of his time at the intersection of AI and the platform. The Music Intelligence Engine is his most interesting project to date. He thinks you should read the whole series.

Leave a Comment

Your email address will not be published. Required fields are marked *

*
*

This site uses Akismet to reduce spam. Learn how your comment data is processed.