From c202e0b75e5c001912f271c9fe9ceb0ecd19798c Mon Sep 17 00:00:00 2001 From: Kirill Erkaev <130300723+ks2999@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:09:12 +0300 Subject: [PATCH 1/5] Contract --- CONTRACTS.yaml | 271 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 CONTRACTS.yaml diff --git a/CONTRACTS.yaml b/CONTRACTS.yaml new file mode 100644 index 0000000..56aa202 --- /dev/null +++ b/CONTRACTS.yaml @@ -0,0 +1,271 @@ +openapi: 3.0.4 +info: + title: UserService API + version: 1.0.0 + description: API для управления пользователями, их профилями и спортивными рейтингами + +servers: + - url: https://api.user.local + description: Local Dev Server + +paths: + /users: + get: + summary: Получить список пользователей + tags: [User Management] + responses: + '200': + description: Список пользователей + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + post: + summary: Создать пользователя + tags: [User Management] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UserCreateRequest' + responses: + '201': + description: Пользователь создан + content: + application/json: + schema: + $ref: '#/components/schemas/User' + + /users/{id}: + get: + summary: Получить пользователя по ID + tags: [User Management] + parameters: + - $ref: '#/components/parameters/UserId' + responses: + '200': + description: Пользователь найден + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '404': + description: Пользователь не найден + patch: + summary: Обновить профиль пользователя + tags: [User Management] + parameters: + - $ref: '#/components/parameters/UserId' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UserUpdateRequest' + responses: + '200': + description: Профиль обновлён + content: + application/json: + schema: + $ref: '#/components/schemas/User' + + /users/{id}/mmr: + get: + summary: Получить MMR пользователя по видам спорта + tags: [User MMR] + parameters: + - $ref: '#/components/parameters/UserId' + responses: + '200': + description: MMR по видам спорта + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/UserSportMmr' + + /users/{id}/avatar: + patch: + summary: Обновить аватар пользователя + tags: [User Management] + parameters: + - $ref: '#/components/parameters/UserId' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + avatar_url: + type: string + responses: + '200': + description: Аватар обновлён + content: + application/json: + schema: + $ref: '#/components/schemas/User' + +components: + parameters: + UserId: + name: id + in: path + required: true + schema: + type: string + format: uuid + description: Идентификатор пользователя + + schemas: + User: + type: object + properties: + id: + type: string + format: uuid + name: + type: string + surname: + type: string + patronymic: + type: string + nullable: true + phone_number: + type: string + email: + type: string + format: email + nullable: true + hashed_password: + type: string + is_admin: + type: boolean + date_of_birth: + type: string + format: date + nullable: true + age: + type: integer + nullable: true + sex: + type: string + enum: [ male, female, other ] + nullable: true + weight: + type: number + format: float + nullable: true + height: + type: number + format: float + nullable: true + created_at: + type: string + format: date-time + bio: + type: string + nullable: true + avatar_url: + type: string + nullable: true + + UserCreateRequest: + type: object + required: + - name + - surname + - phone_number + - hashed_password + properties: + name: + type: string + surname: + type: string + patronymic: + type: string + phone_number: + type: string + email: + type: string + hashed_password: + type: string + is_admin: + type: boolean + date_of_birth: + type: string + format: date + age: + type: integer + sex: + type: string + enum: [ male, female, other ] + weight: + type: number + format: float + height: + type: number + format: float + bio: + type: string + avatar_url: + type: string + + UserUpdateRequest: + type: object + properties: + name: + type: string + surname: + type: string + patronymic: + type: string + phone_number: + type: string + email: + type: string + date_of_birth: + type: string + format: date + age: + type: integer + sex: + type: string + enum: [ male, female, other ] + weight: + type: number + format: float + height: + type: number + format: float + bio: + type: string + avatar_url: + type: string + + UserSportMmr: + type: object + properties: + user_id: + type: string + format: uuid + sport: + type: string + enum: [ football, boxing, basketball, chess, tennis, jiu_jitsu ] + mmr: + type: number + format: double + + ErrorResponse: + type: object + properties: + message: + type: string + code: + type: integer \ No newline at end of file From 38a2f9c93efd246a21fdf4744ea9c0d0d10a9eab Mon Sep 17 00:00:00 2001 From: Shopin-Igor Date: Thu, 3 Jul 2025 13:08:35 +0300 Subject: [PATCH 2/5] Update CONTRACTS.yaml --- CONTRACTS.yaml | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/CONTRACTS.yaml b/CONTRACTS.yaml index 56aa202..1456b7e 100644 --- a/CONTRACTS.yaml +++ b/CONTRACTS.yaml @@ -8,6 +8,10 @@ servers: - url: https://api.user.local description: Local Dev Server +security: + - UserIdHeader: [] + UserPwdHashHeader: [] + paths: /users: get: @@ -113,6 +117,27 @@ paths: $ref: '#/components/schemas/User' components: + securitySchemes: + UserIdHeader: + type: apiKey + in: header + name: X-User-UUID + description: > + RFC‑4122 UUID пользователя. Пример: 123e4567-e89b-12d3-a456-426614174000 + x-example: 123e4567-e89b-12d3-a456-426614174000 + x-pattern: '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$' + x-minLength: 36 + + UserPwdHashHeader: + type: apiKey + in: header + name: X-User-Hash + description: > + bcrypt‑hash (cost=10) от пароля + соль. Пример сокращён. + x-example: "$2b$10$7qGwYnbDOMqSdWwaZ7kz1Oppz92O1dW8r8hUWNu4DwSUjWBo9.TX2" + x-minLength: 32 + x-maxLength: 128 + parameters: UserId: name: id @@ -268,4 +293,4 @@ components: message: type: string code: - type: integer \ No newline at end of file + type: integer From f7b036d1b5f7c6b7ed34c474a3fefb9220025dcc Mon Sep 17 00:00:00 2001 From: Shopin-Igor Date: Fri, 4 Jul 2025 11:54:05 +0300 Subject: [PATCH 3/5] Update CONTRACTS.yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Правки по ревью: - PATCH - изменение одного поля - PUT - изменение всех полей Добавил: - DELETE --- CONTRACTS.yaml | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/CONTRACTS.yaml b/CONTRACTS.yaml index 1456b7e..0f2fed8 100644 --- a/CONTRACTS.yaml +++ b/CONTRACTS.yaml @@ -58,8 +58,9 @@ paths: $ref: '#/components/schemas/User' '404': description: Пользователь не найден + patch: - summary: Обновить профиль пользователя + summary: Частично обновить профиль пользователя tags: [User Management] parameters: - $ref: '#/components/parameters/UserId' @@ -71,12 +72,40 @@ paths: $ref: '#/components/schemas/UserUpdateRequest' responses: '200': - description: Профиль обновлён + description: Профиль частично обновлён content: application/json: schema: $ref: '#/components/schemas/User' + put: + summary: Полностью обновить профиль пользователя + tags: [User Management] + parameters: + - $ref: '#/components/parameters/UserId' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UserCreateRequest' + responses: + '200': + description: Профиль полностью обновлён + content: + application/json: + schema: + $ref: '#/components/schemas/User' + + delete: + summary: Удалить пользователя + tags: [User Management] + parameters: + - $ref: '#/components/parameters/UserId' + responses: + '204': + description: Пользователь удалён, контента нет + /users/{id}/mmr: get: summary: Получить MMR пользователя по видам спорта @@ -123,7 +152,7 @@ components: in: header name: X-User-UUID description: > - RFC‑4122 UUID пользователя. Пример: 123e4567-e89b-12d3-a456-426614174000 + RFC-4122 UUID пользователя. Пример: 123e4567-e89b-12d3-a456-426614174000 x-example: 123e4567-e89b-12d3-a456-426614174000 x-pattern: '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$' x-minLength: 36 @@ -133,7 +162,7 @@ components: in: header name: X-User-Hash description: > - bcrypt‑hash (cost=10) от пароля + соль. Пример сокращён. + bcrypt-hash (cost=10) от пароля + соль. Пример сокращён. x-example: "$2b$10$7qGwYnbDOMqSdWwaZ7kz1Oppz92O1dW8r8hUWNu4DwSUjWBo9.TX2" x-minLength: 32 x-maxLength: 128 @@ -207,7 +236,7 @@ components: - name - surname - phone_number - - hashed_password + - password properties: name: type: string @@ -219,7 +248,7 @@ components: type: string email: type: string - hashed_password: + password: type: string is_admin: type: boolean From c1c56d59d0f3647dc3e2d5320f5c8975bae0efbd Mon Sep 17 00:00:00 2001 From: Shopin-Igor Date: Fri, 4 Jul 2025 14:00:30 +0300 Subject: [PATCH 4/5] Update CONTRACTS.yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit поправил название поля на старое, ошибочно поменял ранее --- CONTRACTS.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRACTS.yaml b/CONTRACTS.yaml index 0f2fed8..1c750b9 100644 --- a/CONTRACTS.yaml +++ b/CONTRACTS.yaml @@ -236,7 +236,7 @@ components: - name - surname - phone_number - - password + - hashed_password properties: name: type: string From 55adcceefd0eabf72d51173b0dabaab843ce210b Mon Sep 17 00:00:00 2001 From: Shopin-Igor Date: Fri, 4 Jul 2025 14:03:29 +0300 Subject: [PATCH 5/5] Update CONTRACTS.yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit поправил название поля (password-> hashed_password) --- CONTRACTS.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRACTS.yaml b/CONTRACTS.yaml index 1c750b9..eae0194 100644 --- a/CONTRACTS.yaml +++ b/CONTRACTS.yaml @@ -248,7 +248,7 @@ components: type: string email: type: string - password: + hashed_password: type: string is_admin: type: boolean