feat(openapi): annotate profile_handler users endpoints (v1.0.8 B-annot)
Some checks failed
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
Veza CI / Backend (Go) (push) Failing after 0s

Fourth batch. Closes the user/profile surface consumed by the
frontend users service. 6 handlers annotated across
internal/handlers/profile_handler.go (now 12/15 annotated).

Handlers annotated:
- SearchUsers            — GET    /users/search
- FollowUser             — POST   /users/{id}/follow
- GetFollowSuggestions   — GET    /users/suggestions
- UnfollowUser           — DELETE /users/{id}/follow
- BlockUser              — POST   /users/{id}/block
- UnblockUser            — DELETE /users/{id}/block

Added a blank `_ "veza-backend-api/internal/models"` import so swaggo
can resolve models.User in doc comments without forcing runtime use
(same pattern as track_hls_handler.go / track_waveform_handler.go).

Spec coverage: /users/* paths now 12 (all frontend-consumed endpoints).
make openapi:  · go build ./...: .

Completes the B-2 backend annotation scope for auth / users / tracks /
playlists — the four services that will migrate to orval in the next
commit. Remaining unannotated handlers (admin, moderation, analytics,
education, cloud, gear, social_group, etc.) are outside the v1.0.8
frontend migration and deferred to v1.0.9.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
senke 2026-04-24 01:09:05 +02:00
parent 72c5381c73
commit 9e948d5102
5 changed files with 1424 additions and 0 deletions

View file

@ -6480,6 +6480,149 @@ const docTemplate = `{
}
}
},
"/users/search": {
"get": {
"description": "Full-text search on users (username, display_name). Paginated. Public.",
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "Search users",
"parameters": [
{
"type": "string",
"description": "Full-text query",
"name": "q",
"in": "query"
},
{
"type": "integer",
"default": 1,
"description": "Page",
"name": "page",
"in": "query"
},
{
"type": "integer",
"default": 20,
"description": "Items per page (max 100)",
"name": "limit",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/internal_handlers.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"pagination": {
"type": "object"
},
"users": {
"type": "array",
"items": {
"$ref": "#/definitions/veza-backend-api_internal_models.User"
}
}
}
}
}
}
]
}
},
"400": {
"description": "Validation (bounds)",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"500": {
"description": "Internal Error",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
}
}
}
},
"/users/suggestions": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Returns suggested users to follow for the authenticated user. Declarative discovery — no behavioural scoring (CLAUDE.md rule 7).",
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "Get follow suggestions",
"parameters": [
{
"type": "integer",
"default": 10,
"description": "Max items (max 50)",
"name": "limit",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/internal_handlers.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"$ref": "#/definitions/veza-backend-api_internal_models.User"
}
}
}
}
}
}
]
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"500": {
"description": "Internal Error",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
}
}
}
},
"/users/{id}": {
"get": {
"description": "Get public profile information for a user",
@ -6679,6 +6822,142 @@ const docTemplate = `{
}
}
},
"/users/{id}/block": {
"post": {
"security": [
{
"BearerAuth": []
}
],
"description": "Authenticated user blocks target user (hides their content, prevents follows). Cannot self-block.",
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "Block user",
"parameters": [
{
"type": "string",
"description": "Target user UUID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/internal_handlers.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
}
}
}
]
}
},
"400": {
"description": "Validation / self-block",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"500": {
"description": "Internal Error",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
}
}
},
"delete": {
"security": [
{
"BearerAuth": []
}
],
"description": "Authenticated user unblocks target user (idempotent).",
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "Unblock user",
"parameters": [
{
"type": "string",
"description": "Target user UUID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/internal_handlers.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
}
}
}
]
}
},
"400": {
"description": "Invalid id",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"500": {
"description": "Internal Error",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
}
}
}
},
"/users/{id}/completion": {
"get": {
"description": "Get profile completion percentage and missing fields",
@ -6741,6 +7020,148 @@ const docTemplate = `{
}
}
},
"/users/{id}/follow": {
"post": {
"security": [
{
"BearerAuth": []
}
],
"description": "Authenticated user follows target user. Creates a notification (F554 grouped) for the target.",
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "Follow user",
"parameters": [
{
"type": "string",
"description": "Target user UUID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/internal_handlers.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
}
}
}
]
}
},
"400": {
"description": "Invalid id",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"404": {
"description": "User not found",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"500": {
"description": "Internal Error",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
}
}
},
"delete": {
"security": [
{
"BearerAuth": []
}
],
"description": "Authenticated user stops following target user (idempotent).",
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "Unfollow user",
"parameters": [
{
"type": "string",
"description": "Target user UUID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/internal_handlers.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
}
}
}
]
}
},
"400": {
"description": "Invalid id",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"500": {
"description": "Internal Error",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
}
}
}
},
"/users/{id}/likes": {
"get": {
"security": [

View file

@ -6474,6 +6474,149 @@
}
}
},
"/users/search": {
"get": {
"description": "Full-text search on users (username, display_name). Paginated. Public.",
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "Search users",
"parameters": [
{
"type": "string",
"description": "Full-text query",
"name": "q",
"in": "query"
},
{
"type": "integer",
"default": 1,
"description": "Page",
"name": "page",
"in": "query"
},
{
"type": "integer",
"default": 20,
"description": "Items per page (max 100)",
"name": "limit",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/internal_handlers.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"pagination": {
"type": "object"
},
"users": {
"type": "array",
"items": {
"$ref": "#/definitions/veza-backend-api_internal_models.User"
}
}
}
}
}
}
]
}
},
"400": {
"description": "Validation (bounds)",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"500": {
"description": "Internal Error",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
}
}
}
},
"/users/suggestions": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "Returns suggested users to follow for the authenticated user. Declarative discovery — no behavioural scoring (CLAUDE.md rule 7).",
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "Get follow suggestions",
"parameters": [
{
"type": "integer",
"default": 10,
"description": "Max items (max 50)",
"name": "limit",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/internal_handlers.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"$ref": "#/definitions/veza-backend-api_internal_models.User"
}
}
}
}
}
}
]
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"500": {
"description": "Internal Error",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
}
}
}
},
"/users/{id}": {
"get": {
"description": "Get public profile information for a user",
@ -6673,6 +6816,142 @@
}
}
},
"/users/{id}/block": {
"post": {
"security": [
{
"BearerAuth": []
}
],
"description": "Authenticated user blocks target user (hides their content, prevents follows). Cannot self-block.",
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "Block user",
"parameters": [
{
"type": "string",
"description": "Target user UUID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/internal_handlers.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
}
}
}
]
}
},
"400": {
"description": "Validation / self-block",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"500": {
"description": "Internal Error",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
}
}
},
"delete": {
"security": [
{
"BearerAuth": []
}
],
"description": "Authenticated user unblocks target user (idempotent).",
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "Unblock user",
"parameters": [
{
"type": "string",
"description": "Target user UUID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/internal_handlers.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
}
}
}
]
}
},
"400": {
"description": "Invalid id",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"500": {
"description": "Internal Error",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
}
}
}
},
"/users/{id}/completion": {
"get": {
"description": "Get profile completion percentage and missing fields",
@ -6735,6 +7014,148 @@
}
}
},
"/users/{id}/follow": {
"post": {
"security": [
{
"BearerAuth": []
}
],
"description": "Authenticated user follows target user. Creates a notification (F554 grouped) for the target.",
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "Follow user",
"parameters": [
{
"type": "string",
"description": "Target user UUID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/internal_handlers.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
}
}
}
]
}
},
"400": {
"description": "Invalid id",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"404": {
"description": "User not found",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"500": {
"description": "Internal Error",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
}
}
},
"delete": {
"security": [
{
"BearerAuth": []
}
],
"description": "Authenticated user stops following target user (idempotent).",
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "Unfollow user",
"parameters": [
{
"type": "string",
"description": "Target user UUID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/internal_handlers.APIResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
}
}
}
]
}
},
"400": {
"description": "Invalid id",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
},
"500": {
"description": "Internal Error",
"schema": {
"$ref": "#/definitions/internal_handlers.APIResponse"
}
}
}
}
},
"/users/{id}/likes": {
"get": {
"security": [

View file

@ -5129,6 +5129,88 @@ paths:
summary: Update Profile
tags:
- User
/users/{id}/block:
delete:
description: Authenticated user unblocks target user (idempotent).
parameters:
- description: Target user UUID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/internal_handlers.APIResponse'
- properties:
data:
properties:
message:
type: string
type: object
type: object
"400":
description: Invalid id
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"500":
description: Internal Error
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
security:
- BearerAuth: []
summary: Unblock user
tags:
- User
post:
description: Authenticated user blocks target user (hides their content, prevents
follows). Cannot self-block.
parameters:
- description: Target user UUID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/internal_handlers.APIResponse'
- properties:
data:
properties:
message:
type: string
type: object
type: object
"400":
description: Validation / self-block
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"500":
description: Internal Error
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
security:
- BearerAuth: []
summary: Block user
tags:
- User
/users/{id}/completion:
get:
consumes:
@ -5167,6 +5249,92 @@ paths:
summary: Get Profile Completion
tags:
- User
/users/{id}/follow:
delete:
description: Authenticated user stops following target user (idempotent).
parameters:
- description: Target user UUID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/internal_handlers.APIResponse'
- properties:
data:
properties:
message:
type: string
type: object
type: object
"400":
description: Invalid id
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"500":
description: Internal Error
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
security:
- BearerAuth: []
summary: Unfollow user
tags:
- User
post:
description: Authenticated user follows target user. Creates a notification
(F554 grouped) for the target.
parameters:
- description: Target user UUID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/internal_handlers.APIResponse'
- properties:
data:
properties:
message:
type: string
type: object
type: object
"400":
description: Invalid id
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"404":
description: User not found
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"500":
description: Internal Error
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
security:
- BearerAuth: []
summary: Follow user
tags:
- User
/users/{id}/likes:
get:
description: Returns paginated tracks the given user has liked. Used for profile
@ -5379,6 +5547,95 @@ paths:
summary: CCPA Do Not Sell opt-out
tags:
- Users
/users/search:
get:
description: Full-text search on users (username, display_name). Paginated.
Public.
parameters:
- description: Full-text query
in: query
name: q
type: string
- default: 1
description: Page
in: query
name: page
type: integer
- default: 20
description: Items per page (max 100)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/internal_handlers.APIResponse'
- properties:
data:
properties:
pagination:
type: object
users:
items:
$ref: '#/definitions/veza-backend-api_internal_models.User'
type: array
type: object
type: object
"400":
description: Validation (bounds)
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"500":
description: Internal Error
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
summary: Search users
tags:
- User
/users/suggestions:
get:
description: Returns suggested users to follow for the authenticated user. Declarative
discovery — no behavioural scoring (CLAUDE.md rule 7).
parameters:
- default: 10
description: Max items (max 50)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/internal_handlers.APIResponse'
- properties:
data:
properties:
users:
items:
$ref: '#/definitions/veza-backend-api_internal_models.User'
type: array
type: object
type: object
"401":
description: Unauthorized
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"500":
description: Internal Error
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
security:
- BearerAuth: []
summary: Get follow suggestions
tags:
- User
/validate:
post:
consumes:

View file

@ -6,6 +6,8 @@ import (
"time"
apperrors "veza-backend-api/internal/errors"
// models imported so swaggo can resolve models.User in doc comments.
_ "veza-backend-api/internal/models"
"veza-backend-api/internal/services"
"veza-backend-api/internal/types"
"veza-backend-api/internal/utils"
@ -267,6 +269,17 @@ func (h *ProfileHandler) ListUsers(c *gin.Context) {
// SearchUsers gère la recherche d'utilisateurs
// BE-API-008: Implement user search endpoint
// @Summary Search users
// @Description Full-text search on users (username, display_name). Paginated. Public.
// @Tags User
// @Produce json
// @Param q query string false "Full-text query"
// @Param page query int false "Page" default(1)
// @Param limit query int false "Items per page (max 100)" default(20)
// @Success 200 {object} handlers.APIResponse{data=object{users=[]models.User,pagination=object}}
// @Failure 400 {object} handlers.APIResponse "Validation (bounds)"
// @Failure 500 {object} handlers.APIResponse "Internal Error"
// @Router /users/search [get]
func (h *ProfileHandler) SearchUsers(c *gin.Context) {
// Récupérer les paramètres de recherche
query := c.Query("q")
@ -308,6 +321,18 @@ func (h *ProfileHandler) SearchUsers(c *gin.Context) {
// FollowUser gère le suivi d'un utilisateur
// POST /api/v1/users/:id/follow
// BE-API-017: Implement user follow/unfollow endpoints
// @Summary Follow user
// @Description Authenticated user follows target user. Creates a notification (F554 grouped) for the target.
// @Tags User
// @Produce json
// @Security BearerAuth
// @Param id path string true "Target user UUID"
// @Success 200 {object} handlers.APIResponse{data=object{message=string}}
// @Failure 400 {object} handlers.APIResponse "Invalid id"
// @Failure 401 {object} handlers.APIResponse "Unauthorized"
// @Failure 404 {object} handlers.APIResponse "User not found"
// @Failure 500 {object} handlers.APIResponse "Internal Error"
// @Router /users/{id}/follow [post]
func (h *ProfileHandler) FollowUser(c *gin.Context) {
// Récupérer l'ID de l'utilisateur à suivre depuis l'URL
userIDStr := c.Param("id")
@ -366,6 +391,16 @@ func (h *ProfileHandler) FollowUser(c *gin.Context) {
// GetFollowSuggestions returns users to follow (v0.10.0 F211)
// GET /api/v1/users/suggestions?limit=10
// @Summary Get follow suggestions
// @Description Returns suggested users to follow for the authenticated user. Declarative discovery — no behavioural scoring (CLAUDE.md rule 7).
// @Tags User
// @Produce json
// @Security BearerAuth
// @Param limit query int false "Max items (max 50)" default(10)
// @Success 200 {object} handlers.APIResponse{data=object{users=[]models.User}}
// @Failure 401 {object} handlers.APIResponse "Unauthorized"
// @Failure 500 {object} handlers.APIResponse "Internal Error"
// @Router /users/suggestions [get]
func (h *ProfileHandler) GetFollowSuggestions(c *gin.Context) {
userID, ok := GetUserIDUUID(c)
if !ok {
@ -393,6 +428,17 @@ func (h *ProfileHandler) GetFollowSuggestions(c *gin.Context) {
// UnfollowUser gère l'arrêt du suivi d'un utilisateur
// DELETE /api/v1/users/:id/follow
// BE-API-017: Implement user follow/unfollow endpoints
// @Summary Unfollow user
// @Description Authenticated user stops following target user (idempotent).
// @Tags User
// @Produce json
// @Security BearerAuth
// @Param id path string true "Target user UUID"
// @Success 200 {object} handlers.APIResponse{data=object{message=string}}
// @Failure 400 {object} handlers.APIResponse "Invalid id"
// @Failure 401 {object} handlers.APIResponse "Unauthorized"
// @Failure 500 {object} handlers.APIResponse "Internal Error"
// @Router /users/{id}/follow [delete]
func (h *ProfileHandler) UnfollowUser(c *gin.Context) {
// Récupérer l'ID de l'utilisateur à ne plus suivre depuis l'URL
userIDStr := c.Param("id")
@ -435,6 +481,17 @@ func (h *ProfileHandler) UnfollowUser(c *gin.Context) {
// BlockUser gère le blocage d'un utilisateur
// POST /api/v1/users/:id/block
// BE-API-018: Implement user block/unblock endpoints
// @Summary Block user
// @Description Authenticated user blocks target user (hides their content, prevents follows). Cannot self-block.
// @Tags User
// @Produce json
// @Security BearerAuth
// @Param id path string true "Target user UUID"
// @Success 200 {object} handlers.APIResponse{data=object{message=string}}
// @Failure 400 {object} handlers.APIResponse "Validation / self-block"
// @Failure 401 {object} handlers.APIResponse "Unauthorized"
// @Failure 500 {object} handlers.APIResponse "Internal Error"
// @Router /users/{id}/block [post]
func (h *ProfileHandler) BlockUser(c *gin.Context) {
// Récupérer l'ID de l'utilisateur à bloquer depuis l'URL
userIDStr := c.Param("id")
@ -487,6 +544,17 @@ func (h *ProfileHandler) BlockUser(c *gin.Context) {
// UnblockUser gère le déblocage d'un utilisateur
// DELETE /api/v1/users/:id/block
// BE-API-018: Implement user block/unblock endpoints
// @Summary Unblock user
// @Description Authenticated user unblocks target user (idempotent).
// @Tags User
// @Produce json
// @Security BearerAuth
// @Param id path string true "Target user UUID"
// @Success 200 {object} handlers.APIResponse{data=object{message=string}}
// @Failure 400 {object} handlers.APIResponse "Invalid id"
// @Failure 401 {object} handlers.APIResponse "Unauthorized"
// @Failure 500 {object} handlers.APIResponse "Internal Error"
// @Router /users/{id}/block [delete]
func (h *ProfileHandler) UnblockUser(c *gin.Context) {
// Récupérer l'ID de l'utilisateur à débloquer depuis l'URL
userIDStr := c.Param("id")

View file

@ -5129,6 +5129,88 @@ paths:
summary: Update Profile
tags:
- User
/users/{id}/block:
delete:
description: Authenticated user unblocks target user (idempotent).
parameters:
- description: Target user UUID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/internal_handlers.APIResponse'
- properties:
data:
properties:
message:
type: string
type: object
type: object
"400":
description: Invalid id
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"500":
description: Internal Error
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
security:
- BearerAuth: []
summary: Unblock user
tags:
- User
post:
description: Authenticated user blocks target user (hides their content, prevents
follows). Cannot self-block.
parameters:
- description: Target user UUID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/internal_handlers.APIResponse'
- properties:
data:
properties:
message:
type: string
type: object
type: object
"400":
description: Validation / self-block
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"500":
description: Internal Error
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
security:
- BearerAuth: []
summary: Block user
tags:
- User
/users/{id}/completion:
get:
consumes:
@ -5167,6 +5249,92 @@ paths:
summary: Get Profile Completion
tags:
- User
/users/{id}/follow:
delete:
description: Authenticated user stops following target user (idempotent).
parameters:
- description: Target user UUID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/internal_handlers.APIResponse'
- properties:
data:
properties:
message:
type: string
type: object
type: object
"400":
description: Invalid id
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"500":
description: Internal Error
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
security:
- BearerAuth: []
summary: Unfollow user
tags:
- User
post:
description: Authenticated user follows target user. Creates a notification
(F554 grouped) for the target.
parameters:
- description: Target user UUID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/internal_handlers.APIResponse'
- properties:
data:
properties:
message:
type: string
type: object
type: object
"400":
description: Invalid id
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"404":
description: User not found
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"500":
description: Internal Error
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
security:
- BearerAuth: []
summary: Follow user
tags:
- User
/users/{id}/likes:
get:
description: Returns paginated tracks the given user has liked. Used for profile
@ -5379,6 +5547,95 @@ paths:
summary: CCPA Do Not Sell opt-out
tags:
- Users
/users/search:
get:
description: Full-text search on users (username, display_name). Paginated.
Public.
parameters:
- description: Full-text query
in: query
name: q
type: string
- default: 1
description: Page
in: query
name: page
type: integer
- default: 20
description: Items per page (max 100)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/internal_handlers.APIResponse'
- properties:
data:
properties:
pagination:
type: object
users:
items:
$ref: '#/definitions/veza-backend-api_internal_models.User'
type: array
type: object
type: object
"400":
description: Validation (bounds)
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"500":
description: Internal Error
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
summary: Search users
tags:
- User
/users/suggestions:
get:
description: Returns suggested users to follow for the authenticated user. Declarative
discovery — no behavioural scoring (CLAUDE.md rule 7).
parameters:
- default: 10
description: Max items (max 50)
in: query
name: limit
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/internal_handlers.APIResponse'
- properties:
data:
properties:
users:
items:
$ref: '#/definitions/veza-backend-api_internal_models.User'
type: array
type: object
type: object
"401":
description: Unauthorized
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
"500":
description: Internal Error
schema:
$ref: '#/definitions/internal_handlers.APIResponse'
security:
- BearerAuth: []
summary: Get follow suggestions
tags:
- User
/validate:
post:
consumes: