# Эндпоинты, с которыми взаимодействует documentation-frontend

Документ описывает все HTTP-эндпоинты внешних сервисов, к которым обращается модуль (микрофронтенд `documentation-frontend`, образ `documentation-frontend-app`, деплой `frontend`). Модуль публикуется как remote для Module Federation (`webpack.config.js`, имя `srx_documentations`).

## Как устроено взаимодействие

Все запросы описаны декларативно в реестре `module/api/endpoints.ts` (объект `endpoints`). Каждый эндпоинт задаётся структурой `Endpoint`:

- `service` — логическое имя сервиса (см. таблицу хостов ниже);
- `method` — HTTP-метод (`GET`/`POST`/`PUT`/`PATCH`/`DELETE`);
- `path(args)` — функция, возвращающая путь запроса (с подстановкой параметров/query);
- `body(args)` — опционально, формирование тела запроса;
- `responseType` — опционально, тип ответа (напр. `blob`);
- `accessToken(args)` — опционально, явная передача access-токена в заголовки;
- `cache`, `queryOptions` — опции кеширования/повторов;
- `showErrorNotification` — показывать ли уведомление об ошибке (по умолчанию `true`).

Запрос выполняется единой функцией `fetch(endpoint, params, controller)` (`module/api/endpoints.ts`), которая через `httpService` (`module/api/http-service.ts`, обёртка `createHttpService` из `@sarex-team/sdk-js` поверх `axios`) отправляет запрос на базовый хост сервиса. Базовый хост выбирается по паре «`service` + окружение»: `httpService` создаётся с картой хостов `apiHosts` и текущим `buildEnv`, и разрешает хост внутри себя. Тот же алгоритм продублирован в экспортируемом хелпере `resolveHost(service)` из `module/api/hosts.ts`. Итоговый URL = `<базовый хост сервиса>` + `path` эндпоинта.

Окружение определяется глобальной константой `BUILD_ENV`, которую webpack подставляет в бандл через `DefinePlugin` (`webpack.config.js`) из переменной сборки `process.env.BUILD_ENV`. Допустимые значения проверяются в `env.js`: `local`/`stage`/`preprod`/`prod`/`contour`. В режиме `local` тип http-сервиса переключается на `"original"` (`module/api/http-service.ts`).

Ошибки маппируются в человекочитаемые сообщения в `module/api/errors.ts` (`resolveNetworkErrorByCode`, `resolveNetworkError`).

## Базовые хосты по сервисам и окружениям

Значения из `module/api/hosts.ts` (объект `apiHosts`). Итоговый URL = `<базовый хост сервиса>` + `path` эндпоинта.

| Сервис (`service`) | Назначение | `local` | `stage` | `preprod` | `prod` | `contour` |
| --- | --- | --- | --- | --- | --- | --- |
| `sarex` | Локальный сервис данных (`/api/core`, `/api/client`) | `/sarex-backend` | `/` | `/` | `/` | `/` |
| `documentations` | Сервис документации (документы, бандлы, файлы) | `https://stage-api.sarex.io/documentations` | `https://stage-api.sarex.io/documentations` | `https://api.preprod.sarex.io/documentations` | `https://api.sarex.io/documentations` | `/documentations` |
| `sarexApi` | Gateway/API Sarex (`/gateway`, `/eav`, `/cde`, `/transmittals`, `/flows`, `/issues`) | `https://stage-api.sarex.io` | `https://stage-api.sarex.io` | `https://api.preprod.sarex.io` | `https://api.sarex.io` | `/` |
| `workspaces` | Сервис рабочих областей | `https://stage-api.sarex.io/workspaces` | `https://stage-api.sarex.io/workspaces` | `https://api.preprod.sarex.io/workspaces` | `https://api.sarex.io/workspaces` | `/workspaces` |
| `workflows` | Сервис обработки документов | `https://stage-api.sarex.io/workflows` | `https://stage-api.sarex.io/workflows` | `https://api.preprod.sarex.io/workflows` | `https://api.sarex.io/workflows` | `/workflows` |
| `processes` | Сервис рабочих процессов (flows, reviews) | `https://stage-api.sarex.io/flows` | `https://stage-api.sarex.io/flows` | `https://api.preprod.sarex.io/flows` | `https://api.sarex.io/flows` | `/flows` |
| `remarks` | Сервис замечаний | `https://stage-api.sarex.io/remarks` | `https://stage-api.sarex.io/remarks` | `https://api.preprod.sarex.io/remarks` | `https://api.sarex.io/remarks` | `/remarks` |
| `files` | Сервис файлов | `https://stage-api.sarex.io/files` | `https://stage-api.sarex.io/files` | `https://api.preprod.sarex.io/files` | `https://api.sarex.io/files` | `/files` |
| `google` | Временное хранилище (GCS) | `https://storage.googleapis.com/srx-tmp` | `https://storage.googleapis.com/srx-tmp` | `https://storage.googleapis.com/srx-tmp` | `https://storage.googleapis.com/srx-tmp` | `https://storage.googleapis.com/srx-tmp` |
| `bim` | BIM-API | `https://stage-bim-api.sarex.io` | `https://stage-bim-api.sarex.io` | `https://bim-api.preprod.sarex.io` | `https://bim-api.sarex.io` | `""` |
| `zitadel` | IdP (аутентификация) | `https://idp.dev.stage.sarex.io` | `https://idp.dev.stage.sarex.io` | `https://login.preprod.sarex.io` | `https://login.sarex.io` | `""` |

