dee7d51c19
На пути /request/items/{id} DELETE действительно заблокирован
(возвращает Unable access entity), но тот же Id можно убрать
через DELETE /issue/items/{id} — он универсален и работает как
для U-записей (созданных через /issue/items), так и для I-записей
(созданных через /request/items). Эмпирически подтверждено чисткой
33 зомби-записей I-6122..I-6176 в test-api-claude за один проход.
Поправлены разделы:
- devprom-alm-api.md §4 «Удаление» — таблица расширена комментарием
про универсальность /issue/items DELETE
- devprom-alm-api.md §6 «Что НЕ работает» — DELETE request/items
отмечен как «не препятствие»
- SKILL.md §«Критически важно» — корректное правило про DELETE
- meeting-wishes-extraction.md антипаттерн №7 — UI больше не нужен
280 lines
20 KiB
Markdown
280 lines
20 KiB
Markdown
# Devprom ALM REST API — рабочая шпаргалка
|
||
|
||
Справочник для загрузки Пожеланий, Заявок, Требований и вложений в Devprom ALM
|
||
через REST API. Имена сущностей сверены с официальной таблицей справочника
|
||
разработчика: `/pm/all/apidocs/list` (например,
|
||
[artsaterra.myalm.ru/pm/all/apidocs/list](https://artsaterra.myalm.ru/pm/all/apidocs/list)),
|
||
где каждая строка — одна сущность с её `ReferenceName` (используется в REST API)
|
||
и русским именем. Ключевые строки, участвующие в режиме Пожеланий из совещания:
|
||
|
||
| № | ReferenceName | Сущность |
|
||
|----|------------------|--------------------|
|
||
| 45 | `issue` | **Пожелание** |
|
||
| 18 | `request` | Доработка (заявка с типом) |
|
||
| 81 | `requesttype` | Тип пожелания |
|
||
| 92 | `requirement` | Требование |
|
||
| 57 | `attachment` | Приложение (файл) |
|
||
| 33 | `company` | Компания |
|
||
| 46 | `user` | Пользователь |
|
||
|
||
Дополнительные эмпирические детали (поведение, которое в публичной
|
||
документации не раскрыто явно) проверены на инстансе `artsaterra.myalm.ru`
|
||
и отмечаются в тексте курсивом _(проверено эмпирически)_.
|
||
|
||
Связанные ресурсы:
|
||
- Публичная документация Devprom: [docs.myalm.ru](https://docs.myalm.ru/)
|
||
- Раздел про управление пожеланиями: [artsaterra.myalm.ru/docs/8835.html](https://artsaterra.myalm.ru/docs/8835.html)
|
||
|
||
---
|
||
|
||
## 0. Базовое
|
||
|
||
- **Хост:** `https://<host>/pm/<project-slug>/api/latest`
|
||
- **Аутентификация:** заголовок `Devprom-Auth-Key: <hex>` (личный API-ключ пользователя)
|
||
- **Content-Type:** `application/json`
|
||
- **Ответ:** HTTP 200 всегда, ошибки валидации приходят в теле как `{"error":"…"}`
|
||
- **PATCH не поддерживается** — HTTP 405. Обновление только через PUT.
|
||
- **Успешный ответ на создание:** иногда возвращается как объект, иногда — как массив с одним элементом. Учитывать оба случая.
|
||
|
||
## 1. Пожелания vs Заявки — КРИТИЧНО
|
||
|
||
В официальной схеме Devprom это **две разные сущности** с разными
|
||
`ReferenceName` (см. таблицу выше):
|
||
|
||
- **`issue` (Пожелание)** — сущность из строки 45. Создаётся без типа,
|
||
UID с префиксом `U-`. В UI живёт в разделе «Пожелания»
|
||
(`/module/requirements/issues`).
|
||
- **`request` (Доработка)** — сущность из строки 18. Создаётся с обязательным
|
||
типом (Доработка / Ошибка), UID с префиксом `I-`. В UI живёт на доске
|
||
заявок (`/issues/board`).
|
||
|
||
| Логический класс | Эндпоинт | Префикс UID | Поле Type | UI-раздел |
|
||
|------------------------------|-------------------|-------------|-----------------|------------------------------------|
|
||
| **Пожелание** (`issue`) | `/issue/items` | `U-` | пусто | `/module/requirements/issues` |
|
||
| **Доработка** (`request`) | `/request/items` | `I-` | 397 (Доработка) / 398 (Ошибка) | `/issues/board` |
|
||
|
||
_Проверено эмпирически:_ GET на `/issue/items/{id}` и `/request/items/{id}`
|
||
возвращает **одну и ту же запись** (разные виды на один ресурс — внутренне
|
||
это один класс `pm_ChangeRequest`). Разница проявляется при POST — сервер
|
||
применяет разную логику автозаполнения в зависимости от эндпоинта.
|
||
|
||
### Почему попасть в «Доску пожеланий» можно только через `/issue/items`
|
||
|
||
_Проверено эмпирически:_ `/request/items` при POST **всегда принудительно
|
||
проставляет `Type=397`** (Доработка), даже если передать `Type: null`,
|
||
`Type: {}` или `Type: {"Id":""}`. Все варианты PUT тоже бессильны — сервер
|
||
восстанавливает 397. Подтверждено на 8 вариантах тела.
|
||
|
||
Поэтому для создания «чистого» Пожелания (с пустым Type и префиксом `U-`)
|
||
используется эндпоинт именно сущности `issue` — **POST на `/issue/items`**.
|
||
|
||
## 2. Алгоритм создания Пожелания (рабочий рецепт)
|
||
|
||
Один POST на одно Пожелание. Без PUT, без привязки к требованиям.
|
||
|
||
```python
|
||
post_body = {
|
||
"Caption": "<заголовок>",
|
||
"Content": "<html-описание>", # по документации; Description тоже принимается
|
||
"Priority": {"Id": "2"}, # 1=Критично, 2=Высокий, 3=Обычный
|
||
"Author": {"Id": "<issueauthor.id>"},
|
||
"Function": {"Id": "<feature.id>"}, # подсистема (группировка)
|
||
"Company": {"Id": "<company.id>"}, # опционально: клиент-источник
|
||
}
|
||
# POST {BASE}/issue/items → {UID: "U-xxxx", Id: "xxxx", ...}
|
||
```
|
||
|
||
Поля `Requirement` и `RequirementDocument` в теле **не передаются**:
|
||
привязка к документу требований — задача пользователя в UI, не API.
|
||
На этапе создания Пожелания она и не нужна — заказчик подтверждает
|
||
пожелания, формализует требования и уже потом вручную связывает одно
|
||
с другим.
|
||
|
||
> **Примечание для других сценариев.** Если всё-таки нужно привязать
|
||
> Пожелание к существующему требованию из API (например, массовая
|
||
> миграция из внешней системы), это делается вторым шагом через
|
||
> `PUT /issue/items/{id}` с тем же телом + `Requirement.Id`
|
||
> — в одном POST эти поля молча игнорируются. Для режима «Пожелания
|
||
> из совещания» этот путь не нужен.
|
||
|
||
### Retry-политика
|
||
|
||
Egress-прокси периодически роняет запросы с HTTP 502/503/504 («DNS cache overflow»). Всегда оборачивать вызов в цикл `retries=3` с `sleep(2..3)`. Это не связано с Devprom — лечится только ретраями.
|
||
|
||
## 3. Поля Пожелания — полный справочник
|
||
|
||
| Поле | Тип / формат | Обязательность | Комментарий |
|
||
|-----------------------|------------------------------|----------------|-------------|
|
||
| `Caption` | string | обязательно | Заголовок пожелания |
|
||
| `Content` | HTML-string | обязательно | Описание. Разрешены: `<p> <b> <ul> <ol> <li> <a> <blockquote> <code>`. Поле `Description` на входе тоже принимается как алиас. |
|
||
| `Priority.Id` | "1" / "2" / "3" | по смыслу | 1=Критично, 2=Высокий, 3=Обычный |
|
||
| `Author.Id` | issueauthor.id | обязательно | Автор пожелания. Справочник инстанс-уровня. |
|
||
| `Function.Id` | feature.id | рекомендовано | Группировка по подсистемам (создаются через `/feature/items`) |
|
||
| `Company.Id` | company.id | опционально | Клиент-источник пожелания. Принимается в POST напрямую. |
|
||
| `Requirement.Id` | requirement.id | **не передавать в режиме Пожелания из совещания** | Привязка к документу требований — задача пользователя в UI. Для других сценариев (миграция) — только через отдельный PUT после POST. |
|
||
| `RequirementDocument` | — | — | **Не передавать**, заполняется сервером автоматически по родителю `Requirement` |
|
||
| `Type.Id` | requesttype.id / пусто | **НЕ передавать для пожелания** | Любая попытка обнулить через API бесполезна; если передать — получится «Заявка» с префиксом I- |
|
||
|
||
## 4. Удаление
|
||
|
||
| Эндпоинт | DELETE работает? | Поведение |
|
||
|------------------------------|------------------|-----------|
|
||
| `DELETE /issue/items/{id}` | **ДА — универсальный** | HTTP 200, запись пропадает. Работает для ЛЮБОЙ записи — и для U- (созданных через `/issue/items`), и для I- (созданных через `/request/items`). Сущности `issue` и `request` указывают на один класс `pm_ChangeRequest` в БД, но DELETE разрешён только на пути `issue/items`. |
|
||
| `DELETE /request/items/{id}` | **НЕТ** | HTTP 200 с `{"error":"Unable access entity"}`, запись не удаляется. Сервер возвращает эту ошибку даже для записей, созданных через `/request/items`. |
|
||
| `DELETE /requirement/items/{id}` | _Не гарантировано_ | Возвращает HTTP 200 с `{"error":"Unable access entity"}`, но GET после этого иногда показывает запись пустой (UID='', Caption=''). Эффект — неявное удаление / повреждение записи. Использовать с осторожностью. |
|
||
|
||
**Практический вывод:** для удаления любой записи Request/Issue —
|
||
всегда `DELETE /issue/items/{id}`, независимо от того, как она была создана.
|
||
|
||
## 5. Справочные эндпоинты (read-only для нашего ключа)
|
||
|
||
| Эндпоинт | Назначение |
|
||
|-------------------------------|------------------------------------|
|
||
| `/requesttype/items` | Типы заявок: Доработка, Ошибка |
|
||
| `/priority/items` | Приоритеты |
|
||
| `/feature/items` | Подсистемы/функции (**имя "feature", не "function"!**) |
|
||
| `/issueauthor/items` | Авторы пожеланий (инстанс-справочник) |
|
||
| `/user/items` | Пользователи проекта |
|
||
| `/company/items` | Компании-клиенты |
|
||
| `/requirement/items` | Требования и документы требований |
|
||
| `/state/items` | Состояния |
|
||
|
||
## 6. Что НЕ работает через API (заблокировано политикой прав)
|
||
|
||
| Операция | Ответ API | Обход |
|
||
|---------------------------------------|------------------------------------|-------|
|
||
| POST `/issueauthor/items` | HTTP 200 + `{"error":"Lack of permissions to create object of IssueAuthor"}` | Только UI: `/pm/<project>/issueauthor` или inline-форма в карточке пожелания |
|
||
| POST `/user/items` | То же | Только UI |
|
||
| DELETE `/request/items/{id}` | `{"error":"Unable access entity"}` | **Не препятствие:** удалять через `DELETE /issue/items/{id}` — он работает для любой записи Request (см. раздел 4). |
|
||
|
||
Пытаться обойти через write-only ключ проекта, `api/v1`, `api/v2`, инстанс-путь без `/pm/<project>/` — **бесполезно**, все варианты дают тот же отказ.
|
||
|
||
## 7. Создание документа требований
|
||
|
||
> ⚠️ **В режиме «Пожелания из совещания» этот путь НЕ используется.**
|
||
> Структуру документов требований (`requirement`, строка 92 таблицы сущностей)
|
||
> выстраивает владелец проекта/аналитик вручную через UI Devprom —
|
||
> постепенно, по мере формализации требований, согласованных с заказчиком.
|
||
> Привязку Пожеланий (`issue`) к требованиям пользователь тоже делает
|
||
> вручную в UI. Режим извлечения пожеланий в эту структуру не вмешивается.
|
||
> Раздел оставлен для справки — на случай других задач (миграция требований,
|
||
> импорт из внешней системы и т.п.).
|
||
|
||
```python
|
||
POST /requirement/items
|
||
body = {
|
||
"Caption": "Корневой документ",
|
||
"Content": "<p>описание</p>",
|
||
# "ParentPage": {"Id": "..."} # если создаём подстраницу
|
||
}
|
||
```
|
||
|
||
Корневой документ — без `ParentPage`. Подстраница — с `ParentPage.Id = <id_корня>`. UID корневых документов присваивается по правилам шаблона проекта (например, `О-1`, `R-35`).
|
||
|
||
## 8. Attachment (приложить файл)
|
||
|
||
По [официальной документации](https://artsaterra.myalm.ru/docs/8835.html):
|
||
|
||
```python
|
||
POST /attachment/items
|
||
body = {
|
||
"FileExt": "transcript.txt",
|
||
"ObjectId": "<request.id>",
|
||
"ObjectClass": "Request", # именно Request — общий класс для issue и request
|
||
"File": "<base64 содержимого>",
|
||
}
|
||
```
|
||
|
||
## 9. Альтернативные и несуществующие эндпоинты
|
||
|
||
Тестировались, но возвращают `{"error":"Unknown entity: ..."}`:
|
||
|
||
- `/userwish/items`, `/wish/items`, `/userrequest/items`, `/suggestion/items`
|
||
- `/admin/request/items`, `/api/latest/admin/request/items`
|
||
- `/pmcustomclass/items`, `/customclass/items`, `/class/items`
|
||
|
||
Существующие служебные варианты:
|
||
|
||
- `/api/v1/request/items`, `/api/v2/request/items` — принимают POST,
|
||
но принудительная логика `Type=397` та же, что на `/api/latest/request/items`;
|
||
использовать не нужно.
|
||
|
||
> Примечание: эндпоинт `/issue/items` — не алиас `/request/items`,
|
||
> а отдельная сущность `issue` (Пожелание) из таблицы сущностей Devprom,
|
||
> строка 45. Под капотом они указывают на один и тот же класс
|
||
> `pm_ChangeRequest`, но серверная логика автозаполнения при POST
|
||
> у них разная (см. раздел 1).
|
||
|
||
## 10. Порядок подготовки проекта для загрузки пожеланий
|
||
|
||
Граница ответственности: **структуру проекта готовит человек через UI,
|
||
пожелания загружает скрипт через API**. Скрипт не создаёт Company,
|
||
Feature, документы требований, IssueAuthor — только читает их.
|
||
|
||
### Делается вручную через UI (один раз на проект, силами аналитика)
|
||
|
||
1. **Company** для каждого клиента, который генерирует пожелания.
|
||
- Пример: «АРД» с доменом `alreadycom.ru`.
|
||
2. **Feature** (подсистемы) — 3–5 на проект по подсистемам целевой
|
||
конфигурации. Можно создать и скриптом (`POST /feature/items`) —
|
||
на `feature` ограничений API нет, но обычно удобнее через UI.
|
||
- Пример для КА 2.5: «НСИ и администрирование», «Продажи», «Склад»,
|
||
«Казначейство», «Производство».
|
||
3. **IssueAuthor** для представителей заказчика — если нужно, чтобы
|
||
автором пожелания был сам клиент, а не аналитик. Только через UI.
|
||
4. **Документы требований** — структуру требований клиент/аналитик
|
||
выстраивает постепенно, по мере работы над проектом. Режим
|
||
извлечения Пожеланий в неё не вмешивается.
|
||
|
||
### Делается скриптом через API (каждое новое совещание)
|
||
|
||
5. **Цикл по Пожеланиям** — для каждого: один POST `/issue/items`
|
||
с полями Caption, Content, Priority, Author, Function и опционально
|
||
Company. `Requirement` не передаётся.
|
||
6. **GET** `/issue/items/{id}` — верификация, что UID начинается
|
||
на `U-`.
|
||
7. **Привязка Пожеланий к требованиям** — **вне скрипта**,
|
||
это ручная работа пользователя в UI, когда требования появятся
|
||
и согласованы с заказчиком.
|
||
|
||
---
|
||
|
||
## Appendix — примеры curl
|
||
|
||
### Создание пожелания (как в документации, с Type=Доработка)
|
||
```bash
|
||
curl -X POST \
|
||
-H "Devprom-Auth-Key: <KEY>" -H "Content-Type: application/json" \
|
||
https://<host>/pm/<proj>/api/latest/request/items \
|
||
-d '{"Caption":"Новая доработка","Content":"<p>Описание</p>","Type":{"Id":"397"}}'
|
||
# → UID=I-xxxx, Type=Доработка
|
||
```
|
||
|
||
### Создание пожелания без типа (рекомендуемый путь)
|
||
```bash
|
||
curl -X POST \
|
||
-H "Devprom-Auth-Key: <KEY>" -H "Content-Type: application/json" \
|
||
https://<host>/pm/<proj>/api/latest/issue/items \
|
||
-d '{"Caption":"Пожелание","Content":"<p>Описание</p>","Priority":{"Id":"2"},"Author":{"Id":"1"},"Function":{"Id":"190"},"Company":{"Id":"146"}}'
|
||
# → UID=U-xxxx, Type=пусто
|
||
```
|
||
|
||
### Привязка к документу требований (не нужна в режиме «Пожелания из совещания»)
|
||
|
||
Используется только для миграционных сценариев:
|
||
|
||
```bash
|
||
curl -X PUT \
|
||
-H "Devprom-Auth-Key: <KEY>" -H "Content-Type: application/json" \
|
||
https://<host>/pm/<proj>/api/latest/issue/items/6179 \
|
||
-d '{"Caption":"Пожелание","Content":"<p>Описание</p>","Priority":{"Id":"2"},"Author":{"Id":"1"},"Function":{"Id":"190"},"Requirement":{"Id":"4378"}}'
|
||
```
|
||
|
||
### Удаление
|
||
```bash
|
||
curl -X DELETE \
|
||
-H "Devprom-Auth-Key: <KEY>" \
|
||
https://<host>/pm/<proj>/api/latest/issue/items/6179
|
||
# → HTTP 200, []
|
||
```
|