На пути /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 больше не нужен
225 lines
16 KiB
Markdown
225 lines
16 KiB
Markdown
# Извлечение Пожеланий из транскрипции совещания
|
||
|
||
Методика превращения транскрипции рабочего совещания с заказчиком
|
||
в набор формализованных Пожеланий в Devprom ALM. Проверена на совещании
|
||
с главбухом АРД (21.04.2026).
|
||
|
||
Связанные файлы:
|
||
- `references/devprom-alm-api.md` — как писать в Devprom через API
|
||
- Скилл `docx` — для возможного экспорта сводки в Word
|
||
|
||
---
|
||
|
||
## Критерии отбора: что становится Пожеланием, а что нет
|
||
|
||
### Становится Пожеланием
|
||
|
||
1. **Доработка конфигурации** — новый реквизит, новое правило, новая форма, интеграция.
|
||
_Пример: «Допреквизит „Доступно для менеджера" в справочнике номенклатуры»._
|
||
2. **Изменение бизнес-процесса с цифровым следом** — новая цепочка документов, автоматизация этапа, блокировка операции.
|
||
_Пример: «Запрет проведения отгрузки при отрицательном остатке»._
|
||
3. **Типовая настройка с конкретным целевым эффектом** — использование типового механизма там, где клиент раньше работал руками.
|
||
_Пример: «Использовать типовой механизм Номенклатура контрагентов»._
|
||
4. **Интеграция с внешней системой** — ЭДО, клиент-банк, маркетплейс, CRM, АТС.
|
||
_Пример: «Автоматическая отправка отгрузочных документов в Диадок»._
|
||
|
||
### НЕ становится Пожеланием
|
||
|
||
1. **Методика внутренней работы заказчика** — как они сейчас живут в Excel, как главбух разбирает почту.
|
||
2. **Нерешённые бизнес-вопросы** без автоматизационного следа — «надо решить, кто отвечает за ставку НДС», «КП оформляем в Word или в 1С».
|
||
3. **Оргмоменты и ответственность** — назначение ролей, регламент согласований без запроса автоматизации.
|
||
4. **Общие рассуждения и отступления** — истории про то, как раньше работали.
|
||
|
||
### Проверочный вопрос
|
||
|
||
_«Если бы это пожелание взял в работу разработчик конфигурации — что конкретно он бы сделал?»_ Если ответ неконкретный («поговорил с главбухом», «уточнил процесс», «подумал») — это **не пожелание**, а открытый вопрос в протокол совещания.
|
||
|
||
---
|
||
|
||
## Пайплайн
|
||
|
||
### Шаг 1 — Выделение тем и спикеров
|
||
|
||
Читаем транскрипцию целиком. Для каждой темы фиксируем:
|
||
|
||
- **Тему** (1 фраза)
|
||
- **Инициатора** (кто первым её подняла + таймкод)
|
||
- **Подтверждающих** (кто согласился, уточнил, добавил детали)
|
||
- **Открытые вопросы** (если обсуждение заблокировалось)
|
||
|
||
Нотация: `[Спикер тайм-код] → ключевая мысль`.
|
||
|
||
### Шаг 2 — Кластеризация
|
||
|
||
Одна тема может обсуждаться несколько раз в разных частях совещания — в начале, в середине (уточнение), в конце («а ещё мы забыли...»). Все упоминания одной темы объединяем в **одно** Пожелание. В `Источники` блока перечисляем все таймкоды всех спикеров.
|
||
|
||
### Шаг 3 — Отсев по критериям
|
||
|
||
Применяем проверочный вопрос из раздела «Критерии отбора». Оставшееся — кандидаты на Пожелания. То, что отсеяли, записываем отдельным списком в сопроводительную заметку («Для обсуждения на внутреннем совещании заказчика») — это протокол, а не Devprom.
|
||
|
||
### Шаг 4 — Классификация
|
||
|
||
Для каждого Пожелания-кандидата:
|
||
|
||
- **Caption** — одна ёмкая фраза, суть. 10–15 слов. Можно цитировать термин конфигурации («допреквизит», «заказ покупателя»).
|
||
- **Priority** — по акцентам речи:
|
||
- `1` (Критично) — заказчик повторил несколько раз, сказал «100%», «без этого работать нельзя», или речь про блокировку ошибок/убытков.
|
||
- `2` (Высокий) — инициатор явно настаивал, есть конкретная цель.
|
||
- `3` (Обычный) — обсудили, согласились, без нажима.
|
||
- **Function** — подсистема КА 2.5 / ERP 2.5. См. `references/ka25-capabilities.md`. Типично: НСИ, Продажи, Закупки, Склад, Казначейство, Производство, Бухгалтерия, Управленческий учёт.
|
||
- **Предметная область** — уточнение внутри подсистемы («Управление доступом менеджеров к НСИ», «Контроль остатков»).
|
||
|
||
### Шаг 5 — Формирование Description
|
||
|
||
Единый шаблон HTML для поля `Content` в Devprom:
|
||
|
||
```html
|
||
<p><b>Заказчик:</b> ФИО, должность (email)</p>
|
||
<p><b>Описание:</b></p>
|
||
<p>Полное описание пожелания в свободной форме — что должно делать,
|
||
какие условия, какие границы. 3–7 предложений.</p>
|
||
<p><b>Источники:</b></p>
|
||
<ul>
|
||
<li>ФИО спикер-1, должность — роль в обсуждении (тайм-коды)</li>
|
||
<li>ФИО спикер-2, роль — (тайм-коды)</li>
|
||
</ul>
|
||
<p><b>Цитаты:</b></p>
|
||
<blockquote>Спикер (тайм-код): «прямая цитата».</blockquote>
|
||
<blockquote>Спикер (тайм-код): «прямая цитата».</blockquote>
|
||
<p><b>Предметная область:</b> Подсистема / Конкретика</p>
|
||
<p><b>Примечание:</b> (опционально) — например, «функционал типовой,
|
||
требует настройки процесса, без разработки»</p>
|
||
<p><b>Источник:</b> Совещание от DD.MM.YYYY, файл
|
||
<code>transcript.txt</code></p>
|
||
```
|
||
|
||
Правила по содержимому:
|
||
|
||
- **Цитаты — обязательны**, 1–3 штуки на пожелание. Без цитат будущий разработчик не поймёт контекст.
|
||
- **Цитаты прямые** — без редактуры речи. Сохранять разговорный стиль, паузы, просторечия. Это контекст, а не литература.
|
||
- **Описание в повествовательной форме** — не «пользователь хочет, чтобы», а прямое «Система должна…», «В справочнике номенклатуры ввести…». Подлежащим делаем объект системы, не пользователя.
|
||
- **Никаких оценок объёма и сроков** — это предмет gap-анализа, не этапа извлечения пожеланий.
|
||
- **Никаких архитектурных решений** — если пожелание порождает архитектурные вопросы, они идут отдельным Пожеланием с типом «Архитектурное решение» или в протокол совещания.
|
||
|
||
### Шаг 6 — Загрузка через API
|
||
|
||
Один POST на одно Пожелание. Никакой привязки к требованиям,
|
||
никаких PUT. Поля `Requirement` и `RequirementDocument` остаются
|
||
пустыми — пользователь вручную прикрепит их в UI, если/когда
|
||
появится профильное требование.
|
||
|
||
```python
|
||
post_body = {
|
||
"Caption": wish["caption"],
|
||
"Content": CUSTOMER_NOTE + wish["description"] + SOURCE_NOTE,
|
||
"Priority": {"Id": wish["priority"]}, # "1"/"2"/"3"
|
||
"Author": {"Id": AUTHOR_ID},
|
||
"Function": {"Id": wish["function_id"]},
|
||
"Company": {"Id": COMPANY_ID}, # опционально
|
||
}
|
||
# POST /issue/items → {UID: "U-xxxx", ...}
|
||
```
|
||
|
||
Подробный справочник полей и поведение API — в
|
||
`references/devprom-alm-api.md`.
|
||
|
||
### Шаг 7 — Верификация
|
||
|
||
После загрузки:
|
||
|
||
- Открыть `/pm/<project>/module/requirements/issues` → все загруженные пожелания должны отображаться одним списком.
|
||
- UID у всех — префикс **`U-`**.
|
||
- У каждого заполнены `Priority`, `Function`, `Author`. Поля `Requirement`
|
||
и `RequirementDocument` пустые — это норма, привязку делает
|
||
пользователь вручную в UI.
|
||
- Открыть одну карточку случайно — проверить форматирование HTML, работу ссылок (mailto:), наличие цитат.
|
||
|
||
### Шаг 8 — Сводка для пользователя
|
||
|
||
После загрузки отдать:
|
||
|
||
- Таблица «№ / UID / Функция / Приоритет / Название / Ссылка»
|
||
- Список того, что намеренно **НЕ стало Пожеланиями** — короткие формулировки с причиной («методика», «открытый вопрос», «оргмомент»).
|
||
|
||
---
|
||
|
||
## Скрипт-шаблон (Python, без внешних зависимостей)
|
||
|
||
Шаблон есть в `templates/wishes-upload.py` (при наличии). Ключевые моменты:
|
||
|
||
```python
|
||
import json, urllib.request, urllib.error, ssl, time
|
||
|
||
HDR = {"Devprom-Auth-Key": "<KEY>",
|
||
"Content-Type": "application/json",
|
||
"Accept": "application/json"}
|
||
BASE = "https://<host>/pm/<project>/api/latest"
|
||
|
||
def call(method, path, body=None, retries=3):
|
||
"""urllib + ретраи по 502/503/504 от egress-прокси."""
|
||
data = json.dumps(body, ensure_ascii=False).encode("utf-8") if body else None
|
||
for attempt in range(1, retries+1):
|
||
req = urllib.request.Request(f"{BASE}/{path}", data=data,
|
||
headers=HDR, method=method)
|
||
try:
|
||
with urllib.request.urlopen(req, timeout=25,
|
||
context=ssl.create_default_context()) as r:
|
||
return r.status, r.read().decode("utf-8")
|
||
except urllib.error.HTTPError as e:
|
||
if e.code in (502, 503, 504) and attempt < retries:
|
||
time.sleep(3 * attempt); continue
|
||
return e.code, e.read().decode("utf-8")
|
||
|
||
for wish in WISHES:
|
||
post_body = {
|
||
"Caption": wish["caption"],
|
||
"Content": CUSTOMER_NOTE + wish["description"] + SOURCE_NOTE,
|
||
"Priority": {"Id": wish["priority"]},
|
||
"Author": {"Id": AUTHOR_ID},
|
||
"Function": {"Id": wish["function"]},
|
||
"Company": {"Id": COMPANY_ID}, # опционально
|
||
}
|
||
code, text = call("POST", "issue/items", post_body)
|
||
r = json.loads(text); r = r[0] if isinstance(r, list) else r
|
||
issue_id = r["Id"]
|
||
# проверка
|
||
_, t = call("GET", f"issue/items/{issue_id}")
|
||
g = json.loads(t)
|
||
assert g["UID"].startswith("U-"), f"префикс не U-: {g['UID']}"
|
||
```
|
||
|
||
---
|
||
|
||
## Анти-паттерны
|
||
|
||
1. **Создание через `/request/items`** — даст префикс I- и попадание в «Заявки».
|
||
_Использовать только `/issue/items`._
|
||
2. **Создание документов требований, Company, Feature или IssueAuthor
|
||
из этого режима** — `POST /requirement/items`, `POST /company/items`
|
||
и т.п. в режиме извлечения Пожеланий **не вызывать**. Эти справочники
|
||
готовит владелец проекта вручную через UI Devprom заранее. Если нужных
|
||
записей нет (например, нет подходящей Function) — остановиться,
|
||
запросить их создание, и только после этого продолжать загрузку.
|
||
3. **Привязка Пожелания к документу требований при создании** — поля
|
||
`Requirement` и `RequirementDocument` в теле POST не передавать.
|
||
Пользователь сам прикрепит пожелание к нужному требованию в UI,
|
||
когда это требование появится. Попытка «сразу правильно» привязать
|
||
ломает процесс согласования с заказчиком.
|
||
4. **Цитаты в пересказе** — обезличивают пожелание, делают его неотличимым от прочих. _Только прямые цитаты в blockquote._
|
||
5. **Смешение в одном Пожелании двух разных требований** — потом невозможно оценить объём и трассировать. _Один атомарный запрос — одно Пожелание._
|
||
6. **Создание IssueAuthor через API** — заблокировано на уровне прав. _Только через UI._
|
||
7. **Попытка удалить запись через `DELETE /request/items/{id}`** — сервер
|
||
отвечает 200 + `Unable access entity`. _Удалять через `DELETE /issue/items/{id}`
|
||
— он работает для любой записи, в том числе для I- (созданных через `/request/items`)._
|
||
|
||
---
|
||
|
||
## Memo для будущих расширений
|
||
|
||
Потенциальные улучшения, если появится потребность:
|
||
|
||
- **Автопривязка транскрипции** к пожеланию через `/attachment/items` (прикрепление `.txt` файла с полной транскрипцией к одному «главному» Пожеланию или к документу требований).
|
||
- **Экспорт сводки в Word** через скилл `docx` — для отправки клиенту или приобщения к протоколу.
|
||
- **Автоопределение Priority по акцентам** — через LLM-классификацию фраз типа «100%», «критично», «можем обсудить позже».
|
||
- **Автоопределение Function** — словарь ключевых слов → подсистема (см. `references/ka25-capabilities.md`).
|