> Хосты `google`, `bim` и `zitadel` заданы в карте хостов, но напрямую в реестре `endpoints` не используются — они задействованы через SDK/вьюер (`@sarex-team/sdk-js`) и механизм аутентификации. В окружении `local` сервис `sarex` проксируется на `/sarex-backend`, в `stage`/`preprod`/`prod` — на `/` (относительные пути), в `contour` все сервисы работают по относительным путям изолированного контура. Отдельного `module-hosts.ts` (карты хостов удалённых модулей) в репозитории нет.

## Эндпоинты по сервисам

### `sarex` — Локальный сервис данных

| Ключ | Метод | Путь | Назначение |
| --- | --- | --- | --- |
| `getSettings` | GET | `/api/client/settings/` | Клиентские настройки (кешируется, `stateTime: 5`) |
| `getUser` | GET | `/api/core/users/{userId}/` | Пользователь по id |
| `getUsersByCompanyId` | GET | `/api/core/users/?company={companyId}&limit={limit}&offset={offset}` | Пользователи компании (пагинация) |
| `getTargets` | GET | `/api/core/targets/` | Список таргетов |
| `getCompanies` | GET | `/api/core/companies/` | Список компаний |
| `getDepartmentById` | GET | `/api/core/admin/departments?company={companyId}` | Отделы компании |
| `getUsersPositionById` | GET | `/api/core/admin/positions/?company={companyId}` | Должности компании |
| `getMrpaList` | POST | `/api/core/mrpa/list/` | Список МЧД (фильтр по пользователю/компании) |
| `getByFullUrl` | GET | `{url}` | Запрос по произвольному URL |

### `documentations` — Сервис документации

