1769 lines
86 KiB
YAML
1769 lines
86 KiB
YAML
openapi: 3.0.3
|
||
|
||
info:
|
||
title: PM Backend API
|
||
version: "1.0.0"
|
||
description: |
|
||
REST API сервиса **pm-backend** (`planning/pm-backend`) — управление
|
||
проектами и папками, задачами (иерархия, связи, ресурсы), базовыми планами
|
||
(состояниями), атрибутами, календарями, настройками КСГ, детализацией задач,
|
||
системным журналом и экспортом.
|
||
|
||
Сервис написан на Python (**Django 5.1 + Django REST Framework**) и запускается
|
||
как ASGI-приложение (`config.asgi_root:application`) через gunicorn с воркерами
|
||
`uvicorn.workers.UvicornWorker` (порт `8000`). Роутинг задан в `config/urls.py`
|
||
и состоит из трёх групп:
|
||
|
||
- публичный API — префикс `/api/pm/msp/` (`sarex.pm.urls`);
|
||
- внешний API v2 — префикс `/api/pm/external/v2/` (`sarex.pm.urls_external`),
|
||
только чтение;
|
||
- внутренний API — префикс `/internal/pm/` (`sarex.pm.urls_internal`),
|
||
предназначен для вызовов внутри кластера, аутентификация не требуется.
|
||
|
||
### Аутентификация
|
||
Публичные (`/api/pm/msp/*`) и внешние (`/api/pm/external/v2/*`) эндпоинты
|
||
требуют аутентификации (DRF `IsAuthenticated`). Проверка выполняется по цепочке
|
||
(`REST_FRAMEWORK.DEFAULT_AUTHENTICATION_CLASSES`):
|
||
|
||
1. **Zitadel** (`ZitadelJWTAuthentication`) — требуются одновременно заголовки
|
||
`Authorization: Bearer <jwt>` и `Identity: Identity <jwt>`. При отсутствии
|
||
любого из них — переход к следующему механизму/ошибка.
|
||
2. **sarex-backend** (`JWTAuthentication`) — подпись токена `Authorization:
|
||
Bearer <jwt>` проверяется публичным RSA-ключом (`AUTH_PUBLIC_KEY`,
|
||
алгоритм `RS512`). При `SERVER_DEBUG=true` аутентификация обходится
|
||
(возвращается анонимный пользователь).
|
||
|
||
Внутренние эндпоинты (`/internal/pm/*`) имеют `authentication_classes=[]` и
|
||
`AllowAny` — доступ ограничивается сетевым слоем. Отдельный публичный эндпоинт
|
||
`/api/pm/msp/external-task-info/` также открыт (`AllowAny`).
|
||
|
||
### Пагинация
|
||
По умолчанию используется DRF `LimitOffsetPagination` (`PAGE_SIZE=1000`).
|
||
Списочные ответы оборачиваются в объект `{ count, next, previous, results }`;
|
||
размер страницы задаётся query-параметром `limit`, смещение — `offset`. Часть
|
||
«тяжёлых» списков (задачи, привязки ресурсов, связи задач) использует
|
||
`ProjectTaskPagination` (`default_limit=30000`).
|
||
|
||
### Обработка ошибок
|
||
Ошибки возвращаются в стандартном формате DRF: ошибки валидации — `400`
|
||
(`{ "<field>": ["<msg>"] }` либо `{ "detail": "..." }`), нет прав — `403`
|
||
(`{ "detail": "..." }`), не аутентифицирован — `401`, не найдено — `404`.
|
||
Объектные права проверяются `PermissionMixin` (raw-SQL), суперпользователь
|
||
их обходит.
|
||
|
||
### Замечания (расхождения кода)
|
||
- Внешние вьюсеты v2 объявляют `http_method_names = ['get']`, поэтому доступны
|
||
только `list`/`retrieve` (и GET-`@action`), даже если в коде есть методы
|
||
записи.
|
||
- Ряд bulk-эндпоинтов принимает JSON-массив (list-сериализатор).
|
||
- Datetime-поля (`DateTimeWithoutTZFiled`) наивные — таймзона отбрасывается.
|
||
- Внутренние эндпоинты принимают/возвращают «сырые» словари, без модельных
|
||
сериализаторов.
|
||
|
||
contact:
|
||
name: pm-backend
|
||
url: https://gitlab/planning/pm-backend
|
||
|
||
servers:
|
||
- url: https://api.sarex.io
|
||
description: Production (ingress)
|
||
- url: https://stage-api.sarex.io
|
||
description: Stage (ingress)
|
||
- url: http://pm-backend-service.planning.svc.cluster.local:8000
|
||
description: Внутрикластерный адрес (ClusterIP, порт 8000) — единственный способ достучаться до /internal/pm
|
||
- url: http://localhost:8000
|
||
description: Локальный запуск (gunicorn/uvicorn, порт 8000)
|
||
|
||
tags:
|
||
- name: projects
|
||
description: Проекты и папки — CRUD, копирование, экспорт, права, шаблоны
|
||
- name: tasks
|
||
description: Задачи проекта — CRUD, массовые операции, права, описания
|
||
- name: resources
|
||
description: Ресурсы и их привязки к задачам и элементам
|
||
- name: states
|
||
description: Состояния проекта (базовые планы)
|
||
- name: relations
|
||
description: Связи задач и проектов, атрибутивные связи
|
||
- name: attributes
|
||
description: Атрибуты проекта и значения атрибутов задач
|
||
- name: calendars
|
||
description: Календари
|
||
- name: settings
|
||
description: Настройки/состояния КСГ
|
||
- name: detailing
|
||
description: Детализация задач, визуальные профили
|
||
- name: comments
|
||
description: Комментарии к задачам
|
||
- name: system-log
|
||
description: Системный журнал и откаты
|
||
- name: external
|
||
description: Внешний API v2 (только чтение)
|
||
- name: internal
|
||
description: Внутренние эндпоинты (только внутри кластера, без аутентификации)
|
||
|
||
security:
|
||
- bearerAuth: []
|
||
|
||
paths:
|
||
# ==========================================================================
|
||
# Projects (/api/pm/msp/projects)
|
||
# ==========================================================================
|
||
/api/pm/msp/projects/:
|
||
get:
|
||
tags: [projects]
|
||
summary: Список проектов и папок
|
||
operationId: listProjects
|
||
parameters:
|
||
- $ref: '#/components/parameters/Limit'
|
||
- $ref: '#/components/parameters/Offset'
|
||
- { name: search, in: query, schema: { type: string } }
|
||
- { name: ids, in: query, description: CSV идентификаторов, schema: { type: string } }
|
||
- { name: resource_id, in: query, schema: { type: string } }
|
||
- { name: company_id, in: query, schema: { type: integer } }
|
||
- { name: parent_id, in: query, schema: { type: integer } }
|
||
- { name: only_children, in: query, schema: { type: boolean } }
|
||
- { name: templates, in: query, schema: { type: boolean } }
|
||
- { name: is_folder, in: query, schema: { type: boolean } }
|
||
- { name: strict, in: query, schema: { type: boolean } }
|
||
- { name: extend, in: query, schema: { type: boolean } }
|
||
- { name: schema, in: query, description: "напр. tiny/detail", schema: { type: string } }
|
||
responses:
|
||
'200':
|
||
description: Страница проектов
|
||
content:
|
||
application/json:
|
||
schema:
|
||
allOf:
|
||
- $ref: '#/components/schemas/PaginatedResponse'
|
||
- type: object
|
||
properties:
|
||
results:
|
||
type: array
|
||
items: { $ref: '#/components/schemas/Project' }
|
||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
post:
|
||
tags: [projects]
|
||
summary: Создать проект/папку
|
||
operationId: createProject
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/ProjectCreate' }
|
||
responses:
|
||
'201':
|
||
description: Проект создан
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Project' }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||
'403': { $ref: '#/components/responses/Forbidden' }
|
||
|
||
/api/pm/msp/projects/{id}/:
|
||
parameters:
|
||
- $ref: '#/components/parameters/PathId'
|
||
get:
|
||
tags: [projects]
|
||
summary: Проект по id
|
||
operationId: retrieveProject
|
||
parameters:
|
||
- { name: extend, in: query, schema: { type: boolean } }
|
||
- { name: schema, in: query, schema: { type: string } }
|
||
responses:
|
||
'200':
|
||
description: Проект
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Project' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
put:
|
||
tags: [projects]
|
||
summary: Полное обновление проекта
|
||
operationId: updateProject
|
||
requestBody:
|
||
required: true
|
||
content: { application/json: { schema: { $ref: '#/components/schemas/ProjectCreate' } } }
|
||
responses:
|
||
'200': { description: Обновлено, content: { application/json: { schema: { $ref: '#/components/schemas/Project' } } } }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
patch:
|
||
tags: [projects]
|
||
summary: Частичное обновление проекта
|
||
operationId: partialUpdateProject
|
||
requestBody:
|
||
required: true
|
||
content: { application/json: { schema: { $ref: '#/components/schemas/ProjectCreate' } } }
|
||
responses:
|
||
'200': { description: Обновлено, content: { application/json: { schema: { $ref: '#/components/schemas/Project' } } } }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
delete:
|
||
tags: [projects]
|
||
summary: Удалить проект
|
||
operationId: deleteProject
|
||
responses:
|
||
'204': { description: Удалено }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/api/pm/msp/projects/root_folder/:
|
||
post:
|
||
tags: [projects]
|
||
summary: Создать корневую папку
|
||
operationId: createRootFolder
|
||
requestBody:
|
||
required: true
|
||
content: { application/json: { schema: { $ref: '#/components/schemas/FolderCreate' } } }
|
||
responses:
|
||
'201': { description: Папка создана, content: { application/json: { schema: { $ref: '#/components/schemas/Project' } } } }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/api/pm/msp/projects/rename/:
|
||
post:
|
||
tags: [projects]
|
||
summary: Переименовать проект
|
||
operationId: renameProject
|
||
responses:
|
||
'200': { description: OK }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/api/pm/msp/projects/import/:
|
||
post:
|
||
tags: [projects]
|
||
summary: Импорт задач в проект
|
||
operationId: importProject
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
pk: { type: integer }
|
||
from_type: { type: string, enum: [sarex, ms_project, primavera, template] }
|
||
update: { type: boolean }
|
||
template_id: { type: integer, nullable: true }
|
||
required: [pk, from_type]
|
||
responses:
|
||
'201': { description: Импорт запущен, content: { application/json: { schema: { type: object, properties: { uuid: { type: string, format: uuid } } } } } }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
|
||
/api/pm/msp/projects/import-from-gasprom/:
|
||
post:
|
||
tags: [projects]
|
||
summary: Импорт проекта из Газпром ЦПС
|
||
operationId: importProjectFromGaspromCps
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
project_name: { type: string }
|
||
company_id: { type: integer }
|
||
file_url: { type: string }
|
||
required: [project_name, company_id, file_url]
|
||
responses:
|
||
'201': { description: Импорт запущен, content: { application/json: { schema: { type: object, properties: { uuid: { type: string, format: uuid } } } } } }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/api/pm/msp/projects/{id}/states/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [projects]
|
||
summary: Состояния (базовые планы) проекта
|
||
operationId: listProjectStates
|
||
responses:
|
||
'200': { description: Список состояний, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/ProjectState' } } } } }
|
||
|
||
/api/pm/msp/projects/{id}/permissions/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [projects]
|
||
summary: Права проекта
|
||
operationId: getProjectPermissions
|
||
responses:
|
||
'200': { description: Права, content: { application/json: { schema: { $ref: '#/components/schemas/PermissionsResponse' } } } }
|
||
post:
|
||
tags: [projects]
|
||
summary: Сохранить права проекта
|
||
operationId: saveProjectPermissions
|
||
requestBody: { required: true, content: { application/json: { schema: { type: object } } } }
|
||
responses:
|
||
'200': { description: Права, content: { application/json: { schema: { $ref: '#/components/schemas/PermissionsResponse' } } } }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/api/pm/msp/projects/{id}/all_permissions/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [projects]
|
||
summary: Все права проекта
|
||
operationId: getProjectAllPermissions
|
||
responses:
|
||
'200': { description: Права, content: { application/json: { schema: { type: object } } } }
|
||
|
||
/api/pm/msp/projects/{id}/copy_project/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
post:
|
||
tags: [projects]
|
||
summary: Копировать проект
|
||
operationId: copyProject
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
parent_id: { type: integer, nullable: true }
|
||
project_name: { type: string }
|
||
assets_mapping: { type: object }
|
||
with_resources: { type: boolean }
|
||
responses:
|
||
'201': { description: Проект скопирован, content: { application/json: { schema: { $ref: '#/components/schemas/Project' } } } }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/api/pm/msp/projects/{id}/create_template/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
post:
|
||
tags: [projects]
|
||
summary: Создать шаблон из проекта
|
||
operationId: createTemplateFromProject
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
project_name: { type: string }
|
||
description: { type: string, nullable: true }
|
||
required: [project_name]
|
||
responses:
|
||
'201': { description: Шаблон создан, content: { application/json: { schema: { $ref: '#/components/schemas/Project' } } } }
|
||
|
||
/api/pm/msp/projects/{id}/export_project_to_pdf/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
post:
|
||
tags: [projects]
|
||
summary: Экспорт проекта в PDF
|
||
operationId: exportProjectToPdf
|
||
requestBody:
|
||
required: true
|
||
content: { application/json: { schema: { $ref: '#/components/schemas/ExportProject' } } }
|
||
responses:
|
||
'200': { description: Задача экспорта запущена }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/api/pm/msp/projects/{id}/project_export/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
post:
|
||
tags: [projects]
|
||
summary: Экспорт проекта (xlsx/xml)
|
||
operationId: projectExport
|
||
responses:
|
||
'200': { description: Экспорт запущен }
|
||
|
||
/api/pm/msp/projects/{id}/key_milestones/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [projects]
|
||
summary: Ключевые вехи проекта
|
||
operationId: getKeyMilestones
|
||
responses:
|
||
'200': { description: Вехи, content: { application/json: { schema: { type: array, items: { type: object } } } } }
|
||
|
||
/api/pm/msp/projects/{id}/profiles/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [projects]
|
||
summary: Визуальные профили проекта
|
||
operationId: getProjectProfiles
|
||
responses:
|
||
'200': { description: Профили, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/VisualProfile' } } } } }
|
||
|
||
/api/pm/msp/projects/{id}/time_markers_data/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [projects]
|
||
summary: Данные временных маркеров
|
||
operationId: getTimeMarkersData
|
||
parameters:
|
||
- { name: attributes, in: query, description: CSV идентификаторов атрибутов, schema: { type: string } }
|
||
- { name: with_hierarchy, in: query, schema: { type: boolean } }
|
||
responses:
|
||
'200': { description: Данные, content: { application/json: { schema: { type: object } } } }
|
||
|
||
/api/pm/msp/projects/{id}/relations/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [projects]
|
||
summary: Связи/интеграции проекта
|
||
operationId: getProjectRelations
|
||
responses:
|
||
'200': { description: Связи, content: { application/json: { schema: { type: array, items: { type: object } } } } }
|
||
|
||
/api/pm/msp/projects/{id}/bulk_integration/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
post:
|
||
tags: [projects]
|
||
summary: Массовое создание интеграций
|
||
operationId: bulkIntegration
|
||
responses:
|
||
'200': { description: OK }
|
||
|
||
/api/pm/msp/projects/{id}/issues_data/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [projects]
|
||
summary: Данные проблем проекта
|
||
operationId: getIssuesData
|
||
responses:
|
||
'200': { description: Данные, content: { application/json: { schema: { type: object } } } }
|
||
|
||
/api/pm/msp/projects/{id}/formula/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
post:
|
||
tags: [projects]
|
||
summary: Пересчёт по формуле
|
||
operationId: applyFormula
|
||
responses:
|
||
'200': { description: OK }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/api/pm/msp/projects/{id}/rule/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [detailing]
|
||
summary: Правило детализации проекта
|
||
operationId: getProjectRule
|
||
responses:
|
||
'200': { description: Правило, content: { application/json: { schema: { type: object } } } }
|
||
post:
|
||
tags: [detailing]
|
||
summary: Создать правило детализации
|
||
operationId: createProjectRule
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
attributes: { type: array, items: { type: integer } }
|
||
summary_fields: { type: array, items: { type: string } }
|
||
mode: { type: string }
|
||
responses:
|
||
'200': { description: OK }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/api/pm/msp/projects/{id}/tasks/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [projects]
|
||
summary: Задачи проекта
|
||
operationId: getProjectTasks
|
||
responses:
|
||
'200': { description: Задачи, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/ProjectTask' } } } } }
|
||
|
||
/api/pm/msp/projects/{id}/create_tasks/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
post:
|
||
tags: [tasks]
|
||
summary: Массовое создание задач
|
||
operationId: bulkCreateTasks
|
||
requestBody:
|
||
required: true
|
||
content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/ProjectTaskCreate' } } } }
|
||
responses:
|
||
'201': { description: Создано, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/ProjectTask' } } } } }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/api/pm/msp/projects/{id}/update_tasks/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
patch:
|
||
tags: [tasks]
|
||
summary: Массовое обновление задач
|
||
operationId: bulkUpdateTasks
|
||
requestBody:
|
||
required: true
|
||
content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/ProjectTaskUpdate' } } } }
|
||
responses:
|
||
'200': { description: Обновлено }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/api/pm/msp/projects/{id}/delete_tasks/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
delete:
|
||
tags: [tasks]
|
||
summary: Массовое удаление задач
|
||
operationId: bulkDeleteTasks
|
||
requestBody:
|
||
required: true
|
||
content: { application/json: { schema: { type: object, properties: { ids: { type: array, items: { type: integer } } } } } }
|
||
responses:
|
||
'204': { description: Удалено }
|
||
|
||
/api/pm/msp/projects/{id}/system-logs/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [system-log]
|
||
summary: Системные логи проекта
|
||
operationId: getSystemLogs
|
||
parameters:
|
||
- { name: task_id, in: query, schema: { type: integer } }
|
||
- $ref: '#/components/parameters/Limit'
|
||
- $ref: '#/components/parameters/Offset'
|
||
responses:
|
||
'200':
|
||
description: Страница логов
|
||
content:
|
||
application/json:
|
||
schema:
|
||
allOf:
|
||
- $ref: '#/components/schemas/PaginatedResponse'
|
||
- type: object
|
||
properties: { results: { type: array, items: { $ref: '#/components/schemas/SystemLog' } } }
|
||
|
||
/api/pm/msp/projects/{id}/system-log-detail/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [system-log]
|
||
summary: Деталь записи журнала
|
||
operationId: getSystemLogDetail
|
||
parameters:
|
||
- { name: log_id, in: query, required: true, schema: { type: integer } }
|
||
responses:
|
||
'200': { description: Деталь, content: { application/json: { schema: { $ref: '#/components/schemas/SystemLog' } } } }
|
||
|
||
/api/pm/msp/projects/{id}/rollback-to-record/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
post:
|
||
tags: [system-log]
|
||
summary: Откат к записи журнала
|
||
operationId: rollbackToRecord
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
log_id: { type: integer }
|
||
read_only: { type: boolean }
|
||
required: [log_id]
|
||
responses:
|
||
'200': { description: OK }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
# ==========================================================================
|
||
# Tasks (/api/pm/msp/tasks)
|
||
# ==========================================================================
|
||
/api/pm/msp/tasks/:
|
||
get:
|
||
tags: [tasks]
|
||
summary: Список задач
|
||
operationId: listTasks
|
||
parameters:
|
||
- $ref: '#/components/parameters/Limit'
|
||
- $ref: '#/components/parameters/Offset'
|
||
- { name: project, in: query, schema: { type: integer } }
|
||
- { name: ids, in: query, schema: { type: string } }
|
||
- { name: name__icontains, in: query, schema: { type: string } }
|
||
- { name: time_start, in: query, schema: { type: string, format: date-time } }
|
||
- { name: time_end, in: query, schema: { type: string, format: date-time } }
|
||
- { name: status, in: query, description: CSV статусов, schema: { type: string } }
|
||
- { name: responsible, in: query, schema: { type: string } }
|
||
- { name: executors, in: query, schema: { type: string } }
|
||
- { name: with_hierarchy, in: query, schema: { type: boolean, default: true } }
|
||
responses:
|
||
'200':
|
||
description: Страница задач
|
||
content:
|
||
application/json:
|
||
schema:
|
||
allOf:
|
||
- $ref: '#/components/schemas/PaginatedResponse'
|
||
- type: object
|
||
properties: { results: { type: array, items: { $ref: '#/components/schemas/ProjectTask' } } }
|
||
post:
|
||
tags: [tasks]
|
||
summary: Создать задачу
|
||
operationId: createTask
|
||
requestBody:
|
||
required: true
|
||
content: { application/json: { schema: { $ref: '#/components/schemas/ProjectTaskCreate' } } }
|
||
responses:
|
||
'201': { description: Создано, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectTask' } } } }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/api/pm/msp/tasks/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [tasks]
|
||
summary: Задача по id
|
||
operationId: retrieveTask
|
||
responses:
|
||
'200': { description: Задача, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectTask' } } } }
|
||
'404': { $ref: '#/components/responses/NotFound' }
|
||
put:
|
||
tags: [tasks]
|
||
summary: Полное обновление задачи
|
||
operationId: updateTask
|
||
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectTaskCreate' } } } }
|
||
responses:
|
||
'200': { description: Обновлено, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectTask' } } } }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
patch:
|
||
tags: [tasks]
|
||
summary: Частичное обновление задачи
|
||
operationId: partialUpdateTask
|
||
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectTaskCreate' } } } }
|
||
responses:
|
||
'200': { description: Обновлено, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectTask' } } } }
|
||
delete:
|
||
tags: [tasks]
|
||
summary: Удалить задачу
|
||
operationId: deleteTask
|
||
responses:
|
||
'204': { description: Удалено }
|
||
|
||
/api/pm/msp/tasks/task_index/:
|
||
patch:
|
||
tags: [tasks]
|
||
summary: Переиндексация задач
|
||
operationId: updateTaskIndex
|
||
responses:
|
||
'200': { description: OK }
|
||
|
||
/api/pm/msp/tasks/copy/:
|
||
post:
|
||
tags: [tasks]
|
||
summary: Копировать задачи
|
||
operationId: copyTasks
|
||
requestBody:
|
||
required: true
|
||
content: { application/json: { schema: { type: object, properties: { ids: { type: array, items: { type: integer } } } } } }
|
||
responses:
|
||
'200': { description: OK }
|
||
|
||
/api/pm/msp/tasks/{id}/permissions/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [tasks]
|
||
summary: Права задачи
|
||
operationId: getTaskPermissions
|
||
responses:
|
||
'200': { description: Права, content: { application/json: { schema: { $ref: '#/components/schemas/PermissionsResponse' } } } }
|
||
post:
|
||
tags: [tasks]
|
||
summary: Сохранить права задачи
|
||
operationId: saveTaskPermissions
|
||
requestBody: { required: true, content: { application/json: { schema: { type: object } } } }
|
||
responses:
|
||
'200': { description: Права, content: { application/json: { schema: { $ref: '#/components/schemas/PermissionsResponse' } } } }
|
||
|
||
/api/pm/msp/tasks/{id}/descriptions/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [tasks]
|
||
summary: Описание задачи
|
||
operationId: getTaskDescription
|
||
responses:
|
||
'200': { description: Описание, content: { application/json: { schema: { $ref: '#/components/schemas/Description' } } } }
|
||
patch:
|
||
tags: [tasks]
|
||
summary: Обновить описание задачи
|
||
operationId: updateTaskDescription
|
||
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/Description' } } } }
|
||
responses:
|
||
'200': { description: Обновлено, content: { application/json: { schema: { $ref: '#/components/schemas/Description' } } } }
|
||
|
||
# ==========================================================================
|
||
# Detailed tasks / descriptions
|
||
# ==========================================================================
|
||
/api/pm/msp/detailed-tasks/:
|
||
get:
|
||
tags: [detailing]
|
||
summary: Список детализированных задач
|
||
operationId: listDetailedTasks
|
||
parameters:
|
||
- { name: task, in: query, schema: { type: integer } }
|
||
- { name: project, in: query, schema: { type: integer } }
|
||
responses:
|
||
'200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/DetailedTask' } } } } }
|
||
post:
|
||
tags: [detailing]
|
||
summary: Создать детализированную задачу
|
||
operationId: createDetailedTask
|
||
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/DetailedTask' } } } }
|
||
responses:
|
||
'201': { description: Создано, content: { application/json: { schema: { $ref: '#/components/schemas/DetailedTask' } } } }
|
||
|
||
/api/pm/msp/detailed-tasks/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
patch:
|
||
tags: [detailing]
|
||
summary: Обновить детализированную задачу
|
||
operationId: updateDetailedTask
|
||
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/DetailedTask' } } } }
|
||
responses:
|
||
'200': { description: Обновлено, content: { application/json: { schema: { $ref: '#/components/schemas/DetailedTask' } } } }
|
||
delete:
|
||
tags: [detailing]
|
||
summary: Удалить детализированную задачу
|
||
operationId: deleteDetailedTask
|
||
responses:
|
||
'204': { description: Удалено }
|
||
|
||
/api/pm/msp/descriptions/upload_file/:
|
||
post:
|
||
tags: [tasks]
|
||
summary: Загрузить файл описания
|
||
operationId: uploadDescriptionFile
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
multipart/form-data:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
file: { type: string, format: binary }
|
||
responses:
|
||
'200': { description: OK }
|
||
|
||
# ==========================================================================
|
||
# Values (actual values)
|
||
# ==========================================================================
|
||
/api/pm/msp/values/:
|
||
get:
|
||
tags: [tasks]
|
||
summary: Фактические значения задач
|
||
operationId: listActualValues
|
||
parameters:
|
||
- { name: task, in: query, schema: { type: integer } }
|
||
- $ref: '#/components/parameters/Limit'
|
||
- $ref: '#/components/parameters/Offset'
|
||
responses:
|
||
'200': { description: Значения, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/ActualValue' } } } } }
|
||
post:
|
||
tags: [tasks]
|
||
summary: Создать фактическое значение
|
||
operationId: createActualValue
|
||
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ActualValueCreate' } } } }
|
||
responses:
|
||
'201': { description: Создано, content: { application/json: { schema: { $ref: '#/components/schemas/ActualValue' } } } }
|
||
|
||
/api/pm/msp/values/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [tasks]
|
||
summary: Значение по id
|
||
operationId: retrieveActualValue
|
||
responses: { '200': { description: Значение, content: { application/json: { schema: { $ref: '#/components/schemas/ActualValue' } } } }, '404': { $ref: '#/components/responses/NotFound' } }
|
||
put:
|
||
tags: [tasks]
|
||
summary: Обновить значение
|
||
operationId: updateActualValue
|
||
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ActualValueCreate' } } } }
|
||
responses: { '200': { description: Обновлено, content: { application/json: { schema: { $ref: '#/components/schemas/ActualValue' } } } } }
|
||
delete:
|
||
tags: [tasks]
|
||
summary: Удалить значение
|
||
operationId: deleteActualValue
|
||
responses: { '204': { description: Удалено } }
|
||
|
||
# ==========================================================================
|
||
# Project states (base plans)
|
||
# ==========================================================================
|
||
/api/pm/msp/project-states/:
|
||
get:
|
||
tags: [states]
|
||
summary: Список состояний
|
||
operationId: listStates
|
||
responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/ProjectState' } } } } } }
|
||
post:
|
||
tags: [states]
|
||
summary: Создать состояние (базовый план)
|
||
operationId: createState
|
||
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectStateCreate' } } } }
|
||
responses: { '201': { description: Создано, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectState' } } } } }
|
||
|
||
/api/pm/msp/project-states/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [states]
|
||
summary: Состояние по id
|
||
operationId: retrieveState
|
||
responses: { '200': { description: Состояние, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectState' } } } }, '404': { $ref: '#/components/responses/NotFound' } }
|
||
put:
|
||
tags: [states]
|
||
summary: Обновить состояние
|
||
operationId: updateState
|
||
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectStateCreate' } } } }
|
||
responses: { '200': { description: Обновлено, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectState' } } } } }
|
||
delete:
|
||
tags: [states]
|
||
summary: Удалить состояние
|
||
operationId: deleteState
|
||
responses: { '204': { description: Удалено } }
|
||
|
||
/api/pm/msp/project-states/{id}/data/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get:
|
||
tags: [states]
|
||
summary: Данные состояния (базового плана)
|
||
operationId: getStateData
|
||
responses: { '200': { description: Данные, content: { application/json: { schema: { type: object } } } } }
|
||
post:
|
||
tags: [states]
|
||
summary: Добавить задачи в базовый план
|
||
operationId: addTasksToState
|
||
responses: { '200': { description: OK } }
|
||
|
||
/api/pm/msp/project-states/{id}/edit_state/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
patch:
|
||
tags: [states]
|
||
summary: Редактировать состояние
|
||
operationId: editState
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
time_start: { type: string, format: date-time, nullable: true }
|
||
time_end: { type: string, format: date-time, nullable: true }
|
||
progress: { type: number, nullable: true }
|
||
planned_value: { type: number, nullable: true }
|
||
unit: { type: string, nullable: true }
|
||
required: [id]
|
||
responses: { '200': { description: OK } }
|
||
|
||
# ==========================================================================
|
||
# Resources
|
||
# ==========================================================================
|
||
/api/pm/msp/resources/:
|
||
get:
|
||
tags: [resources]
|
||
summary: Список ресурсов
|
||
operationId: listResources
|
||
parameters:
|
||
- { name: ids, in: query, schema: { type: string } }
|
||
- { name: projects, in: query, schema: { type: string } }
|
||
- { name: type, in: query, schema: { type: string } }
|
||
- { name: parent, in: query, schema: { type: integer } }
|
||
- { name: company, in: query, schema: { type: integer } }
|
||
- { name: full, in: query, schema: { type: boolean } }
|
||
- { name: extend, in: query, schema: { type: boolean } }
|
||
- $ref: '#/components/parameters/Limit'
|
||
- $ref: '#/components/parameters/Offset'
|
||
responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/Resource' } } } } } }
|
||
post:
|
||
tags: [resources]
|
||
summary: Создать ресурс
|
||
operationId: createResource
|
||
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ResourceCreate' } } } }
|
||
responses: { '201': { description: Создано, content: { application/json: { schema: { $ref: '#/components/schemas/Resource' } } } } }
|
||
|
||
/api/pm/msp/resources/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get: { tags: [resources], summary: Ресурс по id, operationId: retrieveResource, responses: { '200': { description: Ресурс, content: { application/json: { schema: { $ref: '#/components/schemas/Resource' } } } }, '404': { $ref: '#/components/responses/NotFound' } } }
|
||
put: { tags: [resources], summary: Обновить ресурс, operationId: updateResource, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ResourceCreate' } } } }, responses: { '200': { description: Обновлено, content: { application/json: { schema: { $ref: '#/components/schemas/Resource' } } } } } }
|
||
patch: { tags: [resources], summary: Частичное обновление ресурса, operationId: partialUpdateResource, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ResourceCreate' } } } }, responses: { '200': { description: Обновлено, content: { application/json: { schema: { $ref: '#/components/schemas/Resource' } } } } } }
|
||
delete: { tags: [resources], summary: Удалить ресурс, operationId: deleteResource, responses: { '204': { description: Удалено } } }
|
||
|
||
/api/pm/msp/resources/bulk_create/:
|
||
post:
|
||
tags: [resources]
|
||
summary: Массовое создание ресурсов
|
||
operationId: bulkCreateResources
|
||
requestBody: { required: true, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/ResourceCreate' } } } } }
|
||
responses: { '201': { description: Создано } }
|
||
|
||
/api/pm/msp/resources/resource_planning/:
|
||
get:
|
||
tags: [resources]
|
||
summary: Ресурсное планирование
|
||
operationId: resourcePlanning
|
||
parameters:
|
||
- { name: projects, in: query, schema: { type: string } }
|
||
- { name: resource_type, in: query, schema: { type: string, default: human } }
|
||
- { name: start, in: query, required: true, schema: { type: string, format: date-time } }
|
||
- { name: end, in: query, required: true, schema: { type: string, format: date-time } }
|
||
- { name: scale, in: query, schema: { type: string, default: D } }
|
||
- { name: group, in: query, schema: { type: string } }
|
||
responses: { '200': { description: Данные, content: { application/json: { schema: { type: object } } } } }
|
||
|
||
/api/pm/msp/resources/{id}/bind_task/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
post: { tags: [resources], summary: Привязать задачу к ресурсу, operationId: bindTaskToResource, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ResourceTaskRelation' } } } }, responses: { '201': { description: Создано } } }
|
||
|
||
/api/pm/msp/resources/{id}/bind_elements/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
post: { tags: [resources], summary: Привязать элементы к ресурсу, operationId: bindElementsToResource, responses: { '201': { description: Создано } } }
|
||
|
||
# ---- Resource relations ----
|
||
/api/pm/msp/resources-tasks/:
|
||
get:
|
||
tags: [resources]
|
||
summary: Список привязок ресурс-задача
|
||
operationId: listResourceTaskRelations
|
||
parameters:
|
||
- { name: projects, in: query, schema: { type: string } }
|
||
- { name: tasks, in: query, schema: { type: string } }
|
||
- { name: resources, in: query, schema: { type: string } }
|
||
responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/ResourceTaskRelation' } } } } } }
|
||
post: { tags: [resources], summary: Создать привязку ресурс-задача, operationId: createResourceTaskRelation, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ResourceTaskRelation' } } } }, responses: { '201': { description: Создано } } }
|
||
|
||
/api/pm/msp/resources-tasks/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get: { tags: [resources], summary: Привязка по id, operationId: retrieveResourceTaskRelation, responses: { '200': { description: Привязка, content: { application/json: { schema: { $ref: '#/components/schemas/ResourceTaskRelation' } } } } } }
|
||
patch: { tags: [resources], summary: Обновить привязку, operationId: updateResourceTaskRelation, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ResourceTaskRelation' } } } }, responses: { '200': { description: Обновлено } } }
|
||
delete: { tags: [resources], summary: Удалить привязку, operationId: deleteResourceTaskRelation, responses: { '204': { description: Удалено } } }
|
||
|
||
/api/pm/msp/resources-tasks/assign/:
|
||
patch: { tags: [resources], summary: Назначение ресурса на задачи, operationId: assignResourceToTasks, responses: { '200': { description: OK } } }
|
||
|
||
/api/pm/msp/resources-tasks/bulk_update/:
|
||
patch:
|
||
tags: [resources]
|
||
summary: Массовое обновление привязок ресурс-задача
|
||
operationId: bulkUpdateResourceTaskRelations
|
||
requestBody: { required: true, content: { application/json: { schema: { type: object, properties: { ids: { type: array, items: { type: integer } }, profile: { type: integer } } } } } }
|
||
responses: { '200': { description: OK } }
|
||
|
||
/api/pm/msp/resources-tasks/bulk_delete/:
|
||
delete:
|
||
tags: [resources]
|
||
summary: Массовое удаление привязок ресурс-задача
|
||
operationId: bulkDeleteResourceTaskRelations
|
||
requestBody: { required: true, content: { application/json: { schema: { type: object, properties: { ids: { type: array, items: { type: integer } } } } } } }
|
||
responses: { '204': { description: Удалено } }
|
||
|
||
/api/pm/msp/resources-elements/:
|
||
get:
|
||
tags: [resources]
|
||
summary: Список привязок ресурс-элемент
|
||
operationId: listResourceElementRelations
|
||
parameters:
|
||
- { name: resources, in: query, schema: { type: string } }
|
||
- { name: instances, in: query, schema: { type: string } }
|
||
responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/ResourceElementRelation' } } } } } }
|
||
post: { tags: [resources], summary: Создать привязку ресурс-элемент, operationId: createResourceElementRelation, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ResourceElementRelation' } } } }, responses: { '201': { description: Создано } } }
|
||
|
||
# ==========================================================================
|
||
# Relations (task/project)
|
||
# ==========================================================================
|
||
/api/pm/msp/task-relations/:
|
||
get:
|
||
tags: [relations]
|
||
summary: Список связей задач
|
||
operationId: listTaskRelations
|
||
parameters: [ { name: project, in: query, schema: { type: integer } } ]
|
||
responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/Task2TaskRelation' } } } } } }
|
||
post: { tags: [relations], summary: Создать связь задач, operationId: createTaskRelation, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/Task2TaskRelation' } } } }, responses: { '201': { description: Создано } } }
|
||
|
||
/api/pm/msp/task-relations/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
put: { tags: [relations], summary: Обновить связь задач, operationId: updateTaskRelation, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/Task2TaskRelation' } } } }, responses: { '200': { description: Обновлено } } }
|
||
delete: { tags: [relations], summary: Удалить связь задач, operationId: deleteTaskRelation, responses: { '204': { description: Удалено } } }
|
||
|
||
/api/pm/msp/task-relations/bulk_delete/:
|
||
delete:
|
||
tags: [relations]
|
||
summary: Массовое удаление связей задач
|
||
operationId: bulkDeleteTaskRelations
|
||
requestBody: { required: true, content: { application/json: { schema: { type: object, properties: { ids: { type: array, items: { type: integer } } } } } } }
|
||
responses: { '204': { description: Удалено } }
|
||
|
||
/api/pm/msp/project-relations/:
|
||
get: { tags: [relations], summary: Список связей проектов, operationId: listProjectRelations, parameters: [ { name: project, in: query, schema: { type: integer } } ], responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/Project2ProjectRelation' } } } } } } }
|
||
post:
|
||
tags: [relations]
|
||
summary: Создать связь(и) проектов
|
||
operationId: createProjectRelation
|
||
requestBody: { required: true, content: { application/json: { schema: { oneOf: [ { $ref: '#/components/schemas/Project2ProjectRelation' }, { type: array, items: { $ref: '#/components/schemas/Project2ProjectRelation' } } ] } } } }
|
||
responses: { '201': { description: Создано } }
|
||
|
||
/api/pm/msp/project-relations/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
patch: { tags: [relations], summary: Обновить связь проектов, operationId: updateProjectRelation, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/Project2ProjectRelation' } } } }, responses: { '200': { description: Обновлено } } }
|
||
delete: { tags: [relations], summary: Удалить связь проектов, operationId: deleteProjectRelation, responses: { '204': { description: Удалено } } }
|
||
|
||
/api/pm/msp/entity-relations/:
|
||
get: { tags: [relations], summary: Список сущностных связей, operationId: listEntityRelations, parameters: [ { name: project_id, in: query, schema: { type: integer } } ], responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/EntityRelation' } } } } } } }
|
||
post: { tags: [relations], summary: Создать сущностную связь, operationId: createEntityRelation, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/EntityRelation' } } } }, responses: { '201': { description: Создано } } }
|
||
|
||
/api/pm/msp/entity-relations/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
patch: { tags: [relations], summary: Обновить сущностную связь, operationId: updateEntityRelation, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/EntityRelation' } } } }, responses: { '200': { description: Обновлено } } }
|
||
delete: { tags: [relations], summary: Удалить сущностную связь, operationId: deleteEntityRelation, responses: { '204': { description: Удалено } } }
|
||
|
||
# ==========================================================================
|
||
# Attributes
|
||
# ==========================================================================
|
||
/api/pm/msp/project-attribute/:
|
||
get:
|
||
tags: [attributes]
|
||
summary: Атрибуты проекта
|
||
operationId: listProjectAttributes
|
||
parameters: [ { name: project, in: query, schema: { type: integer } } ]
|
||
responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/ProjectAttributeRelation' } } } } } }
|
||
post:
|
||
tags: [attributes]
|
||
summary: Привязать атрибут(ы) к проекту
|
||
operationId: createProjectAttribute
|
||
requestBody: { required: true, content: { application/json: { schema: { oneOf: [ { $ref: '#/components/schemas/ProjectAttributeRelation' }, { type: array, items: { $ref: '#/components/schemas/ProjectAttributeRelation' } } ] } } } }
|
||
responses: { '201': { description: Создано } }
|
||
|
||
/api/pm/msp/project-attribute/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
put: { tags: [attributes], summary: Обновить атрибут проекта, operationId: updateProjectAttribute, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectAttributeRelation' } } } }, responses: { '200': { description: Обновлено } } }
|
||
delete: { tags: [attributes], summary: Удалить атрибут проекта, operationId: deleteProjectAttribute, responses: { '204': { description: Удалено } } }
|
||
|
||
/api/pm/msp/task-value/:
|
||
get:
|
||
tags: [attributes]
|
||
summary: Значения атрибутов задач
|
||
operationId: listTaskValues
|
||
parameters:
|
||
- { name: tasks, in: query, description: CSV, schema: { type: string } }
|
||
- { name: attributes, in: query, description: CSV, schema: { type: string } }
|
||
responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/TaskAttributeValue' } } } } } }
|
||
post:
|
||
tags: [attributes]
|
||
summary: Создать значение(я) атрибутов задач
|
||
operationId: createTaskValue
|
||
requestBody: { required: true, content: { application/json: { schema: { oneOf: [ { $ref: '#/components/schemas/TaskAttributeValue' }, { type: array, items: { $ref: '#/components/schemas/TaskAttributeValue' } } ] } } } }
|
||
responses: { '201': { description: Создано } }
|
||
|
||
# ==========================================================================
|
||
# Calendars
|
||
# ==========================================================================
|
||
/api/pm/msp/calendars/:
|
||
get: { tags: [calendars], summary: Список календарей, operationId: listCalendars, responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/Calendar' } } } } } } }
|
||
post: { tags: [calendars], summary: Создать календарь, operationId: createCalendar, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/Calendar' } } } }, responses: { '201': { description: Создано, content: { application/json: { schema: { $ref: '#/components/schemas/Calendar' } } } } } }
|
||
|
||
/api/pm/msp/calendars/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get: { tags: [calendars], summary: Календарь по id, operationId: retrieveCalendar, responses: { '200': { description: Календарь, content: { application/json: { schema: { $ref: '#/components/schemas/Calendar' } } } } } }
|
||
patch: { tags: [calendars], summary: Изменить календарь, operationId: updateCalendar, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/Calendar' } } } }, responses: { '200': { description: Обновлено } } }
|
||
delete: { tags: [calendars], summary: Удалить календарь, operationId: deleteCalendar, responses: { '204': { description: Удалено } } }
|
||
|
||
# ==========================================================================
|
||
# Project settings (KSG)
|
||
# ==========================================================================
|
||
/api/pm/msp/project-settings/:
|
||
get: { tags: [settings], summary: Список настроек КСГ, operationId: listProjectSettings, responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/ProjectSettings' } } } } } } }
|
||
post: { tags: [settings], summary: Создать настройку КСГ, operationId: createProjectSettings, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectSettings' } } } }, responses: { '201': { description: Создано } } }
|
||
|
||
/api/pm/msp/project-settings/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get: { tags: [settings], summary: Настройка по id, operationId: retrieveProjectSettings, responses: { '200': { description: Настройка, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectSettings' } } } } } }
|
||
patch: { tags: [settings], summary: Изменить настройку, operationId: updateProjectSettings, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectSettings' } } } }, responses: { '200': { description: Обновлено } } }
|
||
delete: { tags: [settings], summary: Удалить настройку, operationId: deleteProjectSettings, responses: { '204': { description: Удалено } } }
|
||
|
||
/api/pm/msp/project-settings/{id}/apply/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
post:
|
||
tags: [settings]
|
||
summary: Применить глобальную настройку
|
||
operationId: applyProjectSettings
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
project_id: { type: integer }
|
||
connect_missing_attributes: { type: boolean }
|
||
required: [project_id]
|
||
responses: { '200': { description: OK } }
|
||
|
||
# ==========================================================================
|
||
# Visual profiles
|
||
# ==========================================================================
|
||
/api/pm/msp/visual-profiles/:
|
||
get: { tags: [detailing], summary: Список визуальных профилей, operationId: listVisualProfiles, responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/VisualProfile' } } } } } } }
|
||
post: { tags: [detailing], summary: Создать визуальный профиль, operationId: createVisualProfile, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/VisualProfile' } } } }, responses: { '201': { description: Создано } } }
|
||
|
||
/api/pm/msp/visual-profiles/{id}:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
patch: { tags: [detailing], summary: Изменить визуальный профиль, operationId: updateVisualProfile, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/VisualProfile' } } } }, responses: { '200': { description: Обновлено } } }
|
||
delete: { tags: [detailing], summary: Удалить визуальный профиль, operationId: deleteVisualProfile, responses: { '204': { description: Удалено } } }
|
||
|
||
# ==========================================================================
|
||
# Comments
|
||
# ==========================================================================
|
||
/api/pm/msp/comments/:
|
||
get: { tags: [comments], summary: Список комментариев, operationId: listComments, responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/Comment' } } } } } } }
|
||
post: { tags: [comments], summary: Создать комментарий, operationId: createComment, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/CommentCreate' } } } }, responses: { '201': { description: Создано } } }
|
||
|
||
# ==========================================================================
|
||
# Descriptions resource
|
||
# ==========================================================================
|
||
/api/pm/msp/descriptions/:
|
||
get: { tags: [tasks], summary: Список описаний, operationId: listDescriptions, parameters: [ { name: task, in: query, schema: { type: integer } } ], responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/Description' } } } } } } }
|
||
post: { tags: [tasks], summary: Создать описание, operationId: createDescription, requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/Description' } } } }, responses: { '201': { description: Создано } } }
|
||
|
||
# ==========================================================================
|
||
# Task info (public/service)
|
||
# ==========================================================================
|
||
/api/pm/msp/task-info/:
|
||
get:
|
||
tags: [tasks]
|
||
summary: Задачи по профилям (not_started/in_progress/completed)
|
||
operationId: getTaskInfo
|
||
parameters:
|
||
- { name: projects, in: query, required: true, description: CSV идентификаторов, schema: { type: string } }
|
||
- { name: date, in: query, required: true, schema: { type: string, format: date-time } }
|
||
- { name: document, in: query, required: true, schema: { type: string } }
|
||
- { name: base_plane, in: query, schema: { type: string } }
|
||
responses: { '200': { description: Данные, content: { application/json: { schema: { type: object } } } } }
|
||
|
||
/api/pm/msp/external-task-info/:
|
||
get:
|
||
tags: [tasks]
|
||
summary: Инфо о фоновой задаче через брокер
|
||
operationId: getExternalTaskInfo
|
||
security: []
|
||
parameters: [ { name: task_id, in: query, schema: { type: string, format: uuid } } ]
|
||
responses: { '200': { description: Данные, content: { application/json: { schema: { type: object } } } } }
|
||
|
||
# ==========================================================================
|
||
# External API v2 (read-only)
|
||
# ==========================================================================
|
||
/api/pm/external/v2/projects/:
|
||
get:
|
||
tags: [external]
|
||
summary: Список проектов (внешний)
|
||
operationId: externalListProjects
|
||
parameters:
|
||
- $ref: '#/components/parameters/Limit'
|
||
- $ref: '#/components/parameters/Offset'
|
||
- { name: search, in: query, schema: { type: string } }
|
||
- { name: ids, in: query, schema: { type: string } }
|
||
- { name: parent_id, in: query, schema: { type: integer } }
|
||
responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/Project' } } } } } }
|
||
|
||
/api/pm/external/v2/projects/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get: { tags: [external], summary: Проект (внешний), operationId: externalRetrieveProject, responses: { '200': { description: Проект, content: { application/json: { schema: { $ref: '#/components/schemas/Project' } } } }, '404': { $ref: '#/components/responses/NotFound' } } }
|
||
|
||
/api/pm/external/v2/projects/{id}/project_data/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get: { tags: [external], summary: Данные проекта (внешний), operationId: externalProjectData, responses: { '200': { description: Данные, content: { application/json: { schema: { type: object } } } } } }
|
||
|
||
/api/pm/external/v2/tasks/:
|
||
get:
|
||
tags: [external]
|
||
summary: Список задач (внешний)
|
||
operationId: externalListTasks
|
||
parameters:
|
||
- { name: extend, in: query, schema: { type: boolean } }
|
||
- { name: ids, in: query, schema: { type: string } }
|
||
- $ref: '#/components/parameters/Limit'
|
||
- $ref: '#/components/parameters/Offset'
|
||
responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/ProjectTask' } } } } } }
|
||
|
||
/api/pm/external/v2/tasks/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get: { tags: [external], summary: Задача (внешний), operationId: externalRetrieveTask, responses: { '200': { description: Задача, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectTask' } } } } } }
|
||
|
||
/api/pm/external/v2/values/:
|
||
get: { tags: [external], summary: Фактические значения (внешний), operationId: externalListValues, responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/ActualValue' } } } } } } }
|
||
|
||
/api/pm/external/v2/values/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get: { tags: [external], summary: Значение (внешний), operationId: externalRetrieveValue, responses: { '200': { description: Значение, content: { application/json: { schema: { $ref: '#/components/schemas/ActualValue' } } } } } }
|
||
|
||
/api/pm/external/v2/project-states/:
|
||
get:
|
||
tags: [external]
|
||
summary: Состояния проекта (внешний)
|
||
operationId: externalListStates
|
||
parameters: [ { name: project_id, in: query, schema: { type: integer } } ]
|
||
responses: { '200': { description: Список, content: { application/json: { schema: { type: array, items: { $ref: '#/components/schemas/ProjectState' } } } } } }
|
||
|
||
/api/pm/external/v2/project-states/{id}/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get: { tags: [external], summary: Состояние (внешний), operationId: externalRetrieveState, responses: { '200': { description: Состояние, content: { application/json: { schema: { $ref: '#/components/schemas/ProjectState' } } } } } }
|
||
|
||
/api/pm/external/v2/project-states/{id}/data/:
|
||
parameters: [ { $ref: '#/components/parameters/PathId' } ]
|
||
get: { tags: [external], summary: Данные состояния (внешний), operationId: externalStateData, responses: { '200': { description: Данные, content: { application/json: { schema: { type: object } } } } } }
|
||
|
||
# ==========================================================================
|
||
# Internal API (no auth, cluster-only)
|
||
# ==========================================================================
|
||
/internal/pm/auto_scheduling/:
|
||
post:
|
||
tags: [internal]
|
||
summary: Интегрированное автопланирование
|
||
operationId: internalAutoScheduling
|
||
security: []
|
||
requestBody: { required: true, content: { application/json: { schema: { type: object, properties: { project_id: { type: integer } }, required: [project_id] } } } }
|
||
responses: { '200': { description: OK } }
|
||
|
||
/internal/pm/integrated_base_plan/:
|
||
post:
|
||
tags: [internal]
|
||
summary: Создать/обновить интегрированные состояния
|
||
operationId: internalIntegratedBasePlan
|
||
security: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
project_id: { type: integer }
|
||
user_id: { type: integer }
|
||
linked_project: { type: integer }
|
||
name: { type: string }
|
||
tasks: { type: array, items: { type: object } }
|
||
task_ids: { type: array, items: { type: integer } }
|
||
state_id: { type: integer }
|
||
responses: { '200': { description: OK } }
|
||
|
||
/internal/pm/detailed_tasks/:
|
||
post:
|
||
tags: [internal]
|
||
summary: Обновить значения атрибутов задачи
|
||
operationId: internalDetailedTasks
|
||
security: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
task_id: { type: integer }
|
||
result_fields: { type: object }
|
||
company_id: { type: integer }
|
||
required: [task_id, company_id]
|
||
responses: { '200': { description: OK } }
|
||
|
||
/internal/pm/sync_tasks/:
|
||
post:
|
||
tags: [internal]
|
||
summary: Синхронизация задач + автопланирование
|
||
operationId: internalSyncTasks
|
||
security: []
|
||
requestBody: { required: true, content: { application/json: { schema: { type: object, properties: { project_id: { type: integer } }, required: [project_id] } } } }
|
||
responses: { '200': { description: OK } }
|
||
|
||
/internal/pm/base_plans/:
|
||
get:
|
||
tags: [internal]
|
||
summary: Получить базовый план
|
||
operationId: internalGetBasePlan
|
||
security: []
|
||
parameters: [ { name: base_plan_id, in: query, required: true, schema: { type: integer } } ]
|
||
responses:
|
||
'200': { description: Данные, content: { application/json: { schema: { type: object } } } }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
/internal/pm/tasks_dates/:
|
||
get:
|
||
tags: [internal]
|
||
summary: Даты и прогресс задач проекта
|
||
operationId: internalTasksDates
|
||
security: []
|
||
parameters: [ { name: project_id, in: query, required: true, schema: { type: integer } } ]
|
||
responses:
|
||
'200': { description: Данные, content: { application/json: { schema: { type: object } } } }
|
||
'400': { $ref: '#/components/responses/BadRequest' }
|
||
|
||
components:
|
||
securitySchemes:
|
||
bearerAuth:
|
||
type: http
|
||
scheme: bearer
|
||
bearerFormat: JWT
|
||
description: |
|
||
JWT в заголовке `Authorization: Bearer <token>`. В режиме sarex-backend
|
||
подпись проверяется публичным ключом (`RS512`); в режиме Zitadel
|
||
дополнительно требуется заголовок `identity`.
|
||
identityToken:
|
||
type: apiKey
|
||
in: header
|
||
name: identity
|
||
description: |
|
||
Заголовок `identity` (`Identity <jwt>`) для режима Zitadel. При его
|
||
наличии полезная нагрузка берётся из этого токена.
|
||
|
||
parameters:
|
||
PathId:
|
||
name: id
|
||
in: path
|
||
required: true
|
||
schema: { type: integer }
|
||
Limit:
|
||
name: limit
|
||
in: query
|
||
required: false
|
||
schema: { type: integer, minimum: 0, default: 1000 }
|
||
Offset:
|
||
name: offset
|
||
in: query
|
||
required: false
|
||
schema: { type: integer, minimum: 0, default: 0 }
|
||
|
||
responses:
|
||
BadRequest:
|
||
description: Некорректный запрос / ошибка валидации
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/ValidationError' }
|
||
Unauthorized:
|
||
description: Токен не предоставлен или невалиден
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Detail' }
|
||
Forbidden:
|
||
description: Недостаточно прав
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Detail' }
|
||
NotFound:
|
||
description: Ресурс не найден
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/Detail' }
|
||
|
||
schemas:
|
||
# --- Общие ------------------------------------------------------------
|
||
Detail:
|
||
type: object
|
||
properties:
|
||
detail: { type: string }
|
||
required: [detail]
|
||
|
||
ValidationError:
|
||
type: object
|
||
description: |
|
||
Ошибка валидации DRF — либо словарь `{ "<field>": ["<msg>", ...] }`,
|
||
либо `{ "detail": "..." }`.
|
||
additionalProperties:
|
||
type: array
|
||
items: { type: string }
|
||
|
||
PaginatedResponse:
|
||
type: object
|
||
description: Обёртка DRF LimitOffsetPagination
|
||
properties:
|
||
count: { type: integer }
|
||
next: { type: string, format: uri, nullable: true }
|
||
previous: { type: string, format: uri, nullable: true }
|
||
results: { type: array, items: { type: object } }
|
||
required: [count, results]
|
||
|
||
# --- Проекты ----------------------------------------------------------
|
||
Project:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
name: { type: string }
|
||
company: { type: integer }
|
||
parent: { type: integer, nullable: true }
|
||
is_folder: { type: boolean }
|
||
resource_id: { type: string, nullable: true }
|
||
document_id: { type: string, nullable: true }
|
||
bundle_id: { type: string, nullable: true }
|
||
description: { type: string, nullable: true }
|
||
settings: { type: object }
|
||
target_date: { type: string, format: date-time, nullable: true }
|
||
project_type: { type: string, nullable: true }
|
||
calendar: { type: integer, nullable: true }
|
||
status: { type: string, readOnly: true }
|
||
creator: { type: integer, readOnly: true }
|
||
permissions: { type: object, readOnly: true }
|
||
restrictions: { type: object, readOnly: true }
|
||
time_start: { type: string, format: date-time, readOnly: true, nullable: true }
|
||
time_end: { type: string, format: date-time, readOnly: true, nullable: true }
|
||
total_cost: { type: number, readOnly: true, nullable: true }
|
||
current_cost: { type: number, readOnly: true, nullable: true }
|
||
progress: { type: number, readOnly: true, nullable: true }
|
||
relations: { type: array, items: { type: object }, readOnly: true }
|
||
rule: { type: object, nullable: true }
|
||
created_at: { type: string, format: date-time, readOnly: true }
|
||
updated_at: { type: string, format: date-time, readOnly: true }
|
||
required: [name, company]
|
||
|
||
ProjectCreate:
|
||
type: object
|
||
properties:
|
||
name: { type: string }
|
||
company_id: { type: integer }
|
||
parent: { type: integer, nullable: true }
|
||
is_folder: { type: boolean }
|
||
resource_id: { type: string, nullable: true }
|
||
ms_file: { type: string, nullable: true }
|
||
description: { type: string, nullable: true }
|
||
document_id: { type: string, nullable: true }
|
||
bundle_id: { type: string, nullable: true }
|
||
settings: { type: object, default: {} }
|
||
target_date: { type: string, format: date-time, nullable: true }
|
||
project_type: { type: string, nullable: true }
|
||
calendar: { type: integer, nullable: true }
|
||
required: [name, company_id]
|
||
|
||
FolderCreate:
|
||
type: object
|
||
properties:
|
||
company: { type: integer }
|
||
company_name: { type: string }
|
||
creator: { type: integer }
|
||
service_account: { type: string, format: uuid }
|
||
folder_name: { type: string, nullable: true }
|
||
required: [company, company_name, creator, service_account]
|
||
|
||
PermissionsResponse:
|
||
type: object
|
||
properties:
|
||
direct_permissions: { type: array, items: { type: object } }
|
||
inherited_permissions: { type: array, items: { type: object } }
|
||
|
||
# --- Задачи -----------------------------------------------------------
|
||
ProjectTask:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
project: { type: integer }
|
||
parent: { type: integer, nullable: true }
|
||
index_prefix: { type: string, nullable: true }
|
||
task_id: { type: string, nullable: true }
|
||
name: { type: string }
|
||
time_start: { type: string, format: date-time, nullable: true }
|
||
time_end: { type: string, format: date-time, nullable: true }
|
||
deadline: { type: string, format: date-time, nullable: true }
|
||
responsible: { type: array, items: { type: integer } }
|
||
executors: { type: array, items: { type: integer } }
|
||
task_type: { type: string }
|
||
unit: { type: string, nullable: true }
|
||
local_index: { type: integer, nullable: true }
|
||
constraint_date: { type: string, format: date-time, nullable: true }
|
||
constraint_type: { type: string, nullable: true }
|
||
cost: { type: number, nullable: true }
|
||
progress: { type: number, nullable: true }
|
||
status: { type: string, nullable: true }
|
||
duration: { type: number, nullable: true }
|
||
planned_duration: { type: number, nullable: true }
|
||
cipher: { type: string, nullable: true }
|
||
is_active: { type: boolean }
|
||
current_cost: { type: number, nullable: true }
|
||
planned_value: { type: number, nullable: true }
|
||
calendar: { type: integer, nullable: true }
|
||
distribution: { type: object, nullable: true }
|
||
actual_value: { type: number, readOnly: true, nullable: true }
|
||
total_cost: { type: number, readOnly: true, nullable: true }
|
||
attributes: { type: array, items: { type: object } }
|
||
permissions: { type: object }
|
||
|
||
ProjectTaskCreate:
|
||
type: object
|
||
properties:
|
||
project: { type: integer }
|
||
parent: { type: integer, nullable: true }
|
||
name: { type: string }
|
||
time_start: { type: string, format: date-time }
|
||
time_end: { type: string, format: date-time }
|
||
deadline: { type: string, format: date-time, nullable: true }
|
||
responsible: { type: array, items: { type: integer } }
|
||
executors: { type: array, items: { type: integer } }
|
||
task_type: { type: string, default: fix_value }
|
||
unit: { type: string, nullable: true }
|
||
cost: { type: number, nullable: true }
|
||
progress: { type: number, nullable: true }
|
||
status: { type: string, nullable: true }
|
||
is_active: { type: boolean, default: true }
|
||
calendar: { type: integer, nullable: true }
|
||
required: [project, name, time_start, time_end]
|
||
|
||
ProjectTaskUpdate:
|
||
type: object
|
||
description: Плоский сериализатор для массового обновления
|
||
properties:
|
||
id: { type: integer }
|
||
name: { type: string }
|
||
time_start: { type: string, format: date-time }
|
||
time_end: { type: string, format: date-time }
|
||
responsible: { type: array, items: { type: integer } }
|
||
executors: { type: array, items: { type: integer } }
|
||
cost: { type: number }
|
||
progress: { type: number }
|
||
status: { type: string }
|
||
required: [id]
|
||
|
||
ActualValue:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
value: { type: number }
|
||
description: { type: string, nullable: true }
|
||
task: { type: integer }
|
||
time_start: { type: string, format: date-time }
|
||
time_end: { type: string, format: date-time }
|
||
creator: { type: integer, readOnly: true }
|
||
created_at: { type: string, format: date-time, readOnly: true }
|
||
updated_at: { type: string, format: date-time, readOnly: true }
|
||
|
||
ActualValueCreate:
|
||
type: object
|
||
properties:
|
||
value: { type: number }
|
||
description: { type: string, nullable: true }
|
||
task: { type: integer }
|
||
time_start: { type: string, format: date-time }
|
||
time_end: { type: string, format: date-time }
|
||
required: [value, task, time_start, time_end]
|
||
|
||
DetailedTask:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
task: { type: integer }
|
||
weight: { type: number, nullable: true }
|
||
data: { type: object }
|
||
|
||
Description:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
task: { type: integer }
|
||
text: { type: string }
|
||
required: [task, text]
|
||
|
||
# --- Состояния --------------------------------------------------------
|
||
ProjectState:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
name: { type: string }
|
||
project: { type: integer }
|
||
creator: { type: integer, readOnly: true }
|
||
is_locked: { type: boolean, readOnly: true }
|
||
|
||
ProjectStateCreate:
|
||
type: object
|
||
properties:
|
||
name: { type: string }
|
||
project: { type: integer }
|
||
required: [name, project]
|
||
|
||
# --- Ресурсы ----------------------------------------------------------
|
||
Resource:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
name: { type: string }
|
||
company: { type: integer }
|
||
calendar: { type: integer, nullable: true }
|
||
project: { type: integer, nullable: true }
|
||
resource_type: { type: string }
|
||
parent: { type: integer, nullable: true }
|
||
cost: { type: number, nullable: true }
|
||
path: { type: string, readOnly: true }
|
||
is_leaf: { type: boolean, readOnly: true }
|
||
elements: { type: array, items: { type: integer } }
|
||
projects: { type: array, items: { type: object } }
|
||
|
||
ResourceCreate:
|
||
type: object
|
||
properties:
|
||
name: { type: string }
|
||
company: { type: integer }
|
||
calendar: { type: integer, nullable: true }
|
||
project: { type: integer, nullable: true }
|
||
resource_type: { type: string }
|
||
parent: { type: integer, nullable: true }
|
||
cost: { type: number, nullable: true }
|
||
required: [name, company]
|
||
|
||
ResourceTaskRelation:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
resource: { type: integer }
|
||
task: { type: integer }
|
||
profile: { type: integer, nullable: true }
|
||
|
||
ResourceElementRelation:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
resource: { type: integer }
|
||
instance: { type: string }
|
||
model_name: { type: string }
|
||
attributes: { type: object }
|
||
path: { type: string, nullable: true }
|
||
|
||
# --- Связи ------------------------------------------------------------
|
||
Task2TaskRelation:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
target: { type: integer }
|
||
source: { type: integer }
|
||
type: { type: string }
|
||
lag: { type: number, nullable: true }
|
||
|
||
Project2ProjectRelation:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
successor: { type: integer }
|
||
predecessor: { type: integer }
|
||
mode: { type: string, nullable: true }
|
||
|
||
EntityRelation:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
project: { type: integer }
|
||
entity_name: { type: string }
|
||
attribute_ids: { type: array, items: { type: integer } }
|
||
settings: { type: object }
|
||
entity_type: { type: string }
|
||
|
||
# --- Атрибуты ---------------------------------------------------------
|
||
ProjectAttributeRelation:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
project: { type: integer }
|
||
asset_id: { type: string, nullable: true }
|
||
attribute_id: { type: integer }
|
||
is_system: { type: boolean }
|
||
default_value: { nullable: true }
|
||
mode: { type: string, nullable: true }
|
||
|
||
TaskAttributeValue:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
task: { type: integer }
|
||
attribute_id: { type: integer }
|
||
type: { type: string, description: "Тип значения (вход): integer/float/string/datetime/date" }
|
||
values: { description: Значение(я) атрибута }
|
||
integer_value: { type: integer, nullable: true }
|
||
float_value: { type: number, nullable: true }
|
||
string_value: { type: string, nullable: true }
|
||
datetime_value: { type: string, format: date-time, nullable: true }
|
||
date_value: { type: string, format: date, nullable: true }
|
||
assets: { type: array, items: { type: string } }
|
||
|
||
# --- Календари --------------------------------------------------------
|
||
Calendar:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
name: { type: string }
|
||
company: { type: integer }
|
||
mask: { type: array, items: { type: integer } }
|
||
work_time_start: { type: string }
|
||
work_time_end: { type: string }
|
||
work_day_duration: { type: number, readOnly: true }
|
||
is_system: { type: boolean }
|
||
holidays: { type: array, items: { type: string, format: date } }
|
||
exception_holidays: { type: array, items: { type: string, format: date } }
|
||
creator: { type: integer, readOnly: true }
|
||
projects_count: { type: integer, readOnly: true }
|
||
created_at: { type: string, format: date-time, readOnly: true }
|
||
updated_at: { type: string, format: date-time, readOnly: true }
|
||
required: [name, mask, work_time_start, work_time_end]
|
||
|
||
# --- Настройки --------------------------------------------------------
|
||
ProjectSettings:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
name: { type: string }
|
||
project: { type: integer, nullable: true }
|
||
state: { type: integer, nullable: true }
|
||
image: { type: string, nullable: true }
|
||
is_default: { type: boolean }
|
||
visibility: { type: string, enum: [global, private, public] }
|
||
company_id: { type: integer, nullable: true }
|
||
service_accounts: { type: array, items: { type: string } }
|
||
creator: { type: integer, readOnly: true }
|
||
created_at: { type: string, format: date-time, readOnly: true }
|
||
updated_at: { type: string, format: date-time, readOnly: true }
|
||
|
||
VisualProfile:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
name: { type: string }
|
||
color: { type: string, description: "HEX-цвет, напр. #RRGGBB" }
|
||
project: { type: integer }
|
||
behavior: { type: object }
|
||
|
||
Comment:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
text: { type: string }
|
||
task: { type: integer }
|
||
creator: { type: integer, readOnly: true }
|
||
created_at: { type: string, format: date-time, readOnly: true }
|
||
updated_at: { type: string, format: date-time, readOnly: true }
|
||
|
||
CommentCreate:
|
||
type: object
|
||
properties:
|
||
text: { type: string }
|
||
task: { type: integer }
|
||
required: [text, task]
|
||
|
||
# --- Системный журнал -------------------------------------------------
|
||
SystemLog:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
project_id: { type: integer }
|
||
user_id: { type: integer, nullable: true }
|
||
created_at: { type: string, format: date-time, readOnly: true }
|
||
message_data: { type: object }
|
||
action: { type: string }
|
||
entity: { type: string }
|
||
changes: { type: object, description: "Только в detail-варианте" }
|
||
|
||
# --- Экспорт ----------------------------------------------------------
|
||
ExportProject:
|
||
type: object
|
||
properties:
|
||
export_fields: { type: array, items: { type: string } }
|
||
export_attrs: { type: array, items: { type: integer } }
|
||
fields_order: { type: array, items: { type: string } }
|
||
data: { type: array, items: { type: object } }
|
||
page_format: { type: string }
|
||
page_size: { type: string }
|
||
left_table_percent_width: { type: number, minimum: 0, maximum: 100 }
|
||
base_plan_ids: { type: array, items: { type: integer } }
|
||
margins: { type: array, items: { type: number } }
|
||
expanded_tasks: { type: array, items: { type: integer } }
|
||
header_text: { type: string }
|
||
footer_text: { type: string }
|
||
display_relations: { type: boolean }
|
||
date_from: { type: string, format: date }
|
||
date_to: { type: string, format: date }
|
||
fields_width: { type: object }
|
||
project_name: { type: string }
|
||
show_counter: { type: boolean }
|
||
font_size: { type: integer }
|
||
conditional_formatting: { type: array, items: { type: object } }
|
||
required: [export_fields, data]
|