1737 lines
65 KiB
YAML
1737 lines
65 KiB
YAML
openapi: 3.0.3
|
||
|
||
info:
|
||
title: Flows Service API
|
||
version: "1.0.0"
|
||
description: |
|
||
REST API сервиса **flows-backend** (`proc/flows-backend`) — управление
|
||
процессами согласования документации: маршрутами (`flows`), их шагами
|
||
(`steps`) и статусами (`statuses`), запусками согласования (`reviews`),
|
||
документами в согласовании (`documents`), действиями пользователей
|
||
(`user-actions`) и очередью задач согласующих (`tasks`).
|
||
|
||
Сервис написан на Python (**FastAPI**). Приложение собирается фабрикой
|
||
`get_app` в `src/flow/main.py`. Роутинг состоит из двух зеркальных групп
|
||
(`src/flow/routers/__init__.py`):
|
||
|
||
- публичный API — префикс `/api/v1` (`API_PREFIX`);
|
||
- внутренний API — префикс `/internal/v1` (`API_INTERNAL_PREFIX`),
|
||
предназначен для вызовов внутри кластера. Набор роутеров идентичен
|
||
публичному, но внутренний префикс исключён из проверки аутентификации.
|
||
|
||
Оба префикса могут дополнительно предваряться `PROXY_PATH_PREFIX`
|
||
(в кластере — `/flows`). Админ-панель (`sqladmin`) смонтирована по
|
||
`/api/admin/`. Интерактивная документация Swagger доступна по `/docs`,
|
||
схема — по `/openapi.json` (с учётом `root_path`).
|
||
|
||
Ниже описан публичный API (`/api/v1`). Внутренний API (`/internal/v1/*`)
|
||
имеет те же пути и тела, но не требует аутентификации на уровне приложения.
|
||
|
||
### Аутентификация
|
||
Публичные эндпоинты требуют заголовок `Authorization: Bearer <jwt>`
|
||
(`src/flow/middleware.py`, `TokenUserMiddleware`). Поддерживаются два режима:
|
||
|
||
1. **Zitadel** — если передан заголовок `identity` (`Bearer <jwt>`),
|
||
полезная нагрузка берётся из этого токена
|
||
(`urn:zitadel:iam:user:metadata`).
|
||
2. **sarex-backend** — если заголовка `identity` нет, данные берутся из
|
||
основного токена (подпись проверяется публичным RSA-ключом
|
||
`JWT_PUBLIC_KEY`).
|
||
|
||
Проверка отключается флагом `JWT_AUTH_ENABLE=False` (тогда все запросы идут
|
||
от дефолтного администратора). Пути `/docs/`, `/openapi.json/` и весь
|
||
`/internal/*` из проверки исключены.
|
||
|
||
### Авторизация (права)
|
||
Доступ к группам проверяется в `PermissionManager` (`src/flow/dependencies.py`)
|
||
по правам пользователя (`src/flow/utils/permissions.py`): напр. `flows`/`steps`/
|
||
`statuses` требуют `base.can_view_flow`/`base.can_add_flow`/… , `reviews`/
|
||
`documents` — `base.can_view_review`/`base.can_add_review`/… Пользователь с
|
||
признаком администратора проверки прав пропускает.
|
||
|
||
### Пагинация
|
||
Списочные эндпоинты используют limit/offset (`LimitOffsetParams`,
|
||
по умолчанию `limit=1000`, `offset=0`). Часть «тяжёлых» списков (`reviews`,
|
||
подсчёты) возвращается как готовый JSON (`Response(media_type=application/json)`),
|
||
поэтому их тело в схеме описано обобщённо.
|
||
|
||
### Обработка ошибок
|
||
Ошибки бизнес-логики возвращаются как `{"detail": "..."}` с
|
||
соответствующим статусом (`400`/`403`/`404`). Ошибки валидации тела/query
|
||
(Pydantic) отдаются FastAPI в стандартном формате `422`.
|
||
|
||
servers:
|
||
- url: https://api.sarex.io/flows/api/v1
|
||
description: production
|
||
- url: https://api.preprod.sarex.io/flows/api/v1
|
||
description: preprod
|
||
- url: https://stage-api.sarex.io/flows/api/v1
|
||
description: stage
|
||
|
||
security:
|
||
- bearerAuth: []
|
||
|
||
tags:
|
||
- name: flows
|
||
description: Маршруты согласования
|
||
- name: reviews
|
||
description: Запуски согласования
|
||
- name: steps
|
||
description: Шаги маршрута
|
||
- name: statuses
|
||
description: Статусы согласования
|
||
- name: documents
|
||
description: Документы в согласовании
|
||
- name: user_actions
|
||
description: Действия пользователей
|
||
- name: tasks
|
||
description: Очередь задач согласующих
|
||
|
||
paths:
|
||
/flows/:
|
||
get:
|
||
tags: [flows]
|
||
summary: Список маршрутов
|
||
description: Фильтры передаются query-параметрами (`MainFilters`). При `full=true` возвращаются вложенные шаги/статусы.
|
||
parameters:
|
||
- { $ref: '#/components/parameters/Limit' }
|
||
- { $ref: '#/components/parameters/Offset' }
|
||
- { in: query, name: full, schema: { type: boolean, default: false } }
|
||
- { in: query, name: resource_id, schema: { type: string }, description: "CSV UUID ресурсов" }
|
||
- { in: query, name: company_id, schema: { type: string } }
|
||
- { in: query, name: is_active, schema: { type: boolean } }
|
||
- { in: query, name: flow_type, schema: { $ref: '#/components/schemas/FlowType' } }
|
||
- { in: query, name: name, schema: { type: string } }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
oneOf: [ { $ref: '#/components/schemas/Flow' }, { $ref: '#/components/schemas/FullFlow' } ]
|
||
post:
|
||
tags: [flows]
|
||
summary: Создать маршрут
|
||
parameters:
|
||
- { in: query, name: full, schema: { type: boolean, default: false } }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/FlowCreate' }
|
||
responses:
|
||
'201':
|
||
description: Создан
|
||
content:
|
||
application/json:
|
||
schema:
|
||
oneOf: [ { $ref: '#/components/schemas/Flow' }, { $ref: '#/components/schemas/FullFlow' } ]
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/flows/filter/:
|
||
post:
|
||
tags: [flows]
|
||
summary: Список маршрутов по фильтру (тело)
|
||
parameters:
|
||
- { $ref: '#/components/parameters/Limit' }
|
||
- { $ref: '#/components/parameters/Offset' }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/MainFilterPostRequest' }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/Flow' } }
|
||
|
||
/flows/light/:
|
||
get:
|
||
tags: [flows]
|
||
summary: Облегчённый список маршрутов (id, name)
|
||
parameters:
|
||
- { $ref: '#/components/parameters/Limit' }
|
||
- { $ref: '#/components/parameters/Offset' }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/FlowLight' } }
|
||
|
||
/flows/count_flows_by_resource/:
|
||
get:
|
||
tags: [flows]
|
||
summary: Количество маршрутов, сгруппированное по resource_id
|
||
responses:
|
||
'200': { $ref: '#/components/responses/JsonObject' }
|
||
post:
|
||
tags: [flows]
|
||
summary: То же по фильтру (тело)
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/MainFilterPostRequest' }
|
||
responses:
|
||
'200': { $ref: '#/components/responses/JsonObject' }
|
||
|
||
/flows/bulk-update/:
|
||
patch:
|
||
tags: [flows]
|
||
summary: Массовое обновление маршрутов (watchers/approvers)
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/FlowBulkUpdate' }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/Flow' } }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/flows/{instance_id}/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
get:
|
||
tags: [flows]
|
||
summary: Маршрут по id
|
||
parameters:
|
||
- { in: query, name: full, schema: { type: boolean, default: false } }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
oneOf: [ { $ref: '#/components/schemas/Flow' }, { $ref: '#/components/schemas/FullFlow' } ]
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
put:
|
||
tags: [flows]
|
||
summary: Обновить маршрут
|
||
parameters:
|
||
- { in: query, name: full, schema: { type: boolean, default: false } }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/FlowCreate' }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
oneOf: [ { $ref: '#/components/schemas/Flow' }, { $ref: '#/components/schemas/FullFlow' } ]
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
delete:
|
||
tags: [flows]
|
||
summary: Удалить маршрут
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Flow' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/flows/{instance_id}/copy/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
post:
|
||
tags: [flows]
|
||
summary: Копировать маршрут
|
||
parameters:
|
||
- { in: query, name: full, schema: { type: boolean, default: false } }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/CopyFlow' }
|
||
responses:
|
||
'201':
|
||
description: Создан
|
||
content:
|
||
application/json:
|
||
schema:
|
||
oneOf: [ { $ref: '#/components/schemas/Flow' }, { $ref: '#/components/schemas/FullFlow' } ]
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/reviews/:
|
||
get:
|
||
tags: [reviews]
|
||
summary: Список review (готовый JSON)
|
||
parameters:
|
||
- { $ref: '#/components/parameters/Limit' }
|
||
- { $ref: '#/components/parameters/Offset' }
|
||
- { in: query, name: join_user_actions, schema: { type: boolean, default: false } }
|
||
- { in: query, name: resource_id, schema: { type: string } }
|
||
- { in: query, name: flow_id, schema: { type: string } }
|
||
- { in: query, name: company_id, schema: { type: string } }
|
||
- { in: query, name: status, schema: { type: string }, description: "CSV значений StateReview" }
|
||
responses:
|
||
'200': { $ref: '#/components/responses/JsonArray' }
|
||
post:
|
||
tags: [reviews]
|
||
summary: Создать review
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/BaseReview' }
|
||
responses:
|
||
'201':
|
||
description: Создан
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Review' }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/reviews/filter/:
|
||
post:
|
||
tags: [reviews]
|
||
summary: Список review по фильтру (тело)
|
||
parameters:
|
||
- { $ref: '#/components/parameters/Limit' }
|
||
- { $ref: '#/components/parameters/Offset' }
|
||
- { in: query, name: join_user_actions, schema: { type: boolean, default: false } }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/MainFilterPostRequest' }
|
||
responses:
|
||
'200': { $ref: '#/components/responses/JsonArray' }
|
||
|
||
/reviews/light/:
|
||
get:
|
||
tags: [reviews]
|
||
summary: Облегчённый список review
|
||
parameters:
|
||
- { $ref: '#/components/parameters/Limit' }
|
||
- { $ref: '#/components/parameters/Offset' }
|
||
- { in: query, name: resource_id, schema: { type: string } }
|
||
- { in: query, name: flow_id, schema: { type: string } }
|
||
- { in: query, name: company_id, schema: { type: string } }
|
||
responses:
|
||
'200': { $ref: '#/components/responses/JsonArray' }
|
||
|
||
/reviews/tasks-count/:
|
||
get:
|
||
tags: [reviews]
|
||
summary: Количество задач текущего пользователя
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/TasksCount' }
|
||
|
||
/reviews/count_by_resource_id/:
|
||
get:
|
||
tags: [reviews]
|
||
summary: Количество review по resource_id
|
||
responses:
|
||
'200': { $ref: '#/components/responses/JsonObject' }
|
||
post:
|
||
tags: [reviews]
|
||
summary: То же по фильтру (тело)
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/MainFilterPostRequest' }
|
||
responses:
|
||
'200': { $ref: '#/components/responses/JsonObject' }
|
||
|
||
/reviews/count_by_reviewer_id/:
|
||
get:
|
||
tags: [reviews]
|
||
summary: Количество review по reviewer_id
|
||
responses:
|
||
'200': { $ref: '#/components/responses/JsonObject' }
|
||
post:
|
||
tags: [reviews]
|
||
summary: То же по фильтру (тело)
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/MainFilterPostRequest' }
|
||
responses:
|
||
'200': { $ref: '#/components/responses/JsonObject' }
|
||
|
||
/reviews/bulk-reviewers-update/:
|
||
patch:
|
||
tags: [reviews]
|
||
summary: Массовое обновление согласующих в review
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/BulkReviewersUpdate' }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/Review' } }
|
||
|
||
/reviews/{instance_id}/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
get:
|
||
tags: [reviews]
|
||
summary: Review по id
|
||
responses:
|
||
'200': { $ref: '#/components/responses/ReviewOk' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
put:
|
||
tags: [reviews]
|
||
summary: Обновить review
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/UpdateBaseReview' }
|
||
responses:
|
||
'200': { $ref: '#/components/responses/ReviewOk' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
patch:
|
||
tags: [reviews]
|
||
summary: Частичное обновление review
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/PatchBaseReview' }
|
||
responses:
|
||
'200': { $ref: '#/components/responses/ReviewOk' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
delete:
|
||
tags: [reviews]
|
||
summary: Удалить review
|
||
responses:
|
||
'200': { $ref: '#/components/responses/ReviewOk' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/reviews/{instance_id}/restart/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
post:
|
||
tags: [reviews]
|
||
summary: Пересчитать динамические поля review
|
||
responses:
|
||
'200': { $ref: '#/components/responses/ReviewOk' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/reviews/{instance_id}/documents/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
get:
|
||
tags: [reviews]
|
||
summary: Документы review
|
||
parameters:
|
||
- { $ref: '#/components/parameters/Limit' }
|
||
- { $ref: '#/components/parameters/Offset' }
|
||
- { in: query, name: document_type, schema: { type: string }, description: "CSV" }
|
||
- { in: query, name: bundle_id, schema: { type: string }, description: "CSV" }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/Document' } }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
put:
|
||
tags: [reviews]
|
||
summary: Обновить статус документов review
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/BaseUpdateDocument' }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/Document' } }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/reviews/{instance_id}/start/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
patch:
|
||
tags: [reviews]
|
||
summary: Начать проверку (таймтрекинг)
|
||
responses:
|
||
'200': { $ref: '#/components/responses/JsonObject' }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/reviews/{instance_id}/approve/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
patch:
|
||
tags: [reviews]
|
||
summary: Пройти review согласующим (принять/отклонить/подписать/аннулировать)
|
||
requestBody:
|
||
required: false
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/StatusForReview' }
|
||
responses:
|
||
'200': { $ref: '#/components/responses/ReviewOk' }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/reviews/{instance_id}/update-bundles/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
patch:
|
||
tags: [reviews]
|
||
summary: Обновить bundle_id подписанных документов
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { type: object, additionalProperties: true }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/Document' } }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/reviews/{instance_id}/update-documents/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
patch:
|
||
tags: [reviews]
|
||
summary: Обновить copied-id документов
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/UpdateDocumentCopiedIds' } }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/Document' } }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/reviews/{instance_id}/change_reviewers/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
patch:
|
||
tags: [reviews]
|
||
summary: Заменить согласующих на текущем шаге
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/PatchCurrentReviewers' } }
|
||
responses:
|
||
'200': { $ref: '#/components/responses/ReviewOk' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/reviews/{instance_id}/change-min-reviewers/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
patch:
|
||
tags: [reviews]
|
||
summary: Изменить минимальное число согласующих на шаге
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/PatchMinReviewersOnStep' }
|
||
responses:
|
||
'200': { $ref: '#/components/responses/ReviewOk' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/reviews/{instance_id}/set-step/{step_id}/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
- { in: path, name: step_id, required: true, schema: { type: integer } }
|
||
patch:
|
||
tags: [reviews]
|
||
summary: Принудительно установить шаг review (только админ)
|
||
responses:
|
||
'200': { $ref: '#/components/responses/ReviewOk' }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/reviews/{instance_id}/switch_to_next_step/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
patch:
|
||
tags: [reviews]
|
||
summary: Перевести review на следующий шаг (только superuser)
|
||
responses:
|
||
'200': { $ref: '#/components/responses/ReviewOk' }
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/reviews/{instance_id}/time-tracking/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
get:
|
||
tags: [reviews]
|
||
summary: Таймтрекинг review
|
||
responses:
|
||
'200': { $ref: '#/components/responses/JsonObject' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/reviews/{review_id}/checklist-results/:
|
||
parameters:
|
||
- { in: path, name: review_id, required: true, schema: { type: integer } }
|
||
patch:
|
||
tags: [reviews]
|
||
summary: Обновить результаты чек-листов review
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/ChecklistResultsUpdateRequest' }
|
||
responses:
|
||
'200': { $ref: '#/components/responses/ReviewOk' }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/reviews/{review_id}/transmittal-created/:
|
||
parameters:
|
||
- { in: path, name: review_id, required: true, schema: { type: integer } }
|
||
post:
|
||
tags: [reviews]
|
||
summary: Зафиксировать созданную по review передачу (transmittal)
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/TransmittalForReviewCreated' }
|
||
responses:
|
||
'200': { $ref: '#/components/responses/ReviewOk' }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/steps/:
|
||
get:
|
||
tags: [steps]
|
||
summary: Список шагов
|
||
parameters:
|
||
- { $ref: '#/components/parameters/Limit' }
|
||
- { $ref: '#/components/parameters/Offset' }
|
||
- { in: query, name: full, schema: { type: boolean, default: false } }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/Step' } }
|
||
post:
|
||
tags: [steps]
|
||
summary: Создать шаг
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/BaseStep' }
|
||
responses:
|
||
'201':
|
||
description: Создан
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Step' }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/steps/{instance_id}/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
get:
|
||
tags: [steps]
|
||
summary: Шаг по id
|
||
parameters:
|
||
- { in: query, name: full, schema: { type: boolean, default: false } }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Step' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
put:
|
||
tags: [steps]
|
||
summary: Обновить шаг
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/BaseStep' }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Step' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
delete:
|
||
tags: [steps]
|
||
summary: Удалить шаг
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Step' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/steps/{instance_id}/active_reviews/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
get:
|
||
tags: [steps]
|
||
summary: Активные review на шаге
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/ActiveReview' } }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/steps/{instance_id}/update_reviewers/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
patch:
|
||
tags: [steps]
|
||
summary: Обновить согласующих шага
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/UpdatedReviewer' } }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Step' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/steps/{instance_id}/get_reviewers/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
get:
|
||
tags: [steps]
|
||
summary: Допустимые согласующие для шага
|
||
parameters:
|
||
- { in: query, name: review_id, schema: { type: integer } }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { type: object, additionalProperties: true } }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/statuses/:
|
||
get:
|
||
tags: [statuses]
|
||
summary: Список статусов
|
||
parameters:
|
||
- { $ref: '#/components/parameters/Limit' }
|
||
- { $ref: '#/components/parameters/Offset' }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/Status' } }
|
||
post:
|
||
tags: [statuses]
|
||
summary: Создать статус
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/BaseStatus' }
|
||
responses:
|
||
'201':
|
||
description: Создан
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Status' }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/statuses/{instance_id}/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
get:
|
||
tags: [statuses]
|
||
summary: Статус по id
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Status' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
put:
|
||
tags: [statuses]
|
||
summary: Обновить статус
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/BaseStatus' }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Status' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
delete:
|
||
tags: [statuses]
|
||
summary: Удалить статус
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Status' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/documents/:
|
||
get:
|
||
tags: [documents]
|
||
summary: Список документов
|
||
description: При `full=true` возвращаются расширенные записи (`ExtendDocument`) с данными review.
|
||
parameters:
|
||
- { $ref: '#/components/parameters/Limit' }
|
||
- { $ref: '#/components/parameters/Offset' }
|
||
- { in: query, name: full, schema: { type: boolean, default: false } }
|
||
- { in: query, name: flow_ids, schema: { type: string }, description: "CSV" }
|
||
- { in: query, name: review_ids, schema: { type: string }, description: "CSV" }
|
||
- { in: query, name: document_ids, schema: { type: string }, description: "CSV" }
|
||
- { in: query, name: bundle_ids, schema: { type: string }, description: "CSV" }
|
||
- { in: query, name: review_status, schema: { type: string }, description: "CSV" }
|
||
- { in: query, name: document_types, schema: { type: string }, description: "CSV" }
|
||
- { in: query, name: document_copied_ids, schema: { type: string }, description: "CSV" }
|
||
- { in: query, name: bundle_copied_ids, schema: { type: string }, description: "CSV" }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
oneOf: [ { $ref: '#/components/schemas/Document' }, { $ref: '#/components/schemas/ExtendDocument' } ]
|
||
post:
|
||
tags: [documents]
|
||
summary: Создать документы (пакетно)
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/BaseDocument' } }
|
||
responses:
|
||
'201':
|
||
description: Создано
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/Document' } }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/documents/filter/:
|
||
post:
|
||
tags: [documents]
|
||
summary: Список документов по фильтру (тело)
|
||
parameters:
|
||
- { $ref: '#/components/parameters/Limit' }
|
||
- { $ref: '#/components/parameters/Offset' }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/DocumentFilterRequest' }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: array
|
||
items:
|
||
oneOf: [ { $ref: '#/components/schemas/Document' }, { $ref: '#/components/schemas/ExtendDocument' } ]
|
||
|
||
/documents/change-copy-paths/:
|
||
patch:
|
||
tags: [documents]
|
||
summary: Изменить пути копирования документов
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/ChangeDocumentCopyPath' } }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/Document' } }
|
||
|
||
/documents/set-status/:
|
||
patch:
|
||
tags: [documents]
|
||
summary: Установить статус документам
|
||
parameters:
|
||
- { in: query, name: document_ids, required: true, schema: { type: string }, description: "CSV id документов" }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/SetDocumentStatusUpdate' }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/SetDocumentStatusRead' } }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/documents/{instance_id}/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
get:
|
||
tags: [documents]
|
||
summary: Документ по id
|
||
responses:
|
||
'200': { $ref: '#/components/responses/DocumentOk' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
put:
|
||
tags: [documents]
|
||
summary: Обновить статус документа
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/BaseUpdateDocument' }
|
||
responses:
|
||
'200': { $ref: '#/components/responses/DocumentOk' }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
patch:
|
||
tags: [documents]
|
||
summary: Установить bundle_id и статус документа
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/SetDocumentBundleIdAndStatus' }
|
||
responses:
|
||
'200': { $ref: '#/components/responses/DocumentOk' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
delete:
|
||
tags: [documents]
|
||
summary: Удалить документ
|
||
responses:
|
||
'200': { $ref: '#/components/responses/DocumentOk' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/user-actions/:
|
||
post:
|
||
tags: [user_actions]
|
||
summary: Создать действие пользователя
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/BaseUserAction' }
|
||
responses:
|
||
'201':
|
||
description: Создано
|
||
content:
|
||
application/json:
|
||
schema: { type: object, properties: { detail: { type: string } } }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/user-actions/bulk-delete-user-action/:
|
||
delete:
|
||
tags: [user_actions]
|
||
summary: Массовое удаление действий
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/ListUserActionsForDelete' }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
deleted_ids: { type: array, items: { type: integer } }
|
||
|
||
/user-actions/{instance_id}/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
patch:
|
||
tags: [user_actions]
|
||
summary: Обновить key/value действия
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/UpdateUserAction' }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/UserActions' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/tasks/:
|
||
get:
|
||
tags: [tasks]
|
||
summary: Список задач очереди
|
||
parameters:
|
||
- { $ref: '#/components/parameters/Limit' }
|
||
- { $ref: '#/components/parameters/Offset' }
|
||
- { in: query, name: review_id, schema: { type: integer } }
|
||
- { in: query, name: reviewer_id, schema: { type: integer } }
|
||
- { in: query, name: is_active, schema: { type: boolean } }
|
||
- { in: query, name: resource_id, schema: { type: string } }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/Task' } }
|
||
|
||
/tasks/reviewers-max-end-dates/:
|
||
get:
|
||
tags: [tasks]
|
||
summary: Максимальные даты окончания задач по согласующим
|
||
parameters:
|
||
- { in: query, name: reviewers_ids, required: true, schema: { type: string }, description: "CSV id" }
|
||
- { in: query, name: duration, required: true, schema: { type: integer } }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { $ref: '#/components/schemas/ReviewerMaxTaskEndDate' } }
|
||
|
||
/tasks/{instance_id}/change-priority/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
patch:
|
||
tags: [tasks]
|
||
summary: Изменить приоритет задачи
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/TaskUpdatePriority' }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Task' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/tasks/{instance_id}/change-duration/:
|
||
parameters:
|
||
- { $ref: '#/components/parameters/InstanceId' }
|
||
patch:
|
||
tags: [tasks]
|
||
summary: Изменить длительность задачи
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/TaskUpdateDuration' }
|
||
responses:
|
||
'200':
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Task' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
components:
|
||
securitySchemes:
|
||
bearerAuth:
|
||
type: http
|
||
scheme: bearer
|
||
bearerFormat: JWT
|
||
description: "Основной токен. Дополнительно может передаваться заголовок `identity: Bearer <jwt>` для режима Zitadel."
|
||
|
||
parameters:
|
||
Limit:
|
||
in: query
|
||
name: limit
|
||
schema: { type: integer, minimum: 0, default: 1000 }
|
||
Offset:
|
||
in: query
|
||
name: offset
|
||
schema: { type: integer, minimum: 0, default: 0 }
|
||
InstanceId:
|
||
in: path
|
||
name: instance_id
|
||
required: true
|
||
schema: { type: integer }
|
||
|
||
responses:
|
||
BadRequest:
|
||
description: Ошибка запроса
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/ApiError' }
|
||
Forbidden:
|
||
description: Недостаточно прав
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/ApiError' }
|
||
NotFound:
|
||
description: Не найдено
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/ApiError' }
|
||
JsonObject:
|
||
description: Готовый JSON-объект (структура зависит от группировки)
|
||
content:
|
||
application/json:
|
||
schema: { type: object, additionalProperties: true }
|
||
JsonArray:
|
||
description: Готовый JSON-массив review (сериализуется на стороне сервиса)
|
||
content:
|
||
application/json:
|
||
schema: { type: array, items: { type: object, additionalProperties: true } }
|
||
ReviewOk:
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Review' }
|
||
DocumentOk:
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Document' }
|
||
|
||
schemas:
|
||
ApiError:
|
||
type: object
|
||
properties:
|
||
detail:
|
||
oneOf: [ { type: string }, { type: array, items: { type: object } } ]
|
||
|
||
FlowType:
|
||
type: string
|
||
enum: [document, schedule]
|
||
Action:
|
||
type: string
|
||
enum: ['Отсутствует', 'Скопировать в папку']
|
||
StatusKey:
|
||
type: string
|
||
enum: ['Согласовано', 'Не согласовано']
|
||
StateReview:
|
||
type: string
|
||
nullable: true
|
||
enum: ['Начато', 'Открыто', 'Копирование документов', 'На подписании', 'Закрыто', 'Завершено', 'Аннулировано']
|
||
StepType:
|
||
type: string
|
||
enum: ['Инициализирующий', 'Обычный', 'Финальный']
|
||
ChangeCopyPathRole:
|
||
type: string
|
||
enum: ['Инициатор при запуске', 'Утверждающий при завершении', 'Инициатор и утверждающий', 'Возможность отсутствует']
|
||
AcceptanceByReviewer:
|
||
type: string
|
||
enum: [accepted, rejected, partly_rejected]
|
||
TimeTrackingMode:
|
||
type: string
|
||
enum: [auto, manual]
|
||
CompletionNotificationsMode:
|
||
type: string
|
||
enum: [disabled, positive_documents_only, all_documents]
|
||
TransmittalDocumentsStatus:
|
||
type: string
|
||
enum: [accepted_only, all_documents]
|
||
TransmittalDocumentsType:
|
||
type: string
|
||
enum: [copy_only, original_only]
|
||
BulkListUpdateType:
|
||
type: string
|
||
enum: [replace, add]
|
||
|
||
FlowActonAdditions:
|
||
type: object
|
||
properties:
|
||
enable_stamp: { type: boolean }
|
||
enable_signature: { type: boolean }
|
||
enable_qr_code: { type: boolean }
|
||
enable_base_plan: { type: boolean }
|
||
required: [enable_stamp, enable_signature, enable_qr_code, enable_base_plan]
|
||
|
||
StepChecklistAssignment:
|
||
type: object
|
||
properties:
|
||
required: { type: boolean }
|
||
reviewers: { type: array, items: { type: string, format: uuid } }
|
||
required: [required, reviewers]
|
||
|
||
BaseFlow:
|
||
type: object
|
||
properties:
|
||
name: { type: string }
|
||
description: { type: string, nullable: true }
|
||
action: { $ref: '#/components/schemas/Action' }
|
||
additions: { $ref: '#/components/schemas/FlowActonAdditions' }
|
||
meta_data: { type: object, additionalProperties: true }
|
||
folder_dst: { type: string, nullable: true }
|
||
folder_dst_relative: { type: string, nullable: true }
|
||
folder_label: { type: string, nullable: true }
|
||
is_active: { type: boolean, nullable: true }
|
||
count_of_step: { type: integer, minimum: 0 }
|
||
launchers: { type: array, items: { type: string, format: uuid } }
|
||
approvers: { type: array, nullable: true, items: { type: string, format: uuid } }
|
||
company_id: { type: integer }
|
||
creator_id: { type: integer, nullable: true }
|
||
changer_id: { type: integer, nullable: true }
|
||
signatories: { type: array, nullable: true, items: { type: integer } }
|
||
resource_id: { type: string, format: uuid, nullable: true }
|
||
steps: { type: array, items: { type: integer } }
|
||
statuses: { type: array, items: { type: integer } }
|
||
change_copy_path_role: { $ref: '#/components/schemas/ChangeCopyPathRole' }
|
||
final_step_duration: { type: integer, nullable: true }
|
||
step_watchers: { type: object, additionalProperties: { type: array, items: { type: string } } }
|
||
flow_type: { $ref: '#/components/schemas/FlowType' }
|
||
finish_step_after_review: { type: boolean }
|
||
skip_empty_steps: { type: boolean }
|
||
time_tracking_mode: { $ref: '#/components/schemas/TimeTrackingMode' }
|
||
attributes: { type: object, additionalProperties: true }
|
||
unset_attributes: { type: array, items: { type: integer } }
|
||
completion_notifications_mode: { $ref: '#/components/schemas/CompletionNotificationsMode' }
|
||
completion_notifications_receivers: { type: array, items: { type: string, format: uuid } }
|
||
checklists: { type: object, additionalProperties: { $ref: '#/components/schemas/StepChecklistAssignment' } }
|
||
transmittal_after_review: { type: boolean }
|
||
transmittal_templates: { type: array, items: { type: string, format: uuid } }
|
||
transmittal_doc_statuses: { $ref: '#/components/schemas/TransmittalDocumentsStatus' }
|
||
transmittal_doc_types: { $ref: '#/components/schemas/TransmittalDocumentsType' }
|
||
folder_dst_ai_assist_enabled: { type: boolean }
|
||
required: [name, additions, meta_data, count_of_step, launchers, company_id]
|
||
|
||
FlowCreate:
|
||
allOf:
|
||
- { $ref: '#/components/schemas/BaseFlow' }
|
||
|
||
Flow:
|
||
allOf:
|
||
- { $ref: '#/components/schemas/BaseFlow' }
|
||
- type: object
|
||
properties:
|
||
id: { type: integer }
|
||
created_at: { type: string, format: date-time }
|
||
updated_at: { type: string, format: date-time }
|
||
required: [id, created_at, updated_at]
|
||
|
||
FullFlow:
|
||
allOf:
|
||
- { $ref: '#/components/schemas/BaseFlow' }
|
||
- type: object
|
||
properties:
|
||
id: { type: integer }
|
||
created_at: { type: string, format: date-time }
|
||
updated_at: { type: string, format: date-time }
|
||
steps: { type: array, items: { $ref: '#/components/schemas/FullStep' } }
|
||
statuses: { type: array, items: { $ref: '#/components/schemas/Status' } }
|
||
required: [id, created_at, updated_at]
|
||
|
||
FlowLight:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
name: { type: string }
|
||
required: [id, name]
|
||
|
||
CopyFlow:
|
||
type: object
|
||
properties:
|
||
name: { type: string }
|
||
required: [name]
|
||
|
||
BulkUpdateListUUID4FieldAction:
|
||
type: object
|
||
properties:
|
||
action: { $ref: '#/components/schemas/BulkListUpdateType' }
|
||
value: { type: array, items: { type: string, format: uuid } }
|
||
required: [action, value]
|
||
|
||
FlowBulkUpdate:
|
||
type: object
|
||
properties:
|
||
ids: { type: array, items: { type: integer } }
|
||
watchers: { $ref: '#/components/schemas/BulkUpdateListUUID4FieldAction' }
|
||
approvers: { $ref: '#/components/schemas/BulkUpdateListUUID4FieldAction' }
|
||
required: [ids]
|
||
|
||
BaseStep:
|
||
type: object
|
||
properties:
|
||
name: { type: string }
|
||
duration: { type: integer, minimum: 0 }
|
||
min_reviewers: { type: integer, nullable: true }
|
||
all_verify: { type: boolean, default: true }
|
||
force_close: { type: boolean, default: false }
|
||
force_close_block_status: { type: boolean, default: false }
|
||
setup_next_step: { type: boolean, default: false }
|
||
task_queue: { type: boolean, default: false }
|
||
set_status: { type: boolean, default: false }
|
||
blocking_step: { type: boolean, default: false }
|
||
flow_id: { type: integer }
|
||
reviewers: { type: array, items: { type: string, format: uuid } }
|
||
blocking_reviewers: { type: array, items: { type: string, format: uuid } }
|
||
only_final_step_blocking: { type: boolean, default: false }
|
||
min_reviewers_by_sa: { type: object, additionalProperties: { type: integer } }
|
||
close_on_rejection: { type: boolean, default: false }
|
||
complete_on_rejection: { type: boolean, default: false }
|
||
complete_on_rejection_reviewers: { type: array, items: { type: string, format: uuid } }
|
||
checklists: { type: object, additionalProperties: { $ref: '#/components/schemas/StepChecklistAssignment' } }
|
||
force_next_step_reviewers: { type: array, items: { type: string, format: uuid } }
|
||
pinned_reviewers: { type: array, items: { type: string, format: uuid } }
|
||
required: [name, duration, flow_id]
|
||
|
||
Step:
|
||
allOf:
|
||
- { $ref: '#/components/schemas/BaseStep' }
|
||
- type: object
|
||
properties:
|
||
id: { type: integer }
|
||
type: { $ref: '#/components/schemas/StepType' }
|
||
required: [id, type]
|
||
|
||
FullStep:
|
||
allOf:
|
||
- { $ref: '#/components/schemas/Step' }
|
||
|
||
ActiveReview:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
name: { type: string }
|
||
required: [id, name]
|
||
|
||
UpdatedReviewer:
|
||
type: object
|
||
properties:
|
||
new_account: { type: string, format: uuid }
|
||
old_account: { type: string, format: uuid, nullable: true }
|
||
skip: { type: boolean }
|
||
required: [new_account, skip]
|
||
|
||
BaseStatus:
|
||
type: object
|
||
properties:
|
||
key: { $ref: '#/components/schemas/StatusKey' }
|
||
value: { type: string }
|
||
flow_id: { type: integer }
|
||
required: [value, flow_id]
|
||
|
||
Status:
|
||
allOf:
|
||
- { $ref: '#/components/schemas/BaseStatus' }
|
||
- type: object
|
||
properties:
|
||
id: { type: integer }
|
||
required: [id]
|
||
|
||
StatusForDocument:
|
||
type: object
|
||
properties:
|
||
key: { type: string }
|
||
value: { type: string }
|
||
id: { type: integer, nullable: true }
|
||
is_copied: { type: boolean, nullable: true }
|
||
bundles_history: { type: array, nullable: true, items: {} }
|
||
required: [key, value]
|
||
|
||
BaseDocument:
|
||
type: object
|
||
properties:
|
||
document_id: { type: integer, minimum: 1 }
|
||
bundle_id: { type: string, format: uuid }
|
||
review_id: { type: integer, minimum: 1 }
|
||
instance_id: { type: integer, nullable: true }
|
||
document_type: { type: string, nullable: true }
|
||
document_copied_id: { type: integer, nullable: true }
|
||
bundle_copied_id: { type: string, format: uuid, nullable: true }
|
||
required: [document_id, bundle_id, review_id]
|
||
|
||
Document:
|
||
allOf:
|
||
- { $ref: '#/components/schemas/BaseDocument' }
|
||
- type: object
|
||
properties:
|
||
id: { type: integer }
|
||
status: { $ref: '#/components/schemas/StatusForDocument' }
|
||
copy_to_folder_dst: { type: string, nullable: true }
|
||
copy_to_folder_label: { type: string, nullable: true }
|
||
is_accepted: { type: boolean, nullable: true }
|
||
statuses: { type: array, nullable: true, items: { $ref: '#/components/schemas/SetDocumentStatusRead' } }
|
||
acceptance_by_reviewer: { $ref: '#/components/schemas/AcceptanceByReviewer' }
|
||
required: [id]
|
||
|
||
ExtendDocument:
|
||
allOf:
|
||
- { $ref: '#/components/schemas/Document' }
|
||
- type: object
|
||
properties:
|
||
review: { type: string }
|
||
review_status: { type: string }
|
||
review_completed_at: { type: string, format: date-time, nullable: true }
|
||
flow_id: { type: integer }
|
||
review_comments: { type: array, items: { $ref: '#/components/schemas/ReviewComment' } }
|
||
required: [review, review_status, flow_id]
|
||
|
||
BaseUpdateDocument:
|
||
type: object
|
||
properties:
|
||
status: { $ref: '#/components/schemas/StatusForDocument' }
|
||
required: [status]
|
||
|
||
ChangeDocumentCopyPath:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
copy_to_folder_dst: { type: string }
|
||
copy_to_folder_label: { type: string }
|
||
required: [id, copy_to_folder_dst, copy_to_folder_label]
|
||
|
||
SetDocumentStatusUpdate:
|
||
type: object
|
||
properties:
|
||
status_id: { type: integer }
|
||
required: [status_id]
|
||
|
||
SetDocumentStatusRead:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
document_id: { type: integer }
|
||
user_id: { type: integer }
|
||
step: { $ref: '#/components/schemas/Step' }
|
||
status: { $ref: '#/components/schemas/Status' }
|
||
required: [id, document_id, user_id, step, status]
|
||
|
||
SetDocumentBundleIdAndStatus:
|
||
type: object
|
||
properties:
|
||
bundle_id: { type: string, format: uuid, nullable: true }
|
||
status: { $ref: '#/components/schemas/StatusForDocument' }
|
||
|
||
UpdateDocumentCopiedIds:
|
||
type: object
|
||
properties:
|
||
document_id: { type: integer }
|
||
document_copied_id: { type: integer }
|
||
bundle_copied_id: { type: string, format: uuid }
|
||
required: [document_id, document_copied_id, bundle_copied_id]
|
||
|
||
DocumentFilterRequest:
|
||
type: object
|
||
properties:
|
||
flow_ids: { type: string, nullable: true }
|
||
review_ids: { type: string, nullable: true }
|
||
document_ids: { type: string, nullable: true }
|
||
bundle_ids: { type: string, nullable: true }
|
||
review_status: { type: string, nullable: true }
|
||
document_types: { type: string, nullable: true }
|
||
document_copied_ids: { type: string, nullable: true }
|
||
bundle_copied_ids: { type: string, nullable: true }
|
||
full: { type: boolean, default: false }
|
||
|
||
ReviewComment:
|
||
type: object
|
||
properties:
|
||
comment: { type: string }
|
||
creator_id: { type: integer }
|
||
created_at: { type: string, format: date-time }
|
||
step_name: { type: string }
|
||
required: [comment, creator_id, created_at, step_name]
|
||
|
||
BaseCreateDocument:
|
||
type: object
|
||
properties:
|
||
document_id: { type: integer, minimum: 1 }
|
||
bundle_id: { type: string, format: uuid, nullable: true }
|
||
is_folder: { type: boolean, default: false }
|
||
instance_id: { type: integer, nullable: true }
|
||
required: [document_id]
|
||
|
||
BaseReview:
|
||
type: object
|
||
properties:
|
||
name: { type: string }
|
||
flow_id: { type: integer, minimum: 1 }
|
||
folder_dst: { type: string, nullable: true }
|
||
folder_label: { type: string, nullable: true }
|
||
resource_id: { type: string, format: uuid, nullable: true }
|
||
meta_data: { type: object, additionalProperties: true }
|
||
documents: { type: array, items: { $ref: '#/components/schemas/BaseCreateDocument' } }
|
||
comment: { type: string, nullable: true }
|
||
attributes: { type: object, additionalProperties: true }
|
||
checklist_results: { type: object, additionalProperties: { type: array, items: { type: integer } } }
|
||
required: [name, flow_id]
|
||
|
||
UpdateBaseReview:
|
||
type: object
|
||
properties:
|
||
name: { type: string }
|
||
flow_id: { type: integer, minimum: 1 }
|
||
folder_dst: { type: string, nullable: true }
|
||
folder_label: { type: string, nullable: true }
|
||
resource_id: { type: string, format: uuid, nullable: true }
|
||
meta_data: { type: object, additionalProperties: true }
|
||
attributes: { type: object, additionalProperties: true }
|
||
required: [name, flow_id]
|
||
|
||
PatchBaseReview:
|
||
type: object
|
||
properties:
|
||
name: { type: string, nullable: true }
|
||
resource_id: { type: string, format: uuid, nullable: true }
|
||
status: { $ref: '#/components/schemas/StateReview' }
|
||
attributes: { type: object, nullable: true, additionalProperties: true }
|
||
|
||
PatchCurrentReviewers:
|
||
type: object
|
||
properties:
|
||
was: { type: string, format: uuid, nullable: true }
|
||
became: { type: string, format: uuid, nullable: true }
|
||
required: { type: boolean, default: false }
|
||
force_next_step_reviewer: { type: boolean, default: false }
|
||
|
||
PatchMinReviewersOnStep:
|
||
type: object
|
||
properties:
|
||
new_value: { type: integer, minimum: 1 }
|
||
required: [new_value]
|
||
|
||
StatusForReview:
|
||
type: object
|
||
properties:
|
||
status: { $ref: '#/components/schemas/StateReview' }
|
||
comment: { type: string, nullable: true }
|
||
duration: { type: integer, minimum: 0, nullable: true }
|
||
reviewers: { type: array, nullable: true, items: { $ref: '#/components/schemas/PatchCurrentReviewers' } }
|
||
|
||
ReviewersUpdate:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
current_reviewers: { type: array, nullable: true, items: { type: string, format: uuid } }
|
||
completed_reviewers: { type: array, nullable: true, items: { type: string, format: uuid } }
|
||
current_signatories: { type: array, nullable: true, items: { type: integer } }
|
||
completed_signatories: { type: array, nullable: true, items: { type: integer } }
|
||
required: [id]
|
||
|
||
BulkReviewersUpdate:
|
||
type: object
|
||
properties:
|
||
reviews: { type: array, items: { $ref: '#/components/schemas/ReviewersUpdate' } }
|
||
required: [reviews]
|
||
|
||
Review:
|
||
type: object
|
||
description: |
|
||
Итоговая структура review. Сериализатор дополнительно раскладывает
|
||
user_actions по шагам flow и добавляет агрегаты `count_of_document`,
|
||
`Согласовано`, `Не согласовано`.
|
||
properties:
|
||
id: { type: integer }
|
||
name: { type: string }
|
||
status: { $ref: '#/components/schemas/StateReview' }
|
||
folder_dst: { type: string, nullable: true }
|
||
folder_label: { type: string, nullable: true }
|
||
current_step: { type: integer, nullable: true }
|
||
current_step_id: { type: integer }
|
||
current_step_expired_at: { type: string, format: date-time, nullable: true }
|
||
created_at: { type: string, format: date-time }
|
||
updated_at: { type: string, format: date-time }
|
||
expired_at: { type: string, format: date-time, nullable: true }
|
||
completed_at: { type: string, format: date-time, nullable: true }
|
||
min_reviewers: { type: integer, nullable: true }
|
||
creator_id: { type: integer }
|
||
resource_id: { type: string, format: uuid, nullable: true }
|
||
current_reviewers: { type: array, items: { type: string, format: uuid } }
|
||
completed_reviewers: { type: array, items: { type: string, format: uuid } }
|
||
current_signatories: { type: array, nullable: true, items: { type: integer } }
|
||
completed_signatories: { type: array, nullable: true, items: { type: integer } }
|
||
flow: { $ref: '#/components/schemas/FullFlow' }
|
||
meta_data: { type: object, additionalProperties: true }
|
||
current_reviewers_by_sa: { type: object, additionalProperties: { type: integer } }
|
||
current_reviewers_changes: { type: array, items: { type: string, format: uuid } }
|
||
time_tracking_mode: { $ref: '#/components/schemas/TimeTrackingMode' }
|
||
attributes: { type: object, additionalProperties: true }
|
||
checklist_results: { type: object, additionalProperties: { type: array, items: { type: integer } } }
|
||
force_next_step_reviewers: { type: array, items: { type: string, format: uuid } }
|
||
transmittal_ids: { type: array, items: { type: string, format: uuid } }
|
||
count_of_document: { type: integer }
|
||
required: [id, name, status, current_step_id, created_at, updated_at, creator_id]
|
||
|
||
ChecklistResultsUpdateRequest:
|
||
type: object
|
||
properties:
|
||
step_id: { type: integer }
|
||
add_results: { type: array, items: { type: integer } }
|
||
remove_results: { type: array, items: { type: integer } }
|
||
required: [step_id]
|
||
|
||
TransmittalForReviewCreated:
|
||
type: object
|
||
properties:
|
||
review_id: { type: integer }
|
||
transmittal_id: { type: string, format: uuid }
|
||
required: [review_id, transmittal_id]
|
||
|
||
BaseUserAction:
|
||
type: object
|
||
properties:
|
||
action: { type: string }
|
||
key: { type: string, nullable: true }
|
||
value: { type: string }
|
||
creator_id: { type: integer }
|
||
step_id: { type: integer }
|
||
document_id: { type: integer, nullable: true }
|
||
review_id: { type: integer }
|
||
required: [action, value, creator_id, step_id, review_id]
|
||
|
||
UserActions:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
action: { type: string }
|
||
key: { type: string, nullable: true }
|
||
value: { type: string }
|
||
creator_id: { type: integer }
|
||
created_at: { type: string, format: date-time }
|
||
step_id: { type: integer }
|
||
document_id: { type: integer, nullable: true }
|
||
review_id: { type: integer }
|
||
required: [id, action, value, creator_id, created_at, step_id, review_id]
|
||
|
||
ListUserActionsForDelete:
|
||
type: object
|
||
properties:
|
||
ids: { type: array, items: { type: integer } }
|
||
required: [ids]
|
||
|
||
UpdateUserAction:
|
||
type: object
|
||
properties:
|
||
key: { type: string, nullable: true }
|
||
value: { type: string, nullable: true }
|
||
|
||
Task:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
priority: { type: integer, minimum: 1, nullable: true }
|
||
start_date: { type: string, format: date-time }
|
||
duration: { type: integer, minimum: 0 }
|
||
end_date: { type: string, format: date-time }
|
||
review: { type: object, additionalProperties: true }
|
||
reviewer_id: { type: integer }
|
||
is_active: { type: boolean }
|
||
step_id: { type: integer, nullable: true }
|
||
review_expired_at: { type: string, format: date-time, nullable: true }
|
||
current_reviewers: { type: array, items: { type: integer } }
|
||
completed_reviewers: { type: array, items: { type: integer } }
|
||
required: [id, start_date, duration, end_date, reviewer_id, is_active]
|
||
|
||
TaskUpdatePriority:
|
||
type: object
|
||
properties:
|
||
priority: { type: integer, minimum: 1 }
|
||
required: [priority]
|
||
|
||
TaskUpdateDuration:
|
||
type: object
|
||
properties:
|
||
duration: { type: integer, minimum: 1 }
|
||
required: [duration]
|
||
|
||
TasksCount:
|
||
type: object
|
||
properties:
|
||
tasks_count: { type: integer }
|
||
required: [tasks_count]
|
||
|
||
ReviewerMaxTaskEndDate:
|
||
type: object
|
||
properties:
|
||
reviewer_id: { type: integer }
|
||
max_task_end_date: { type: string, format: date-time }
|
||
required: [reviewer_id, max_task_end_date]
|
||
|
||
MainFilterPostRequest:
|
||
type: object
|
||
description: Схема фильтрации для POST /flows/filter/, /reviews/filter/ и подсчётов.
|
||
properties:
|
||
created_at_after: { type: string, nullable: true }
|
||
created_at_before: { type: string, nullable: true }
|
||
updated_at_after: { type: string, nullable: true }
|
||
updated_at_before: { type: string, nullable: true }
|
||
expired_before: { type: string, nullable: true }
|
||
current_step_expired_before: { type: string, nullable: true }
|
||
resource_id: { type: array, nullable: true, items: { type: string } }
|
||
flow_id: { type: array, nullable: true, items: { type: string } }
|
||
launcher_id: { type: array, nullable: true, items: { type: string } }
|
||
reviewers_ids: { type: array, nullable: true, items: { type: string } }
|
||
reviewers_sa: { type: array, nullable: true, items: { type: string } }
|
||
launcher_sa: { type: array, nullable: true, items: { type: string } }
|
||
action: { type: array, nullable: true, items: { type: string } }
|
||
approvers: { type: array, nullable: true, items: { type: string } }
|
||
step_watchers: { type: array, nullable: true, items: { type: string } }
|
||
reviewers: { type: array, nullable: true, items: { type: string } }
|
||
current_reviewers: { type: array, nullable: true, items: { type: string } }
|
||
completed_reviewers: { type: array, nullable: true, items: { type: string } }
|
||
signatories: { type: array, nullable: true, items: { type: string } }
|
||
current_signatories: { type: array, nullable: true, items: { type: string } }
|
||
completed_signatories: { type: array, nullable: true, items: { type: string } }
|
||
company_id: { type: string, nullable: true }
|
||
creator_id: { type: string, nullable: true }
|
||
changer_id: { type: string, nullable: true }
|
||
name: { type: string, nullable: true }
|
||
status: { type: array, nullable: true, items: { $ref: '#/components/schemas/StateReview' } }
|
||
flow_type: { $ref: '#/components/schemas/FlowType' }
|
||
full: { type: boolean, default: false }
|
||
is_active: { type: boolean, nullable: true }
|
||
enable_stamp: { type: boolean, nullable: true }
|
||
enable_signature: { type: boolean, nullable: true }
|
||
enable_qr_code: { type: boolean, nullable: true }
|
||
has_reviewers: { type: boolean, nullable: true }
|
||
attributes: { type: object, nullable: true, additionalProperties: true }
|