| Ключ | Метод | Путь | Назначение |
| --- | --- | --- | --- |
| `getDisks` | GET | `/api/v1/disks` | Список дисков |
| `getDocumentTypes` | GET | `/api/v1/documents/types` | Справочник типов документов |
| `getAllPermmission` | GET | `/api/v1/permissions` | Все права доступа |
| `getDocPermission` | GET | `/api/v1/documents/{id}/permissions` | Права доступа документа |
| `postPermission` | POST | `/api/v1/documents/{id}/permissions` | Выдать права сервисному аккаунту |
| `postBundle` | POST | `/api/v1/bundles` | Создать бандл |
| `postFile` | POST | `/api/v1/bundles/{bundleId}/{fileKey}?single_upload=1` | Загрузить файл (single upload) |
| `uploadFileStart` | POST | `/api/v1/bundles/{bundleId}/{key}/upload_multipart` | Начать multipart-загрузку файла |
| `uploadFolderStart` | POST | `/api/v1/bundles/{bundleId}/{key}/upload_multipart?upload_path={folderPath}` | Начать multipart-загрузку с указанием пути |
| `uploadPart` | PUT | `/api/v1/bundles/{bundleId}/{bundleKey}?part_number={partNumber}` | Загрузить часть файла |
| `bundleComplite` | POST | `/api/v1/bundles/{bundleId}/upload_finish` | Завершить загрузку бандла |
| `bundleCompleteUpload` | POST | `/api/v1/bundles/{bundleId}/upload_finish` | Завершить загрузку бандла (дубль ключа) |
| `getFile` | GET | `/api/v1/bundles/{bundleId}/{bundleKey}` | Получить файл бандла |
| `updateComment` | PATCH | `/api/v1/bundles/{bundleId}/comment` | Обновить комментарий бандла |
| `getBundles` | GET | `/api/v1/documents/{id}/bundles` | Бандлы документа |
| `addBundle` | POST | `/api/v1/documents/{documentId}/add_bundle` | Привязать бандл к документу |
| `moveBundles` | PATCH | `/api/v1/documents/{documentId}/move_bundles` | Переместить бандлы |
| `removeBundle` | DELETE | `/api/v1/bundles/{id}` | Удалить бандл |
| `postWorkspace` | POST | `/api/v1/workspaces` | Создать рабочую область |
| `getDocumentById` | GET | `/api/v1/documents/{id}` | Документ по id |
| `getDocumentWithBundles` | GET | `/api/v1/documents/{id}?extend=bundles` | Документ с бандлами |
| `changeDocument` | PATCH | `/api/v1/documents/{documentId}` | Переименовать документ |
| `changeDocumentName` | PATCH | `/api/v1/documents/{id}` | Переименовать документ |
| `updatePath` | PATCH | `/api/v1/documents/{id}/update-path` | Сменить родителя документа |
| `updateDocumentsPaths` | PATCH | `/api/v1/documents/update-path` | Массовая смена родителя |
| `deleteDocument` | DELETE | `/api/v1/documents/{id}` | Удалить документ |
| `deleteDocuments` | DELETE | `/api/v1/documents?document_ids={ids}` | Удалить несколько документов |
| `getFolderChildrenWithActiveProcesses` | POST | `/api/v1/documents/flows` | Дети папки с активными процессами |
| `downloadFile` | GET | `/api/v1/bundles/{lastBundleId}/{key}/download` | Скачать файл (с флагами `include_original_pdf`/`include_printable_pdf`) |
| `downloadFiles` | GET | `/api/v1/download_url/documents?document_ids={documentIds}` | Получить ссылку на скачивание документов |
| `downloadAllFiles` | GET | `/api/v1/bundles/{lastBundleId}/download` | Скачать все файлы бандла |
| `downloadFolder` | GET | `/api/v1/documents/{docId}/download?depth={depth}` | Скачать папку |
| `getFoldersDownloadUrl` | GET | `/api/v1/documents/get_folders_download_url?document_ids={ids}` | Ссылка на скачивание папок |
| `conversionFile` | POST | `/api/v1/conversion` | Конвертация документа (в IFC) |
| `addMarks` | PUT | `/api/v1/bundles/{bundleId}/marks` | Добавить штампы/QR/подписи |
| `sign` | POST | `/api/v1/bundles/{bundleId}/sign` | Подписать бандл |
| `cancelQrCode` | PATCH | `/api/v1/bundles/{bundleId}/cancel_qr` | Отменить QR-код |
| `restartWorkflow` | POST | `/api/v1/bundles/{bundleId}/restart` | Перезапустить workflow бандла |
| `getPublicLink` | GET | `/api/v1/public/documents/public_link/{public_link_id}` | Получить публичную ссылку |
| `createPublicLink` | POST | `/api/v1/documents/public_link` | Создать публичную ссылку |
| `updatePublicLink` | PATCH | `/api/v1/documents/public_link/{public_link_id}` | Обновить публичную ссылку |
| `deletePublicLink` | DELETE | `/api/v1/documents/public_link/{public_link_id}` | Удалить публичную ссылку |
| `removeDoc` | DELETE | `/api/v1/documents/bin?parent_id={id}` | Переместить в корзину |
| `recoveryDocument` | PATCH | `/api/v1/documents/bin/restore?parent_id={id}` | Восстановить из корзины |
| `copyFolderStructure` | POST | `/api/v1/documents/copy_structure` | Копировать структуру папок |
| `getTemplateJSON` | GET | `/api/v1/templates/{bundleId}` | JSON-шаблон бандла |
| `uploadSingleTemplate` | POST | `/api/v1/bundles/{bundleId}/{key}/upload_single` | Загрузить файл шаблона |
| `createReport` | POST | `/api/v1/documents/create_report` | Сформировать отчёт по документам |
| `updateChangelog` | PATCH | `api/v1/changelogs/{bundleId}` | Обновить запись журнала изменений |
| `createChangelog` | POST | `api/v1/changelogs/create` | Создать запись журнала изменений |
| `getFavorites` | GET | `/api/v1/favorite_documents?company_id={companyId}` | Избранные документы |
| `createFavoriteDocument` | POST | `/api/v1/favorite_documents` | Добавить документ в избранное |
| `deleteFavoriteDocument` | DELETE | `/api/v1/favorite_documents/{documentId}` | Убрать документ из избранного |
| `getNearestNameTemplate` | GET | `/api/v1/documents/{documentId}/name_template` | Ближайший шаблон именования (без уведомления об ошибке) |
| `getDocumentNameTemplate` | GET | `/api/v1/name_templates/{documentId}` | Шаблон именования документа (без уведомления об ошибке) |
| `createNameTemplate` | POST | `/api/v1/name_templates/create` | Создать шаблон именования |
| `updateNameTemplate` | PATCH | `/api/v1/name_templates/{documentId}` | Обновить шаблон именования |
| `deleteNameTemplate` | DELETE | `/api/v1/name_templates/{documentId}` | Удалить шаблон именования |
| `createLink` | POST | `/api/v1/links` | Создать ярлык (ссылку на документ) |
| `getBundleMrpas` | GET | `/api/v1/bundles/{bundleId}/mrpas` | МЧД бандла |

