openapi: 3.0.3 info: title: Documentation API v2 version: "1.0" description: | REST API сервиса **documentation-api-v2** (`pdm/documentation-api-v2`) — Go-сервис домена «documentations» (v2): управление дисками, документами, бандлами, data source, страницами, публичными ссылками, workflow-обработкой и загрузкой файлов (в т.ч. multipart). Сервис написан на Go (**Fiber v2**, `github.com/gofiber/fiber/v2`). HTTP-сервер собирается в `internal/api/httpserver/server.go`. Спецификация ниже получена конвертацией сгенерированной `swag`-схемы (`docs/swagger.yaml`, Swagger 2.0) в OpenAPI 3.0.3 и нормализацией путей под реальные маршруты Fiber. Роутинг состоит из двух групп (`server.go`, `App.Run`): - публичный API — префикс `/api/v1`; - внутренний API — префикс `/internal/v1` (для вызовов внутри кластера). Интерактивная документация Swagger UI доступна по `/swagger/*`. Служебный эндпоинт проб k8s — `GET /ping` (вне групп, без аутентификации). ### Аутентификация JWT-middleware (`pkg/middleware/jwt_auth`) подключён **только к группе `/api/v1`**. Токен передаётся заголовком `Authorization: Bearer ` либо query-параметром `?auth_jwt=` (`JWTToCtx`). Поддерживаются два режима (`jwtauth.New`): 1. **Zitadel** — если передан заголовок `Identity: Bearer `, полезная нагрузка (`urn:zitadel:iam:user:metadata`) берётся из identity-токена без проверки подписи (доверие обеспечивает Istio). 2. **sarex-backend** — если заголовка `Identity` нет, подпись основного токена проверяется публичным RSA-ключом `PUBLIC_KEY` (PKIX). Для маршрутов публичных/временных ссылок (`/api/v1/public/*` и `download_type=temporary`) токен проверяется HMAC-секретом `DOCUMENT_PUBLIC_LINK_JWT_SECRET`. Эндпоинты `/internal/v1/*` middleware аутентификации на уровне приложения **не проходят** — доступ ограничивается сетевым слоем кластера. (В исходной swag-схеме параметр `Authorization` у них помечен как обязательный — это артефакт аннотаций, а не рантайм-поведение.) ### Пагинация Явной пагинации у списочных ответов нет: коллекции возвращаются целиком (массивом или объектом-обёрткой, напр. `GetDiskListResponse.disks`, `ServiceAccountsResponse.service_account`). Часть выборок ограничивается параметрами запроса (`company_id`, `extend`, `upload_path`). ### Обработка ошибок Ошибки возвращаются как JSON `application/json` со схемой `AppError` — `{ message, error_code }` (`internal/api/apperrors`). Код `error_code` определяет HTTP-статус (`apperrors/error_response.go`): | `error_code` | Константа | HTTP-статус | | --- | --- | --- | | `PDM-0000` | SystemErrorCode | 500 | | `PDM-0001` | ErrNotFoundCode | 404 | | `PDM-0002` | ErrNoAuthCode | (ошибки авторизации → 401) | | `PDM-0003` | ErrNoAccessCode | 403 | | `PDM-0004` | ErrInvalidCode | 400 | | `PDM-0005` | ErrGoneCode | 410 | ### Замечания (расхождения кода/схемы) - Ошибки аутентификации middleware отдаёт статусом **401** (в swag-схеме эти ответы не описаны — там только `400`/`404`/`500`). - Ошибка «истёкшая публичная ссылка» маппится на **`410 Gone`** (`ErrGoneCode`), а не на `404`. - Путь загрузки части файла содержит двойной слэш — `POST /api/v1/uploads//multipart/{upload_id}/{part_num}` (так в схеме и маршруте). - `api_server` задаёт очень большой `BodyLimit` (5 ТБ) для загрузки файлов. contact: name: Sarex url: https://gitlab/pdm/documentation-api-v2 servers: - url: http://api-v2-service.documentations description: Stage (ClusterIP, порт 80 → 8080) - url: http://api-v2-service.documentations-preprod description: Preprod (ClusterIP) - url: http://api-v2-service.documentations-prod description: Production (ClusterIP) - url: http://localhost:8000 description: Локальный запуск (API_ADDRESS) tags: - name: document description: Документы (создание, изменение, перемещение, скачивание) - name: disk description: Диски и их проекты/сервис-аккаунты - name: bundle description: Бандлы и загрузка файлов - name: page description: Страницы data source - name: upload description: Multipart-загрузка - name: workflow description: Workflow-обработка и вебхуки - name: workspace description: Рабочие области - name: permission description: Типы прав доступа - name: data_source description: Data source (внутренние проверки) security: - bearerAuth: [] paths: # ========================================================================== # Documents (public /api/v1) # ========================================================================== /api/v1/documents: post: tags: [document] summary: create document description: Create document with bundle and data_sources. operationId: createDocument requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateDocumentRequest' responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Document' '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/documents/types: get: tags: [document] summary: types description: Descriptions of possible documents. operationId: getDocumentTypes responses: '200': description: OK content: application/json: schema: type: array items: $ref: '#/components/schemas/BundleTypeStruct' /api/v1/documents/{document_id}: get: tags: [document] summary: get document description: >- Get document by document_id and optional "extend". If "extend" is "bundles", returns bundles with all data_sources and pages. operationId: getDocument parameters: - { name: document_id, in: path, required: true, schema: { type: integer }, example: 999 } - { name: extend, in: query, required: false, schema: { type: string }, example: bundles } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/Document' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } patch: tags: [document] summary: change document description: Change document's name. operationId: changeDocument parameters: - { name: document_id, in: path, required: true, schema: { type: integer }, example: 999 } requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/PatchDocument' } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/Document' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } delete: tags: [document] summary: delete document description: Delete document (soft delete). operationId: deleteDocument parameters: - { name: document_id, in: path, required: true, schema: { type: integer }, example: 999 } responses: '200': { description: OK } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/documents/{document_id}/update-path: patch: tags: [document] summary: move document to another folder description: Move document to another folder. operationId: updateDocumentPath parameters: - { name: document_id, in: path, required: true, schema: { type: integer }, example: 999 } requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/PatchDocumentPath' } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/Document' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/documents/{document_id}/move_bundles: patch: tags: [document] summary: move bundles description: >- Move bundles to document. The source document is marked as deleted if it has no bundles left after the move. operationId: moveBundles parameters: - { name: document_id, in: path, required: true, schema: { type: string }, example: "1" } requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/MoveBundleRequest' } responses: '200': description: OK content: application/json: schema: type: array items: { $ref: '#/components/schemas/Bundle' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/documents/{document_id}/add_bundle: post: tags: [document] summary: add bundle to document description: Add created and uploaded bundle to an existing document. operationId: addBundleToDocument parameters: - { name: document_id, in: path, required: true, schema: { type: integer }, example: 999 } requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/AddBundleRequest' } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/Bundle' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/documents/{document_id}/ancestors: get: tags: [document] summary: get ancestors of documents operationId: getDocumentAncestors parameters: - { name: document_id, in: path, required: true, schema: { type: integer }, example: 999 } responses: '200': description: OK content: application/json: schema: type: array items: { $ref: '#/components/schemas/Document' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/documents/{document_id}/download: get: tags: [document] summary: get url for download document operationId: getDocumentDownloadURL parameters: - { name: document_id, in: path, required: true, schema: { type: integer }, example: 999 } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/DownloadURLResponse' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/documents/{document_ids}/company: get: tags: [document] summary: get company_ids by document_ids description: Get map of documents and companies. operationId: getDocumentsCompanyMap parameters: - { name: document_ids, in: path, required: true, schema: { type: string }, example: "1,2,3,4,5" } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/DocumentCompanyMap' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } # ========================================================================== # Disks # ========================================================================== /api/v1/disks: get: tags: [disk] summary: get disks description: >- Get disks. company_id requests disks of a specific company; by default the user gets disks of all their companies. operationId: getDisks parameters: - { name: company_id, in: query, required: true, schema: { type: integer }, example: 1 } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/GetDiskListResponse' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } post: tags: [disk] summary: create disk description: Create disk. Requires admin permissions in Django. operationId: createDisk requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/CreateDiskRequest' } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/Disk' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } delete: tags: [disk] summary: delete disk description: >- Soft delete of a disk (marks the disk, not the document, as deleted). Requires admin permissions in Django. disk_id passed as path in the underlying route. operationId: deleteDisk parameters: - { name: disk_id, in: path, required: true, schema: { type: string }, example: 2e3bda68-09bb-4bc0-b3c3-984117256c8b } responses: '200': { description: OK } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/disks/{disk_id}/projects: get: tags: [disk] summary: get projects description: Get projects by disk_id. operationId: getDiskProjects parameters: - { name: disk_id, in: path, required: true, schema: { type: string }, example: 2e3bda68-09bb-4bc0-b3c3-984117256c8b } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/GetDiskListResponse' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/disks/{disk_id}/service_accounts: get: tags: [disk] summary: get service accounts description: Get service accounts by disk_id. operationId: getDiskServiceAccounts parameters: - { name: disk_id, in: path, required: true, schema: { type: string }, example: 2e3bda68-09bb-4bc0-b3c3-984117256c8b } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/ServiceAccountsResponse' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } # ========================================================================== # Bundles # ========================================================================== /api/v1/bundles/{bundle_id}/bucket_name: get: tags: [bundle] summary: get bucket name description: Get bucket name by bundle_id. operationId: getBucketName parameters: - { name: bundle_id, in: path, required: true, schema: { type: string } } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/BucketNameResponse' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/bundles/{bundle_id}/download: get: tags: [bundle] summary: get url for download bundle operationId: getBundleDownloadURL parameters: - { name: bundle_id, in: path, required: true, schema: { type: string } } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/DownloadURLResponse' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/bundles/{bundle_id}/{bundle_key}/download: get: tags: [bundle] summary: get url for download bundle (data_source) description: Get url for download of a specific data_source of a bundle. operationId: getBundleDataSourceDownloadURL parameters: - { name: bundle_id, in: path, required: true, schema: { type: string } } - { name: bundle_key, in: path, required: true, schema: { type: string }, example: las } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/DownloadURLResponse' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/bundles/{bundle_id}/{bundle_key}/upload_multipart: post: tags: [bundle] summary: initial multipart upload description: Initialize a multipart upload for chunked file upload to storage. operationId: initMultipartUpload parameters: - { name: bundle_id, in: path, required: true, schema: { type: string } } - { name: bundle_key, in: path, required: true, schema: { type: string }, example: potree } - { name: upload_path, in: query, required: false, schema: { type: string }, example: r/1/1/2 } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/MultipartUpload' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/bundles/{bundle_id}/{bundle_key}/upload_single: post: tags: [bundle] summary: upload single file description: >- Upload a single file to storage for a specific bundle. Bundle and DataSource must already exist. operationId: uploadSingleFile parameters: - { name: bundle_id, in: path, required: true, schema: { type: string } } - { name: bundle_key, in: path, required: true, schema: { type: string }, example: potree } - { name: upload_path, in: query, required: false, schema: { type: string }, example: data/r/r.bin } responses: '200': { description: OK } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/bundles/{bundle_id}/upload_finish: post: tags: [bundle] summary: finish upload description: >- Finish upload: change bundle status from "created" to "uploaded", update data_source file sizes, check for files in storage. operationId: finishUpload parameters: - { name: bundle_id, in: path, required: true, schema: { type: string } } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/Bundle' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } # ========================================================================== # Pages # ========================================================================== /api/v1/pages: post: tags: [page] summary: create page description: Creates a page for a specified data_source_id. operationId: createPage requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/CreatePageRequest' } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/Page' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/pages/{data_source}/{page_key}/download: get: tags: [page] summary: get download url page operationId: getPageDownloadURL parameters: - { name: data_source, in: path, required: true, schema: { type: string }, example: "1" } - { name: page_key, in: path, required: true, schema: { type: string }, example: "2" } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/DownloadURLResponse' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } # ========================================================================== # Permissions # ========================================================================== /api/v1/permissions: get: tags: [permission] summary: permission types operationId: getPermissionTypes responses: '200': description: OK content: application/json: schema: type: array items: { $ref: '#/components/schemas/PermissionType' } # ========================================================================== # Uploads (multipart parts) # ========================================================================== /api/v1/uploads//multipart/{upload_id}/{part_num}: post: tags: [upload] summary: upload multipart upload part description: >- Upload a part of a file to storage. NB: the route contains a double slash after `uploads` (as registered). operationId: uploadMultipartPart parameters: - { name: upload_id, in: path, required: true, schema: { type: string } } - { name: part_num, in: path, required: true, schema: { type: integer }, example: 1 } requestBody: required: true content: multipart/form-data: schema: type: object properties: file: type: string format: binary required: [file] responses: '200': { description: OK } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/uploads/multipart/{upload_id}/abort: post: tags: [upload] summary: abort multipart upload operationId: abortMultipartUpload parameters: - { name: upload_id, in: path, required: true, schema: { type: string } } responses: '200': { description: OK } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/uploads/multipart/{upload_id}/complete: post: tags: [upload] summary: complete multipart upload description: >- Complete a multipart upload. When all parts are uploaded, marks parts in storage and database as "completed". operationId: completeMultipartUpload parameters: - { name: upload_id, in: path, required: true, schema: { type: string } } responses: '200': { description: OK } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } # ========================================================================== # Workflows # ========================================================================== /api/v1/workflows/{workflow_id}: get: tags: [workflow] summary: get workflow operationId: getWorkflow parameters: - { name: workflow_id, in: path, required: true, schema: { type: string } } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/Workflow' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } post: tags: [workflow] summary: webhook description: >- Determines and updates workflow status (and bundle workflow status). On success both are set to "done"; if bundle has no document_id, status is set to "No document". operationId: workflowWebhook parameters: - { name: workflow_id, in: path, required: true, schema: { type: string } } responses: '200': { description: OK } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } # ========================================================================== # Workspaces # ========================================================================== /api/v1/workspaces: post: tags: [workspace] summary: create workspace description: Creates a workspace document that may include other documents. operationId: createWorkspace requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/CreateWorkspaceRequest' } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/Document' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /api/v1/workspaces/{ws_id}: get: tags: [workspace] summary: get workspace document description: Get document with workspace type. operationId: getWorkspace parameters: - { name: ws_id, in: path, required: true, schema: { type: string } } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/Document' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } # ========================================================================== # Internal (/internal/v1) — без app-аутентификации, только внутри кластера # ========================================================================== /internal/v1/bundles/{bundle_id}: get: tags: [bundle] summary: get internal bundle description: Get internal bundle by bundle_id. operationId: getInternalBundle security: [] parameters: - { name: bundle_id, in: path, required: true, schema: { type: string } } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/Bundle' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /internal/v1/bundles/{bundle_id}/workflow: post: tags: [bundle] summary: add workflow description: Add workflow to bundle. operationId: addBundleWorkflow security: [] parameters: - { name: bundle_id, in: path, required: true, schema: { type: string } } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/Workflow' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /internal/v1/documents/{document_id}: delete: tags: [document] summary: internal delete document description: Internal delete document (soft delete). operationId: internalDeleteDocument security: [] parameters: - { name: document_id, in: path, required: true, schema: { type: integer }, example: 999 } responses: '200': { description: OK } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } /internal/v1/is_folder/bundles/{bundle_id}/{bundle_key}: get: tags: [data_source] summary: is data_source folder handler description: Returns whether the data_source is a folder or not. operationId: isDataSourceFolder security: [] parameters: - { name: bundle_id, in: path, required: true, schema: { type: string } } - { name: bundle_key, in: path, required: true, schema: { type: string }, example: potree } responses: '200': description: OK content: application/json: schema: { $ref: '#/components/schemas/IsDataSourceFolderResponse' } '400': { $ref: '#/components/responses/BadRequest' } '404': { $ref: '#/components/responses/NotFound' } '500': { $ref: '#/components/responses/ServerError' } components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT description: >- JWT в заголовке `Authorization: Bearer ` или в query-параметре `auth_jwt`. Режим sarex-backend проверяется RSA-ключом `PUBLIC_KEY`; режим Zitadel — по заголовку `Identity`. responses: BadRequest: description: Bad Request content: application/json: schema: { $ref: '#/components/schemas/AppError' } NotFound: description: Not Found content: application/json: schema: { $ref: '#/components/schemas/AppError' } ServerError: description: Internal Server Error content: application/json: schema: { $ref: '#/components/schemas/AppError' } schemas: ErrCodeType: type: string enum: [PDM-0000, PDM-0001, PDM-0002, PDM-0003, PDM-0004, PDM-0005] description: >- SystemErrorCode / ErrNotFoundCode / ErrNoAuthCode / ErrNoAccessCode / ErrInvalidCode / ErrGoneCode AppError: type: object properties: message: { type: string } error_code: { $ref: '#/components/schemas/ErrCodeType' } AddBundleRequest: type: object required: [bundle_id] properties: bundle_id: { type: string } BucketNameResponse: type: object properties: bucket_name: { type: string } Bundle: type: object properties: attributes: { type: object, additionalProperties: true } author: { $ref: '#/components/schemas/User' } bim_id: { type: integer } bundle_copied_from: { type: string } created_at: { type: string } data_sources: type: array items: { $ref: '#/components/schemas/DataSource' } date: { type: string, description: optional field for django integration } document_id: { type: integer } has_digital_signature: { type: boolean } has_qr_code: { type: boolean } has_stamp: { type: boolean } id: { type: string } size: { type: integer } type: { $ref: '#/components/schemas/BundleType' } upload_status: { $ref: '#/components/schemas/BundleUploadStatus' } workflow: { $ref: '#/components/schemas/Workflow' } workflow_status: { $ref: '#/components/schemas/BundleWorkflowStatus' } BundleKey: type: string enum: - las - potree - e57 - clouds - panoramas_json - panoramas - glb - original - tiles - tif - tif_dem - metadata - colored-relief-tif - topographic_tiles - geojson - ap_rasterized_las - ap_rasterized_potree - ab_las - ab_potree - deviation_json - bim - bim_optimized - bim_optimizedGz - bim_metadata - bim_metadataGz - bim_metadata_static - bim_metadata_staticGz - diff_json - ifc - nwd - rvt - nwc - abap_json - cloud_ooc - debug_abap_json - pdf - p7s - xlsx - dxf - docx - dwg BundleKeyField: type: object properties: allowed_extensions: type: array items: { type: string } can_be_downloaded_by_user: { type: boolean } can_be_uploaded_by_user: { type: boolean } file: { type: boolean } folder: { type: boolean } key: { $ref: '#/components/schemas/BundleKey' } required: { type: boolean } title: { type: string } BundleType: type: string enum: - cloud - bim - bimv2 - surface - other_files - deviation - dem - orthophoto - dxf - ksg - docx - dwg - pdf - xlsx - abap - c2c - c2s BundleTypeStruct: type: object properties: fields: type: array items: { $ref: '#/components/schemas/BundleKeyField' } name: { $ref: '#/components/schemas/BundleType' } title: { type: string } BundleUploadStatus: type: string enum: [created, uploaded] BundleWorkflowStatus: type: string enum: [created, skipped, done, errored] CreateDiskRequest: type: object required: [admin_ids, company_id, storage_type] properties: admin_ids: type: array minItems: 1 items: { type: integer } company_id: { type: integer } storage_type: type: string maxLength: 50 enum: [sarex] CreateDocumentRequest: type: object required: [disk_id, is_folder, name, parent_id] properties: bundle_id: { type: string } disk_id: { type: string } is_folder: { type: boolean } is_project: { type: boolean } name: { type: string, maxLength: 250 } parent_id: { type: integer } target_id: { type: integer } CreatePageRequest: type: object properties: data_source: { type: string } id: { type: string } page_order: { type: integer } thumbnail: { type: string } CreateWorkspaceRequest: type: object required: [disk_id, documents, name, parent_id] properties: disk_id: { type: string } documents: type: array items: { type: integer } name: { type: string, maxLength: 250 } parent_id: { type: integer } DataSource: type: object properties: file_name: { type: string } format: { $ref: '#/components/schemas/DataSourceFormat' } id: { type: string } key: { $ref: '#/components/schemas/BundleKey' } pages: type: array items: { $ref: '#/components/schemas/Page' } size: { type: integer } type: { $ref: '#/components/schemas/DataSourceUploadType' } DataSourceFormat: type: string enum: [glb, json, gz, s3d] DataSourceUploadType: type: string enum: [file, folder] DisableButton: type: string enum: [workspace, delete, rename, create, project, download, history, add_doc_to_ws, del_doc_from_ws] Disk: type: object properties: admin_ids: type: array items: { type: integer } bucket_name: { type: string } company_id: { type: integer } created_at: { type: string } disable_button: type: array items: { $ref: '#/components/schemas/DisableButton' } document_id: { type: integer } id: { type: string } name: { type: string } permissions_editable: { type: boolean } storage_type: { type: string } Document: type: object properties: author: { $ref: '#/components/schemas/User' } bundles: type: array items: { $ref: '#/components/schemas/Bundle' } created_at: { type: string } dashboard_id: { type: integer } disable_button: type: array items: { $ref: '#/components/schemas/DisableButton' } disk_id: { type: string } document_copied_from: { type: integer } files: type: array items: { type: integer } folders: type: array items: { type: integer } has_digital_signature: { type: boolean } has_public_link: { type: boolean } has_qr_code: { type: boolean } has_stamp: { type: boolean } id: { type: integer } is_folder: { type: boolean } name: { type: string } path: { type: string } project_id: { type: integer } public_link: { type: string } public_link_available: { type: boolean } public_link_expiration_time: { type: string } public_link_id: { type: string } type: { $ref: '#/components/schemas/DocumentType' } workspace_id: { type: string } DocumentCompanyMap: type: object properties: result: type: object additionalProperties: { type: integer } DocumentType: type: string enum: - workspace - dashboard - cloud - bim - bimv2 - project - folder - root - surface - pdf - xlsx - orthophoto - dem - dxf - ksg - docx - dwg DownloadURLResponse: type: object properties: download_url: { type: string } GetDiskListResponse: type: object properties: disks: type: array items: { $ref: '#/components/schemas/Disk' } IsDataSourceFolderResponse: type: object properties: result: { type: boolean } MoveBundleRequest: type: object required: [bundle_ids] properties: bundle_ids: type: array items: { type: string } MultipartUpload: type: object properties: upload_id: { type: string } Page: type: object properties: id: { type: string } page_order: { type: integer } thumbnail: { type: string } PatchDocument: type: object required: [name] properties: name: { type: string } PatchDocumentPath: type: object required: [parent_id] properties: parent_id: { type: integer } PermissionType: type: object properties: label: { type: string } value: { type: string } ServiceAccount: type: object properties: id: { type: string } name: { type: string } type: { type: string } username: { type: string } ServiceAccountsResponse: type: object properties: service_account: type: array items: { $ref: '#/components/schemas/ServiceAccount' } User: type: object properties: companies: type: array items: { type: integer } departments: type: array items: { $ref: '#/components/schemas/UserDepartment' } first_name: { type: string } id: { type: integer } is_superuser: { type: boolean } last_name: { type: string } positions: type: array items: { $ref: '#/components/schemas/UserPosition' } service_account_id: { type: string } username: { type: string } UserDepartment: type: object properties: id: { type: integer } service_account_id: { type: string } UserPosition: type: object properties: id: { type: integer } service_account_id: { type: string } Workflow: type: object properties: company_id: { type: integer } created_at: { type: string } id: { type: string } name: { type: string } state: { type: string } task_runs: type: array items: { type: object, additionalProperties: true } tasks: type: array items: { type: object, additionalProperties: true } updated_at: { type: string } valid_until: { type: string }