Track
The core entity representing a publishable audio recording. Every Track belongs to one Album and carries editorial, commercial and legal metadata, plus references to artists, genres, moods and the processing artifacts (HLS segments and jobs).
apps/api/src/Features/Tracks/Models/Track.cs1 Full schema
The class inherits from BaseModel, which provides
Id (Guid), CreatedAtUtc and
UpdatedAtUtc. EF Core maps it to the
tracks table in PostgreSQL.
public class Track : BaseModel
{
// Identity
public required string Title { get; set; }
public required short Duration { get; set; } // seconds
public Guid AlbumId { get; set; }
public Album Album { get; set; } = null!;
public TrackStatus Status { get; set; } = TrackStatus.Queued;
public DateTime? PublishedAtUtc { get; set; }
public DateTime? DeletedAtUtc { get; set; }
// Editorial
public string? SortTitle { get; set; }
public string? VersionQualifier { get; set; }
public TrackVersionType VersionType { get; set; } = TrackVersionType.Original;
public bool IsExplicit { get; set; }
public ContentAdvisory ContentAdvisory { get; set; } = ContentAdvisory.NotRated;
public Guid? CleanVersionOfTrackId { get; set; }
public Track? CleanVersionOf { get; set; }
public string? PrimaryLanguage { get; set; }
public bool IsInstrumental { get; set; }
public string? Lyrics { get; set; }
// Commercial overrides (null = inherit from Album)
public int? PLineYearOverride { get; set; }
public string? PLineHolderOverride { get; set; }
public int? CLineYearOverride { get; set; }
public string? CLineHolderOverride { get; set; }
public bool? AiGeneratedOverride { get; set; }
public string? Isrc { get; set; }
// DMCA / legal
public string? TakedownReason { get; set; }
public DateTime? TakedownAtUtc { get; set; }
// Navigation (EF Core)
public ICollection<Artist> Artists { get; set; } = [];
public ICollection<TrackContributor> Contributors { get; set; } = [];
public ICollection<Genre> Genres { get; set; } = [];
public ICollection<Mood> Moods { get; set; } = [];
public TrackAudioFeatures? AudioFeatures{ get; set; }
public ICollection<TrackSegment> Segments { get; set; } = [];
public ICollection<TrackJob> Jobs { get; set; } = [];
}
2 Identity
| Field | Type | Description |
|---|---|---|
Id |
Guid |
Primary key. Inherited from BaseModel. |
Title |
string · required |
Display title shown in UIs and search. |
Duration |
short · required |
Duration in seconds. A short
covers up to ~9 h — plenty for any real song.
|
AlbumId / Album |
Guid + nav |
Required FK. Every track belongs to exactly one Album
(singles also get an album shell).
OnDelete = Restrict.
|
Status |
TrackStatus enum |
Current pipeline state. See §6. |
PublishedAtUtc |
DateTime? |
When the track was published. null before the
first publish.
|
DeletedAtUtc |
DateTime? |
Soft delete. Pairs with Status = Deleted. |
CreatedAtUtc |
DateTime |
Inherited from BaseModel. |
UpdatedAtUtc |
DateTime |
Inherited from BaseModel. |
3 Editorial
Metadata describing the version and content of the recording. Used by the catalog, search and display surfaces.
| Field | Type | Description |
|---|---|---|
SortTitle |
string? |
Title normalised for sorting (drops "The ", emoji, case, etc.). Used in alphabetical listings. |
VersionQualifier |
string? |
Free-form suffix (e.g. "feat. X", "Live at Wembley"). Shown next to the title. |
VersionType |
TrackVersionType enum |
Version kind: Original, Remix, Live, Acoustic, RadioEdit, Extended, SpedUp, Slowed, Instrumental, Demo, Remaster, Cover, Other. See auxiliary enums. |
IsExplicit |
bool |
Boolean parental-advisory flag. Usually aligned with
ContentAdvisory.
|
ContentAdvisory |
ContentAdvisory enum |
NotRated · Clean · Explicit · Edited. Lets a clean version be distinguished from an edited one (censored words). |
CleanVersionOfTrackId |
Guid? |
Pointer to the matching explicit track when this is a clean
version. Self-reference with OnDelete = SetNull.
|
PrimaryLanguage |
string? |
ISO 639-1/2 code of the lyrics' main language (e.g. "pt", "en"). Useful for filters and recommendation. |
IsInstrumental |
bool |
Editorial declaration. Independent of the
VoiceProbability computed by the enricher.
|
Lyrics |
string? |
Plain-text lyrics. No timed sync (LRC) for now. |
4 Commercial & identifiers
The *Override fields let a specific track diverge from
its parent Album. When null, the value is inherited from
the Album.
| Field | Type | Description |
|---|---|---|
PLineYearOverride |
int? |
Recording year (℗ year). Overrides the Album. |
PLineHolderOverride |
string? |
Holder of the recording rights (℗). Override. |
CLineYearOverride |
int? |
Composition year (© year). Overrides the Album. |
CLineHolderOverride |
string? |
Holder of the composition rights (©). Override. |
AiGeneratedOverride |
bool? |
AI-use declaration. Overrides the Album to flag one specific AI-generated track. |
Isrc |
string? |
International Standard Recording Code (12 chars, format
CC-XXX-YY-NNNNN). A unique, permanent identifier
for a recording.
|
5 DMCA & legal
| Field | Type | Description |
|---|---|---|
TakedownReason |
string? |
Reason for the takedown (DMCA, TOS violation, etc.). Always
present when Status = TakenDown.
|
TakedownAtUtc |
DateTime? |
When the takedown took effect. |
6 State machine (TrackStatus)
A track's lifecycle is driven by the TrackStatus enum.
Valid transitions are exercised by the API and the Worker consumers.
| Value | Int | Meaning |
|---|---|---|
| Queued | 0 |
Upload accepted; a TrackJob is created and a
ProcessTrackMessage published.
|
| Processing | 1 |
ProcessTrackConsumer is doing HLS encoding and
acoustic analysis (librosa).
|
| Failed | 2 |
Unrecoverable failure during processing. The message goes to the DLQ. |
| Ready | 3 |
The track has segments + audio features; it can be played and published. |
| Published | 4 |
Visible in the public catalog. |
| Archived | 5 |
Removed from the catalog but preserved. |
| Deleted | 6 |
Soft delete. Pairs with DeletedAtUtc. |
| TakenDown | 7 |
Removed via DMCA/TOS. TakedownReason and
TakedownAtUtc are populated.
|
| Enriching | 8 |
Acoustic analysis done; waiting on the ML enricher. Non-blocking — the track is already playable (segments exist). |
If EnrichTrackAudioConsumer fails 3 times,
TrackAudioFeatures.EnrichmentStatus is set to
Failed, but the Track's Status
still advances to Ready. The UI shows a
warning icon; the user is never blocked.
7 Auxiliary enums
TrackVersionType
| Value | Int | Typical use |
|---|---|---|
Original | 0 | Default version of the recording. |
Remix | 1 | Remix by another artist; pairs with VersionQualifier. |
Live | 2 | Live recording. |
Acoustic | 3 | Acoustic version. |
RadioEdit | 4 | Radio edit (shorter, no profanity). |
Extended | 5 | 12" mix, extended cut. |
SpedUp | 6 | Sped-up trend (TikTok). |
Slowed | 7 | Slowed + reverb. |
Instrumental | 8 | No vocals. Distinct from the editorial IsInstrumental flag. |
Demo | 9 | Pre-production. |
Remaster | 10 | Technical remaster. |
Cover | 11 | Cover of a third-party work. |
Other | 99 | Escape hatch. |
ContentAdvisory
| Value | Int | Meaning |
|---|---|---|
NotRated | 0 | No rating. Default. |
Clean | 1 | No explicit content. |
Explicit | 2 | Explicit content (language, themes). |
Edited | 3 | Edited version of an Explicit original — used together with CleanVersionOfTrackId. |
8 Navigation properties
EF Core resolves these properties when they are pulled in via
.Include(). By default they are
not loaded (no lazy loading).
| Property | Type | Cardinality | OnDelete |
|---|---|---|---|
Album |
Album |
Many-to-One (required) | Restrict |
CleanVersionOf |
Track? |
Self-reference (optional) | SetNull |
Artists |
ICollection<Artist> |
Many-to-Many · track_artists |
Cascade (on the join table) |
Contributors |
ICollection<TrackContributor> |
One-to-Many (with role) | Cascade |
Genres |
ICollection<Genre> |
Many-to-Many · track_genres |
Cascade (on the join table) |
Moods |
ICollection<Mood> |
Many-to-Many · track_moods |
Cascade (on the join table) |
AudioFeatures |
TrackAudioFeatures? |
One-to-One | Cascade |
Segments |
ICollection<TrackSegment> |
One-to-Many (HLS .ts segments) | Cascade |
Jobs |
ICollection<TrackJob> |
One-to-Many (job audit trail) | Cascade |
For the complete ER model, see Relationships.