### `sarexApi` — Gateway/API Sarex

Через этот сервис проходят запросы к `/gateway`, `/eav`, `/cde`, а также к сабпутям других доменов, доступным через общий шлюз: `/transmittals`, `/flows`, `/issues`.

| Ключ | Метод | Путь | Назначение |
| --- | --- | --- | --- |
| `getDocuments` | GET | `/gateway/api/v1/disks/{id}/documents?parent_id={parentId}&child_id={childId}` | Документы диска (по родителю/потомку) |
| `getFolderChildren` | GET | `/gateway/api/v1/disks/{diskId}/documents?parent_id={documentId}` | Дети папки |
| `getSearch` | GET | `/gateway/api/v4/disks/{diskId}/documents?...` | Поиск/фильтрация документов (root_document, limit, filters, bookmark) |
| `createDocument` | POST | `/gateway/api/v1/documents` | Создать документ/папку/проект |
| `fetchDocumentPaths` | POST | `/gateway/api/v1/documents/ancestors` | Предки документов |
| `getAttributesByDocument` | GET | `/gateway/api/v1/documents/{id}/attributes` | Атрибуты документа |
| `updateAttributes` | PUT | `/gateway/api/v1/documents/{id}/attributes` | Обновить атрибуты документа |
| `addAttributes` | POST | `/gateway/eav/api/v0/entity/` | Создать сущность атрибутов (EAV) |
| `getDefaultAttributes` | GET | `/eav/api/v0/schema/?model=document&company_id={companyId}&type_identifier={docType}` | Схема атрибутов по типу |
| `getAttributes` | GET | `/eav/api/v0/attribute/?company_id={params}` | Атрибуты компании |
| `getAttributesWithParams` | GET | `/eav/api/v0/schema/?model=document&{params}` | Схема атрибутов с параметрами |
| `updateSubscription` | POST | `/gateway/api/v1/subscription/` | Создать/обновить подписку |
| `deleteSubscription` | DELETE | `/gateway/api/v1/documents/{documentId}/subscription/` | Удалить подписку |
| `getActivityLog` | GET | `/gateway/api/v1/system_log/?model_names=document&...` | Журнал активности документа |
| `fetchResourceByDocumentId` | GET | `/gateway/api/v1/resources-rpc/resource-by-document-id/{id}/` | Ресурс по id документа |
| `getUsersWithTransmittalProjectPermissions` | GET | `/gateway/api/v2/users/?limit=5000&offset=0&resource_id={projectId}&permissions={permissions}` | Пользователи с правами в проекте |
| `getRemovedDocuments` | GET | `/gateway/api/v1/documents/bin?parent_id={id}{params}` | Удалённые документы в папке |
| `getRemovedFilteredDocuments` | GET | `/gateway/api/v1/documents/bin{params}` | Удалённые документы (фильтр) |
| `getTemplates` | GET | `/gateway/api/v1/disks/{diskId}/flat_documents?type={type}` | Плоский список документов по типу |
| `getFileSize` | GET | `/gateway/api/v1/documents/size?disk_id={diskId}&document_id={documentId}` | Размер документа |
| `completeUpload` | POST | `{uploadUrl}/complete` | Завершение загрузки (по переданному URL) |
| `createTransmittal` | POST | `/transmittals/api/v1/transmittals/create` | Создать трансмиттал |
| `getTransmittalById` | GET | `/transmittals/api/v1/transmittals/{transmittalId}` | Трансмиттал по id |
| `getTransmittalsByBundleId` | POST | `/transmittals/internal/v1/transmittals/by_bundle_ids` | Трансмитталы по id бандлов |
| `getTemplateListForSelect` | GET | `/transmittals/api/v1/transmittal_templates/select?resource={resourceId}` | Список шаблонов трансмитталов для выбора |
| `getSingleTemplate` | GET | `/transmittals/api/v1/transmittal_templates/{templateId}?resource={resourceId}` | Шаблон трансмиттала по id |
| `createPrescriptionDocument` | POST | `/issues/api/prescriptions/{prescriptionId}/generate/` | Сгенерировать документ по предписанию |
| `loadReviewData` | GET | `/flows/api/v1/documents/?bundle_ids={ids}&limit=10000&full=true` | Данные согласований по бандлам (с явным access-токеном) |
| `searchAssets` | POST | `eav/api/v4/assets/search/` | Поиск активов по id |
| `getProjectAssets` | GET | `eav/api/v4/assets/?linkable_to_project={resourceId}&parentId=null` | Активы проекта |
| `getAssetsList` | GET | `eav/api/v4/assets/?tenant_id={tenantId}&linkable_to_project={resourceId}&depth=0&...` | Список активов (поиск/пагинация) |
| `getAssets` | GET | `eav/api/v4/assets/?{params}` | Активы по произвольным параметрам |
| `getAssetLevels` | GET | `eav/api/v4/assets/?tenant_id={tenantId}&parent_id={parentAssetId}&path_contains={id}` | Уровни активов |
| `getBindings` | GET | `/cde/app/v1/bundles/{bundleId}/bindings` | Привязки бандла |
| `createSession` | POST | `/cde/app/v1/s32d/sessions/` | Создать S32D-сессию |
| `getSessionList` | GET | `/cde/app/v1/s32d/sessions/` | Список S32D-сессий |
| `uploadS32DSingle` | PUT | `/cde/app/v1/s32d/sessions/{sessionId}/archive` | Загрузить архив S32D (single) |
| `s32dMultipartInit` | POST | `/cde/app/v1/s32d/sessions/{sessionId}/archive/multipart` | Начать multipart-загрузку архива S32D |
| `s32dMultipartUploadPart` | PUT | `/cde/app/v1/s32d/sessions/{sessionId}/archive/multipart/{uploadId}/parts/{partNumber}` | Загрузить часть архива S32D |
| `s32dMultipartComplete` | POST | `/cde/app/v1/s32d/sessions/{sessionId}/archive/multipart/{uploadId}/complete` | Завершить multipart-загрузку S32D |
| `startS32DProcess` | POST | `/cde/app/v1/s32d/sessions/{sessionId}/process` | Запустить обработку S32D |

