openapi: 3.0.3 info: title: PDM API version: "0.1.0" description: | REST API сервиса **pdm** (`pdm/pdm`, образ `pdmv2`) — шлюз/агрегатор над Postgres и множеством внутренних сервисов Sarex: документации, ресурсы и разрешения, замечания, вложения, состояния/рабочие области, подписки, атрибуты (EAV), инспекции, релизы, заметки, чертежи, BIM, трансмитталы, системный лог. Сервис написан на Go (**Fiber v2**). Приложение собирается в `internal/controller/http/v1.Setup` (`internal/controller/http/v1/router.go`), точка входа — `cmd/httpserver/main.go`. Роутинг делится на группы: - публичный API — префикс `/api` с версиями `v1`/`v2`/`v3`/`v4` (`group.Group("v1")` и т.д.); - внутренний API — префикс `/internal` (healthcheck, pprof, служебные ручки), без аутентификации на уровне приложения. Готовой спецификации (swagger) в репозитории нет — данный документ восстановлен из роутеров `internal/controller/http/**/router.go`. Сервер слушает порт `8080` (хардкод в `internal/app/http/httpserver.go`). ### Аутентификация Аутентификация применяется middleware `pkg/httpserver/middleware/auth.go` ко всем путям с префиксом `/api`. Токен передаётся заголовком `Authorization: Bearer `. Поддерживаются два режима: 1. **sarex-backend** (по умолчанию) — если заголовка `Identity` нет, подпись основного JWT проверяется публичным ключом из `PUBLIC_KEY` (PKIX). Из claims извлекаются `user_id`, `is_superuser`, `company_ids`, `service_accounts`, `permissions` и т.д. 2. **Zitadel** — если передан дополнительный заголовок `Identity: Bearer `, полезная нагрузка берётся из этого токена (`urn:zitadel:iam:user:metadata`); основной токен кладётся как `access_token`. Подпись identity-токена приложением не проверяется (`ParseUnverified`) — доверие обеспечивается сетевым слоем. При отсутствии заголовка `Authorization`, неверной схеме (не `Bearer`) или ошибке разбора токена возвращается **401 Unauthorized** (пустое тело). Пути `/internal/*` аутентификации на уровне приложения не требуют. ### Пагинация Списочные эндпоинты используют пагинацию через query-параметры `limit` и `offset` (напр. `internal/controller/http/v1/document/downloaded.go`, `flat.go`). Единого конверта ответа нет — формат зависит от эндпоинта. ### Обработка ошибок Ошибки бизнес-слоя оборачиваются в `AppError` (`internal/app_errors/errors.go`) и сериализуются как JSON `{ "message": "...", "error_code": "GW-XXXX" }`. HTTP-статус выбирается по `error_code` в `internal/app_errors/middleware.go`: | error_code | Статус | Значение | | --- | --- | --- | | `GW-0001` | 404 | Ресурс не найден | | `GW-0002` | 401 | Не аутентифицирован | | `GW-0003` | 403 | Нет доступа | | `GW-0004` | 400 | Некорректный запрос | | `GW-0014` | 400 | Ошибка валидации состояния | | `GW-0000` | 500 | Системная ошибка | Не все роутеры используют обёртку `middleware.ErrorHandler` — часть обработчиков возвращает ошибки/статусы напрямую, поэтому формат ответа об ошибке может отличаться от `AppError`. ### Замечания (расхождения кода) - Пути с сегментом `*` (напр. `/api/v1/disks/*/documents`, `/api/v1/documents/*/attributes`, `/api/v1/targets/*/remarks/*`) — это «жадные» wildcard-сегменты Fiber, захватывающие путь документа/цели целиком (включая `/`). В спецификации они представлены параметром пути. - Часть эндпоинтов завершается слэшем (`/`), часть — нет; поведение определяется определениями групп во Fiber. - v0-роутер (`internal/controller/http/v0`, на `labstack/echo`) в рантайме не подключён. contact: name: pdm url: https://gitlab.com/sarex-team/pdm servers: - url: http://pdm-api.documentations:8080 description: Stage (внутренний адрес в кластере, namespace documentations) - url: http://pdm-api.documentations-preprod:8080 description: Preprod (внутренний адрес в кластере) - url: http://pdm-api.documentations-prod:8080 description: Production (внутренний адрес в кластере) security: - bearerAuth: [] tags: - name: documents description: Документы, диски, проекты, атрибуты (v1/v2/v3/v4) - name: resources description: Ресурсы и разрешения (v1/v2) - name: remarks description: Замечания по таргетам - name: attachments description: Вложения - name: states description: Состояния рабочих областей - name: subscriptions description: Подписки - name: system_log description: Системный лог - name: targets description: Таргеты - name: inspections description: Инспекции - name: users description: Пользователи - name: eav description: Атрибуты (EAV) - name: releases description: Релизы - name: notes description: Заметки - name: drawings description: Чертежи (сечения и экспорты) - name: internal description: Служебные эндпоинты (без аутентификации) paths: # ---------------- v1: documents ---------------- /api/v1/disks/{diskPath}/documents: get: tags: [documents] summary: Список документов по диску (v1) parameters: - $ref: '#/components/parameters/DiskPath' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Offset' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/disks/{diskPath}/downloaded_documents: get: tags: [documents] summary: Список скачанных документов диска parameters: - $ref: '#/components/parameters/DiskPath' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Offset' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/disks/{diskPath}/flat_documents: get: tags: [documents] summary: Плоский список документов диска parameters: - $ref: '#/components/parameters/DiskPath' - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Offset' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/disks/{diskId}/thumbnails: post: tags: [documents] summary: Превью документов диска parameters: - name: diskId in: path required: true schema: { type: string } responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/projects/: get: tags: [documents] summary: Получить проект по ID документа responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/documents: post: tags: [documents] summary: Создать документ responses: '200': { $ref: '#/components/responses/Ok' } '400': { $ref: '#/components/responses/BadRequest' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/documents/{documentPath}/attributes: get: tags: [documents] summary: Атрибуты документа parameters: - $ref: '#/components/parameters/DocumentPath' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } put: tags: [documents] summary: Создать/обновить атрибуты документа parameters: - $ref: '#/components/parameters/DocumentPath' responses: '200': { $ref: '#/components/responses/Ok' } '400': { $ref: '#/components/responses/BadRequest' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/documents/{documentPath}/subscription/: delete: tags: [documents] summary: Удалить подписку по ID документа parameters: - $ref: '#/components/parameters/DocumentPath' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/documents/bin: get: tags: [documents] summary: Список удалённых документов (корзина) responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/documents/approving_users: post: tags: [documents] summary: Согласующие пользователи responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/documents/bundle_versions: post: tags: [documents] summary: Версии бандлов документов responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/documents/ancestors: post: tags: [documents] summary: Предки документов responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/documents/size: get: tags: [documents] summary: Размер папки responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/documents/related_documents: get: tags: [documents] summary: Связанные документы responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } post: tags: [documents] summary: Создать связи документов responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/documents/related_documents/bulk_delete: post: tags: [documents] summary: Массовое удаление связей документов responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } # ---------------- v1: remarks ---------------- /api/v1/targets/{targetPath}/remarks: post: tags: [remarks] summary: Создать замечание для таргета parameters: - $ref: '#/components/parameters/TargetPath' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/targets/{targetPath}/remarks/{remarkPath}: get: tags: [remarks] summary: Получить замечание parameters: - $ref: '#/components/parameters/TargetPath' - $ref: '#/components/parameters/RemarkPath' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } patch: tags: [remarks] summary: Обновить замечание parameters: - $ref: '#/components/parameters/TargetPath' - $ref: '#/components/parameters/RemarkPath' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } # ---------------- v1: resources ---------------- /api/v1/resources/: get: tags: [resources] summary: Список ресурсов responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/resources/users-with-resources/: post: tags: [resources] summary: Пользователи с ресурсами responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/resources/permissions-bulk/: patch: tags: [resources] summary: Массовое обновление разрешений responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/resources/{uuid}/: get: tags: [resources] summary: Ресурс по UUID parameters: - name: uuid in: path required: true schema: { type: string, format: uuid } responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/resource-permissions/: get: tags: [resources] summary: Разрешения на ресурсы responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } post: tags: [resources] summary: Массовое создание разрешений на ресурс responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/resource-permissions/{id}/: delete: tags: [resources] summary: Удалить разрешение на ресурс parameters: - $ref: '#/components/parameters/IdPath' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/bulk_delete/resource-permissions/: post: tags: [resources] summary: Массовое удаление разрешений на ресурс responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/company-resource-permissions/: get: tags: [resources] summary: Разрешения компаний на ресурсы responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } post: tags: [resources] summary: Создать разрешение компании на ресурс responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/company-resource-permissions/{id}/: delete: tags: [resources] summary: Удалить разрешение компании на ресурс parameters: - $ref: '#/components/parameters/IdPath' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/resources-rpc/resource-by-document-id/{id}/: get: tags: [resources] summary: Ресурс по ID документа parameters: - $ref: '#/components/parameters/IdPath' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/resources-rpc/parent-document-by-resource-id/{uuid}/: get: tags: [resources] summary: Родительская папка проекта по UUID ресурса parameters: - name: uuid in: path required: true schema: { type: string, format: uuid } responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } # ---------------- v1: attachments ---------------- /api/v1/attachments: post: tags: [attachments] summary: Создать вложение responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } get: tags: [attachments] summary: Список вложений responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/attachments/{id}: get: tags: [attachments] summary: Вложение по ID parameters: - $ref: '#/components/parameters/IdPathPlain' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } delete: tags: [attachments] summary: Удалить вложение parameters: - $ref: '#/components/parameters/IdPathPlain' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } # ---------------- v1: states (workspace) ---------------- /api/v1/workspace/{ws_id}: post: tags: [states] summary: Создать состояние с вложением parameters: - $ref: '#/components/parameters/WsId' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } get: tags: [states] summary: Состояния с вложениями parameters: - $ref: '#/components/parameters/WsId' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/workspace/{ws_id}/dynamic_states: post: tags: [states] summary: Создать динамические состояния parameters: - $ref: '#/components/parameters/WsId' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } get: tags: [states] summary: Динамические состояния parameters: - $ref: '#/components/parameters/WsId' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/workspace/states/{id}: get: tags: [states] summary: Состояние по ID parameters: - $ref: '#/components/parameters/IdPathPlain' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/workspace/dynamic_states/{id}: get: tags: [states] summary: Динамическое состояние по ID parameters: - $ref: '#/components/parameters/IdPathPlain' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } # ---------------- v1: subscriptions ---------------- /api/v1/subscription/: post: tags: [subscriptions] summary: Создать подписку responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } # ---------------- v1: system_log ---------------- /api/v1/system_log/: get: tags: [system_log] summary: Отфильтрованный системный лог responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } post: tags: [system_log] summary: Записать в системный лог responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } # ---------------- v1: targets ---------------- /api/v1/targets/: get: tags: [targets] summary: Список таргетов responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/targets/{targetPath}/: get: tags: [targets] summary: Таргет по ID parameters: - $ref: '#/components/parameters/TargetPath' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } # ---------------- v1: inspections ---------------- /api/v1/inspections/: post: tags: [inspections] summary: Создать инспекцию responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } get: tags: [inspections] summary: Список инспекций responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/inspections/{id}: get: tags: [inspections] summary: Инспекция по ID parameters: - $ref: '#/components/parameters/IdInt' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } patch: tags: [inspections] summary: Обновить инспекцию parameters: - $ref: '#/components/parameters/IdInt' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } delete: tags: [inspections] summary: Удалить инспекцию parameters: - $ref: '#/components/parameters/IdInt' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/inspections/created_at/daterange: get: tags: [inspections] summary: Диапазон дат создания responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/inspections/inspection_date/daterange: get: tags: [inspections] summary: Диапазон дат инспекций responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/inspections/available_responsible_users: get: tags: [inspections] summary: Доступные ответственные пользователи responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/inspections/available_inspection_dates: get: tags: [inspections] summary: Доступные даты инспекций responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/inspections/export: get: tags: [inspections] summary: Экспорт инспекций responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } # ---------------- v1: users / eav / releases / notes ---------------- /api/v1/users/: get: tags: [users] summary: Пользователи по разрешению на ресурс responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/attribute/: get: tags: [eav] summary: Получить атрибуты (EAV) responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/releases/{id}: get: tags: [releases] summary: Список релизов по ID проекта parameters: - $ref: '#/components/parameters/IdInt' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/notes/{service_id}/{entity_id}/{instance_id}/: get: tags: [notes] summary: Заметки по сервису/сущности/инстансу parameters: - { name: service_id, in: path, required: true, schema: { type: string } } - { name: entity_id, in: path, required: true, schema: { type: string } } - { name: instance_id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } # ---------------- v1: drawings ---------------- /api/v1/drawings/cross-sections: post: tags: [drawings] summary: Создать сечение responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } get: tags: [drawings] summary: Сечения по ID инстанса responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/drawings/cross-sections/{cross_section_id}/data: get: tags: [drawings] summary: Данные сечения parameters: - { name: cross_section_id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/drawings/cross-sections/{cross_section_id}: delete: tags: [drawings] summary: Удалить сечение parameters: - { name: cross_section_id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/drawings/exports: post: tags: [drawings] summary: Создать экспорт responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } get: tags: [drawings] summary: Список экспортов responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v1/drawings/exports/{export_id}: delete: tags: [drawings] summary: Удалить экспорт parameters: - { name: export_id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } # ---------------- v2 ---------------- /api/v2/resources/: get: tags: [resources] summary: Расширенный список ресурсов (v2) responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v2/resources: post: tags: [resources] summary: Создать расширенный ресурс (v2) responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v2/resources/{id}: get: tags: [resources] summary: Расширенный ресурс по ID (v2) parameters: - $ref: '#/components/parameters/IdPathPlain' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } patch: tags: [resources] summary: Обновить расширенный ресурс (v2) parameters: - $ref: '#/components/parameters/IdPathPlain' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } delete: tags: [resources] summary: Удалить расширенный ресурс (v2) parameters: - $ref: '#/components/parameters/IdPathPlain' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v2/users/: get: tags: [users] summary: Пользователи по ресурсу (v2) responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v2/disks/{diskPath}/documents: get: tags: [documents] summary: Список документов по диску (v2) parameters: - $ref: '#/components/parameters/DiskPath' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } # ---------------- v3 / v4 ---------------- /api/v3/disks/{diskPath}/documents: get: tags: [documents] summary: Упрощённый список документов по диску (v3) parameters: - $ref: '#/components/parameters/DiskPath' responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } /api/v4/disks/{disk_id}/documents: get: tags: [documents] summary: Поиск документов по диску (v4) parameters: - { name: disk_id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/Ok' } '401': { $ref: '#/components/responses/Unauthorized' } # ---------------- internal ---------------- /internal/v1/documents/approving_users: post: tags: [internal] summary: Согласующие пользователи (внутренний, без аутентификации) security: [] responses: '200': { $ref: '#/components/responses/Ok' } /internal/healthz/startup: get: tags: [internal] summary: Startup-проба (БД, опционально Valkey) security: [] responses: '200': { description: OK } '503': { description: Service Unavailable } /internal/healthz/live: get: tags: [internal] summary: Liveness-проба security: [] responses: '200': { description: OK } /internal/healthz/ready: get: tags: [internal] summary: Readiness-проба security: [] responses: '200': { description: OK } '503': { description: Service Unavailable } components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT description: | JWT в заголовке `Authorization: Bearer `. В режиме Zitadel дополнительно передаётся заголовок `Identity: Bearer `. parameters: Limit: name: limit in: query required: false schema: { type: integer, format: int64, minimum: 0 } description: Размер страницы Offset: name: offset in: query required: false schema: { type: integer, format: int64, minimum: 0 } description: Смещение DiskPath: name: diskPath in: path required: true schema: { type: string } description: Жадный wildcard-сегмент Fiber (может содержать `/`) — путь/ID диска DocumentPath: name: documentPath in: path required: true schema: { type: string } description: Жадный wildcard-сегмент Fiber — путь/ID документа TargetPath: name: targetPath in: path required: true schema: { type: string } description: Жадный wildcard-сегмент Fiber — путь/ID таргета RemarkPath: name: remarkPath in: path required: true schema: { type: string } description: Жадный wildcard-сегмент Fiber — путь/ID замечания WsId: name: ws_id in: path required: true schema: { type: string } description: UUID рабочей области IdPath: name: id in: path required: true schema: { type: string } IdPathPlain: name: id in: path required: true schema: { type: string } IdInt: name: id in: path required: true schema: { type: integer } description: Числовой идентификатор (Fiber-ограничение `:id`) responses: Ok: description: Успешный ответ (структура зависит от эндпоинта) content: application/json: schema: {} BadRequest: description: Некорректный запрос content: application/json: schema: { $ref: '#/components/schemas/AppError' } Unauthorized: description: Не аутентифицирован (пустое тело) Forbidden: description: Нет доступа content: application/json: schema: { $ref: '#/components/schemas/AppError' } NotFound: description: Ресурс не найден content: application/json: schema: { $ref: '#/components/schemas/AppError' } schemas: AppError: type: object description: Формат ошибки бизнес-слоя (`internal/app_errors/errors.go`) properties: message: type: string example: not found error_code: type: string description: Внутренний код ошибки (`GW-XXXX`) enum: [GW-0000, GW-0001, GW-0002, GW-0003, GW-0004, GW-0014] example: GW-0001 required: [message, error_code]