openapi: 3.0.3 info: title: EAV Service API version: "1.0.0" description: | REST API сервиса **eav-python** (`platform/eav-python`) — реализация паттерна **EAV (Entity-Attribute-Value)** для платформы Sarex: управление атрибутами, группами атрибутов, единицами измерения, опциями значений, схемами (доменами) и ассетами. Компонент используется всеми модулями платформы (инспекции, документы, задачи КСГ, замечания, BIM и т.д.) для гибкой атрибуции моделей. Сервис написан на Python (**Django 4.1 + Django REST Framework**) и запускается как WSGI-приложение (`config.wsgi`) через uWSGI (порт `8000`). Роутинг задан в `config/urls.py`. Внутри приложения существует несколько версий API, которые снаружи публикуются под собственными префиксами через Istio VirtualService (`.helm/templates/mesh-config.yaml`): | Внешний префикс (ingress) | Внутренний путь (приложение) | Назначение | | --- | --- | --- | | `/eav/api/v0` | `/api/v4` | Публичный API (защищённый дубликат v0) | | `/eav/api/v1` | `/api/v6` | Публичный API (защищённый дубликат v1) | | `/eav/api/v2` | `/api/v5` | Публичный API (защищённый дубликат v2) | | `/eav/api/v3` | `/api/v3` | Публичный API v3 | | `/eav/api/v4` | `/api/v4` | Публичный API v4 | | `/eav/admin/` | `/eav/admin/` | Django-admin | Внутренние (не опубликованные через ingress) версии `/api/v0`, `/api/v1`, `/api/v2` — незащищённые (исторические) варианты тех же ресурсов; `/api/v4`–`/api/v6` — их защищённые дубликаты. Ниже документированы ресурсы на примере пути `/api/v0/*` (форма запросов/ответов у соответствующих защищённых версий совпадает). ### Аутентификация Проверка выполняется по цепочке DRF (`REST_FRAMEWORK.DEFAULT_AUTHENTICATION_CLASSES`): 1. **Zitadel** (`ZitadelJWTAuthentication`) — требуются одновременно заголовки `Authorization: Bearer ` и `Identity: Identity `. Полезная нагрузка (в т.ч. `tenant_identifier`) берётся из токена `Identity`. При отсутствии заголовка `Identity` — переход к следующему механизму. 2. **sarex-backend** (`rest_framework_simplejwt.JWTAuthentication`) — подпись токена `Authorization: Bearer ` проверяется публичным RSA-ключом (`JWT_PUBLIC_KEY`, алгоритм `RS512`). 3. Дополнительно поддерживаются `SessionAuthentication` и `BasicAuthentication` (для Django-admin / служебного доступа). Глобальные права — `AllowAny` (`DEFAULT_PERMISSION_CLASSES`); ограничение доступа к отдельным ресурсам обеспечивается на уровне view/Istio. ### Пагинация Списочные ответы используют DRF `LimitOffsetPagination` (`PAGE_SIZE = 10000`). Управление — query-параметрами `limit` и `offset`. ### Мультиарендность Многие эндпоинты принимают `company_id` и/или `tenant_identifier` (query) для выборки атрибутов/схем в контексте конкретной компании. Специфичные для компании атрибуты «замещают» общие (системные). ### Типы атрибутов (`TypeEnum`) `0` — целочисленный, `1` — с плавающей запятой, `2` — строка, `3` — одно из списка, `4` — многие из списка, `5` — да/нет, `6` — дата со временем, `7` — дата. servers: - url: https://api.sarex.io/eav/api description: Production (external, через ingress) - url: https://stage-api.sarex.io/eav/api description: Stage (external, через ingress) - url: http://eav-service.eav-prod/api description: Внутренний адрес в кластере security: - bearerAuth: [] - bearerAuth: [] identityAuth: [] paths: /api/v0/attribute/: get: operationId: attribute_list parameters: - in: query name: company_id description: ID компании schema: type: string nullable: true title: ID компании - in: query name: tenant_identifier description: Идентификатор компании schema: type: string nullable: true title: Идентификатор компании tags: - Attribute responses: '200': content: application/json: schema: $ref: '#/components/schemas/AttributeRetrieve' description: '' post: operationId: attribute_create tags: - Attribute requestBody: content: application/json: schema: $ref: '#/components/schemas/AttributeCreate' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AttributeCreate' multipart/form-data: schema: $ref: '#/components/schemas/AttributeCreate' required: true responses: '201': content: application/json: schema: $ref: '#/components/schemas/AttributeCreate' description: '' /api/v0/attribute/{id}/: get: operationId: attribute_retrieve parameters: - in: path name: id schema: type: integer description: ID атрибута required: true tags: - Attribute responses: '200': content: application/json: schema: $ref: '#/components/schemas/AttributeRetrieve' description: '' put: operationId: attribute_update parameters: - in: path name: id schema: type: integer description: ID атрибута required: true tags: - Attribute requestBody: content: application/json: schema: $ref: '#/components/schemas/AttributeCreate' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AttributeCreate' multipart/form-data: schema: $ref: '#/components/schemas/AttributeCreate' required: true responses: '200': content: application/json: schema: $ref: '#/components/schemas/AttributeCreate' description: '' patch: operationId: attribute_partial_update parameters: - in: path name: id schema: type: integer description: ID атрибута required: true tags: - Attribute requestBody: content: application/json: schema: $ref: '#/components/schemas/AttributeUpdate' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AttributeUpdate' multipart/form-data: schema: $ref: '#/components/schemas/AttributeUpdate' responses: '200': content: application/json: schema: $ref: '#/components/schemas/AttributeCreate' description: '' delete: operationId: attribute_destroy parameters: - in: path name: id schema: type: integer description: ID атрибута required: true tags: - Attribute responses: '204': description: '' /api/v0/attribute-group/: get: operationId: attribute_group_list tags: - Attribute Group responses: '200': content: application/json: schema: $ref: '#/components/schemas/AttributeGroupRetrieve' description: '' post: operationId: attribute_group_create tags: - Attribute Group requestBody: content: application/json: schema: $ref: '#/components/schemas/AttributeCreate' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AttributeCreate' multipart/form-data: schema: $ref: '#/components/schemas/AttributeCreate' required: true responses: '201': content: application/json: schema: $ref: '#/components/schemas/AttributeCreate' description: '' /api/v0/attribute-group/{id}/: get: operationId: attribute_group_retrieve parameters: - in: path name: id schema: type: integer description: ID группы атрибутов required: true tags: - Attribute Group responses: '200': content: application/json: schema: $ref: '#/components/schemas/AttributeGroupRetrieve' description: '' put: operationId: attribute_group_update parameters: - in: path name: id schema: type: integer description: ID группы атрибутов required: true tags: - Attribute Group requestBody: content: application/json: schema: $ref: '#/components/schemas/AttributeCreate' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AttributeCreate' multipart/form-data: schema: $ref: '#/components/schemas/AttributeCreate' required: true responses: '200': content: application/json: schema: $ref: '#/components/schemas/AttributeCreate' description: '' patch: operationId: attribute_group_partial_update parameters: - in: path name: id schema: type: integer description: ID группы атрибутов required: true tags: - Attribute Group requestBody: content: application/json: schema: $ref: '#/components/schemas/AttributeUpdate' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AttributeUpdate' multipart/form-data: schema: $ref: '#/components/schemas/AttributeUpdate' responses: '200': content: application/json: schema: $ref: '#/components/schemas/AttributeCreate' description: '' delete: operationId: attribute_group_destroy parameters: - in: path name: id schema: type: integer description: ID группы атрибутов required: true tags: - Attribute Group responses: '204': description: '' /api/v0/schema/: get: operationId: attribute_schema_list parameters: - in: query name: model_name description: Наименование модели schema: type: string - in: query name: service_name description: Наименование сервиса schema: type: string - in: query name: type_identifier description: ID типа модели schema: type: string tags: - Attribute Schema responses: '200': content: application/json: schema: $ref: '#/components/schemas/AttributeSchemaRetrieve' description: '' post: operationId: attribute_schema_create tags: - Attribute Schema requestBody: content: application/json: schema: $ref: '#/components/schemas/AttributeSchemaCreate' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AttributeSchemaCreate' multipart/form-data: schema: $ref: '#/components/schemas/AttributeSchemaCreate' required: true responses: '201': content: application/json: schema: $ref: '#/components/schemas/AttributeSchemaCreate' description: '' /api/v0/schema/{id}/: get: operationId: attribute_schema_retrieve parameters: - in: path name: id schema: type: integer description: ID схемы атрибутов required: true tags: - Attribute Schema responses: '200': content: application/json: schema: $ref: '#/components/schemas/AttributeSchemaRetrieve' description: '' put: operationId: attribute_schema_update parameters: - in: path name: id schema: type: integer description: ID схемы атрибутов required: true tags: - Attribute Schema requestBody: content: application/json: schema: $ref: '#/components/schemas/AttributeSchemaCreate' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AttributeSchemaCreate' multipart/form-data: schema: $ref: '#/components/schemas/AttributeSchemaCreate' required: true responses: '200': content: application/json: schema: $ref: '#/components/schemas/AttributeSchemaCreate' description: '' patch: operationId: attribute_schema_partial_update parameters: - in: path name: id schema: type: integer description: ID схемы атрибутов required: true tags: - Attribute Schema requestBody: content: application/json: schema: $ref: '#/components/schemas/AttributeSchemaUpdate' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/AttributeSchemaUpdate' multipart/form-data: schema: $ref: '#/components/schemas/AttributeSchemaUpdate' responses: '200': content: application/json: schema: $ref: '#/components/schemas/AttributeSchemaCreate' description: '' delete: operationId: attribute_schema_destroy parameters: - in: path name: id schema: type: integer description: ID схемы атрибутов required: true tags: - Attribute Schema responses: '204': description: '' /api/v0/unit-option/: get: operationId: unit_option_list tags: - Unit Option responses: '200': content: application/json: schema: $ref: '#/components/schemas/UnitOptionRetrieve' description: '' post: operationId: unit_option_create tags: - Unit Option requestBody: content: application/json: schema: $ref: '#/components/schemas/UnitOptionCreate' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/UnitOptionCreate' multipart/form-data: schema: $ref: '#/components/schemas/UnitOptionCreate' required: true responses: '201': content: application/json: schema: $ref: '#/components/schemas/UnitOptionCreate' description: '' /api/v0/unit-option/{id}/: get: operationId: unit_option_retrieve parameters: - in: path name: id schema: type: integer description: ID единицы измерения required: true tags: - Unit Option responses: '200': content: application/json: schema: $ref: '#/components/schemas/UnitOptionRetrieve' description: '' put: operationId: unit_option_update parameters: - in: path name: id schema: type: integer description: ID единицы измерения required: true tags: - Unit Option requestBody: content: application/json: schema: $ref: '#/components/schemas/UnitOptionCreate' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/UnitOptionCreate' multipart/form-data: schema: $ref: '#/components/schemas/UnitOptionCreate' required: true responses: '200': content: application/json: schema: $ref: '#/components/schemas/UnitOptionCreate' description: '' patch: operationId: unit_option_partial_update parameters: - in: path name: id schema: type: integer description: ID единицы измерения required: true tags: - Unit Option requestBody: content: application/json: schema: $ref: '#/components/schemas/UnitOptionUpdate' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/UnitOptionUpdate' multipart/form-data: schema: $ref: '#/components/schemas/UnitOptionUpdate' responses: '200': content: application/json: schema: $ref: '#/components/schemas/UnitOptionCreate' description: '' delete: operationId: unit_option_destroy parameters: - in: path name: id schema: type: integer description: ID единицы измерения required: true tags: - Unit Option responses: '204': description: '' /api/v0/value-option/: get: operationId: value_option_list tags: - Value Option responses: '200': content: application/json: schema: $ref: '#/components/schemas/ValueOptionRetrieve' description: '' post: operationId: value_option_create tags: - Value Option requestBody: content: application/json: schema: $ref: '#/components/schemas/ValueOptionCreate' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/ValueOptionCreate' multipart/form-data: schema: $ref: '#/components/schemas/ValueOptionCreate' required: true responses: '201': content: application/json: schema: $ref: '#/components/schemas/ValueOptionCreate' description: '' /api/v0/value-option/{id}/: get: operationId: value_option_retrieve parameters: - in: path name: id schema: type: integer description: ID опции значения атрибута required: true tags: - Value Option responses: '200': content: application/json: schema: $ref: '#/components/schemas/ValueOptionRetrieve' description: '' put: operationId: value_option_update parameters: - in: path name: id schema: type: integer description: ID опции значения атрибута required: true tags: - Value Option requestBody: content: application/json: schema: $ref: '#/components/schemas/ValueOptionCreate' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/ValueOptionCreate' multipart/form-data: schema: $ref: '#/components/schemas/ValueOptionCreate' required: true responses: '200': content: application/json: schema: $ref: '#/components/schemas/ValueOptionCreate' description: '' patch: operationId: value_option_partial_update parameters: - in: path name: id schema: type: integer description: ID опции значения атрибута required: true tags: - Value Option requestBody: content: application/json: schema: $ref: '#/components/schemas/ValueOptionUpdate' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/ValueOptionUpdate' multipart/form-data: schema: $ref: '#/components/schemas/ValueOptionUpdate' responses: '200': content: application/json: schema: $ref: '#/components/schemas/ValueOptionCreate' description: '' delete: operationId: value_option_destroy parameters: - in: path name: id schema: type: integer description: ID опции значения атрибута required: true tags: - Value Option responses: '204': description: '' components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT description: >- JWT в заголовке `Authorization: Bearer `. Подпись проверяется публичным RSA-ключом (RS512) для механизма sarex-backend. identityAuth: type: apiKey in: header name: Identity description: >- Токен Zitadel в заголовке `Identity: Identity ` (используется вместе с `Authorization` для механизма ZitadelJWTAuthentication). schemas: AttributeRetrieve: type: object properties: id: type: integer readOnly: true title: ID атрибута name: type: string readOnly: true title: Наименование атрибута type: type: string readOnly: true title: Тип атрибута group: type: integer readOnly: true nullable: true title: Группа атрибута author: type: string readOnly: true title: Автор атрибута tenant_identifier: type: string readOnly: true nullable: true title: Идентификатор компании created_at: type: string format: date-time readOnly: true title: Время создания атрибута updated_at: type: string format: date-time readOnly: true title: Время последнего обновления атрибута options: type: array items: $ref: '#/components/schemas/ValueOptionRetrieve' title: Опции значения атрибута required: - author - created_at - group - id - name - options - tenant_identifier - type - updated_at AttributeCreate: type: object properties: id: type: integer readOnly: true title: ID атрибута name: type: string title: Наименование атрибута maxLength: 512 type: allOf: - $ref: '#/components/schemas/TypeEnum' title: Тип атрибута minimum: 0 maximum: 32767 group: type: integer nullable: true title: Группа атрибута author: type: string title: Автор атрибута maxLength: 512 tenant_identifier: type: string nullable: true title: Идентификатор компании maxLength: 512 is_common: type: boolean title: Общий для компаний required: - author - id - name AttributeUpdate: type: object properties: id: type: integer readOnly: true title: ID атрибута name: type: string title: Наименование атрибута maxLength: 512 type: allOf: - $ref: '#/components/schemas/TypeEnum' title: Тип атрибута minimum: 0 maximum: 32767 group: type: integer nullable: true title: Группа атрибута author: type: string title: Автор атрибута maxLength: 512 tenant_identifier: type: string nullable: true title: Идентификатор компании maxLength: 512 is_common: type: boolean title: Общий для компаний AttributeGroupRetrieve: type: object properties: id: type: integer readOnly: true title: ID группы атрибутов name: type: string readOnly: true title: Наименование группы атрибутов parent: type: integer readOnly: true title: Родительская группа атрибутов author: type: string readOnly: true title: Автор группы атрибутов tenant_identifier: type: string readOnly: true nullable: true title: Идентификатор компании created_at: type: string format: date-time readOnly: true title: Время создания группы атрибутов updated_at: type: string format: date-time readOnly: true title: Время последнего обновления группы атрибутов required: - author - created_at - id - name - parent - tenant_identifier - updated_at AttributeSchemaRetrieve: type: object properties: id: type: integer readOnly: true title: ID схемы атрибутов name: type: string readOnly: true title: Наименование схемы атрибутов group: type: integer readOnly: true nullable: true title: Группа схемы атрибутов model_name: type: string readOnly: true title: ID модели type_identifier: type: string readOnly: true title: ID типа модели attributes: type: array items: $ref: '#/components/schemas/AttributeRetrieve' title: Атрибуты readOnly: true tenant_identifier: type: string readOnly: true nullable: true title: Идентификатор компании is_common: type: boolean readOnly: true default: false title: Общий для компаний created_at: type: string format: date-time readOnly: true title: Время создания схемы атрибутов updated_at: type: string format: date-time readOnly: true title: Время последнего обновления схемы атрибутов required: - attributes - created_at - group - id - is_common - model_name - name - tenant_identifier - type_identifier - updated_at AttributeSchemaCreate: type: object properties: id: type: integer readOnly: true title: ID схемы атрибутов name: type: string title: Наименование схемы атрибутов maxLength: 512 group: type: integer nullable: true title: Группа схемы атрибутов model_name: type: string title: ID модели maxLength: 512 type_identifier: type: string title: ID типа модели maxLength: 512 attributes: type: array items: $ref: '#/components/schemas/AttributeCreate' readOnly: true title: Атрибуты tenant_identifier: type: string nullable: true title: Идентификатор компании maxLength: 512 is_common: type: boolean default: false title: Общий для компаний created_at: type: string format: date-time readOnly: true title: Время создания схемы атрибутов updated_at: type: string format: date-time readOnly: true title: Время последнего обновления схемы атрибутов required: - attributes - created_at - id - model_name - name - tenant_identifier - type_identifier - updated_at AttributeSchemaUpdate: type: object properties: id: type: integer readOnly: true title: ID схемы атрибутов name: type: string title: Наименование схемы атрибутов maxLength: 512 group: type: integer nullable: true title: Группа схемы атрибутов model_name: type: string title: ID модели maxLength: 512 type_identifier: type: string title: ID типа модели maxLength: 512 attributes: type: array items: $ref: '#/components/schemas/AttributeCreate' readOnly: true title: Атрибуты tenant_identifier: type: string nullable: true title: Идентификатор компании maxLength: 512 is_common: type: boolean default: false title: Общий для компаний created_at: type: string format: date-time readOnly: true title: Время создания схемы атрибутов updated_at: type: string format: date-time readOnly: true title: Время последнего обновления схемы атрибутов UnitOptionRetrieve: type: object properties: id: type: integer readOnly: true title: ID единицы измерения name: type: string readOnly: true title: Наименование единицы измерения author: type: string readOnly: true title: Автор единицы измерения tenant_identifier: type: string readOnly: true nullable: true title: Идентификатор компании created_at: type: string format: date-time readOnly: true title: Время создания единицы измерения updated_at: type: string format: date-time readOnly: true title: Время последнего обновления единицы измерения required: - author - created_at - id - name - tenant_identifier - updated_at UnitOptionCreate: type: object properties: id: type: integer readOnly: true title: ID единицы измерения name: type: string title: Наименование единицы измерения maxLength: 512 author: type: string title: Автор единицы измерения maxLength: 512 tenant_identifier: type: string nullable: true title: Идентификатор компании maxLength: 512 is_common: type: boolean title: Общий для компаний required: - author - id - name UnitOptionUpdate: type: object properties: id: type: integer readOnly: true title: ID единицы измерения name: type: string title: Наименование единицы измерения maxLength: 512 author: type: string title: Автор единицы измерения maxLength: 512 tenant_identifier: type: string nullable: true title: Идентификатор компании maxLength: 512 is_common: type: boolean title: Общий для компаний ValueOptionRetrieve: type: object properties: id: type: integer readOnly: true title: ID опции значения attribute: type: integer readOnly: true title: ID атрибута value: type: string title: Значение author: type: string readOnly: true title: Автор опции значения tenant_identifier: type: string readOnly: true nullable: true title: Идентификатор компании created_at: type: string format: date-time readOnly: true title: Время создания опции значения updated_at: type: string format: date-time readOnly: true title: Время последнего обновления опции значения name: type: string readOnly: true title: Наименование опции значения required: - attribute - author - created_at - id - name - tenant_identifier - updated_at - value ValueOptionCreate: type: object properties: id: type: integer readOnly: true title: ID опции значения value: type: string title: Значение author: type: string title: Автор опции значения maxLength: 512 tenant_identifier: type: string nullable: true title: Идентификатор компании maxLength: 512 is_common: type: boolean title: Общий для компаний name: type: string title: Наименование опции значения maxLength: 1024 required: - author - id - value ValueOptionUpdate: type: object properties: id: type: integer readOnly: true title: ID опции значения value: type: string title: Значение author: type: string title: Автор опции значения maxLength: 512 tenant_identifier: type: string nullable: true title: Идентификатор компании maxLength: 512 is_common: type: boolean title: Общий для компаний name: type: string title: Наименование опции значения maxLength: 1024 TypeEnum: enum: - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 type: integer description: |- * `0` - Целочисленное * `1` - С плавающей запятой * `2` - Строковое * `3` - Одно из списка * `4` - Многие из списка * `5` - Да/Нет * `6` - Дата со временем * `7` - Дата