### `processes` — Сервис рабочих процессов (flows)

| Ключ | Метод | Путь | Назначение |
| --- | --- | --- | --- |
| `getProcesses` | GET | `/api/v1/flows/?{query}` | Список процессов (flows) |
| `createReview` | POST | `/api/v1/reviews/` | Создать review |
| `deleteReview` | DELETE | `/api/v1/reviews/{id}/` | Удалить review |
| `activateReview` | PATCH | `/api/v1/reviews/{id}/approve/` | Активировать/утвердить review |
| `createReviewDocuments` | POST | `/api/v1/documents/` | Добавить документы в review |

### `workflows` — Сервис обработки документов

| Ключ | Метод | Путь | Назначение |
| --- | --- | --- | --- |
| `getWorkflow` | GET | `/api/v1/workflows/{workflowId}` | Workflow по id |
| `getWorkflows` | POST | `/api/v1/workflows/batch` | Пакетное получение workflow |

### `workspaces` — Сервис рабочих областей

| Ключ | Метод | Путь | Назначение |
| --- | --- | --- | --- |
| `getWorkspaces` | GET | `/api/v1/workspaces/{uuid}` | Рабочая область по uuid |

### `remarks` — Сервис замечаний

| Ключ | Метод | Путь | Назначение |
| --- | --- | --- | --- |
| `getRemarksTotalCount` | GET | `/api/v1/total_count` | Общее число замечаний |

