Merge branch 'feature/H-3657' into 'master'

H-3657: задокументировал user-list-cache (источник usersListKey)

See merge request hrbox-public/api!36
This commit was merged in pull request #36.
This commit is contained in:
2026-05-28 14:02:47 +00:00
+675 -7
View File
@@ -69,6 +69,10 @@ tags:
description: Methods for admin wallet transactions — manual and excel-based credit/debit. description: Methods for admin wallet transactions — manual and excel-based credit/debit.
- name: file-processing - name: file-processing
description: Methods for polling async file processing (excel import/export, archives). Scoped to current user's files. description: Methods for polling async file processing (excel import/export, archives). Scoped to current user's files.
- name: user-list-cache
description: Methods for caching ad-hoc employee selections to pass to mass operations (e.g. wallet credit/debit).
- name: file
description: Methods for uploading files via signed-URL (S3-style two-step flow). Required before any flow that consumes file_id (e.g. wallet excel import).
- name: user-api-token - name: user-api-token
description: Methods for managing personal API tokens (PATs) for server-to-server access. Requires "api-tokens-manage" permission. description: Methods for managing personal API tokens (PATs) for server-to-server access. Requires "api-tokens-manage" permission.
- name: admin-user-api-token - name: admin-user-api-token
@@ -558,6 +562,229 @@ paths:
500: 500:
description: Server Error description: Server Error
/user/index:
get:
tags:
- user
summary: Получить список сотрудников
description: |
Возвращает постраничный список активных сотрудников тенанта.
Выдача ограничена пользователями со статусом `ACTIVE`; скрытые
и не валидные для отображения записи исключаются.
Эндпоинт может использоваться интеграциями для получения
идентификаторов пользователей (`user_id`), которые в дальнейшем
передаются в `/user-list-cache/set-user-list` или другие методы
массовых операций.
Сортировка поддерживается по нескольким полям, включая `name`,
`created_at`, `last_login_at`. Размер страницы по умолчанию — 10,
максимально допустимый — 20.
operationId: userIndex
parameters:
- name: page
in: query
schema: { type: integer, minimum: 1, default: 1 }
- name: per-page
in: query
schema: { type: integer, minimum: 1, maximum: 20, default: 10 }
- name: sort
in: query
schema: { type: string }
description: |
Поле сортировки. Для сортировки по убыванию используется префикс `-`.
Примеры: `-created_at`, `name`, `-last_login_at`.
- name: searchQuery
in: query
schema: { type: string }
description: |
Сквозной поиск по имени, фамилии, e-mail, телефону и должности.
- name: id
in: query
schema:
oneOf:
- type: string
format: uuid
- type: array
items: { type: string, format: uuid }
description: |
Идентификатор пользователя. Допускается передача нескольких
значений в виде массива `?id[]=...&id[]=...`.
- name: not_id
in: query
schema: { type: string, format: uuid }
description: Исключить пользователя с указанным идентификатором.
- name: email
in: query
schema: { type: string }
description: Поиск по электронной почте.
- name: phone_auth
in: query
schema: { type: string }
description: Поиск по номеру телефона.
- name: name
in: query
schema: { type: string }
description: Поиск по полному имени.
- name: first_name
in: query
schema: { type: string }
description: Поиск по имени.
- name: last_name
in: query
schema: { type: string }
description: Поиск по фамилии.
- name: middle_name
in: query
schema: { type: string }
description: Поиск по отчеству.
- name: position
in: query
schema: { type: string }
description: Поиск по должности.
- name: company
in: query
schema: { type: string }
description: Поиск по наименованию компании.
- name: department_id
in: query
schema:
oneOf:
- type: string
format: uuid
- type: array
items: { type: string, format: uuid }
description: Идентификатор подразделения.
- name: reg_status_id
in: query
schema: { type: string }
description: |
Статус регистрации пользователя. Допустимые значения:
`1` — без аккаунта, `2` — приглашён, `3` — активен,
`4` — заблокирован. Допускается передача нескольких значений
через запятую.
- name: gender_id
in: query
schema: { type: string }
description: Идентификатор пола.
- name: is_boss
in: query
schema: { type: boolean }
description: Признак руководящей должности.
- name: is_external
in: query
schema: { type: boolean }
description: Признак внешнего сотрудника.
- name: group_id
in: query
schema: { type: string, format: uuid }
description: Идентификатор группы сотрудников.
- name: duty_id
in: query
schema: { type: string, format: uuid }
description: Идентификатор обязанности.
- name: spec_id
in: query
schema: { type: string, format: uuid }
description: Идентификатор специализации.
- name: created_at
in: query
schema: { type: string }
description: |
Период создания записи в формате `<начало>|<конец>`,
где даты указаны по ISO 8601.
- name: last_login_at
in: query
schema: { type: string }
description: |
Период последнего входа в систему в формате `<начало>|<конец>`.
- name: user_list_key
in: query
schema: { type: string, format: uuid }
description: |
Ключ закэшированной выборки пользователей, полученный
от `/user-list-cache/set-user-list`.
- name: expand
in: query
schema: { type: string }
description: |
Список дополнительных полей через запятую. Поддерживаемые
значения: `isBoss`, `faceUrl`, `iconUrl`, `photoUrl`,
`employment`, `cityName`, `statusText`,
`profileCorporateContacts`, `isFavoriteUser`, `contacts`,
`statusTypes`.
responses:
200:
description: Список сотрудников.
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/userProfile'
_links:
$ref: '#/components/schemas/_links'
_meta:
$ref: '#/components/schemas/_meta'
401:
description: Запрос не авторизован.
/user/search:
get:
tags:
- user
summary: Найти сотрудников по строке поиска
description: |
Компактный поиск пользователей по строке. Возвращает до `limit`
записей с минимальным набором полей, достаточным для отображения
в выпадающих списках и подсказках.
Поле `users` в ответе содержит пустой массив, если параметр `q`
не передан либо у текущего пользователя отсутствует право
`show-structure-names`.
operationId: userSearch
parameters:
- name: q
in: query
required: true
schema: { type: string, maxLength: 255 }
description: |
Строка поиска. Применяется к полному имени, электронной почте,
должности и наименованию подразделения.
- name: limit
in: query
schema: { type: integer, minimum: 1, default: 10 }
description: Максимальное количество возвращаемых записей.
- name: offset
in: query
schema: { type: integer, minimum: 0, default: 0 }
description: Смещение выборки.
responses:
200:
description: Результаты поиска.
content:
application/json:
schema:
type: object
properties:
q:
type: string
users:
type: array
items:
type: object
properties:
id: { type: string, format: uuid }
name: { type: string }
employmentId: { type: string, format: uuid, nullable: true }
position: { type: string }
departmentName: { type: string }
isBoss: { type: boolean }
iconUrl: { type: string, nullable: true }
/user/items: /user/items:
get: get:
tags: tags:
@@ -7114,14 +7341,37 @@ paths:
/admin/wallet-transaction/create: /admin/wallet-transaction/create:
post: post:
tags: [admin-wallet-transaction] tags: [admin-wallet-transaction]
summary: Провести начисление/списание по форме summary: Провести начисление или списание по форме
description: | description: |
Массовая операция через `usersListKey` (ключ закэшированной выборки сотрудников). Массовая операция по выборке сотрудников. Выполняется асинхронно;
Запускается асинхронно через launcher. баланс и история транзакций обновляются в течение нескольких секунд
после успешного приёма запроса.
Soft-error состояния возвращаются в `message.type=warning`: ## Получение значения `usersListKey`
- "Укажите сотрудников" — выборка пустая
- "Невозможно провести транзакцию, у некоторых сотрудников недостаточно средств..." — debit, не хватает баланса (имена в тексте) 1. Выборка сотрудников сохраняется методом
`POST /api/v2/user-list-cache/set-user-list` с телом
`{key, userList: {usersId: [...]}}`. Срок жизни сохранённой
выборки — 24 часа.
2. Использованное значение `key` передаётся в данный метод
в качестве параметра `usersListKey`.
Подробное описание формата и пример приведены в описании метода
`/user-list-cache/set-user-list`.
## Состояния, возвращаемые с предупреждением
Ответ имеет код `200 OK` и содержит `message.type = "warning"`
в следующих случаях.
- `"Укажите сотрудников"` — выборка по `usersListKey` пустая.
Возможные причины: ключ не найден, срок его действия истёк
либо запрос `set-user-list` был выполнен в формате
`application/x-www-form-urlencoded` без последующей корректной
передачи `userList`.
- `"Невозможно провести транзакцию, у некоторых сотрудников
недостаточно средств на балансе: <имена>"` — debit, не хватает
баланса хотя бы у одного юзера; вся операция отменяется.
operationId: adminWalletTransactionCreate operationId: adminWalletTransactionCreate
requestBody: requestBody:
required: true required: true
@@ -7273,6 +7523,180 @@ paths:
schema: schema:
$ref: '#/components/schemas/FileProcessing' $ref: '#/components/schemas/FileProcessing'
/file/prepare-upload:
post:
tags: [file]
summary: Зарегистрировать файл и получить ссылку для загрузки
description: |
Первый шаг двухэтапной загрузки. Создаёт запись о файле и
возвращает временную подписанную ссылку для прямой загрузки
содержимого в объектное хранилище.
## Последовательность вызовов
1. `POST /api/v2/file/prepare-upload` с метаданными файла.
В ответе возвращаются запись `File` и объект `uploadInfo`,
содержащий ссылку `signedUrl`.
2. `PUT <signedUrl>` с содержимым файла в теле запроса
и заголовком `Content-Type`, соответствующим типу файла.
Запрос выполняется напрямую в объектное хранилище.
3. `POST /api/v2/file/finish-upload?id=<File.id>` — подтверждает
завершение загрузки. После этого идентификатор файла может
быть использован в методах, ожидающих параметр `file_id`
(например, `POST /admin/wallet-transaction/excel-processing`).
## Ошибки валидации
При несоответствии файла ограничениям по типу или размеру
возвращается объект вида `{error: {message, validation: {...}}}`.
## Идемпотентность
При передаче в теле запроса значения существующего идентификатора
возвращается имеющаяся запись. Если файл ещё не загружен —
в ответе также присутствует объект `uploadInfo` с новой ссылкой.
Для уже загруженного файла объект `uploadInfo` в ответе отсутствует.
operationId: filePrepareUpload
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/FilePrepareUploadBody'
responses:
200:
description: Файл зарегистрирован, ссылка для загрузки получена.
content:
application/json:
schema:
$ref: '#/components/schemas/FilePrepareUploadResponse'
/file/finish-upload:
post:
tags: [file]
summary: Подтвердить завершение загрузки файла
description: |
Второй шаг двухэтапной загрузки. Переводит запись о файле
в состояние UPLOADED после успешной передачи содержимого
по ссылке, полученной от `/file/prepare-upload`.
До вызова этого метода идентификатор файла не может быть
использован в методах, требующих загруженный файл. Например,
`POST /admin/wallet-transaction/excel-processing` отклонит
запрос со ссылкой на файл, не имеющий статуса UPLOADED.
operationId: fileFinishUpload
parameters:
- name: id
in: query
required: true
schema: { type: string, format: uuid }
description: |
Идентификатор файла, полученный от `/file/prepare-upload`.
responses:
200:
description: Загрузка файла подтверждена.
content:
application/json:
schema:
type: object
properties:
File:
$ref: '#/components/schemas/File'
400:
description: Параметр `id` не передан или имеет некорректный формат.
404:
description: Файл с указанным идентификатором не найден.
/user-list-cache/set-user-list:
post:
tags: [user-list-cache]
summary: Сохранить выборку сотрудников и получить её идентификатор
description: |
Сохраняет в кэше выборку сотрудников, описанную через поля
`UserListForm` (списки идентификаторов пользователей,
подразделений, групп, динамические условия и т.п.), и связывает
её с переданным ключом `key`. Полученный ключ используется
в методах массовых операций — например, передаётся в качестве
значения `usersListKey` в `POST /api/v2/admin/wallet-transaction/create`.
Время жизни ключа в кэше — 24 часа. Повторный вызов с тем же
значением `key` перезаписывает ранее сохранённую выборку.
## Требования к формату запроса
Поле `userList` представляет собой вложенный объект.
Запрос должен передаваться в формате `application/json`.
При передаче запроса в формате `application/x-www-form-urlencoded`
вложенный объект не разбирается сервером, выборка сохраняется
пустой, а последующие массовые операции возвращают предупреждение
вида `{type: "warning", text: "Укажите сотрудников"}`.
## Пример запроса
```json
POST /api/v2/user-list-cache/set-user-list
Content-Type: application/json
Authorization: Bearer hrb_...
{
"key": "integration-key-2026-05-22",
"userList": {
"usersId": ["25840ad3-a07f-4893-aa70-3a696b79a6f1"]
}
}
```
Значение `key` формируется клиентом и может содержать
до 50 символов.
operationId: userListCacheSet
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UserListCacheSetBody'
responses:
200:
description: |
Успешное сохранение выборки (`data: true`) либо ошибки валидации
в стандартном формате `httpJsonResponse`.
content:
application/json:
schema:
$ref: '#/components/schemas/httpJsonResponse'
/user-list-cache/user-list-data:
get:
tags: [user-list-cache]
summary: Получить состав сохранённой выборки сотрудников
description: |
Возвращает развёрнутый состав выборки по её ключу, включая
списки пользователей, подразделений и групп, исходное описание
выборки и нормализованные условия. Используется для
предварительного просмотра перед выполнением массовых операций.
Если ключ не найден или срок его действия истёк, поле `userList`
возвращается пустым, прочие коллекции — пустыми массивами.
operationId: userListCacheData
parameters:
- name: key
in: query
required: true
schema: { type: string, maxLength: 50 }
description: Идентификатор сохранённой выборки.
responses:
200:
description: Состав выборки.
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/httpJsonResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/UserListData'
/user-api-token: /user-api-token:
get: get:
tags: [user-api-token] tags: [user-api-token]
@@ -12642,7 +13066,12 @@ components:
file_id: file_id:
type: string type: string
format: uuid format: uuid
description: ID предварительно загруженного xlsx-файла description: |
UUID предварительно загруженного xlsx-файла. Загружается двумя
шагами через `/file/prepare-upload` → PUT по signedUrl →
`/file/finish-upload`. Файл должен быть в статусе UPLOADED
(`file_status_id = 5`), иначе сервер вернёт ошибку
«Ошибка загрузки файла».
mappings: mappings:
type: array type: array
description: | description: |
@@ -12742,6 +13171,245 @@ components:
_meta: _meta:
$ref: '#/components/schemas/_meta' $ref: '#/components/schemas/_meta'
UserListForm:
type: object
description: |
Описание выборки сотрудников. Все поля являются опциональными;
указанные критерии объединяются по логическому ИЛИ — пользователь
включается в выборку при соответствии хотя бы одному из них.
properties:
usersId:
type: array
description: Список идентификаторов пользователей.
items:
type: string
format: uuid
departmentsId:
type: array
description: |
Список идентификаторов подразделений. В выборку включаются
все сотрудники указанных подразделений.
items:
type: string
format: uuid
isDepartmentRecursive:
type: boolean
default: false
description: |
При значении `true` в выборку включаются также сотрудники
вложенных подразделений.
userGroupsId:
type: array
description: Список идентификаторов статических групп сотрудников.
items:
type: string
format: uuid
userGroupConditions:
type: array
description: |
Динамические условия выборки. Каждый элемент — объект
со структурой `{condition, operator, values}`.
items:
type: object
employmentStatuses:
type: array
description: Фильтр по статусам трудоустройства.
items:
type: integer
fileProcessingId:
type: string
format: uuid
nullable: true
description: |
Идентификатор записи `FileProcessing` с результатом обработки
xlsx-файла. При указании выборка формируется из этого результата.
UserListCacheSetBody:
type: object
required: [key, userList]
properties:
key:
type: string
maxLength: 50
description: |
Идентификатор выборки. Формируется клиентом. То же значение
передаётся в методы массовых операций в качестве `usersListKey`.
example: "integration-key-2026-05-22"
userList:
$ref: '#/components/schemas/UserListForm'
UserListData:
type: object
description: |
Развёрнутый состав сохранённой выборки. Возвращается
в ответе `GET /user-list-cache/user-list-data`.
properties:
userList:
$ref: '#/components/schemas/UserListForm'
users:
type: array
description: Пользователи, входящие в выборку.
items:
type: object
departments:
type: array
description: Подразделения, указанные в выборке.
items:
type: object
userGroups:
type: array
description: Группы, указанные в выборке.
items:
type: object
userGroupConditions:
type: array
description: Динамические условия выборки.
items:
type: object
userGroupConditionsReadable:
type: array
description: Динамические условия выборки в текстовом представлении.
items:
type: object
userGroupConditionValues:
type: array
nullable: true
description: Значения, разрешённые в динамических условиях выборки.
items:
type: object
fileProcessing:
allOf:
- $ref: '#/components/schemas/FileProcessing'
nullable: true
File:
type: object
description: Запись о файле, хранящемся в HRBox.
properties:
id: { type: string, format: uuid }
name:
type: string
description: 'Имя файла. Пример: `wallet_import.xlsx`.'
ext:
type: string
description: Расширение файла без точки.
fid:
type: string
description: |
Внутренний идентификатор файла в хранилище.
Обычно имеет вид `<id>.<ext>`.
url:
type: string
format: uri
description: |
Публичный URL для доступа к файлу.
Имеет вид `https://<домен-тенанта>/file/open/<fid>`.
file_type:
type: string
enum: [image, video, document, archive, other]
description: Тип содержимого файла.
mime_type:
type: string
description: MIME-тип файла.
size:
type: integer
description: Размер файла в байтах.
file_status_id:
type: integer
description: |
Статус загрузки файла. Допустимые значения:
* `1` — PREPARED, запись создана, содержимое не загружено;
* `5` — UPLOADED, файл загружен и доступен для использования;
* иные значения соответствуют внутренним состояниям обработки.
is_public:
type: boolean
description: Доступность файла без авторизации.
is_common:
type: boolean
description: Признак общего файла.
is_system:
type: boolean
description: Признак системного файла.
meta:
type: object
nullable: true
description: |
Произвольные метаданные файла (например, размеры изображения).
created_at: { type: string }
user_id:
type: string
format: uuid
description: Идентификатор пользователя, загрузившего файл.
chat_channel_id:
type: string
format: uuid
nullable: true
description: |
Идентификатор канала чата, к которому привязан файл,
если применимо.
FilePrepareUploadBody:
type: object
required: [name, ext, size, file_type]
properties:
name:
type: string
description: Имя файла.
example: "wallet_import.xlsx"
ext:
type: string
description: Расширение файла без точки.
example: "xlsx"
size:
type: integer
description: Размер файла в байтах.
example: 5120
file_type:
type: string
enum: [image, video, document, archive, other]
description: Тип содержимого файла.
example: document
mime_type:
type: string
description: MIME-тип файла.
example: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
is_public:
type: boolean
default: false
description: |
При значении `true` файл доступен без авторизации.
Используется, например, для изображений профиля.
meta:
type: object
description: |
Произвольные метаданные файла. Например, для изображений
могут передаваться размеры: `{"width": 100, "height": 100}`.
id:
type: string
format: uuid
description: |
Идентификатор существующей записи о файле. При передаче
возвращается имеющаяся запись (идемпотентное поведение).
FilePrepareUploadResponse:
type: object
properties:
File:
$ref: '#/components/schemas/File'
uploadInfo:
type: object
description: |
Сведения для загрузки содержимого файла. Поле отсутствует
в ответе, если файл уже находится в статусе UPLOADED.
properties:
signedUrl:
type: string
format: uri
description: |
Временная подписанная ссылка для PUT-запроса с содержимым
файла. Запрос выполняется напрямую в объектное хранилище
и не требует авторизации HRBox.
UserApiTokenStatus: UserApiTokenStatus:
type: integer type: integer
description: | description: |