919 lines
35 KiB
YAML
919 lines
35 KiB
YAML
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 <jwt>`. Поддерживаются два режима:
|
||
|
||
1. **sarex-backend** (по умолчанию) — если заголовка `Identity` нет, подпись
|
||
основного JWT проверяется публичным ключом из `PUBLIC_KEY` (PKIX). Из
|
||
claims извлекаются `user_id`, `is_superuser`, `company_ids`,
|
||
`service_accounts`, `permissions` и т.д.
|
||
2. **Zitadel** — если передан дополнительный заголовок
|
||
`Identity: Bearer <jwt>`, полезная нагрузка берётся из этого токена
|
||
(`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 <jwt>`. В режиме Zitadel
|
||
дополнительно передаётся заголовок `Identity: Bearer <jwt>`.
|
||
|
||
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<int>`)
|
||
|
||
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]
|