Add TotalPlays + UniqueListeners to HomeStatsDto, composed at
StatsController from IEventService (no migration). Card reads via
existing persistent-state-bridged round-trip.
Per-track high-res datum keyed by EntryKey in the renamed track-waveforms vault; computed at upload for all tracks, regenerable per-track via CMS, with a re-runnable backfill. Mix read path repointed so it keeps working.
New nullable Description column (max 4000) on ReleaseEntity, rides the Genre write channel through upload + edit; multiline CMS input. Migration authored, not applied.
Retire the three-card overview for a search + medium + genre browser over all
releases. Adds q/genre filter params to the api/release paged read path,
mirroring the existing api/track/page TrackFilter pattern.
Promote the Session/Mix single-track rule from a CMS-form convention to a
domain invariant: declare cardinality as data in MediumRules, enforce it in
UnifiedTrackService before the vault write (no orphan), return 409, and read
the same rule in the batch-form collapse.
Add ReleaseMedium enum (Cut/Session/Mix) and two 1:1 satellite entities
(SessionMetadata, MixMetadata) with EF configs and an additive migration.
ReleaseDto.ReleaseType is now nullable, nulled for non-Cut at the converter.
Existing releases default to Cut via column default; no data migration.
GET api/track/waveform-status and POST api/track/{id}/waveform (ApiKey);
CmsTrackService methods; TrackPreProcessing page with per-row and
sequential bulk generation; nav links from TrackList and Index.
ILoudnessAlgorithm strategy (RmsLoudnessAlgorithm first impl), WaveformProfileService
stores quantized byte[] sidecar in new MediaFileVault (profiles vault), wired into
UnifiedTrackService.UploadAsync; failure is logged and swallowed. WaveformProfileDto
and WaveformProfileOptions in shared projects.