### `files` — Сервис файлов

| Ключ | Метод | Путь | Назначение |
| --- | --- | --- | --- |
| `downloadBundlesMrpas` | POST | `/api/v1/bundles_mrpas/` | Скачать МЧД бандлов (ответ `blob`) |

## Обработка ошибок

Маппинг ошибок выполняется в `module/api/errors.ts`. Функция `fetch` (`module/api/endpoints.ts`) перехватывает `AxiosError` и вызывает:

- `resolveNetworkErrorByCode(service, code, endpoint, method, data)` — при HTTP-ответе с кодом ≥ 400 и при отмене запроса (`CanceledError`/`ERR_CANCELED`, внутренний код `-1` → «Запрос был отменен»);
- `resolveNetworkError(service, error)` — при сетевой ошибке без ответа сервера.

Базовый маппинг кодов (`httpCodeToError`): `400` — «некорректный формат запроса», `401` — «ошибка авторизации», `403` — «доступ запрещен», `404` — «ресурс не найден», `500` — «ошибка сервера». Для неизвестного кода подбирается ближайший (`4xx` → `400`, иначе → `500`). К сообщению добавляется человекочитаемое имя сервиса из `getServiceToName()` (напр. `documentations`/`sarexApi` → «Сервис документации», `sarex` → «Локальный сервис данных», `processes` → «Сервис рабочих процессов», `workflows` → «Сервис обработки документов», `remarks` → «Сервис замечаний», `workspaces` → «Сервис рабочих областей», `files` → «Сервис файлов»).

Для части кодов сообщение уточняется по эндпоинту и методу:

- `401` — набор сообщений `error401Messages` (истёкшая/невалидная сессия, завершённая сессия); по умолчанию — «Ваш токен невалиден, обновите страницу».
- `403` — тип определяется `determine403ErrorType(endpoint, method)` (напр. чтение/создание/редактирование/удаление/перемещение документа, скачивание, загрузка файла, управление доступом, изменение атрибутов, создание review/трансмиттала, доступ к диску/проекту), сообщения — `error403Messages`.
- `400` — тип определяется `determine400ErrorType(endpoint, method, data)` с анализом текста `data.message` (конфликт имени, дубликат, отсутствие/некорректность расширения, некорректный формат), сообщения — `error400Messages`.
- `409` — тип определяется `determine409ErrorType(endpoint, method, data)` (дубликаты имён документов/папок/ярлыков, конфликт при `copy_structure`), сообщения — `error409Messages`.

По умолчанию у запросов включён показ уведомления об ошибке (`showErrorNotification !== false`); отдельные эндпоинты отключают его (`getNearestNameTemplate`, `getDocumentNameTemplate`). Типы кодов ошибок описаны в `module/api/types.ts`.
