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.cs

1 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.
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.

stateDiagram-v2 direction LR [*] --> Queued: upload ok Queued --> Processing: ProcessTrack starts Processing --> Enriching: HLS + librosa OK Processing --> Failed: unrecoverable error Enriching --> Ready: enrichment OK Enriching --> Ready: fail-open (3 retries) Ready --> Published: artist publishes Published --> Archived: archive Ready --> Archived: archive Published --> TakenDown: DMCA / TOS Ready --> TakenDown: DMCA / TOS Ready --> Deleted: soft delete Failed --> [*] TakenDown --> [*] Deleted --> [*]
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).
Fail-open on enrichment

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
Original0Default version of the recording.
Remix1Remix by another artist; pairs with VersionQualifier.
Live2Live recording.
Acoustic3Acoustic version.
RadioEdit4Radio edit (shorter, no profanity).
Extended512" mix, extended cut.
SpedUp6Sped-up trend (TikTok).
Slowed7Slowed + reverb.
Instrumental8No vocals. Distinct from the editorial IsInstrumental flag.
Demo9Pre-production.
Remaster10Technical remaster.
Cover11Cover of a third-party work.
Other99Escape hatch.

ContentAdvisory

Value Int Meaning
NotRated0No rating. Default.
Clean1No explicit content.
Explicit2Explicit content (language, themes).
Edited3Edited version of an Explicit original — used together with CleanVersionOfTrackId.

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.