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": {
|
"/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": {
|
"post": {
|
||||||
"security": [
|
"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": {
|
"/tracks/chunk": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"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": {
|
"/tracks/{id}/comments": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Get paginated list of comments for a track",
|
"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": {
|
"/tracks/{id}/status": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -4108,6 +4763,41 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"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": {
|
"internal_core_track.CompleteChunkedUploadRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"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": {
|
"internal_handlers.APIResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -4162,8 +4914,11 @@ const docTemplate = `{
|
||||||
"minLength": 1
|
"minLength": 1
|
||||||
},
|
},
|
||||||
"parent_id": {
|
"parent_id": {
|
||||||
"description": "Changed to *uuid.UUID",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"description": "Position in seconds (0 = top-level, no specific time)",
|
||||||
|
"type": "number"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -4364,6 +5119,10 @@ const docTemplate = `{
|
||||||
"confirm_text": {
|
"confirm_text": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"keep_public_tracks": {
|
||||||
|
"description": "If true, public tracks remain (attributed to deleted account)",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"password": {
|
"password": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -4777,6 +5536,10 @@ const docTemplate = `{
|
||||||
"promo_code_id": {
|
"promo_code_id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"refund_deadline": {
|
||||||
|
"description": "v0.12.0: 14-day refund deadline",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"description": "pending, completed, failed, refunded",
|
"description": "pending, completed, failed, refunded",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
|
@ -5120,6 +5883,14 @@ const docTemplate = `{
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"is_default_favorites": {
|
||||||
|
"description": "v0.10.4 F136",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"is_editorial": {
|
||||||
|
"description": "v0.10.4 F141",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"is_public": {
|
"is_public": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
|
@ -5261,15 +6032,9 @@ const docTemplate = `{
|
||||||
"is_public": {
|
"is_public": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"like_count": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"musical_key": {
|
"musical_key": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"play_count": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"sample_rate": {
|
"sample_rate": {
|
||||||
"description": "Hz",
|
"description": "Hz",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
|
@ -5386,6 +6151,14 @@ const docTemplate = `{
|
||||||
"description": "Virtual field for input",
|
"description": "Virtual field for input",
|
||||||
"type": "string"
|
"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": {
|
"role": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -5421,6 +6194,12 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securityDefinitions": {
|
"securityDefinitions": {
|
||||||
|
"ApiKeyAuth": {
|
||||||
|
"description": "Developer API key (obtain from Developer Portal). Format: vza_xxxxx",
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "X-API-Key",
|
||||||
|
"in": "header"
|
||||||
|
},
|
||||||
"BearerAuth": {
|
"BearerAuth": {
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"name": "Authorization",
|
"name": "Authorization",
|
||||||
|
|
@ -5432,7 +6211,7 @@ const docTemplate = `{
|
||||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||||
var SwaggerInfo = &swag.Spec{
|
var SwaggerInfo = &swag.Spec{
|
||||||
Version: "1.2.0",
|
Version: "1.2.0",
|
||||||
Host: "localhost:8080",
|
Host: "localhost:18080",
|
||||||
BasePath: "/api/v1",
|
BasePath: "/api/v1",
|
||||||
Schemes: []string{},
|
Schemes: []string{},
|
||||||
Title: "Veza Backend API",
|
Title: "Veza Backend API",
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
},
|
},
|
||||||
"version": "1.2.0"
|
"version": "1.2.0"
|
||||||
},
|
},
|
||||||
"host": "localhost:8080",
|
"host": "localhost:18080",
|
||||||
"basePath": "/api/v1",
|
"basePath": "/api/v1",
|
||||||
"paths": {
|
"paths": {
|
||||||
"/api/v1/dashboard": {
|
"/api/v1/dashboard": {
|
||||||
|
|
@ -2343,6 +2343,106 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/tracks": {
|
"/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": {
|
"post": {
|
||||||
"security": [
|
"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": {
|
"/tracks/chunk": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"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": {
|
"/tracks/{id}/comments": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Get paginated list of comments for a track",
|
"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": {
|
"/tracks/{id}/status": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -4102,6 +4757,41 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"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": {
|
"internal_core_track.CompleteChunkedUploadRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"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": {
|
"internal_handlers.APIResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -4156,8 +4908,11 @@
|
||||||
"minLength": 1
|
"minLength": 1
|
||||||
},
|
},
|
||||||
"parent_id": {
|
"parent_id": {
|
||||||
"description": "Changed to *uuid.UUID",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"description": "Position in seconds (0 = top-level, no specific time)",
|
||||||
|
"type": "number"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -4358,6 +5113,10 @@
|
||||||
"confirm_text": {
|
"confirm_text": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"keep_public_tracks": {
|
||||||
|
"description": "If true, public tracks remain (attributed to deleted account)",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"password": {
|
"password": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -4771,6 +5530,10 @@
|
||||||
"promo_code_id": {
|
"promo_code_id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"refund_deadline": {
|
||||||
|
"description": "v0.12.0: 14-day refund deadline",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"description": "pending, completed, failed, refunded",
|
"description": "pending, completed, failed, refunded",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
|
@ -5114,6 +5877,14 @@
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"is_default_favorites": {
|
||||||
|
"description": "v0.10.4 F136",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"is_editorial": {
|
||||||
|
"description": "v0.10.4 F141",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"is_public": {
|
"is_public": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
|
@ -5255,15 +6026,9 @@
|
||||||
"is_public": {
|
"is_public": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"like_count": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"musical_key": {
|
"musical_key": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"play_count": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"sample_rate": {
|
"sample_rate": {
|
||||||
"description": "Hz",
|
"description": "Hz",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
|
@ -5380,6 +6145,14 @@
|
||||||
"description": "Virtual field for input",
|
"description": "Virtual field for input",
|
||||||
"type": "string"
|
"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": {
|
"role": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -5415,6 +6188,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securityDefinitions": {
|
"securityDefinitions": {
|
||||||
|
"ApiKeyAuth": {
|
||||||
|
"description": "Developer API key (obtain from Developer Portal). Format: vza_xxxxx",
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "X-API-Key",
|
||||||
|
"in": "header"
|
||||||
|
},
|
||||||
"BearerAuth": {
|
"BearerAuth": {
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"name": "Authorization",
|
"name": "Authorization",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,29 @@
|
||||||
basePath: /api/v1
|
basePath: /api/v1
|
||||||
definitions:
|
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:
|
internal_core_track.CompleteChunkedUploadRequest:
|
||||||
properties:
|
properties:
|
||||||
upload_id:
|
upload_id:
|
||||||
|
|
@ -22,6 +46,51 @@ definitions:
|
||||||
- total_chunks
|
- total_chunks
|
||||||
- total_size
|
- total_size
|
||||||
type: object
|
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:
|
internal_handlers.APIResponse:
|
||||||
properties:
|
properties:
|
||||||
data: {}
|
data: {}
|
||||||
|
|
@ -36,8 +105,10 @@ definitions:
|
||||||
minLength: 1
|
minLength: 1
|
||||||
type: string
|
type: string
|
||||||
parent_id:
|
parent_id:
|
||||||
description: Changed to *uuid.UUID
|
|
||||||
type: string
|
type: string
|
||||||
|
timestamp:
|
||||||
|
description: Position in seconds (0 = top-level, no specific time)
|
||||||
|
type: number
|
||||||
required:
|
required:
|
||||||
- content
|
- content
|
||||||
type: object
|
type: object
|
||||||
|
|
@ -178,6 +249,9 @@ definitions:
|
||||||
properties:
|
properties:
|
||||||
confirm_text:
|
confirm_text:
|
||||||
type: string
|
type: string
|
||||||
|
keep_public_tracks:
|
||||||
|
description: If true, public tracks remain (attributed to deleted account)
|
||||||
|
type: boolean
|
||||||
password:
|
password:
|
||||||
type: string
|
type: string
|
||||||
reason:
|
reason:
|
||||||
|
|
@ -468,6 +542,9 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
promo_code_id:
|
promo_code_id:
|
||||||
type: string
|
type: string
|
||||||
|
refund_deadline:
|
||||||
|
description: 'v0.12.0: 14-day refund deadline'
|
||||||
|
type: string
|
||||||
status:
|
status:
|
||||||
description: pending, completed, failed, refunded
|
description: pending, completed, failed, refunded
|
||||||
type: string
|
type: string
|
||||||
|
|
@ -698,6 +775,12 @@ definitions:
|
||||||
type: integer
|
type: integer
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
|
is_default_favorites:
|
||||||
|
description: v0.10.4 F136
|
||||||
|
type: boolean
|
||||||
|
is_editorial:
|
||||||
|
description: v0.10.4 F141
|
||||||
|
type: boolean
|
||||||
is_public:
|
is_public:
|
||||||
type: boolean
|
type: boolean
|
||||||
title:
|
title:
|
||||||
|
|
@ -794,12 +877,8 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
is_public:
|
is_public:
|
||||||
type: boolean
|
type: boolean
|
||||||
like_count:
|
|
||||||
type: integer
|
|
||||||
musical_key:
|
musical_key:
|
||||||
type: string
|
type: string
|
||||||
play_count:
|
|
||||||
type: integer
|
|
||||||
sample_rate:
|
sample_rate:
|
||||||
description: Hz
|
description: Hz
|
||||||
type: integer
|
type: integer
|
||||||
|
|
@ -880,6 +959,15 @@ definitions:
|
||||||
password:
|
password:
|
||||||
description: Virtual field for input
|
description: Virtual field for input
|
||||||
type: string
|
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:
|
role:
|
||||||
type: string
|
type: string
|
||||||
slug:
|
slug:
|
||||||
|
|
@ -902,7 +990,7 @@ definitions:
|
||||||
success:
|
success:
|
||||||
type: boolean
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
host: localhost:8080
|
host: localhost:18080
|
||||||
info:
|
info:
|
||||||
contact:
|
contact:
|
||||||
email: support@veza.app
|
email: support@veza.app
|
||||||
|
|
@ -2350,6 +2438,71 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- Playlist
|
- Playlist
|
||||||
/tracks:
|
/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:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- multipart/form-data
|
- multipart/form-data
|
||||||
|
|
@ -2396,6 +2549,152 @@ paths:
|
||||||
summary: Upload Track
|
summary: Upload Track
|
||||||
tags:
|
tags:
|
||||||
- Track
|
- 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:
|
/tracks/{id}/comments:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -2554,6 +2853,102 @@ paths:
|
||||||
summary: Delete comment
|
summary: Delete comment
|
||||||
tags:
|
tags:
|
||||||
- Comment
|
- 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:
|
/tracks/{id}/status:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -2597,6 +2992,108 @@ paths:
|
||||||
summary: Get Upload Status
|
summary: Get Upload Status
|
||||||
tags:
|
tags:
|
||||||
- Track
|
- 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:
|
/tracks/chunk:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -3428,6 +3925,11 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- Webhook
|
- Webhook
|
||||||
securityDefinitions:
|
securityDefinitions:
|
||||||
|
ApiKeyAuth:
|
||||||
|
description: 'Developer API key (obtain from Developer Portal). Format: vza_xxxxx'
|
||||||
|
in: header
|
||||||
|
name: X-API-Key
|
||||||
|
type: apiKey
|
||||||
BearerAuth:
|
BearerAuth:
|
||||||
in: header
|
in: header
|
||||||
name: Authorization
|
name: Authorization
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,21 @@ type BatchUpdateRequest struct {
|
||||||
// ListTracks gère la liste des tracks avec pagination, filtres et tri.
|
// 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.
|
// 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.
|
// 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) {
|
func (h *TrackHandler) ListTracks(c *gin.Context) {
|
||||||
cursor := c.Query("cursor")
|
cursor := c.Query("cursor")
|
||||||
page := c.DefaultQuery("page", "1")
|
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
|
// 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) {
|
func (h *TrackHandler) GetTrack(c *gin.Context) {
|
||||||
trackIDStr := c.Param("id")
|
trackIDStr := c.Param("id")
|
||||||
if trackIDStr == "" {
|
if trackIDStr == "" {
|
||||||
|
|
@ -196,6 +221,21 @@ func hideLikeCountFromTrack(track *models.Track) map[string]interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateTrack gère la mise à jour d'un track
|
// 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) {
|
func (h *TrackHandler) UpdateTrack(c *gin.Context) {
|
||||||
userID, ok := h.getUserID(c)
|
userID, ok := h.getUserID(c)
|
||||||
if !ok {
|
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
|
// 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) {
|
func (h *TrackHandler) GetLyrics(c *gin.Context) {
|
||||||
trackIDStr := c.Param("id")
|
trackIDStr := c.Param("id")
|
||||||
if trackIDStr == "" {
|
if trackIDStr == "" {
|
||||||
|
|
@ -311,6 +361,21 @@ func (h *TrackHandler) GetLyrics(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateLyrics gère la création/mise à jour des paroles
|
// 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) {
|
func (h *TrackHandler) UpdateLyrics(c *gin.Context) {
|
||||||
userID, ok := h.getUserID(c)
|
userID, ok := h.getUserID(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -348,6 +413,19 @@ func (h *TrackHandler) UpdateLyrics(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteTrack gère la suppression d'un track
|
// 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) {
|
func (h *TrackHandler) DeleteTrack(c *gin.Context) {
|
||||||
userID, ok := h.getUserID(c)
|
userID, ok := h.getUserID(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -392,6 +470,18 @@ func (h *TrackHandler) DeleteTrack(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchDeleteTracks gère la suppression en lot de plusieurs tracks
|
// 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) {
|
func (h *TrackHandler) BatchDeleteTracks(c *gin.Context) {
|
||||||
userID, ok := h.getUserID(c)
|
userID, ok := h.getUserID(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -436,6 +526,18 @@ func (h *TrackHandler) BatchDeleteTracks(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchUpdateTracks gère la mise à jour en lot de plusieurs tracks
|
// 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) {
|
func (h *TrackHandler) BatchUpdateTracks(c *gin.Context) {
|
||||||
userID, ok := h.getUserID(c)
|
userID, ok := h.getUserID(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,29 @@
|
||||||
basePath: /api/v1
|
basePath: /api/v1
|
||||||
definitions:
|
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:
|
internal_core_track.CompleteChunkedUploadRequest:
|
||||||
properties:
|
properties:
|
||||||
upload_id:
|
upload_id:
|
||||||
|
|
@ -22,6 +46,51 @@ definitions:
|
||||||
- total_chunks
|
- total_chunks
|
||||||
- total_size
|
- total_size
|
||||||
type: object
|
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:
|
internal_handlers.APIResponse:
|
||||||
properties:
|
properties:
|
||||||
data: {}
|
data: {}
|
||||||
|
|
@ -36,8 +105,10 @@ definitions:
|
||||||
minLength: 1
|
minLength: 1
|
||||||
type: string
|
type: string
|
||||||
parent_id:
|
parent_id:
|
||||||
description: Changed to *uuid.UUID
|
|
||||||
type: string
|
type: string
|
||||||
|
timestamp:
|
||||||
|
description: Position in seconds (0 = top-level, no specific time)
|
||||||
|
type: number
|
||||||
required:
|
required:
|
||||||
- content
|
- content
|
||||||
type: object
|
type: object
|
||||||
|
|
@ -178,6 +249,9 @@ definitions:
|
||||||
properties:
|
properties:
|
||||||
confirm_text:
|
confirm_text:
|
||||||
type: string
|
type: string
|
||||||
|
keep_public_tracks:
|
||||||
|
description: If true, public tracks remain (attributed to deleted account)
|
||||||
|
type: boolean
|
||||||
password:
|
password:
|
||||||
type: string
|
type: string
|
||||||
reason:
|
reason:
|
||||||
|
|
@ -468,6 +542,9 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
promo_code_id:
|
promo_code_id:
|
||||||
type: string
|
type: string
|
||||||
|
refund_deadline:
|
||||||
|
description: 'v0.12.0: 14-day refund deadline'
|
||||||
|
type: string
|
||||||
status:
|
status:
|
||||||
description: pending, completed, failed, refunded
|
description: pending, completed, failed, refunded
|
||||||
type: string
|
type: string
|
||||||
|
|
@ -698,6 +775,12 @@ definitions:
|
||||||
type: integer
|
type: integer
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
|
is_default_favorites:
|
||||||
|
description: v0.10.4 F136
|
||||||
|
type: boolean
|
||||||
|
is_editorial:
|
||||||
|
description: v0.10.4 F141
|
||||||
|
type: boolean
|
||||||
is_public:
|
is_public:
|
||||||
type: boolean
|
type: boolean
|
||||||
title:
|
title:
|
||||||
|
|
@ -794,12 +877,8 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
is_public:
|
is_public:
|
||||||
type: boolean
|
type: boolean
|
||||||
like_count:
|
|
||||||
type: integer
|
|
||||||
musical_key:
|
musical_key:
|
||||||
type: string
|
type: string
|
||||||
play_count:
|
|
||||||
type: integer
|
|
||||||
sample_rate:
|
sample_rate:
|
||||||
description: Hz
|
description: Hz
|
||||||
type: integer
|
type: integer
|
||||||
|
|
@ -880,6 +959,15 @@ definitions:
|
||||||
password:
|
password:
|
||||||
description: Virtual field for input
|
description: Virtual field for input
|
||||||
type: string
|
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:
|
role:
|
||||||
type: string
|
type: string
|
||||||
slug:
|
slug:
|
||||||
|
|
@ -902,7 +990,7 @@ definitions:
|
||||||
success:
|
success:
|
||||||
type: boolean
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
host: localhost:8080
|
host: localhost:18080
|
||||||
info:
|
info:
|
||||||
contact:
|
contact:
|
||||||
email: support@veza.app
|
email: support@veza.app
|
||||||
|
|
@ -2350,6 +2438,71 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- Playlist
|
- Playlist
|
||||||
/tracks:
|
/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:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- multipart/form-data
|
- multipart/form-data
|
||||||
|
|
@ -2396,6 +2549,152 @@ paths:
|
||||||
summary: Upload Track
|
summary: Upload Track
|
||||||
tags:
|
tags:
|
||||||
- Track
|
- 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:
|
/tracks/{id}/comments:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -2554,6 +2853,102 @@ paths:
|
||||||
summary: Delete comment
|
summary: Delete comment
|
||||||
tags:
|
tags:
|
||||||
- Comment
|
- 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:
|
/tracks/{id}/status:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -2597,6 +2992,108 @@ paths:
|
||||||
summary: Get Upload Status
|
summary: Get Upload Status
|
||||||
tags:
|
tags:
|
||||||
- Track
|
- 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:
|
/tracks/chunk:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -3428,14 +3925,13 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- Webhook
|
- Webhook
|
||||||
securityDefinitions:
|
securityDefinitions:
|
||||||
BearerAuth:
|
|
||||||
description: "JWT Bearer token. Format: Bearer {token}"
|
|
||||||
in: header
|
|
||||||
name: Authorization
|
|
||||||
type: apiKey
|
|
||||||
ApiKeyAuth:
|
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
|
in: header
|
||||||
name: X-API-Key
|
name: X-API-Key
|
||||||
type: apiKey
|
type: apiKey
|
||||||
|
BearerAuth:
|
||||||
|
in: header
|
||||||
|
name: Authorization
|
||||||
|
type: apiKey
|
||||||
swagger: "2.0"
|
swagger: "2.0"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue