iac/apps/transmittal/openapi.yaml

1293 lines
52 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

openapi: 3.0.3
info:
title: Transmittal Service API
version: "1.0.0"
description: |
REST API сервиса **transmittal-api** (`pdm/transmittal-api`) — управление
трансмитталами (передачей документации на согласование), их шаблонами,
шагами/действиями маршрута согласования и генерацией актов.
Сервис написан на Python (**FastAPI**). Приложение собирается фабрикой
`get_application` в `src/transmittal_service/app/http_server.py`. Роутинг
состоит из двух групп:
- публичный API — префикс `/api/v1` (`controller/http/api/v1/api.py`);
- внутренний API — префикс `/internal/v1` (`controller/http/internal/v1/api.py`),
предназначен для вызовов внутри кластера (через ingress не публикуется).
Интерактивная документация Swagger доступна по `/api/docs`, схема —
по `/api/openapi.json` (с учётом `root_path`).
### Аутентификация
Публичные эндпоинты (кроме `/api/v1/healthcheck`) требуют аутентификации.
Токен передаётся заголовком `Authorization: Bearer <jwt>` (FastAPI
`HTTPBearer`). Поддерживаются два режима (`controller/http/security.py`):
1. **Zitadel** — если передан дополнительный заголовок `identity`
(`Identity <jwt>`), полезная нагрузка берётся из этого токена
(`urn:zitadel:iam:user:metadata`). Валидность проверяется на уровне
Istio, подпись сервисом не проверяется.
2. **sarex-backend** — если заголовка `identity` нет, подпись основного
токена проверяется публичным RSA-ключом
(`TRANSMITTAL_SERVICE_AUTH__PUBLIC_KEY`, алгоритм `RS512`).
Внутренние эндпоинты (`/internal/v1/*`) аутентификации на уровне приложения
не требуют — ограничение доступа обеспечивается сетевым слоем.
### Пагинация
Списочные ответы используют «bookmark»-пагинацию. Ответ оборачивается в
`Page` — `{ result, next, prev }`, где `next`/`prev` — курсоры (bookmark).
Размер страницы задаётся параметром `limit` (в теле или query, зависит от
эндпоинта), продолжение — параметром `bookmark`. Часть ответов оборачивается
в более простой `Result` — `{ result }` (без курсоров).
### Обработка ошибок
Ошибки возвращаются в формате **RFC 7807** (`application/problem+json`),
схема `ApiError` — `{ type, title, status, detail, instance }`
(`controller/http/middleware.py`, класс `ExceptionHandler`). Идентификатор
запроса возвращается в заголовке `X-Request-Id`, длительность обработки —
в `Server-Timing`.
### Замечания (расхождения кода)
- Ошибка «ресурс не найден» (`NotFound`) маппится на статус **`410 Gone`**,
а не на привычный `404 Not Found`.
- При отсутствии/некорректности `Authorization` FastAPI `HTTPBearer`
возвращает `403`, тогда как ошибки разбора токена в middleware дают `401`.
- Ошибки валидации тела/параметров запроса (Pydantic) отдаются FastAPI в
стандартном формате `422` (не `application/problem+json`).
- Конфликт имени шаблона (`TemplateNameIsNotUnique`) возвращает `409`.
contact:
name: transmittal-api
url: https://gitlab/pdm/transmittal-api
servers:
- url: https://api.sarex.io/transmittals
description: Production (ingress, root_path=/transmittals)
- url: https://stage-api.sarex.io/transmittals
description: Stage (ingress, root_path=/transmittals)
- url: http://transmittal-service.transmittal-api-stage.svc.cluster.local
description: Внутрикластерный адрес (ClusterIP, порт 80 → 8000). Единственный способ достучаться до /internal/v1
- url: http://localhost:8001
description: Локальный запуск (Uvicorn, порт по умолчанию 8001)
tags:
- name: infra
description: Служебные эндпоинты (проверка доступности)
- name: transmittals
description: Трансмитталы — создание, просмотр, согласование, поиск, акты
- name: transmittal_templates
description: Шаблоны трансмитталов
- name: steps
description: Шаги маршрута согласования
- name: internal
description: Внутренние эндпоинты (только внутри кластера)
security:
- bearerAuth: []
paths:
# ==========================================================================
# Infra
# ==========================================================================
/api/v1/healthcheck:
get:
tags: [infra]
summary: Проверка доступности зависимостей
description: |
Параллельно проверяет доступность всех внешних зависимостей (БД, S3,
и HTTP-сервисов) и возвращает агрегированный статус `healthy` или
`partially_healthy`. Аутентификация не требуется.
operationId: healthcheck
security: []
responses:
'200':
description: Статус доступности зависимостей
content:
application/json:
schema:
$ref: '#/components/schemas/HealthCheckResponse'
# ==========================================================================
# Steps
# ==========================================================================
/api/v1/steps:
get:
tags: [steps]
summary: Список шагов
operationId: getSteps
parameters:
- name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 32767
default: 100
- name: bookmark
in: query
required: false
schema:
type: string
nullable: true
responses:
'200':
description: Страница шагов
content:
application/json:
schema:
$ref: '#/components/schemas/Page_StepReadResponseDto'
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'422': { $ref: '#/components/responses/ValidationError' }
/api/v1/steps/{id}:
get:
tags: [steps]
summary: Шаг по id
operationId: getStep
parameters:
- name: id
in: path
required: true
schema:
type: integer
minimum: 0
maximum: 32767
responses:
'200':
description: Шаг
content:
application/json:
schema:
$ref: '#/components/schemas/StepReadResponseDto'
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'410': { $ref: '#/components/responses/Gone' }
'422': { $ref: '#/components/responses/ValidationError' }
# ==========================================================================
# Transmittals
# ==========================================================================
/api/v1/transmittals:
post:
tags: [transmittals]
summary: Список трансмитталов ресурса
description: Пагинированный список трансмитталов по `resource_id` со сводной статистикой по статусам.
operationId: listTransmittals
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalListRequestDto'
responses:
'200':
description: Страница трансмитталов и статистика по статусам
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalListResponseDto'
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'422': { $ref: '#/components/responses/ValidationError' }
/api/v1/transmittals/create:
post:
tags: [transmittals]
summary: Создать трансмиттал
description: |
Создаёт трансмиттал. Требуется хотя бы один документ (`documents_to_approve`)
и хотя бы один получатель (`receivers`).
operationId: createTransmittal
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalCreateRequestDto'
responses:
'200':
description: Идентификатор созданного трансмиттала
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalCreateResponseDto'
'400': { $ref: '#/components/responses/BadRequest' }
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'422': { $ref: '#/components/responses/ValidationError' }
/api/v1/transmittals/global_statuses:
post:
tags: [transmittals]
summary: Глобальные статусы по набору ресурсов
description: Возвращает статистику статусов трансмитталов по списку `resource_ids`.
operationId: getGlobalStatuses
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalGetGlobalStatusesRequestDto'
responses:
'200':
description: Статистика статусов по ресурсам
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalGetGlobalStatusesResponseDto'
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'422': { $ref: '#/components/responses/ValidationError' }
/api/v1/transmittals/status:
get:
tags: [transmittals]
summary: Справочник статусов
operationId: listStatuses
responses:
'200':
description: Список типов статусов
content:
application/json:
schema:
$ref: '#/components/schemas/StatusesListResponseDto'
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
/api/v1/transmittals/count:
get:
tags: [transmittals]
summary: Число открытых трансмитталов пользователя
description: Количество незакрытых трансмитталов, требующих действия текущего пользователя.
operationId: myOpenTransmittalsCount
responses:
'200':
description: Количество открытых трансмитталов
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalOpenCountResponseDto'
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
/api/v1/transmittals/search:
post:
tags: [transmittals]
summary: Поиск трансмитталов в ресурсе
description: Поиск и фильтрация трансмитталов в рамках одного ресурса (`resource_id`).
operationId: searchTransmittals
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalSearchFilterRequestDto'
responses:
'200':
description: Страница трансмитталов и статистика по статусам
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalListResponseDto'
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'422': { $ref: '#/components/responses/ValidationError' }
/api/v1/transmittals/search/resources:
post:
tags: [transmittals]
summary: Поиск по нескольким ресурсам
description: Фильтрация трансмитталов по списку ресурсов (`resource_ids`); возвращает статистику статусов по ресурсам.
operationId: searchTransmittalsResources
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalSearchFilterDto'
responses:
'200':
description: Статистика статусов по ресурсам
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalGetGlobalStatusesResponseDto'
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'422': { $ref: '#/components/responses/ValidationError' }
/api/v1/transmittals/{transmittal_id}:
parameters:
- $ref: '#/components/parameters/TransmittalId'
get:
tags: [transmittals]
summary: Трансмиттал по id
operationId: getTransmittal
responses:
'200':
description: Трансмиттал с историей действий и документами
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalReadResponseDto'
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'410': { $ref: '#/components/responses/Gone' }
'422': { $ref: '#/components/responses/ValidationError' }
delete:
tags: [transmittals]
summary: Удалить трансмиттал
operationId: deleteTransmittal
responses:
'204': { description: Удалено }
'400': { $ref: '#/components/responses/BadRequest' }
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'410': { $ref: '#/components/responses/Gone' }
'422': { $ref: '#/components/responses/ValidationError' }
/api/v1/transmittals/{transmittal_id}/approve:
parameters:
- $ref: '#/components/parameters/TransmittalId'
put:
tags: [transmittals]
summary: Принять трансмиттал
description: Фиксирует действие «принять» текущего пользователя на текущем шаге (с опциональным комментарием). По завершении может инициировать генерацию акта.
operationId: approveTransmittal
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UserActionCreateRequest'
responses:
'200':
description: Созданное действие пользователя
content:
application/json:
schema:
$ref: '#/components/schemas/UserActionCreateResponseDto'
'400': { $ref: '#/components/responses/BadRequest' }
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'410': { $ref: '#/components/responses/Gone' }
'422': { $ref: '#/components/responses/ValidationError' }
/api/v1/transmittals/{transmittal_id}/decline:
parameters:
- $ref: '#/components/parameters/TransmittalId'
put:
tags: [transmittals]
summary: Отклонить трансмиттал
description: Фиксирует действие «отклонить» текущего пользователя на текущем шаге (с опциональным комментарием).
operationId: declineTransmittal
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UserActionCreateRequest'
responses:
'200':
description: Созданное действие пользователя
content:
application/json:
schema:
$ref: '#/components/schemas/UserActionCreateResponseDto'
'400': { $ref: '#/components/responses/BadRequest' }
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'410': { $ref: '#/components/responses/Gone' }
'422': { $ref: '#/components/responses/ValidationError' }
/api/v1/transmittals/{transmittal_id}/act_available:
parameters:
- $ref: '#/components/parameters/TransmittalId'
get:
tags: [transmittals]
summary: Доступность акта
description: Признак готовности акта для скачивания по данному трансмитталу.
operationId: actAvailable
responses:
'200':
description: Готовность акта
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalGetActReadinessResponse'
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'410': { $ref: '#/components/responses/Gone' }
'422': { $ref: '#/components/responses/ValidationError' }
/api/v1/transmittals/{transmittal_id}/download_act:
parameters:
- $ref: '#/components/parameters/TransmittalId'
get:
tags: [transmittals]
summary: Скачать акт
description: Возвращает presigned-URL для скачивания акта из S3.
operationId: downloadAct
responses:
'200':
description: Presigned-URL акта
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalDownloadActResponse'
'400': { $ref: '#/components/responses/BadRequest' }
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'410': { $ref: '#/components/responses/Gone' }
'422': { $ref: '#/components/responses/ValidationError' }
/api/v1/transmittals/{transmittal_id}/link_review:
parameters:
- $ref: '#/components/parameters/TransmittalId'
post:
tags: [transmittals]
summary: Привязать review к трансмитталу
operationId: linkReview
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalLinkReviewRequest'
responses:
'204': { description: Review привязан }
'400': { $ref: '#/components/responses/BadRequest' }
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'410': { $ref: '#/components/responses/Gone' }
'422': { $ref: '#/components/responses/ValidationError' }
# ==========================================================================
# Transmittal templates
# ==========================================================================
/api/v1/transmittal_templates:
post:
tags: [transmittal_templates]
summary: Список шаблонов трансмитталов
description: Пагинированный список шаблонов с фильтрами. Тело запроса опционально (при отсутствии применяются значения по умолчанию).
operationId: listTransmittalTemplates
requestBody:
required: false
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalTemplateListFiltersRequest'
responses:
'200':
description: Страница шаблонов
content:
application/json:
schema:
$ref: '#/components/schemas/Page_TransmittalTemplateListResponse'
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'422': { $ref: '#/components/responses/ValidationError' }
/api/v1/transmittal_templates/create:
post:
tags: [transmittal_templates]
summary: Создать шаблон
operationId: createTransmittalTemplate
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalTemplateCreateRequestDto'
responses:
'200':
description: Идентификатор созданного шаблона
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalTemplateCreateResponseDto'
'400': { $ref: '#/components/responses/BadRequest' }
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'409': { $ref: '#/components/responses/Conflict' }
'422': { $ref: '#/components/responses/ValidationError' }
/api/v1/transmittal_templates/select:
get:
tags: [transmittal_templates]
summary: Шаблоны для выбора
description: Плоский список шаблонов (id/имя/автор), доступных для выбора в рамках ресурса.
operationId: listTransmittalTemplatesForSelect
parameters:
- name: resource
in: query
required: true
schema:
type: string
format: uuid
- name: template_id
in: query
required: false
description: Один или несколько id шаблонов для фильтрации
schema:
type: array
items:
type: string
format: uuid
nullable: true
responses:
'200':
description: Список шаблонов для выбора
content:
application/json:
schema:
$ref: '#/components/schemas/Result_TransmittalTemplateSelectListResponse'
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'422': { $ref: '#/components/responses/ValidationError' }
/api/v1/transmittal_templates/{transmittal_template_id}:
parameters:
- $ref: '#/components/parameters/TransmittalTemplateId'
get:
tags: [transmittal_templates]
summary: Шаблон по id
operationId: getTransmittalTemplate
parameters:
- name: resource
in: query
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Шаблон трансмиттала
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalTemplateGetSingleResponse'
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'410': { $ref: '#/components/responses/Gone' }
'422': { $ref: '#/components/responses/ValidationError' }
patch:
tags: [transmittal_templates]
summary: Обновить шаблон
operationId: updateTransmittalTemplate
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalTemplateUpdateRequest'
responses:
'204': { description: Обновлено }
'400': { $ref: '#/components/responses/BadRequest' }
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'409': { $ref: '#/components/responses/Conflict' }
'410': { $ref: '#/components/responses/Gone' }
'422': { $ref: '#/components/responses/ValidationError' }
delete:
tags: [transmittal_templates]
summary: Удалить шаблон
operationId: deleteTransmittalTemplate
responses:
'204': { description: Удалено }
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'410': { $ref: '#/components/responses/Gone' }
'422': { $ref: '#/components/responses/ValidationError' }
# ==========================================================================
# Internal (cluster-only)
# ==========================================================================
/internal/v1/transmittals:
post:
tags: [internal]
summary: Список трансмитталов (внутренний)
description: Внутренний список трансмитталов по фильтрам. Без аутентификации на уровне приложения; доступен только внутри кластера.
operationId: internalGetTransmittals
security: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalListInternalRequest'
responses:
'200':
description: Список трансмитталов
content:
application/json:
schema:
$ref: '#/components/schemas/Result_TransmittalReadListResponseDto'
'422': { $ref: '#/components/responses/ValidationError' }
/internal/v1/transmittals/by_bundle_ids:
post:
tags: [internal]
summary: Трансмитталы по bundle id (внутренний)
description: Возвращает трансмитталы, связанные с переданными `bundle_ids`. Без аутентификации на уровне приложения; доступен только внутри кластера.
operationId: internalGetTransmittalsByBundleIds
security: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TransmittalGetByBundleIdsRequest'
responses:
'200':
description: Трансмитталы по bundle id
content:
application/json:
schema:
$ref: '#/components/schemas/Result_TransmittalGetByBundleIdsResponse'
'422': { $ref: '#/components/responses/ValidationError' }
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
JWT в заголовке `Authorization: Bearer <token>`. Проверяется публичным
ключом (`RS512`) в режиме sarex-backend либо принимается как есть в
режиме Zitadel (см. заголовок `identity`).
identityToken:
type: apiKey
in: header
name: identity
description: |
Опциональный заголовок `identity` (`Identity <jwt>`) для режима Zitadel.
При его наличии полезная нагрузка берётся из этого токена, а подпись
основного токена сервисом не проверяется.
parameters:
TransmittalId:
name: transmittal_id
in: path
required: true
schema:
type: string
format: uuid
TransmittalTemplateId:
name: transmittal_template_id
in: path
required: true
schema:
type: string
format: uuid
responses:
BadRequest:
description: Некорректный запрос / бизнес-правило нарушено
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
Unauthorized:
description: Токен не предоставлен или невалиден
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
Forbidden:
description: Недостаточно прав
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
Conflict:
description: Конфликт (например, имя шаблона уже занято)
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
Gone:
description: Запрошенный ресурс не существует (маппинг `NotFound` → `410`)
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
ValidationError:
description: Ошибка валидации тела/параметров запроса (FastAPI/Pydantic)
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
schemas:
# --- Общие ------------------------------------------------------------
ApiError:
type: object
description: Ошибка в формате RFC 7807 (application/problem+json)
properties:
type: { type: string }
title: { type: string }
status: { type: integer }
detail: { type: string }
instance:
type: string
description: URL запроса, вызвавшего ошибку
required: [type, title, status, detail, instance]
HTTPValidationError:
type: object
properties:
detail:
type: array
items:
$ref: '#/components/schemas/ValidationErrorItem'
ValidationErrorItem:
type: object
properties:
loc:
type: array
items:
anyOf:
- type: string
- type: integer
msg: { type: string }
type: { type: string }
required: [loc, msg, type]
ReceiversRequestDto:
type: object
description: Получатели трансмиттала (запрос). Хотя бы один из наборов должен быть непуст.
properties:
users:
type: array
items: { type: integer, minimum: 0, maximum: 9223372036854775807 }
uniqueItems: true
departments:
type: array
items: { type: integer }
uniqueItems: true
roles:
type: array
items: { type: integer }
uniqueItems: true
ReceiversReadResponseDto:
type: object
properties:
users: { type: array, items: { type: integer } }
departments: { type: array, items: { type: integer } }
roles: { type: array, items: { type: integer } }
required: [users, departments, roles]
ReceiversFilterDto:
type: object
properties:
users: { type: array, items: { type: integer } }
departments: { type: array, items: { type: integer } }
roles: { type: array, items: { type: integer } }
DocumentVersionRequestDto:
type: object
properties:
document_id: { type: integer, minimum: 0, maximum: 2147483647 }
bundle_id: { type: string, format: uuid }
required: [document_id, bundle_id]
DocumentVersionReadResponse:
type: object
properties:
document_id: { type: integer }
bundle_id: { type: string, format: uuid }
required: [document_id, bundle_id]
StatusReadResponseDto:
type: object
properties:
id: { type: integer }
name: { type: string }
slug: { type: string }
required: [id, name, slug]
StatusSimpleDto:
type: object
properties:
slug: { type: string }
name: { type: string }
required: [slug, name]
StatusesListResponseDto:
type: object
properties:
statuses:
type: array
items: { $ref: '#/components/schemas/StatusSimpleDto' }
required: [statuses]
StepReadResponseDto:
type: object
properties:
id: { type: integer }
name: { type: string }
slug: { type: string }
required: [id, name, slug]
ActionReadResponse:
type: object
properties:
id: { type: integer }
step_id: { type: integer }
name: { type: string }
slug: { type: string }
required: [id, step_id, name, slug]
ReviewLightResponse:
type: object
properties:
id: { type: integer }
name: { type: string }
required: [id, name]
UserActionCreateRequest:
type: object
properties:
comment: { type: string, nullable: true }
UserActionCreateResponseDto:
type: object
properties:
id: { type: string, format: uuid }
transmittal_id: { type: string, format: uuid }
action_id: { type: integer }
comment: { type: string, nullable: true }
required: [id, transmittal_id, action_id, comment]
UserActionReadResponse:
type: object
properties:
id: { type: string, format: uuid }
user_id: { type: integer }
transmittal_id: { type: string, format: uuid }
action_id: { type: integer }
comment: { type: string, nullable: true }
action: { $ref: '#/components/schemas/ActionReadResponse' }
created_at: { type: string, format: date-time }
required: [id, user_id, transmittal_id, action_id, comment, action, created_at]
# --- Wrappers ---------------------------------------------------------
Page_StepReadResponseDto:
type: object
properties:
result:
type: array
items: { $ref: '#/components/schemas/StepReadResponseDto' }
next: { type: string }
prev: { type: string }
required: [result, next, prev]
Page_TransmittalReadListResponseDto:
type: object
properties:
result:
type: array
items: { $ref: '#/components/schemas/TransmittalReadListResponseDto' }
next: { type: string }
prev: { type: string }
required: [result, next, prev]
Page_TransmittalTemplateListResponse:
type: object
properties:
result:
type: array
items: { $ref: '#/components/schemas/TransmittalTemplateListResponse' }
next: { type: string }
prev: { type: string }
required: [result, next, prev]
Result_TransmittalTemplateSelectListResponse:
type: object
properties:
result:
type: array
items: { $ref: '#/components/schemas/TransmittalTemplateSelectListResponse' }
required: [result]
Result_TransmittalReadListResponseDto:
type: object
properties:
result:
type: array
items: { $ref: '#/components/schemas/TransmittalReadListResponseDto' }
required: [result]
Result_TransmittalGetByBundleIdsResponse:
type: object
properties:
result:
type: array
items: { $ref: '#/components/schemas/TransmittalGetByBundleIdsResponse' }
required: [result]
# --- Transmittals -----------------------------------------------------
TransmittalCreateRequestDto:
type: object
properties:
name: { type: string, minLength: 1, maxLength: 255 }
company_id: { type: integer, minimum: 0, maximum: 18446744073709551615 }
additional_information: { type: string, nullable: true }
resource_id: { type: string, format: uuid }
auto_send: { type: boolean }
documents_to_approve:
type: array
description: Не менее одного документа
minItems: 1
uniqueItems: true
items: { $ref: '#/components/schemas/DocumentVersionRequestDto' }
receivers: { $ref: '#/components/schemas/ReceiversRequestDto' }
deadline_at:
type: string
format: date-time
nullable: true
description: Дедлайн в будущем
required: [name, company_id, additional_information, resource_id, auto_send, documents_to_approve, receivers, deadline_at]
TransmittalCreateResponseDto:
type: object
properties:
id: { type: string, format: uuid }
required: [id]
TransmittalListRequestDto:
type: object
properties:
limit: { type: integer, default: 1000 }
bookmark: { type: string, nullable: true }
resource_id: { type: string, format: uuid }
required: [resource_id]
TransmittalReadListResponseDto:
type: object
properties:
id: { type: string, format: uuid }
resource_id: { type: string, format: uuid }
created_by: { type: integer }
current_step_id: { type: integer }
"no": { type: integer }
name: { type: string }
additional_information: { type: string, nullable: true }
steps: { type: array, items: { type: integer } }
auto_send: { type: boolean }
receivers: { $ref: '#/components/schemas/ReceiversReadResponseDto' }
deadline_at: { type: string, format: date-time, nullable: true }
status: { $ref: '#/components/schemas/StatusReadResponseDto' }
step: { $ref: '#/components/schemas/StepReadResponseDto' }
sent_at: { type: string, format: date-time, nullable: true }
received_at: { type: string, format: date-time, nullable: true }
act_available: { type: boolean }
reviews:
type: array
nullable: true
items: { $ref: '#/components/schemas/ReviewLightResponse' }
required: [id, resource_id, created_by, current_step_id, "no", name, additional_information, steps, auto_send, receivers, deadline_at, status, step, sent_at, received_at, act_available]
TransmittalReadResponseDto:
type: object
properties:
id: { type: string, format: uuid }
resource_id: { type: string, format: uuid }
created_by: { type: integer }
current_step_id: { type: integer }
"no": { type: integer }
name: { type: string }
additional_information: { type: string, nullable: true }
steps: { type: array, items: { type: integer } }
auto_send: { type: boolean }
receivers: { $ref: '#/components/schemas/ReceiversReadResponseDto' }
deadline_at: { type: string, format: date-time, nullable: true }
sent_at: { type: string, format: date-time, nullable: true }
received_at: { type: string, format: date-time, nullable: true }
act_available: { type: boolean }
status: { $ref: '#/components/schemas/StatusReadResponseDto' }
step: { $ref: '#/components/schemas/StepReadResponseDto' }
documents_to_approve:
type: array
items: { $ref: '#/components/schemas/DocumentVersionReadResponse' }
history:
type: array
items: { $ref: '#/components/schemas/UserActionReadResponse' }
required: [id, resource_id, created_by, current_step_id, "no", name, additional_information, steps, auto_send, receivers, deadline_at, sent_at, received_at, act_available, status, step, documents_to_approve, history]
TransmittalStatusesStatResponseDto:
type: object
properties:
status: { $ref: '#/components/schemas/StatusReadResponseDto' }
count: { type: integer }
required: [status, count]
TransmittalListResponseDto:
type: object
properties:
page: { $ref: '#/components/schemas/Page_TransmittalReadListResponseDto' }
statuses_stat:
type: array
items: { $ref: '#/components/schemas/TransmittalStatusesStatResponseDto' }
required: [page, statuses_stat]
TransmittalGlobalStatusesStatResponseDto:
type: object
properties:
resource_id: { type: string, format: uuid }
statuses:
type: array
items: { $ref: '#/components/schemas/TransmittalStatusesStatResponseDto' }
required: [resource_id, statuses]
TransmittalGetGlobalStatusesRequestDto:
type: object
properties:
resource_ids:
type: array
items: { type: string, format: uuid }
required: [resource_ids]
TransmittalGetGlobalStatusesResponseDto:
type: object
properties:
result:
type: array
items: { $ref: '#/components/schemas/TransmittalGlobalStatusesStatResponseDto' }
required: [result]
TransmittalDownloadActResponse:
type: object
properties:
presigned_url: { type: string }
required: [presigned_url]
TransmittalGetActReadinessResponse:
type: object
properties:
act_available: { type: boolean }
required: [act_available]
TransmittalOpenCountResponseDto:
type: object
properties:
count: { type: integer }
required: [count]
TransmittalLinkReviewRequest:
type: object
properties:
review_id: { type: integer }
required: [review_id]
TransmittalSearchFilterRequestDto:
type: object
description: Фильтр поиска в рамках одного ресурса
properties:
q: { type: string, nullable: true }
resource_id: { type: string, format: uuid }
status_slug: { type: array, items: { type: string } }
created_by: { type: array, items: { type: integer } }
receivers:
nullable: true
allOf: [{ $ref: '#/components/schemas/ReceiversFilterDto' }]
created_from: { type: string, format: date-time, nullable: true }
created_to: { type: string, format: date-time, nullable: true }
received_from: { type: string, format: date-time, nullable: true }
received_to: { type: string, format: date-time, nullable: true }
deadline_at: { type: string, format: date-time, nullable: true }
unlimited: { type: boolean, nullable: true, default: false }
auto_send: { type: array, items: { type: boolean } }
limit: { type: integer, nullable: true, default: 100 }
bookmark: { type: string, nullable: true }
required: [resource_id]
TransmittalSearchFilterDto:
type: object
description: Фильтр поиска по нескольким ресурсам
properties:
q: { type: string, nullable: true }
resource_ids: { type: array, items: { type: string, format: uuid } }
status_slug: { type: array, items: { type: string } }
created_by: { type: array, items: { type: integer } }
receivers:
nullable: true
allOf: [{ $ref: '#/components/schemas/ReceiversFilterDto' }]
created_from: { type: string, format: date-time, nullable: true }
created_to: { type: string, format: date-time, nullable: true }
received_from: { type: string, format: date-time, nullable: true }
received_to: { type: string, format: date-time, nullable: true }
deadline_at: { type: string, format: date-time, nullable: true }
unlimited: { type: boolean, nullable: true, default: false }
auto_send: { type: array, items: { type: boolean } }
limit: { type: integer, nullable: true, default: 100 }
bookmark: { type: string, nullable: true }
# --- Internal ---------------------------------------------------------
TransmittalListInternalRequest:
type: object
properties:
limit: { type: integer, default: 100 }
transmittal_ids: { type: array, items: { type: string, format: uuid } }
company_id: { type: integer, nullable: true }
resource_id: { type: string, format: uuid, nullable: true }
TransmittalGetByBundleIdsRequest:
type: object
properties:
bundle_ids: { type: array, items: { type: string, format: uuid } }
required: [bundle_ids]
TransmittalGetByBundleIdsReadDto:
type: object
properties:
id: { type: string, format: uuid }
name: { type: string }
status: { $ref: '#/components/schemas/StatusReadResponseDto' }
created_at: { type: string, format: date-time }
required: [id, name, status, created_at]
TransmittalGetByBundleIdsResponse:
type: object
properties:
bundle_id: { type: string, format: uuid }
transmittals:
type: array
items: { $ref: '#/components/schemas/TransmittalGetByBundleIdsReadDto' }
required: [bundle_id, transmittals]
# --- Templates --------------------------------------------------------
TransmittalTemplateListFiltersRequest:
type: object
properties:
include_wo_resources: { type: boolean, default: true }
resources: { type: array, nullable: true, items: { type: string, format: uuid } }
companies: { type: array, nullable: true, items: { type: integer } }
q: { type: string, nullable: true }
bookmark: { type: string, nullable: true }
limit: { type: integer, default: 20 }
TransmittalTemplateListResponse:
type: object
properties:
id: { type: string, format: uuid }
name: { type: string }
is_active: { type: boolean }
resource_id: { type: string, format: uuid, nullable: true }
allowed_initiators:
nullable: true
allOf: [{ $ref: '#/components/schemas/ReceiversReadResponseDto' }]
created_by: { type: integer }
created_at: { type: string, format: date-time }
has_deadline_interval: { type: boolean }
deadline_interval: { type: integer, minimum: 1, nullable: true, description: Интервал дедлайна в днях }
auto_send: { type: boolean, nullable: true }
has_additional_information: { type: boolean }
additional_information: { type: string, nullable: true }
receivers:
nullable: true
allOf: [{ $ref: '#/components/schemas/ReceiversReadResponseDto' }]
invalid_receivers:
nullable: true
allOf: [{ $ref: '#/components/schemas/ReceiversReadResponseDto' }]
required: [id, name, is_active, resource_id, allowed_initiators, created_by, created_at, has_deadline_interval, deadline_interval, auto_send, has_additional_information, additional_information, receivers, invalid_receivers]
TransmittalTemplateCreateRequestDto:
type: object
properties:
name: { type: string, minLength: 1, maxLength: 255 }
resource_id: { type: string, format: uuid, nullable: true }
allowed_initiators:
nullable: true
allOf: [{ $ref: '#/components/schemas/ReceiversRequestDto' }]
company_id: { type: integer }
has_deadline_interval: { type: boolean }
deadline_interval: { type: integer, minimum: 1, nullable: true, description: Интервал дедлайна в днях }
auto_send: { type: boolean, nullable: true }
has_additional_information: { type: boolean }
additional_information: { type: string, nullable: true }
receivers:
nullable: true
allOf: [{ $ref: '#/components/schemas/ReceiversRequestDto' }]
required: [name, resource_id, allowed_initiators, company_id, has_deadline_interval, deadline_interval, auto_send, has_additional_information, additional_information, receivers]
TransmittalTemplateCreateResponseDto:
type: object
properties:
id: { type: string, format: uuid }
required: [id]
TransmittalTemplateSelectListResponse:
type: object
properties:
id: { type: string, format: uuid }
name: { type: string }
created_by: { type: integer }
required: [id, name, created_by]
TransmittalTemplateGetSingleResponse:
type: object
properties:
name: { type: string }
created_by: { type: integer }
has_deadline_interval: { type: boolean }
deadline_interval: { type: integer, minimum: 1, nullable: true, description: Интервал дедлайна в днях }
auto_send: { type: boolean, nullable: true }
has_additional_information: { type: boolean }
additional_information: { type: string, nullable: true }
receivers:
nullable: true
allOf: [{ $ref: '#/components/schemas/ReceiversReadResponseDto' }]
invalid_receivers:
nullable: true
allOf: [{ $ref: '#/components/schemas/ReceiversReadResponseDto' }]
required: [name, created_by, has_deadline_interval, deadline_interval, auto_send, has_additional_information, additional_information, receivers, invalid_receivers]
TransmittalTemplateUpdateRequest:
type: object
description: Частичное обновление. Все поля опциональны.
properties:
name: { type: string, minLength: 1, maxLength: 255, nullable: true }
is_active: { type: boolean, nullable: true }
resource_id: { type: string, format: uuid, nullable: true }
allowed_initiators:
nullable: true
allOf: [{ $ref: '#/components/schemas/ReceiversRequestDto' }]
has_deadline_interval: { type: boolean, nullable: true }
deadline_interval: { type: integer, minimum: 1, nullable: true, description: Интервал дедлайна в днях }
auto_send: { type: boolean, nullable: true }
has_additional_information: { type: boolean, nullable: true }
additional_information: { type: string, nullable: true }
receivers:
nullable: true
allOf: [{ $ref: '#/components/schemas/ReceiversRequestDto' }]
# --- Infra ------------------------------------------------------------
ResourceStatus:
type: object
properties:
name: { type: string }
available: { type: boolean }
required: [name, available]
HealthCheckResponse:
type: object
properties:
availability:
type: array
items: { $ref: '#/components/schemas/ResourceStatus' }
status:
type: string
enum: [healthy, partially_healthy]
description: Вычисляемое поле — `healthy`, если доступны все зависимости
readOnly: true
required: [availability, status]