docs: reconcile DeepDrftAPI CLAUDE.md endpoint surface to Phase 9 (release family, track/page unauth, medium fields)
This commit is contained in:
@@ -13,7 +13,7 @@ DeepDrftHome is a **net10.0** solution consisting of ten projects implementing a
|
|||||||
- **DeepDrftManager**: ASP.NET Core host. Blazor Web App with server-rendered `InteractiveServer` render mode. Hosts all CMS Razor components and pages under `Components/Pages/Cms/`, `Components/Pages/Tracks/`, `Components/Layout/CmsLayout.razor`, and `Components/Shared/` (all inlined from the former `DeepDrftCms` RCL). Gated by AuthBlocks login and hierarchical `Admin` role authorization. All track operations (upload, metadata read/write, delete) are HTTP proxies via `ICmsTrackService` / `CmsTrackService` injected directly into Blazor components; no in-process data layer.
|
- **DeepDrftManager**: ASP.NET Core host. Blazor Web App with server-rendered `InteractiveServer` render mode. Hosts all CMS Razor components and pages under `Components/Pages/Cms/`, `Components/Pages/Tracks/`, `Components/Layout/CmsLayout.razor`, and `Components/Shared/` (all inlined from the former `DeepDrftCms` RCL). Gated by AuthBlocks login and hierarchical `Admin` role authorization. All track operations (upload, metadata read/write, delete) are HTTP proxies via `ICmsTrackService` / `CmsTrackService` injected directly into Blazor components; no in-process data layer.
|
||||||
- **DeepDrftShared.Client**: Razor Class Library. Shared Blazor components consumed by both `DeepDrftPublic` and `DeepDrftManager` for consistency across public and admin surfaces.
|
- **DeepDrftShared.Client**: Razor Class Library. Shared Blazor components consumed by both `DeepDrftPublic` and `DeepDrftManager` for consistency across public and admin surfaces.
|
||||||
- **DeepDrftData**: Class library. EF Core domain logic: `DeepDrftContext`, `TrackConfiguration`, `Migrations`, `TrackRepository`, `TrackService`, `TrackManager`. Consumed by `DeepDrftAPI` and tests.
|
- **DeepDrftData**: Class library. EF Core domain logic: `DeepDrftContext`, `TrackConfiguration`, `Migrations`, `TrackRepository`, `TrackService`, `TrackManager`. Consumed by `DeepDrftAPI` and tests.
|
||||||
- **DeepDrftAPI**: ASP.NET Core host. Dual-database authority (SQL metadata + FileDatabase binary). AuthBlocks API host (owns registration, migration/seed, JWT endpoints). Seven track endpoints: `GET api/track/{id}` unauthenticated streaming; `PUT api/track/{id}` vault write (ApiKey); `POST api/track/upload` upload + SQL persist (ApiKey); `DELETE api/track/{id:long}` SQL delete + vault remove (ApiKey); `GET api/track/page` paged metadata list (unauthenticated); `GET api/track/meta/{id:long}` single metadata (ApiKey); `PUT api/track/meta/{id:long}` metadata update (ApiKey).
|
- **DeepDrftAPI**: ASP.NET Core host. Dual-database authority (SQL metadata + FileDatabase binary). AuthBlocks API host (owns registration, migration/seed, JWT endpoints). Track endpoints: streaming, vault write, upload+persist, delete+cleanup, paged list with filters, single metadata (ApiKey-gated operations), metadata update, waveform profiles, release-track join operations. Release endpoints: paged list with medium filter, single read, mix waveform compute, session hero-image upload (all unauthenticated reads; authenticated writes via ApiKey). Image endpoints: authenticated upload, unauthenticated streaming.
|
||||||
- **DeepDrftContent**: Class library. The FileDatabase implementation in full (Models, Services, Utils, Abstractions, Constants), `AudioProcessor`, content-side `TrackService`. Consumed by hosts and tests.
|
- **DeepDrftContent**: Class library. The FileDatabase implementation in full (Models, Services, Utils, Abstractions, Constants), `AudioProcessor`, content-side `TrackService`. Consumed by hosts and tests.
|
||||||
- **DeepDrftModels**: Shared contracts. `TrackEntity`, `TrackDto`, `PagingParameters<T>`, `PagedResult<T>`. Every project references this.
|
- **DeepDrftModels**: Shared contracts. `TrackEntity`, `TrackDto`, `PagingParameters<T>`, `PagedResult<T>`. Every project references this.
|
||||||
- **DeepDrftTests**: NUnit test suite. Comprehensive FileDatabase tests (vault creation, media storage, indexing, factory patterns, utilities). Integration-focused with temp-directory test isolation.
|
- **DeepDrftTests**: NUnit test suite. Comprehensive FileDatabase tests (vault creation, media storage, indexing, factory patterns, utilities). Integration-focused with temp-directory test isolation.
|
||||||
|
|||||||
+140
-11
@@ -6,13 +6,15 @@ See the root `CLAUDE.md` for full architecture overview. This file covers what i
|
|||||||
|
|
||||||
## One-line purpose
|
## One-line purpose
|
||||||
|
|
||||||
Dual-database authority for tracks (SQL metadata + FileDatabase binary) and images (FileDatabase binary), and AuthBlocks API host (JWT auth, role/admin seed). Seven track endpoints expose CRUD with upload+persist, delete+cleanup, paged listing, and metadata operations. Two image endpoints provide authenticated upload and unauthenticated streaming. ApiKey middleware for track/image endpoints, JWT + AuthBlocks endpoints for auth. CORS, forwarded headers. **FileDatabase implementation lives in `DeepDrftContent`; SQL services in `DeepDrftData`.**
|
Dual-database authority for tracks (SQL metadata + FileDatabase binary), releases (SQL metadata with media-specific satellites), and images (FileDatabase binary); AuthBlocks API host (JWT auth, role/admin seed). Track endpoints expose CRUD with upload+persist, delete+cleanup, paged listing with filters, metadata operations, waveform profiles, and release associations. Release endpoints provide paged listing with medium filter, single-release read, and media-specific operations (mix waveform compute, session hero-image upload). Image endpoints provide authenticated upload and unauthenticated streaming. ApiKey middleware for authenticated endpoints, JWT + AuthBlocks for auth. CORS, forwarded headers. **FileDatabase implementation lives in `DeepDrftContent`; SQL services in `DeepDrftData`.**
|
||||||
|
|
||||||
## What lives here now (only)
|
## What lives here now (only)
|
||||||
|
|
||||||
- `Program.cs`, `Startup.cs`: HTTP host config, DI wiring, middleware setup, port binding. AuthBlocks startup: `AddAuthBlocks`, `UseAuthBlocksStartupAsync`, `MapAuthBlocks`, authentication/authorization middleware.
|
- `Program.cs`, `Startup.cs`: HTTP host config, DI wiring, middleware setup, port binding. AuthBlocks startup: `AddAuthBlocks`, `UseAuthBlocksStartupAsync`, `MapAuthBlocks`, authentication/authorization middleware.
|
||||||
- `Services/UnifiedTrackService.cs`: Host-internal orchestrator. Coordinates vault write + SQL persist for upload (`UploadAsync`), and SQL delete + vault remove for delete (`DeleteAsync`).
|
- `Services/UnifiedTrackService.cs`: Host-internal orchestrator. Coordinates vault write + SQL persist for upload (`UploadAsync`), and SQL delete + vault remove for delete (`DeleteAsync`).
|
||||||
- `Controllers/TrackController.cs`: Seven track endpoints (see below).
|
- `Services/UnifiedReleaseService.cs`: Host-internal orchestrator. Coordinates release mutations (mix waveform compute + store, session hero-image upload + link).
|
||||||
|
- `Controllers/TrackController.cs`: Track endpoints (see below).
|
||||||
|
- `Controllers/ReleaseController.cs`: Release endpoints (see below).
|
||||||
- `Middleware/ApiKeyAuthenticationMiddleware.cs`, `Middleware/ApiKeyAuthorizeAttribute.cs`: ApiKey validation logic (for track endpoints only).
|
- `Middleware/ApiKeyAuthenticationMiddleware.cs`, `Middleware/ApiKeyAuthorizeAttribute.cs`: ApiKey validation logic (for track endpoints only).
|
||||||
- `Models/`: Settings POCOs only (`ApiKeySettings`, `CorsSettings`, `FileDatabaseSettings`). No domain code.
|
- `Models/`: Settings POCOs only (`ApiKeySettings`, `CorsSettings`, `FileDatabaseSettings`). No domain code.
|
||||||
- `environment/filedatabase.json`: FileDatabase vault path config (loaded via CredentialTools, not in repo).
|
- `environment/filedatabase.json`: FileDatabase vault path config (loaded via CredentialTools, not in repo).
|
||||||
@@ -26,7 +28,7 @@ Dual-database authority for tracks (SQL metadata + FileDatabase binary) and imag
|
|||||||
- EF Core context and repository — in `DeepDrftData`.
|
- EF Core context and repository — in `DeepDrftData`.
|
||||||
- **Hosts only own HTTP surface and wiring.** New domain code goes in `*.Services` (shared libraries) or host-internal `Services/` folders (e.g., `UnifiedTrackService` here for dual-database orchestration).
|
- **Hosts only own HTTP surface and wiring.** New domain code goes in `*.Services` (shared libraries) or host-internal `Services/` folders (e.g., `UnifiedTrackService` here for dual-database orchestration).
|
||||||
|
|
||||||
## The endpoint surface (seven endpoints)
|
## The endpoint surface
|
||||||
|
|
||||||
### GET api/track/{trackId} (unauthenticated)
|
### GET api/track/{trackId} (unauthenticated)
|
||||||
|
|
||||||
@@ -37,6 +39,69 @@ Returns the WAV bytes from the `tracks` vault with HTTP Range support.
|
|||||||
- Streams the file directly from disk with `enableRangeProcessing: true`, supporting both full-file and partial-range requests without synthesizing WAV headers or buffering.
|
- Streams the file directly from disk with `enableRangeProcessing: true`, supporting both full-file and partial-range requests without synthesizing WAV headers or buffering.
|
||||||
- Returns 200 for full-file requests, 206 for Range requests, 404 if track not found, 500 if vault operations fail (with error swallowing — the vault returns `null`).
|
- Returns 200 for full-file requests, 206 for Range requests, 404 if track not found, 500 if vault operations fail (with error swallowing — the vault returns `null`).
|
||||||
|
|
||||||
|
### GET api/track/albums (unauthenticated)
|
||||||
|
|
||||||
|
Returns a list of all releases with per-release track counts. Public browse data, same auth posture as `GET api/track/page`.
|
||||||
|
|
||||||
|
- **Response**: `List<ReleaseDto>` where each release carries its title, artist, genre, release date, medium, and track count.
|
||||||
|
- Returns 200 with the release list on success. Returns 500 on query error.
|
||||||
|
|
||||||
|
### GET api/track/genres (unauthenticated)
|
||||||
|
|
||||||
|
Returns distinct non-null genres with per-genre track counts. Public browse data, same auth posture as `GET api/track/page`.
|
||||||
|
|
||||||
|
- **Response**: A collection of genre strings with track counts.
|
||||||
|
- Returns 200 on success. Returns 500 on query error.
|
||||||
|
|
||||||
|
### GET api/track/random (unauthenticated)
|
||||||
|
|
||||||
|
Picks one track at random from the full library and returns its metadata. Public, same auth posture as `GET api/track/page`.
|
||||||
|
|
||||||
|
- **Response**: A single `TrackDto` selected uniformly at random.
|
||||||
|
- Returns 200 on success. Returns 404 if the library is empty (a valid state). Returns 500 on query error.
|
||||||
|
|
||||||
|
### GET api/track/{trackId}/waveform (unauthenticated)
|
||||||
|
|
||||||
|
Returns the stored waveform loudness profile for a track as base64-encoded bytes. Public listener data, same auth posture as `GET api/track/{trackId}`.
|
||||||
|
|
||||||
|
- **Route parameter `trackId`** (string): the entry id (TrackEntity.EntryKey).
|
||||||
|
- **Response**: `WaveformProfileDto` with `BucketCount` (number of loudness buckets) and `Data` (base64-encoded byte array).
|
||||||
|
- Returns 200 on success. Returns 404 if no profile is stored (existing tracks may predate profiling, or computation failed at upload — the frontend falls back to a flat seekbar). Returns 500 on vault error.
|
||||||
|
|
||||||
|
### POST api/track/{trackId}/waveform ([ApiKeyAuthorize])
|
||||||
|
|
||||||
|
Admin backfill: computes and stores a waveform profile for an existing track from its vault audio.
|
||||||
|
|
||||||
|
- **Header `ApiKey`**: required. Validated by `ApiKeyAuthenticationMiddleware`.
|
||||||
|
- **Route parameter `trackId`** (string): the entry id (TrackEntity.EntryKey).
|
||||||
|
- Fetches audio from vault, decodes it, computes a loudness profile, and stores the profile in the `waveform-profiles` vault.
|
||||||
|
- Returns 200 on success. Returns 404 if no audio is stored under that key. Returns 500 if WAV decoding or vault write fails.
|
||||||
|
|
||||||
|
### GET api/track/meta/by-key/{entryKey} (unauthenticated)
|
||||||
|
|
||||||
|
Single track metadata by vault entry key (EntryKey). Unauthenticated, reachable through the public proxy.
|
||||||
|
|
||||||
|
- **Route parameter `entryKey`** (string): the TrackEntity.EntryKey.
|
||||||
|
- **Response**: `TrackDto` for the matching track.
|
||||||
|
- Returns 200 on success. Returns 404 if not found. Returns 500 on query error.
|
||||||
|
|
||||||
|
### GET api/track/waveform-status ([ApiKeyAuthorize])
|
||||||
|
|
||||||
|
Admin backfill view: returns every track with a flag indicating whether a waveform profile is stored. Used by the CMS PreProcessing panel to flag tracks needing waveform computation.
|
||||||
|
|
||||||
|
- **Header `ApiKey`**: required. Validated by `ApiKeyAuthenticationMiddleware`.
|
||||||
|
- **Response**: `List<WaveformStatusDto>` with `TrackId`, `EntryKey`, `TrackName`, and `HasProfile` (bool).
|
||||||
|
- Returns 200 on success. Returns 500 on query error.
|
||||||
|
|
||||||
|
### DELETE api/track/release/{id:long} ([ApiKeyAuthorize])
|
||||||
|
|
||||||
|
Soft-delete a release row. Used by the albums browser to remove an orphaned release (one with no live tracks).
|
||||||
|
|
||||||
|
- **Header `ApiKey`**: required. Validated by `ApiKeyAuthenticationMiddleware`.
|
||||||
|
- **Route parameter `id`** (long): the SQL release ID.
|
||||||
|
- Calls `ITrackService.DeleteRelease`.
|
||||||
|
- Returns 200 on success. Returns 500 on deletion error.
|
||||||
|
|
||||||
### PUT api/track/{trackId} ([ApiKeyAuthorize])
|
### PUT api/track/{trackId} ([ApiKeyAuthorize])
|
||||||
|
|
||||||
**Authenticated endpoint.** Writes pre-processed audio bytes to the `tracks` vault.
|
**Authenticated endpoint.** Writes pre-processed audio bytes to the `tracks` vault.
|
||||||
@@ -61,10 +126,13 @@ Returns the WAV bytes from the `tracks` vault with HTTP Range support.
|
|||||||
- `genre` (string, optional)
|
- `genre` (string, optional)
|
||||||
- `releaseDate` (string, optional, format `YYYY-MM-DD`)
|
- `releaseDate` (string, optional, format `YYYY-MM-DD`)
|
||||||
- `createdByUserId` (long, required): audit trail — who uploaded this track.
|
- `createdByUserId` (long, required): audit trail — who uploaded this track.
|
||||||
|
- `releaseType` (string, optional): enum `ReleaseType` (e.g., `Single`, `Album`, `EP`). Defaults to `Single` if null or unrecognized.
|
||||||
|
- `medium` (string, optional): enum `ReleaseMedium` (e.g., `Cut`, `Mix`, `Session`). Defaults to `Cut` if null or unrecognized.
|
||||||
|
- `trackNumber` (int?, optional): track position within the release (1-based). Defaults to 1 if ≤ 0 or null.
|
||||||
- The upload stream is copied to a temp file under `Path.GetTempPath()` with the appropriate extension (`.wav`, `.mp3`, or `.flac`). The audio processor reads from disk and requires the correct extension for format detection. The temp file is always deleted in a `finally` block — success or failure.
|
- The upload stream is copied to a temp file under `Path.GetTempPath()` with the appropriate extension (`.wav`, `.mp3`, or `.flac`). The audio processor reads from disk and requires the correct extension for format detection. The temp file is always deleted in a `finally` block — success or failure.
|
||||||
- `[RequestSizeLimit(1 GB)]` + `[RequestFormLimits(MultipartBodyLengthLimit = 1 GB)]` lift the per-request ceiling above the framework default (~28 MB) so production-sized files are accepted. The body is streamed to the temp file, not buffered in memory.
|
- `[RequestSizeLimit(1 GB)]` + `[RequestFormLimits(MultipartBodyLengthLimit = 1 GB)]` lift the per-request ceiling above the framework default (~28 MB) so production-sized files are accepted. The body is streamed to the temp file, not buffered in memory.
|
||||||
- Calls `UnifiedTrackService.UploadAsync`, which orchestrates: `TrackContentService.AddTrackAsync` (format-agnostic vault write via router) → `TrackManager` (SQL persist with `createdByUserId`).
|
- Calls `UnifiedTrackService.UploadAsync`, which orchestrates: `TrackContentService.AddTrackAsync` (format-agnostic vault write via router) → `TrackManager` (SQL persist with `createdByUserId`).
|
||||||
- Returns 200 with the **persisted** `TrackDto` JSON (Id populated) on success. Returns 400 for missing/invalid form fields or unsupported audio format. Returns 500 if processing fails.
|
- Returns 200 with the **persisted** `TrackDto` JSON (Id populated) on success. Returns 400 for missing/invalid form fields or unsupported audio format. Returns 409 if the request violates domain cardinality rules (e.g., track number conflict). Returns 500 if processing fails.
|
||||||
|
|
||||||
### DELETE api/track/{id:long} ([ApiKeyAuthorize])
|
### DELETE api/track/{id:long} ([ApiKeyAuthorize])
|
||||||
|
|
||||||
@@ -75,17 +143,20 @@ Returns the WAV bytes from the `tracks` vault with HTTP Range support.
|
|||||||
- Calls `UnifiedTrackService.DeleteAsync`, which: looks up SQL row → deletes SQL row → deletes vault entry via EntryKey.
|
- Calls `UnifiedTrackService.DeleteAsync`, which: looks up SQL row → deletes SQL row → deletes vault entry via EntryKey.
|
||||||
- Returns 200 on success, 404 if track not found, 500 if deletion fails.
|
- Returns 200 on success, 404 if track not found, 500 if deletion fails.
|
||||||
|
|
||||||
### GET api/track/page ([ApiKeyAuthorize])
|
### GET api/track/page (unauthenticated)
|
||||||
|
|
||||||
**Authenticated endpoint.** Paged metadata list from SQL. Used by CMS track browser.
|
Paged metadata list from SQL with optional filtering. Public browser data, same auth posture as `GET api/track/{id}`.
|
||||||
|
|
||||||
- **Header `ApiKey`**: required. Validated by `ApiKeyAuthenticationMiddleware`.
|
|
||||||
- **Query parameters**:
|
- **Query parameters**:
|
||||||
- `page` (int, optional, default 1): 1-based page number.
|
- `page` (int, optional, default 1): 1-based page number.
|
||||||
- `pageSize` (int, optional, default 20): tracks per page.
|
- `pageSize` (int, optional, default 20): tracks per page.
|
||||||
- `sortColumn` (string, optional): sort field. Supported: `"TrackName"`, `"Artist"`, `"Album"`, `"Genre"`, `"ReleaseDate"`. Defaults to `Id`.
|
- `sortColumn` (string, optional): sort field. Supported: `"TrackName"`, `"Artist"`, `"Album"`, `"Genre"`, `"ReleaseDate"`. Defaults to `Id`.
|
||||||
- `sortDescending` (bool, optional, default false): sort direction.
|
- `sortDescending` (bool, optional, default false): sort direction.
|
||||||
- Calls `ITrackService.GetPaged` (via DI), which is actually `TrackManager` from `DeepDrftData`.
|
- `q` (string, optional): search text filter (matches track name / artist).
|
||||||
|
- `album` (string, optional): album title filter.
|
||||||
|
- `genre` (string, optional): genre filter.
|
||||||
|
- `releaseId` (long?, optional): release ID filter (authoritative join; preferred over album title).
|
||||||
|
- Calls `ITrackService.GetPaged` with optional `TrackFilter` (null if all filter params are empty).
|
||||||
- Returns 200 with `PagedResult<TrackDto>` JSON (`Items`, `TotalCount`, `PageNumber`, `PageSize`). Returns 500 on query error.
|
- Returns 200 with `PagedResult<TrackDto>` JSON (`Items`, `TotalCount`, `PageNumber`, `PageSize`). Returns 500 on query error.
|
||||||
|
|
||||||
### GET api/track/meta/{id:long} ([ApiKeyAuthorize])
|
### GET api/track/meta/{id:long} ([ApiKeyAuthorize])
|
||||||
@@ -103,9 +174,18 @@ Returns the WAV bytes from the `tracks` vault with HTTP Range support.
|
|||||||
|
|
||||||
- **Header `ApiKey`**: required. Validated by `ApiKeyAuthenticationMiddleware`.
|
- **Header `ApiKey`**: required. Validated by `ApiKeyAuthenticationMiddleware`.
|
||||||
- **Route parameter `id`** (long): the SQL track ID.
|
- **Route parameter `id`** (long): the SQL track ID.
|
||||||
- **Body**: `UpdateTrackMetadataRequest` with fields: `TrackName`, `Artist`, `Album?`, `Genre?`, `ReleaseDate?`, `ImagePath?` (tri-state: null = no change, "" = clear, value = set).
|
- **Body**: `UpdateTrackMetadataRequest` with fields:
|
||||||
- Looks up SQL row by ID (returns `TrackDto`), updates the provided fields (nulls in the request for optional metadata clear those fields; `ImagePath` follows tri-state logic), and persists the DTO via `ITrackService.Update`.
|
- `TrackName` (string, required)
|
||||||
- Returns 200 with the updated `TrackDto` on success. Returns 404 if track not found. Returns 500 on update error.
|
- `Artist` (string, required)
|
||||||
|
- `Album` (string?, optional)
|
||||||
|
- `Genre` (string?, optional)
|
||||||
|
- `ReleaseDate` (DateOnly?, optional)
|
||||||
|
- `ImagePath` (string?, tri-state: null = no change, "" = clear, value = set)
|
||||||
|
- `ReleaseType` (ReleaseType?, optional): updates the linked release if present; null = no change.
|
||||||
|
- `Medium` (ReleaseMedium?, optional): updates the linked release if present; null = no change. When `Medium` is set to non-`Cut`, also resets `ReleaseType` to `Single` (the DB default) to avoid stale studio-format values.
|
||||||
|
- `TrackNumber` (int?, optional): track position within the release; validated > 0 when provided.
|
||||||
|
- Looks up SQL row by ID, updates the provided fields, and persists via `ITrackService.Update`. Track-cardinal fields (`TrackName`, `TrackNumber`) update the track row; release-cardinal fields (`Artist`, `Album`, `Genre`, `ReleaseDate`, `ImagePath`, `ReleaseType`, `Medium`) update the linked release (if present; loose tracks ignore these).
|
||||||
|
- Returns 200 on success. Returns 400 if `TrackNumber` ≤ 0 (when provided). Returns 404 if track not found. Returns 500 on update error.
|
||||||
|
|
||||||
## The image endpoints (two endpoints)
|
## The image endpoints (two endpoints)
|
||||||
|
|
||||||
@@ -126,6 +206,55 @@ Returns image bytes from the `images` vault.
|
|||||||
- Streams the image file directly from disk without buffering.
|
- Streams the image file directly from disk without buffering.
|
||||||
- Returns 404 if image not found. Returns 500 if vault operations fail (with error swallowing — the vault returns `null`).
|
- Returns 404 if image not found. Returns 500 if vault operations fail (with error swallowing — the vault returns `null`).
|
||||||
|
|
||||||
|
## The release endpoints
|
||||||
|
|
||||||
|
### GET api/release (unauthenticated)
|
||||||
|
|
||||||
|
Paged release list, optionally filtered to one medium. Public browse data, same auth posture as `GET api/track/page`.
|
||||||
|
|
||||||
|
- **Query parameters**:
|
||||||
|
- `medium` (string, optional): enum `ReleaseMedium` (e.g., `Cut`, `Mix`, `Session`). If provided, only releases of that medium are returned; the matching medium's metadata satellite is populated, others are null.
|
||||||
|
- `page` (int, optional, default 1): 1-based page number.
|
||||||
|
- `pageSize` (int, optional, default 20): releases per page.
|
||||||
|
- `sortColumn` (string, optional): sort field (typically `"Title"`).
|
||||||
|
- `sortDescending` (bool, optional, default false): sort direction.
|
||||||
|
- Returns 200 with `PagedResult<ReleaseDto>` on success. Returns 400 if `medium` is unrecognized. Returns 500 on query error.
|
||||||
|
|
||||||
|
### GET api/release/{id:long} (unauthenticated)
|
||||||
|
|
||||||
|
Single release with both metadata navs (nulls for non-matching media). Public, same auth posture as `GET api/release`.
|
||||||
|
|
||||||
|
- **Route parameter `id`** (long): the SQL release ID.
|
||||||
|
- **Response**: `ReleaseDto` with `Id`, `Title`, `Artist`, `Genre`, `ReleaseDate`, `Medium`, `ImagePath`, and media-specific metadata satellites (`MixMetadata` for Cut/Mix, `SessionMetadata` for Session; others null).
|
||||||
|
- Returns 200 on success. Returns 404 if not found. Returns 500 on query error.
|
||||||
|
|
||||||
|
### GET api/release/{id:long}/mix/waveform (unauthenticated)
|
||||||
|
|
||||||
|
Serves the high-res waveform datum for a Mix release as base64-encoded bytes. Mirrors `GET api/track/{id}/waveform` but reads from the `mix-waveforms` vault.
|
||||||
|
|
||||||
|
- **Route parameter `id`** (long): the SQL release ID.
|
||||||
|
- **Response**: `WaveformProfileDto` with `BucketCount` and `Data` (base64).
|
||||||
|
- Returns 200 on success. Returns 404 if the release is not a Mix, carries no waveform key, or no datum is stored. Returns 500 on query/vault error.
|
||||||
|
|
||||||
|
### POST api/release/{id:long}/mix/waveform ([ApiKeyAuthorize])
|
||||||
|
|
||||||
|
Server-side trigger: fetch the Mix's track audio from the vault, compute a 2048-bucket waveform, store it in the `mix-waveforms` vault, and link it via `MixMetadata.WaveformEntryKey`. No request body.
|
||||||
|
|
||||||
|
- **Header `ApiKey`**: required. Validated by `ApiKeyAuthenticationMiddleware`.
|
||||||
|
- **Route parameter `id`** (long): the SQL release ID.
|
||||||
|
- Calls `UnifiedReleaseService.TriggerMixWaveformAsync`.
|
||||||
|
- Returns 200 on success. Returns 404 if the release is missing, is not a Mix, has no track, or the track audio is not stored. Returns 500 on compute/storage failure.
|
||||||
|
|
||||||
|
### POST api/release/{id:long}/session/hero-image ([ApiKeyAuthorize])
|
||||||
|
|
||||||
|
Stores a hero image in the `images` vault and links it via `SessionMetadata.HeroImageEntryKey`. The release must be a Session medium (enforced in the service).
|
||||||
|
|
||||||
|
- **Header `ApiKey`**: required. Validated by `ApiKeyAuthenticationMiddleware`.
|
||||||
|
- **Route parameter `id`** (long): the SQL release ID.
|
||||||
|
- **Form field `image`** (`IFormFile`, required): the image bytes (PNG, JPEG, or other format supported by `ImageProcessor`). Maximum file size 50 MB.
|
||||||
|
- Validates MIME type (rejects unsupported types with `.bin` sentinel). Calls `UnifiedReleaseService.SetHeroImageAsync`.
|
||||||
|
- Returns 200 on success. Returns 400 for missing file or unsupported MIME type. Returns 404 if release not found. Returns 500 on processing or vault failure.
|
||||||
|
|
||||||
## ApiKey middleware behaviour
|
## ApiKey middleware behaviour
|
||||||
|
|
||||||
`ApiKeyAuthenticationMiddleware` runs on every request but only enforces on endpoints with `[ApiKeyAuthorize]` metadata.
|
`ApiKeyAuthenticationMiddleware` runs on every request but only enforces on endpoints with `[ApiKeyAuthorize]` metadata.
|
||||||
|
|||||||
Reference in New Issue
Block a user