feat(openapi): annotate track CRUD handlers + regen spec (v1.0.8 B-annot)
Some checks failed
Veza CI / Backend (Go) (push) Failing after 0s
Veza CI / Frontend (Web) (push) Failing after 0s
Veza CI / Rust (Stream Server) (push) Failing after 0s
Frontend CI / test (push) Failing after 0s
Security Scan / Secret Scanning (gitleaks) (push) Failing after 0s
Veza CI / Notify on failure (push) Failing after 0s
Some checks failed
Veza CI / Backend (Go) (push) Failing after 0s
Veza CI / Frontend (Web) (push) Failing after 0s
Veza CI / Rust (Stream Server) (push) Failing after 0s
Frontend CI / test (push) Failing after 0s
Security Scan / Secret Scanning (gitleaks) (push) Failing after 0s
Veza CI / Notify on failure (push) Failing after 0s
First batch of the backend OpenAPI annotation campaign. Adds full
swaggo annotations to the 8 handlers in internal/core/track/track_crud_handler.go
so the resulting openapi.yaml exposes the track CRUD surface to
orval-generated frontend clients.
Handlers annotated (all under @Tags Track):
- ListTracks — GET /tracks
- GetTrack — GET /tracks/{id}
- UpdateTrack — PUT /tracks/{id} (Auth, ownership)
- GetLyrics — GET /tracks/{id}/lyrics
- UpdateLyrics — PUT /tracks/{id}/lyrics (Auth, ownership)
- DeleteTrack — DELETE /tracks/{id} (Auth, ownership)
- BatchDeleteTracks — POST /tracks/batch/delete (Auth)
- BatchUpdateTracks — POST /tracks/batch/update (Auth)
Each block follows the established pattern (auth.go + marketplace.go):
Summary / Description / Tags / Accept / Produce / Security when auth-required /
Param (path/query/body) with concrete types / Success envelope typed via
response.APIResponse{data=...} / Failure 400/401/403/404/500 / Router.
make openapi: ✅ valid (Swagger 2.0)
go build ./...: ✅
openapi.yaml: +490 LOC, 8 new paths exposed under /tracks.
Part of the Option B campaign tracked in
/home/senke/.claude/plans/audit-fonctionnel-wild-hickey.md.
~364 handlers total remain unannotated across 16 files in /internal/core/
and ~55 files in /internal/handlers/. Subsequent commits will annotate
one handler file at a time so each regenerated spec stays bisectable.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7fd43ab609
commit
2aa2e6cd51
5 changed files with 2692 additions and 34 deletions
|
|
@ -2349,6 +2349,106 @@ const docTemplate = `{
|
|||
}
|
||||
},
|
||||
"/tracks": {
|
||||
"get": {
|
||||
"description": "List tracks with pagination, filters, sort. Cursor-based when ?cursor provided, otherwise page/limit offset.",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "List tracks",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Opaque pagination cursor (overrides page)",
|
||||
"name": "cursor",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"default": 1,
|
||||
"description": "Page number, 1-based (ignored if cursor set)",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"default": 20,
|
||||
"description": "Items per page (max 100)",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by creator UUID",
|
||||
"name": "user_id",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by genre",
|
||||
"name": "genre",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by audio format (mp3, flac, wav, ogg, m4a, aac)",
|
||||
"name": "format",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "created_at",
|
||||
"description": "Sort column (created_at, play_count, title)",
|
||||
"name": "sort_by",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pagination": {
|
||||
"type": "object"
|
||||
},
|
||||
"tracks": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid query params",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
|
|
@ -2426,6 +2526,172 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/tracks/batch/delete": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Soft-delete up to N tracks in one request. Per-track ownership checked (admin can delete others).",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "Batch delete tracks",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "List of track UUIDs",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_core_track.BatchDeleteRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"deleted": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"failed": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Validation / batch size exceeded",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tracks/batch/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Apply a partial metadata update to up to N tracks in one request. Per-track ownership checked.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "Batch update tracks",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Track UUIDs + shared updates map",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_core_track.BatchUpdateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"failed": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"updated": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Validation / batch size exceeded",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tracks/chunk": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
|
@ -2812,6 +3078,240 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/tracks/{id}": {
|
||||
"get": {
|
||||
"description": "Retrieve a single track. Private play_count / like_count are omitted for non-owners (v0.10.3 F202).",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "Get track by ID",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Track UUID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"track": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid track id",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Track not found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Update the metadata of an existing track. Caller must own the track or be admin.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "Update track metadata",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Track UUID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Updated metadata",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_core_track.UpdateTrackRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"track": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Validation / invalid id",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Not owner / no admin",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Track not found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Soft-delete a track (sets deleted_at). Caller must own the track or be admin.",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "Delete track",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Track UUID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid track id",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Not owner / no admin",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Track not found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tracks/{id}/comments": {
|
||||
"get": {
|
||||
"description": "Get paginated list of comments for a track",
|
||||
|
|
@ -3066,6 +3566,161 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/tracks/{id}/lyrics": {
|
||||
"get": {
|
||||
"description": "Returns the current lyrics for a track, or null if no lyrics exist.",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "Get track lyrics",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Track UUID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "lyrics may be null",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"lyrics": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid track id",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Track not found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Replace the lyrics of a track. Caller must own the track or be admin.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "Create or update track lyrics",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Track UUID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Lyrics payload",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_core_track.UpdateLyricsRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"lyrics": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Validation / invalid id",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Not owner / no admin",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Track not found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tracks/{id}/status": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
|
@ -4108,6 +4763,41 @@ const docTemplate = `{
|
|||
}
|
||||
},
|
||||
"definitions": {
|
||||
"internal_core_track.BatchDeleteRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"track_ids"
|
||||
],
|
||||
"properties": {
|
||||
"track_ids": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_core_track.BatchUpdateRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"track_ids",
|
||||
"updates"
|
||||
],
|
||||
"properties": {
|
||||
"track_ids": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"updates": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_core_track.CompleteChunkedUploadRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
@ -4140,6 +4830,68 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"internal_core_track.UpdateLyricsRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_core_track.UpdateTrackRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"album": {
|
||||
"type": "string",
|
||||
"maxLength": 255
|
||||
},
|
||||
"artist": {
|
||||
"type": "string",
|
||||
"maxLength": 255
|
||||
},
|
||||
"bpm": {
|
||||
"type": "integer",
|
||||
"maximum": 300,
|
||||
"minimum": 0
|
||||
},
|
||||
"genre": {
|
||||
"description": "legacy, single",
|
||||
"type": "string",
|
||||
"maxLength": 100
|
||||
},
|
||||
"genres": {
|
||||
"description": "v0.10.1: max 3, taxonomy slugs",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"is_public": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"musical_key": {
|
||||
"type": "string",
|
||||
"maxLength": 10
|
||||
},
|
||||
"tags": {
|
||||
"description": "v0.10.1: max 10, 30 chars each",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"maxLength": 255,
|
||||
"minLength": 1
|
||||
},
|
||||
"year": {
|
||||
"type": "integer",
|
||||
"maximum": 2100,
|
||||
"minimum": 1900
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_handlers.APIResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -4162,8 +4914,11 @@ const docTemplate = `{
|
|||
"minLength": 1
|
||||
},
|
||||
"parent_id": {
|
||||
"description": "Changed to *uuid.UUID",
|
||||
"type": "string"
|
||||
},
|
||||
"timestamp": {
|
||||
"description": "Position in seconds (0 = top-level, no specific time)",
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -4364,6 +5119,10 @@ const docTemplate = `{
|
|||
"confirm_text": {
|
||||
"type": "string"
|
||||
},
|
||||
"keep_public_tracks": {
|
||||
"description": "If true, public tracks remain (attributed to deleted account)",
|
||||
"type": "boolean"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
@ -4777,6 +5536,10 @@ const docTemplate = `{
|
|||
"promo_code_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"refund_deadline": {
|
||||
"description": "v0.12.0: 14-day refund deadline",
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"description": "pending, completed, failed, refunded",
|
||||
"type": "string"
|
||||
|
|
@ -5120,6 +5883,14 @@ const docTemplate = `{
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_default_favorites": {
|
||||
"description": "v0.10.4 F136",
|
||||
"type": "boolean"
|
||||
},
|
||||
"is_editorial": {
|
||||
"description": "v0.10.4 F141",
|
||||
"type": "boolean"
|
||||
},
|
||||
"is_public": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -5261,15 +6032,9 @@ const docTemplate = `{
|
|||
"is_public": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"like_count": {
|
||||
"type": "integer"
|
||||
},
|
||||
"musical_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"play_count": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sample_rate": {
|
||||
"description": "Hz",
|
||||
"type": "integer"
|
||||
|
|
@ -5386,6 +6151,14 @@ const docTemplate = `{
|
|||
"description": "Virtual field for input",
|
||||
"type": "string"
|
||||
},
|
||||
"password_changed_at": {
|
||||
"description": "F016: Password expiration tracking",
|
||||
"type": "string"
|
||||
},
|
||||
"promoted_to_creator_at": {
|
||||
"description": "v1.0.6: set the first time a user self-promotes to ` + "`" + `role='creator'` + "`" + `\nvia POST /api/v1/users/me/upgrade-creator. NULL for users who never\ntook that path (still 'user', or promoted by an admin out-of-band).",
|
||||
"type": "string"
|
||||
},
|
||||
"role": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
@ -5421,6 +6194,12 @@ const docTemplate = `{
|
|||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"ApiKeyAuth": {
|
||||
"description": "Developer API key (obtain from Developer Portal). Format: vza_xxxxx",
|
||||
"type": "apiKey",
|
||||
"name": "X-API-Key",
|
||||
"in": "header"
|
||||
},
|
||||
"BearerAuth": {
|
||||
"type": "apiKey",
|
||||
"name": "Authorization",
|
||||
|
|
@ -5432,7 +6211,7 @@ const docTemplate = `{
|
|||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfo = &swag.Spec{
|
||||
Version: "1.2.0",
|
||||
Host: "localhost:8080",
|
||||
Host: "localhost:18080",
|
||||
BasePath: "/api/v1",
|
||||
Schemes: []string{},
|
||||
Title: "Veza Backend API",
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
},
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"host": "localhost:8080",
|
||||
"host": "localhost:18080",
|
||||
"basePath": "/api/v1",
|
||||
"paths": {
|
||||
"/api/v1/dashboard": {
|
||||
|
|
@ -2343,6 +2343,106 @@
|
|||
}
|
||||
},
|
||||
"/tracks": {
|
||||
"get": {
|
||||
"description": "List tracks with pagination, filters, sort. Cursor-based when ?cursor provided, otherwise page/limit offset.",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "List tracks",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Opaque pagination cursor (overrides page)",
|
||||
"name": "cursor",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"default": 1,
|
||||
"description": "Page number, 1-based (ignored if cursor set)",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"default": 20,
|
||||
"description": "Items per page (max 100)",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by creator UUID",
|
||||
"name": "user_id",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by genre",
|
||||
"name": "genre",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by audio format (mp3, flac, wav, ogg, m4a, aac)",
|
||||
"name": "format",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "created_at",
|
||||
"description": "Sort column (created_at, play_count, title)",
|
||||
"name": "sort_by",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pagination": {
|
||||
"type": "object"
|
||||
},
|
||||
"tracks": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid query params",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
|
|
@ -2420,6 +2520,172 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/tracks/batch/delete": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Soft-delete up to N tracks in one request. Per-track ownership checked (admin can delete others).",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "Batch delete tracks",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "List of track UUIDs",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_core_track.BatchDeleteRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"deleted": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"failed": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Validation / batch size exceeded",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tracks/batch/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Apply a partial metadata update to up to N tracks in one request. Per-track ownership checked.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "Batch update tracks",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Track UUIDs + shared updates map",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_core_track.BatchUpdateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"failed": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"updated": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Validation / batch size exceeded",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tracks/chunk": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
|
@ -2806,6 +3072,240 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/tracks/{id}": {
|
||||
"get": {
|
||||
"description": "Retrieve a single track. Private play_count / like_count are omitted for non-owners (v0.10.3 F202).",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "Get track by ID",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Track UUID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"track": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid track id",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Track not found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Update the metadata of an existing track. Caller must own the track or be admin.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "Update track metadata",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Track UUID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Updated metadata",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_core_track.UpdateTrackRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"track": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_models.Track"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Validation / invalid id",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Not owner / no admin",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Track not found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Soft-delete a track (sets deleted_at). Caller must own the track or be admin.",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "Delete track",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Track UUID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid track id",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Not owner / no admin",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Track not found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tracks/{id}/comments": {
|
||||
"get": {
|
||||
"description": "Get paginated list of comments for a track",
|
||||
|
|
@ -3060,6 +3560,161 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/tracks/{id}/lyrics": {
|
||||
"get": {
|
||||
"description": "Returns the current lyrics for a track, or null if no lyrics exist.",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "Get track lyrics",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Track UUID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "lyrics may be null",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"lyrics": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid track id",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Track not found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Replace the lyrics of a track. Caller must own the track or be admin.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Track"
|
||||
],
|
||||
"summary": "Create or update track lyrics",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Track UUID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Lyrics payload",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/internal_core_track.UpdateLyricsRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"lyrics": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Validation / invalid id",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Not owner / no admin",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Track not found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/veza-backend-api_internal_response.APIResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tracks/{id}/status": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
|
@ -4102,6 +4757,41 @@
|
|||
}
|
||||
},
|
||||
"definitions": {
|
||||
"internal_core_track.BatchDeleteRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"track_ids"
|
||||
],
|
||||
"properties": {
|
||||
"track_ids": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_core_track.BatchUpdateRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"track_ids",
|
||||
"updates"
|
||||
],
|
||||
"properties": {
|
||||
"track_ids": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"updates": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_core_track.CompleteChunkedUploadRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
@ -4134,6 +4824,68 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"internal_core_track.UpdateLyricsRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_core_track.UpdateTrackRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"album": {
|
||||
"type": "string",
|
||||
"maxLength": 255
|
||||
},
|
||||
"artist": {
|
||||
"type": "string",
|
||||
"maxLength": 255
|
||||
},
|
||||
"bpm": {
|
||||
"type": "integer",
|
||||
"maximum": 300,
|
||||
"minimum": 0
|
||||
},
|
||||
"genre": {
|
||||
"description": "legacy, single",
|
||||
"type": "string",
|
||||
"maxLength": 100
|
||||
},
|
||||
"genres": {
|
||||
"description": "v0.10.1: max 3, taxonomy slugs",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"is_public": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"musical_key": {
|
||||
"type": "string",
|
||||
"maxLength": 10
|
||||
},
|
||||
"tags": {
|
||||
"description": "v0.10.1: max 10, 30 chars each",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"maxLength": 255,
|
||||
"minLength": 1
|
||||
},
|
||||
"year": {
|
||||
"type": "integer",
|
||||
"maximum": 2100,
|
||||
"minimum": 1900
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal_handlers.APIResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -4156,8 +4908,11 @@
|
|||
"minLength": 1
|
||||
},
|
||||
"parent_id": {
|
||||
"description": "Changed to *uuid.UUID",
|
||||
"type": "string"
|
||||
},
|
||||
"timestamp": {
|
||||
"description": "Position in seconds (0 = top-level, no specific time)",
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -4358,6 +5113,10 @@
|
|||
"confirm_text": {
|
||||
"type": "string"
|
||||
},
|
||||
"keep_public_tracks": {
|
||||
"description": "If true, public tracks remain (attributed to deleted account)",
|
||||
"type": "boolean"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
@ -4771,6 +5530,10 @@
|
|||
"promo_code_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"refund_deadline": {
|
||||
"description": "v0.12.0: 14-day refund deadline",
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"description": "pending, completed, failed, refunded",
|
||||
"type": "string"
|
||||
|
|
@ -5114,6 +5877,14 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_default_favorites": {
|
||||
"description": "v0.10.4 F136",
|
||||
"type": "boolean"
|
||||
},
|
||||
"is_editorial": {
|
||||
"description": "v0.10.4 F141",
|
||||
"type": "boolean"
|
||||
},
|
||||
"is_public": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -5255,15 +6026,9 @@
|
|||
"is_public": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"like_count": {
|
||||
"type": "integer"
|
||||
},
|
||||
"musical_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"play_count": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sample_rate": {
|
||||
"description": "Hz",
|
||||
"type": "integer"
|
||||
|
|
@ -5380,6 +6145,14 @@
|
|||
"description": "Virtual field for input",
|
||||
"type": "string"
|
||||
},
|
||||
"password_changed_at": {
|
||||
"description": "F016: Password expiration tracking",
|
||||
"type": "string"
|
||||
},
|
||||
"promoted_to_creator_at": {
|
||||
"description": "v1.0.6: set the first time a user self-promotes to `role='creator'`\nvia POST /api/v1/users/me/upgrade-creator. NULL for users who never\ntook that path (still 'user', or promoted by an admin out-of-band).",
|
||||
"type": "string"
|
||||
},
|
||||
"role": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
@ -5415,6 +6188,12 @@
|
|||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"ApiKeyAuth": {
|
||||
"description": "Developer API key (obtain from Developer Portal). Format: vza_xxxxx",
|
||||
"type": "apiKey",
|
||||
"name": "X-API-Key",
|
||||
"in": "header"
|
||||
},
|
||||
"BearerAuth": {
|
||||
"type": "apiKey",
|
||||
"name": "Authorization",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,29 @@
|
|||
basePath: /api/v1
|
||||
definitions:
|
||||
internal_core_track.BatchDeleteRequest:
|
||||
properties:
|
||||
track_ids:
|
||||
items:
|
||||
type: string
|
||||
minItems: 1
|
||||
type: array
|
||||
required:
|
||||
- track_ids
|
||||
type: object
|
||||
internal_core_track.BatchUpdateRequest:
|
||||
properties:
|
||||
track_ids:
|
||||
items:
|
||||
type: string
|
||||
minItems: 1
|
||||
type: array
|
||||
updates:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
required:
|
||||
- track_ids
|
||||
- updates
|
||||
type: object
|
||||
internal_core_track.CompleteChunkedUploadRequest:
|
||||
properties:
|
||||
upload_id:
|
||||
|
|
@ -22,6 +46,51 @@ definitions:
|
|||
- total_chunks
|
||||
- total_size
|
||||
type: object
|
||||
internal_core_track.UpdateLyricsRequest:
|
||||
properties:
|
||||
content:
|
||||
type: string
|
||||
type: object
|
||||
internal_core_track.UpdateTrackRequest:
|
||||
properties:
|
||||
album:
|
||||
maxLength: 255
|
||||
type: string
|
||||
artist:
|
||||
maxLength: 255
|
||||
type: string
|
||||
bpm:
|
||||
maximum: 300
|
||||
minimum: 0
|
||||
type: integer
|
||||
genre:
|
||||
description: legacy, single
|
||||
maxLength: 100
|
||||
type: string
|
||||
genres:
|
||||
description: 'v0.10.1: max 3, taxonomy slugs'
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
is_public:
|
||||
type: boolean
|
||||
musical_key:
|
||||
maxLength: 10
|
||||
type: string
|
||||
tags:
|
||||
description: 'v0.10.1: max 10, 30 chars each'
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
title:
|
||||
maxLength: 255
|
||||
minLength: 1
|
||||
type: string
|
||||
year:
|
||||
maximum: 2100
|
||||
minimum: 1900
|
||||
type: integer
|
||||
type: object
|
||||
internal_handlers.APIResponse:
|
||||
properties:
|
||||
data: {}
|
||||
|
|
@ -36,8 +105,10 @@ definitions:
|
|||
minLength: 1
|
||||
type: string
|
||||
parent_id:
|
||||
description: Changed to *uuid.UUID
|
||||
type: string
|
||||
timestamp:
|
||||
description: Position in seconds (0 = top-level, no specific time)
|
||||
type: number
|
||||
required:
|
||||
- content
|
||||
type: object
|
||||
|
|
@ -178,6 +249,9 @@ definitions:
|
|||
properties:
|
||||
confirm_text:
|
||||
type: string
|
||||
keep_public_tracks:
|
||||
description: If true, public tracks remain (attributed to deleted account)
|
||||
type: boolean
|
||||
password:
|
||||
type: string
|
||||
reason:
|
||||
|
|
@ -468,6 +542,9 @@ definitions:
|
|||
type: string
|
||||
promo_code_id:
|
||||
type: string
|
||||
refund_deadline:
|
||||
description: 'v0.12.0: 14-day refund deadline'
|
||||
type: string
|
||||
status:
|
||||
description: pending, completed, failed, refunded
|
||||
type: string
|
||||
|
|
@ -698,6 +775,12 @@ definitions:
|
|||
type: integer
|
||||
id:
|
||||
type: string
|
||||
is_default_favorites:
|
||||
description: v0.10.4 F136
|
||||
type: boolean
|
||||
is_editorial:
|
||||
description: v0.10.4 F141
|
||||
type: boolean
|
||||
is_public:
|
||||
type: boolean
|
||||
title:
|
||||
|
|
@ -794,12 +877,8 @@ definitions:
|
|||
type: string
|
||||
is_public:
|
||||
type: boolean
|
||||
like_count:
|
||||
type: integer
|
||||
musical_key:
|
||||
type: string
|
||||
play_count:
|
||||
type: integer
|
||||
sample_rate:
|
||||
description: Hz
|
||||
type: integer
|
||||
|
|
@ -880,6 +959,15 @@ definitions:
|
|||
password:
|
||||
description: Virtual field for input
|
||||
type: string
|
||||
password_changed_at:
|
||||
description: 'F016: Password expiration tracking'
|
||||
type: string
|
||||
promoted_to_creator_at:
|
||||
description: |-
|
||||
v1.0.6: set the first time a user self-promotes to `role='creator'`
|
||||
via POST /api/v1/users/me/upgrade-creator. NULL for users who never
|
||||
took that path (still 'user', or promoted by an admin out-of-band).
|
||||
type: string
|
||||
role:
|
||||
type: string
|
||||
slug:
|
||||
|
|
@ -902,7 +990,7 @@ definitions:
|
|||
success:
|
||||
type: boolean
|
||||
type: object
|
||||
host: localhost:8080
|
||||
host: localhost:18080
|
||||
info:
|
||||
contact:
|
||||
email: support@veza.app
|
||||
|
|
@ -2350,6 +2438,71 @@ paths:
|
|||
tags:
|
||||
- Playlist
|
||||
/tracks:
|
||||
get:
|
||||
description: List tracks with pagination, filters, sort. Cursor-based when ?cursor
|
||||
provided, otherwise page/limit offset.
|
||||
parameters:
|
||||
- description: Opaque pagination cursor (overrides page)
|
||||
in: query
|
||||
name: cursor
|
||||
type: string
|
||||
- default: 1
|
||||
description: Page number, 1-based (ignored if cursor set)
|
||||
in: query
|
||||
name: page
|
||||
type: integer
|
||||
- default: 20
|
||||
description: Items per page (max 100)
|
||||
in: query
|
||||
name: limit
|
||||
type: integer
|
||||
- description: Filter by creator UUID
|
||||
in: query
|
||||
name: user_id
|
||||
type: string
|
||||
- description: Filter by genre
|
||||
in: query
|
||||
name: genre
|
||||
type: string
|
||||
- description: Filter by audio format (mp3, flac, wav, ogg, m4a, aac)
|
||||
in: query
|
||||
name: format
|
||||
type: string
|
||||
- default: created_at
|
||||
description: Sort column (created_at, play_count, title)
|
||||
in: query
|
||||
name: sort_by
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
pagination:
|
||||
type: object
|
||||
tracks:
|
||||
items:
|
||||
$ref: '#/definitions/veza-backend-api_internal_models.Track'
|
||||
type: array
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Invalid query params
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
summary: List tracks
|
||||
tags:
|
||||
- Track
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
|
|
@ -2396,6 +2549,152 @@ paths:
|
|||
summary: Upload Track
|
||||
tags:
|
||||
- Track
|
||||
/tracks/{id}:
|
||||
delete:
|
||||
description: Soft-delete a track (sets deleted_at). Caller must own the track
|
||||
or be admin.
|
||||
parameters:
|
||||
- description: Track UUID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Invalid track id
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"403":
|
||||
description: Not owner / no admin
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"404":
|
||||
description: Track not found
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: Delete track
|
||||
tags:
|
||||
- Track
|
||||
get:
|
||||
description: Retrieve a single track. Private play_count / like_count are omitted
|
||||
for non-owners (v0.10.3 F202).
|
||||
parameters:
|
||||
- description: Track UUID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
track:
|
||||
$ref: '#/definitions/veza-backend-api_internal_models.Track'
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Invalid track id
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"404":
|
||||
description: Track not found
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
summary: Get track by ID
|
||||
tags:
|
||||
- Track
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Update the metadata of an existing track. Caller must own the track
|
||||
or be admin.
|
||||
parameters:
|
||||
- description: Track UUID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
- description: Updated metadata
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/internal_core_track.UpdateTrackRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
track:
|
||||
$ref: '#/definitions/veza-backend-api_internal_models.Track'
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Validation / invalid id
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"403":
|
||||
description: Not owner / no admin
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"404":
|
||||
description: Track not found
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: Update track metadata
|
||||
tags:
|
||||
- Track
|
||||
/tracks/{id}/comments:
|
||||
get:
|
||||
consumes:
|
||||
|
|
@ -2554,6 +2853,102 @@ paths:
|
|||
summary: Delete comment
|
||||
tags:
|
||||
- Comment
|
||||
/tracks/{id}/lyrics:
|
||||
get:
|
||||
description: Returns the current lyrics for a track, or null if no lyrics exist.
|
||||
parameters:
|
||||
- description: Track UUID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: lyrics may be null
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
lyrics:
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Invalid track id
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"404":
|
||||
description: Track not found
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
summary: Get track lyrics
|
||||
tags:
|
||||
- Track
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Replace the lyrics of a track. Caller must own the track or be
|
||||
admin.
|
||||
parameters:
|
||||
- description: Track UUID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
- description: Lyrics payload
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/internal_core_track.UpdateLyricsRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
lyrics:
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Validation / invalid id
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"403":
|
||||
description: Not owner / no admin
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"404":
|
||||
description: Track not found
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: Create or update track lyrics
|
||||
tags:
|
||||
- Track
|
||||
/tracks/{id}/status:
|
||||
get:
|
||||
consumes:
|
||||
|
|
@ -2597,6 +2992,108 @@ paths:
|
|||
summary: Get Upload Status
|
||||
tags:
|
||||
- Track
|
||||
/tracks/batch/delete:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Soft-delete up to N tracks in one request. Per-track ownership
|
||||
checked (admin can delete others).
|
||||
parameters:
|
||||
- description: List of track UUIDs
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/internal_core_track.BatchDeleteRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
deleted:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
failed:
|
||||
items:
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Validation / batch size exceeded
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: Batch delete tracks
|
||||
tags:
|
||||
- Track
|
||||
/tracks/batch/update:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Apply a partial metadata update to up to N tracks in one request.
|
||||
Per-track ownership checked.
|
||||
parameters:
|
||||
- description: Track UUIDs + shared updates map
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/internal_core_track.BatchUpdateRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
failed:
|
||||
items:
|
||||
type: object
|
||||
type: array
|
||||
updated:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Validation / batch size exceeded
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: Batch update tracks
|
||||
tags:
|
||||
- Track
|
||||
/tracks/chunk:
|
||||
post:
|
||||
consumes:
|
||||
|
|
@ -3428,6 +3925,11 @@ paths:
|
|||
tags:
|
||||
- Webhook
|
||||
securityDefinitions:
|
||||
ApiKeyAuth:
|
||||
description: 'Developer API key (obtain from Developer Portal). Format: vza_xxxxx'
|
||||
in: header
|
||||
name: X-API-Key
|
||||
type: apiKey
|
||||
BearerAuth:
|
||||
in: header
|
||||
name: Authorization
|
||||
|
|
|
|||
|
|
@ -54,6 +54,21 @@ type BatchUpdateRequest struct {
|
|||
// ListTracks gère la liste des tracks avec pagination, filtres et tri.
|
||||
// v0.931: Supports cursor-based pagination via ?cursor=xxx&limit=20 for consistent performance.
|
||||
// Falls back to page/limit (offset) when cursor is not provided.
|
||||
// @Summary List tracks
|
||||
// @Description List tracks with pagination, filters, sort. Cursor-based when ?cursor provided, otherwise page/limit offset.
|
||||
// @Tags Track
|
||||
// @Produce json
|
||||
// @Param cursor query string false "Opaque pagination cursor (overrides page)"
|
||||
// @Param page query int false "Page number, 1-based (ignored if cursor set)" default(1)
|
||||
// @Param limit query int false "Items per page (max 100)" default(20)
|
||||
// @Param user_id query string false "Filter by creator UUID"
|
||||
// @Param genre query string false "Filter by genre"
|
||||
// @Param format query string false "Filter by audio format (mp3, flac, wav, ogg, m4a, aac)"
|
||||
// @Param sort_by query string false "Sort column (created_at, play_count, title)" default(created_at)
|
||||
// @Success 200 {object} response.APIResponse{data=object{tracks=[]models.Track,pagination=object}}
|
||||
// @Failure 400 {object} response.APIResponse "Invalid query params"
|
||||
// @Failure 500 {object} response.APIResponse "Internal Error"
|
||||
// @Router /tracks [get]
|
||||
func (h *TrackHandler) ListTracks(c *gin.Context) {
|
||||
cursor := c.Query("cursor")
|
||||
page := c.DefaultQuery("page", "1")
|
||||
|
|
@ -138,6 +153,16 @@ func (h *TrackHandler) ListTracks(c *gin.Context) {
|
|||
}
|
||||
|
||||
// GetTrack gère la récupération d'un track par ID
|
||||
// @Summary Get track by ID
|
||||
// @Description Retrieve a single track. Private play_count / like_count are omitted for non-owners (v0.10.3 F202).
|
||||
// @Tags Track
|
||||
// @Produce json
|
||||
// @Param id path string true "Track UUID"
|
||||
// @Success 200 {object} response.APIResponse{data=object{track=models.Track}}
|
||||
// @Failure 400 {object} response.APIResponse "Invalid track id"
|
||||
// @Failure 404 {object} response.APIResponse "Track not found"
|
||||
// @Failure 500 {object} response.APIResponse "Internal Error"
|
||||
// @Router /tracks/{id} [get]
|
||||
func (h *TrackHandler) GetTrack(c *gin.Context) {
|
||||
trackIDStr := c.Param("id")
|
||||
if trackIDStr == "" {
|
||||
|
|
@ -196,6 +221,21 @@ func hideLikeCountFromTrack(track *models.Track) map[string]interface{} {
|
|||
}
|
||||
|
||||
// UpdateTrack gère la mise à jour d'un track
|
||||
// @Summary Update track metadata
|
||||
// @Description Update the metadata of an existing track. Caller must own the track or be admin.
|
||||
// @Tags Track
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param id path string true "Track UUID"
|
||||
// @Param request body UpdateTrackRequest true "Updated metadata"
|
||||
// @Success 200 {object} response.APIResponse{data=object{track=models.Track}}
|
||||
// @Failure 400 {object} response.APIResponse "Validation / invalid id"
|
||||
// @Failure 401 {object} response.APIResponse "Unauthorized"
|
||||
// @Failure 403 {object} response.APIResponse "Not owner / no admin"
|
||||
// @Failure 404 {object} response.APIResponse "Track not found"
|
||||
// @Failure 500 {object} response.APIResponse "Internal Error"
|
||||
// @Router /tracks/{id} [put]
|
||||
func (h *TrackHandler) UpdateTrack(c *gin.Context) {
|
||||
userID, ok := h.getUserID(c)
|
||||
if !ok {
|
||||
|
|
@ -279,6 +319,16 @@ func (h *TrackHandler) UpdateTrack(c *gin.Context) {
|
|||
}
|
||||
|
||||
// GetLyrics gère la récupération des paroles d'un track
|
||||
// @Summary Get track lyrics
|
||||
// @Description Returns the current lyrics for a track, or null if no lyrics exist.
|
||||
// @Tags Track
|
||||
// @Produce json
|
||||
// @Param id path string true "Track UUID"
|
||||
// @Success 200 {object} response.APIResponse{data=object{lyrics=object}} "lyrics may be null"
|
||||
// @Failure 400 {object} response.APIResponse "Invalid track id"
|
||||
// @Failure 404 {object} response.APIResponse "Track not found"
|
||||
// @Failure 500 {object} response.APIResponse "Internal Error"
|
||||
// @Router /tracks/{id}/lyrics [get]
|
||||
func (h *TrackHandler) GetLyrics(c *gin.Context) {
|
||||
trackIDStr := c.Param("id")
|
||||
if trackIDStr == "" {
|
||||
|
|
@ -311,6 +361,21 @@ func (h *TrackHandler) GetLyrics(c *gin.Context) {
|
|||
}
|
||||
|
||||
// UpdateLyrics gère la création/mise à jour des paroles
|
||||
// @Summary Create or update track lyrics
|
||||
// @Description Replace the lyrics of a track. Caller must own the track or be admin.
|
||||
// @Tags Track
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param id path string true "Track UUID"
|
||||
// @Param request body UpdateLyricsRequest true "Lyrics payload"
|
||||
// @Success 200 {object} response.APIResponse{data=object{lyrics=object}}
|
||||
// @Failure 400 {object} response.APIResponse "Validation / invalid id"
|
||||
// @Failure 401 {object} response.APIResponse "Unauthorized"
|
||||
// @Failure 403 {object} response.APIResponse "Not owner / no admin"
|
||||
// @Failure 404 {object} response.APIResponse "Track not found"
|
||||
// @Failure 500 {object} response.APIResponse "Internal Error"
|
||||
// @Router /tracks/{id}/lyrics [put]
|
||||
func (h *TrackHandler) UpdateLyrics(c *gin.Context) {
|
||||
userID, ok := h.getUserID(c)
|
||||
if !ok {
|
||||
|
|
@ -348,6 +413,19 @@ func (h *TrackHandler) UpdateLyrics(c *gin.Context) {
|
|||
}
|
||||
|
||||
// DeleteTrack gère la suppression d'un track
|
||||
// @Summary Delete track
|
||||
// @Description Soft-delete a track (sets deleted_at). Caller must own the track or be admin.
|
||||
// @Tags Track
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param id path string true "Track UUID"
|
||||
// @Success 200 {object} response.APIResponse{data=object{message=string}}
|
||||
// @Failure 400 {object} response.APIResponse "Invalid track id"
|
||||
// @Failure 401 {object} response.APIResponse "Unauthorized"
|
||||
// @Failure 403 {object} response.APIResponse "Not owner / no admin"
|
||||
// @Failure 404 {object} response.APIResponse "Track not found"
|
||||
// @Failure 500 {object} response.APIResponse "Internal Error"
|
||||
// @Router /tracks/{id} [delete]
|
||||
func (h *TrackHandler) DeleteTrack(c *gin.Context) {
|
||||
userID, ok := h.getUserID(c)
|
||||
if !ok {
|
||||
|
|
@ -392,6 +470,18 @@ func (h *TrackHandler) DeleteTrack(c *gin.Context) {
|
|||
}
|
||||
|
||||
// BatchDeleteTracks gère la suppression en lot de plusieurs tracks
|
||||
// @Summary Batch delete tracks
|
||||
// @Description Soft-delete up to N tracks in one request. Per-track ownership checked (admin can delete others).
|
||||
// @Tags Track
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param request body BatchDeleteRequest true "List of track UUIDs"
|
||||
// @Success 200 {object} response.APIResponse{data=object{deleted=[]string,failed=[]object}}
|
||||
// @Failure 400 {object} response.APIResponse "Validation / batch size exceeded"
|
||||
// @Failure 401 {object} response.APIResponse "Unauthorized"
|
||||
// @Failure 500 {object} response.APIResponse "Internal Error"
|
||||
// @Router /tracks/batch/delete [post]
|
||||
func (h *TrackHandler) BatchDeleteTracks(c *gin.Context) {
|
||||
userID, ok := h.getUserID(c)
|
||||
if !ok {
|
||||
|
|
@ -436,6 +526,18 @@ func (h *TrackHandler) BatchDeleteTracks(c *gin.Context) {
|
|||
}
|
||||
|
||||
// BatchUpdateTracks gère la mise à jour en lot de plusieurs tracks
|
||||
// @Summary Batch update tracks
|
||||
// @Description Apply a partial metadata update to up to N tracks in one request. Per-track ownership checked.
|
||||
// @Tags Track
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param request body BatchUpdateRequest true "Track UUIDs + shared updates map"
|
||||
// @Success 200 {object} response.APIResponse{data=object{updated=[]string,failed=[]object}}
|
||||
// @Failure 400 {object} response.APIResponse "Validation / batch size exceeded"
|
||||
// @Failure 401 {object} response.APIResponse "Unauthorized"
|
||||
// @Failure 500 {object} response.APIResponse "Internal Error"
|
||||
// @Router /tracks/batch/update [post]
|
||||
func (h *TrackHandler) BatchUpdateTracks(c *gin.Context) {
|
||||
userID, ok := h.getUserID(c)
|
||||
if !ok {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,29 @@
|
|||
basePath: /api/v1
|
||||
definitions:
|
||||
internal_core_track.BatchDeleteRequest:
|
||||
properties:
|
||||
track_ids:
|
||||
items:
|
||||
type: string
|
||||
minItems: 1
|
||||
type: array
|
||||
required:
|
||||
- track_ids
|
||||
type: object
|
||||
internal_core_track.BatchUpdateRequest:
|
||||
properties:
|
||||
track_ids:
|
||||
items:
|
||||
type: string
|
||||
minItems: 1
|
||||
type: array
|
||||
updates:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
required:
|
||||
- track_ids
|
||||
- updates
|
||||
type: object
|
||||
internal_core_track.CompleteChunkedUploadRequest:
|
||||
properties:
|
||||
upload_id:
|
||||
|
|
@ -22,6 +46,51 @@ definitions:
|
|||
- total_chunks
|
||||
- total_size
|
||||
type: object
|
||||
internal_core_track.UpdateLyricsRequest:
|
||||
properties:
|
||||
content:
|
||||
type: string
|
||||
type: object
|
||||
internal_core_track.UpdateTrackRequest:
|
||||
properties:
|
||||
album:
|
||||
maxLength: 255
|
||||
type: string
|
||||
artist:
|
||||
maxLength: 255
|
||||
type: string
|
||||
bpm:
|
||||
maximum: 300
|
||||
minimum: 0
|
||||
type: integer
|
||||
genre:
|
||||
description: legacy, single
|
||||
maxLength: 100
|
||||
type: string
|
||||
genres:
|
||||
description: 'v0.10.1: max 3, taxonomy slugs'
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
is_public:
|
||||
type: boolean
|
||||
musical_key:
|
||||
maxLength: 10
|
||||
type: string
|
||||
tags:
|
||||
description: 'v0.10.1: max 10, 30 chars each'
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
title:
|
||||
maxLength: 255
|
||||
minLength: 1
|
||||
type: string
|
||||
year:
|
||||
maximum: 2100
|
||||
minimum: 1900
|
||||
type: integer
|
||||
type: object
|
||||
internal_handlers.APIResponse:
|
||||
properties:
|
||||
data: {}
|
||||
|
|
@ -36,8 +105,10 @@ definitions:
|
|||
minLength: 1
|
||||
type: string
|
||||
parent_id:
|
||||
description: Changed to *uuid.UUID
|
||||
type: string
|
||||
timestamp:
|
||||
description: Position in seconds (0 = top-level, no specific time)
|
||||
type: number
|
||||
required:
|
||||
- content
|
||||
type: object
|
||||
|
|
@ -178,6 +249,9 @@ definitions:
|
|||
properties:
|
||||
confirm_text:
|
||||
type: string
|
||||
keep_public_tracks:
|
||||
description: If true, public tracks remain (attributed to deleted account)
|
||||
type: boolean
|
||||
password:
|
||||
type: string
|
||||
reason:
|
||||
|
|
@ -468,6 +542,9 @@ definitions:
|
|||
type: string
|
||||
promo_code_id:
|
||||
type: string
|
||||
refund_deadline:
|
||||
description: 'v0.12.0: 14-day refund deadline'
|
||||
type: string
|
||||
status:
|
||||
description: pending, completed, failed, refunded
|
||||
type: string
|
||||
|
|
@ -698,6 +775,12 @@ definitions:
|
|||
type: integer
|
||||
id:
|
||||
type: string
|
||||
is_default_favorites:
|
||||
description: v0.10.4 F136
|
||||
type: boolean
|
||||
is_editorial:
|
||||
description: v0.10.4 F141
|
||||
type: boolean
|
||||
is_public:
|
||||
type: boolean
|
||||
title:
|
||||
|
|
@ -794,12 +877,8 @@ definitions:
|
|||
type: string
|
||||
is_public:
|
||||
type: boolean
|
||||
like_count:
|
||||
type: integer
|
||||
musical_key:
|
||||
type: string
|
||||
play_count:
|
||||
type: integer
|
||||
sample_rate:
|
||||
description: Hz
|
||||
type: integer
|
||||
|
|
@ -880,6 +959,15 @@ definitions:
|
|||
password:
|
||||
description: Virtual field for input
|
||||
type: string
|
||||
password_changed_at:
|
||||
description: 'F016: Password expiration tracking'
|
||||
type: string
|
||||
promoted_to_creator_at:
|
||||
description: |-
|
||||
v1.0.6: set the first time a user self-promotes to `role='creator'`
|
||||
via POST /api/v1/users/me/upgrade-creator. NULL for users who never
|
||||
took that path (still 'user', or promoted by an admin out-of-band).
|
||||
type: string
|
||||
role:
|
||||
type: string
|
||||
slug:
|
||||
|
|
@ -902,7 +990,7 @@ definitions:
|
|||
success:
|
||||
type: boolean
|
||||
type: object
|
||||
host: localhost:8080
|
||||
host: localhost:18080
|
||||
info:
|
||||
contact:
|
||||
email: support@veza.app
|
||||
|
|
@ -2350,6 +2438,71 @@ paths:
|
|||
tags:
|
||||
- Playlist
|
||||
/tracks:
|
||||
get:
|
||||
description: List tracks with pagination, filters, sort. Cursor-based when ?cursor
|
||||
provided, otherwise page/limit offset.
|
||||
parameters:
|
||||
- description: Opaque pagination cursor (overrides page)
|
||||
in: query
|
||||
name: cursor
|
||||
type: string
|
||||
- default: 1
|
||||
description: Page number, 1-based (ignored if cursor set)
|
||||
in: query
|
||||
name: page
|
||||
type: integer
|
||||
- default: 20
|
||||
description: Items per page (max 100)
|
||||
in: query
|
||||
name: limit
|
||||
type: integer
|
||||
- description: Filter by creator UUID
|
||||
in: query
|
||||
name: user_id
|
||||
type: string
|
||||
- description: Filter by genre
|
||||
in: query
|
||||
name: genre
|
||||
type: string
|
||||
- description: Filter by audio format (mp3, flac, wav, ogg, m4a, aac)
|
||||
in: query
|
||||
name: format
|
||||
type: string
|
||||
- default: created_at
|
||||
description: Sort column (created_at, play_count, title)
|
||||
in: query
|
||||
name: sort_by
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
pagination:
|
||||
type: object
|
||||
tracks:
|
||||
items:
|
||||
$ref: '#/definitions/veza-backend-api_internal_models.Track'
|
||||
type: array
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Invalid query params
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
summary: List tracks
|
||||
tags:
|
||||
- Track
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
|
|
@ -2396,6 +2549,152 @@ paths:
|
|||
summary: Upload Track
|
||||
tags:
|
||||
- Track
|
||||
/tracks/{id}:
|
||||
delete:
|
||||
description: Soft-delete a track (sets deleted_at). Caller must own the track
|
||||
or be admin.
|
||||
parameters:
|
||||
- description: Track UUID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Invalid track id
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"403":
|
||||
description: Not owner / no admin
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"404":
|
||||
description: Track not found
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: Delete track
|
||||
tags:
|
||||
- Track
|
||||
get:
|
||||
description: Retrieve a single track. Private play_count / like_count are omitted
|
||||
for non-owners (v0.10.3 F202).
|
||||
parameters:
|
||||
- description: Track UUID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
track:
|
||||
$ref: '#/definitions/veza-backend-api_internal_models.Track'
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Invalid track id
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"404":
|
||||
description: Track not found
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
summary: Get track by ID
|
||||
tags:
|
||||
- Track
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Update the metadata of an existing track. Caller must own the track
|
||||
or be admin.
|
||||
parameters:
|
||||
- description: Track UUID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
- description: Updated metadata
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/internal_core_track.UpdateTrackRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
track:
|
||||
$ref: '#/definitions/veza-backend-api_internal_models.Track'
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Validation / invalid id
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"403":
|
||||
description: Not owner / no admin
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"404":
|
||||
description: Track not found
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: Update track metadata
|
||||
tags:
|
||||
- Track
|
||||
/tracks/{id}/comments:
|
||||
get:
|
||||
consumes:
|
||||
|
|
@ -2554,6 +2853,102 @@ paths:
|
|||
summary: Delete comment
|
||||
tags:
|
||||
- Comment
|
||||
/tracks/{id}/lyrics:
|
||||
get:
|
||||
description: Returns the current lyrics for a track, or null if no lyrics exist.
|
||||
parameters:
|
||||
- description: Track UUID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: lyrics may be null
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
lyrics:
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Invalid track id
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"404":
|
||||
description: Track not found
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
summary: Get track lyrics
|
||||
tags:
|
||||
- Track
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Replace the lyrics of a track. Caller must own the track or be
|
||||
admin.
|
||||
parameters:
|
||||
- description: Track UUID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
- description: Lyrics payload
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/internal_core_track.UpdateLyricsRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
lyrics:
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Validation / invalid id
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"403":
|
||||
description: Not owner / no admin
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"404":
|
||||
description: Track not found
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: Create or update track lyrics
|
||||
tags:
|
||||
- Track
|
||||
/tracks/{id}/status:
|
||||
get:
|
||||
consumes:
|
||||
|
|
@ -2597,6 +2992,108 @@ paths:
|
|||
summary: Get Upload Status
|
||||
tags:
|
||||
- Track
|
||||
/tracks/batch/delete:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Soft-delete up to N tracks in one request. Per-track ownership
|
||||
checked (admin can delete others).
|
||||
parameters:
|
||||
- description: List of track UUIDs
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/internal_core_track.BatchDeleteRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
deleted:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
failed:
|
||||
items:
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Validation / batch size exceeded
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: Batch delete tracks
|
||||
tags:
|
||||
- Track
|
||||
/tracks/batch/update:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Apply a partial metadata update to up to N tracks in one request.
|
||||
Per-track ownership checked.
|
||||
parameters:
|
||||
- description: Track UUIDs + shared updates map
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/internal_core_track.BatchUpdateRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
failed:
|
||||
items:
|
||||
type: object
|
||||
type: array
|
||||
updated:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: Validation / batch size exceeded
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
"500":
|
||||
description: Internal Error
|
||||
schema:
|
||||
$ref: '#/definitions/veza-backend-api_internal_response.APIResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: Batch update tracks
|
||||
tags:
|
||||
- Track
|
||||
/tracks/chunk:
|
||||
post:
|
||||
consumes:
|
||||
|
|
@ -3428,14 +3925,13 @@ paths:
|
|||
tags:
|
||||
- Webhook
|
||||
securityDefinitions:
|
||||
BearerAuth:
|
||||
description: "JWT Bearer token. Format: Bearer {token}"
|
||||
in: header
|
||||
name: Authorization
|
||||
type: apiKey
|
||||
ApiKeyAuth:
|
||||
description: "Developer API key. Format: vza_xxxxx (obtain from Developer Portal)"
|
||||
description: 'Developer API key (obtain from Developer Portal). Format: vza_xxxxx'
|
||||
in: header
|
||||
name: X-API-Key
|
||||
type: apiKey
|
||||
BearerAuth:
|
||||
in: header
|
||||
name: Authorization
|
||||
type: apiKey
|
||||
swagger: "2.0"
|
||||
|
|
|
|||
Loading…
Reference in a new issue