375 lines
16 KiB
Markdown
375 lines
16 KiB
Markdown
# Межпроектная маршрутизация задач
|
||
|
||
## Цель
|
||
|
||
Добавить в `NODE.DC TM` отдельный сценарий межпроектной постановки задач между контурами без перепрошивки штатного `Intake`.
|
||
|
||
Базовая идея:
|
||
- `Рабочие элементы` переименовываются в `Внутренний контур`
|
||
- рядом появляется новый модуль `Внешние контуры`
|
||
- пользователь из проекта-источника создает внешний запрос
|
||
- запрос уходит в целевой проект
|
||
- в целевом проекте он становится обычной задачей
|
||
- в проекте-источнике сохраняется видимый объект маршрутизации со статусом, историей и материалами
|
||
|
||
## Почему выбран именно этот путь
|
||
|
||
Не трогаем штатный `Intake` как пользовательский модуль.
|
||
|
||
Используем его только как внутренний backend-мост, потому что:
|
||
- механизм уже умеет создавать bridge между `Issue` и `IntakeIssue`
|
||
- уже есть переход из `TRIAGE` в default-state проекта
|
||
- уже есть `extra JSON` для метаданных маршрутизации
|
||
- это самый безопасный путь для форка и дальнейших обновлений
|
||
|
||
## Термины
|
||
|
||
### Внутренний контур
|
||
|
||
То, что сейчас в UI является обычными рабочими элементами проекта.
|
||
|
||
### Внешние контуры
|
||
|
||
Новый отдельный модуль проекта, через который задача отправляется в другой проект внутри того же workspace.
|
||
|
||
### Проект-источник
|
||
|
||
Проект, из которого инициируется запрос.
|
||
|
||
### Целевой проект
|
||
|
||
Проект, в котором задача реально исполняется.
|
||
|
||
### Исходная карточка внешнего контура
|
||
|
||
Карточка или запись в проекте-источнике, где инициатор видит:
|
||
- текущий статус
|
||
- целевой проект
|
||
- назначенного исполнителя
|
||
- историю обработки
|
||
- файлы
|
||
- уведомления о ходе работы
|
||
|
||
### Целевая задача
|
||
|
||
Обычная задача в целевом проекте, которая попадает в обычный workflow этого проекта.
|
||
|
||
## Ключевой продуктовый результат
|
||
|
||
Пользователь из `Менеджеры` должен иметь возможность:
|
||
- открыть `Внешние контуры`
|
||
- выбрать целевой проект, например `Бухгалтерия`
|
||
- описать запрос
|
||
- назначить исполнителя из `Бухгалтерия`
|
||
- отправить запрос
|
||
|
||
После этого:
|
||
- у `Бухгалтерия` появляется обычная задача в их проекте
|
||
- у отправителя в `Менеджеры` появляется запись во `Внешних контурах`
|
||
- у этой записи есть статусная пришлепка
|
||
- при любом изменении статуса в целевом проекте статус в источнике обновляется
|
||
- если в целевом проекте меняют описание, прикладывают файлы, комментируют или закрывают задачу, это отражается в источнике
|
||
- инициатор получает уведомления о существенных изменениях
|
||
|
||
## Текущий статус реализации
|
||
|
||
На текущем этапе уже реализовано:
|
||
- отдельный модуль `Внешние контуры`
|
||
- отдельный backend endpoint маршрутизации
|
||
- создание target issue в целевом проекте через intake bridge
|
||
- немедленный перевод target issue в обычный workflow целевого проекта
|
||
- source-side список отправленных запросов
|
||
- source-side детальный экран на базе shell `Предложений`
|
||
- status pill по фактическому состоянию target issue
|
||
- чтение и редактирование title/description/priority/due date/assignees/labels через target issue API
|
||
|
||
Текущее ограничение MVP:
|
||
- выбор `Внешнего контура` сейчас доступен только среди проектов, в которых отправитель уже состоит
|
||
- это осознанное упрощение первого рабочего вертикального среза
|
||
- за счет этого source-side карточка может безопасно использовать обычные target issue API без отдельного proxy-слоя для комментариев и файлов
|
||
|
||
## Обязательные требования
|
||
|
||
### 1. Отдельный модуль
|
||
|
||
`Внешние контуры` не должны быть переименованным `Intake`.
|
||
|
||
Это отдельная новая вкладка проекта.
|
||
|
||
### 2. Обычная задача в целевом проекте
|
||
|
||
Задача не должна висеть в ручном triage.
|
||
|
||
После отправки она должна сразу попадать в обычный workflow целевого проекта, в его default-state.
|
||
|
||
### 3. Статусная пришлепка в источнике
|
||
|
||
У каждой записи во `Внешних контурах` в списке должен быть видимый статус.
|
||
|
||
Для первой версии правильнее показывать фактическое имя текущего статуса целевой задачи:
|
||
- `В плане`
|
||
- `К выполнению`
|
||
- `В работе`
|
||
- `Готово`
|
||
- `Отменено`
|
||
- либо любой другой кастомный статус целевого проекта
|
||
|
||
То есть источник видит не абстрактное `accepted`, а реальный текущий статус исполнения.
|
||
|
||
### 4. Зеркалирование изменений из целевого проекта в источник
|
||
|
||
Изменения в целевой задаче должны отражаться в исходной карточке внешнего контура.
|
||
|
||
Минимальный обязательный набор:
|
||
- изменение статуса
|
||
- изменение названия
|
||
- изменение описания
|
||
- добавление/удаление файлов
|
||
- комментарии и служебные заметки по задаче
|
||
- закрытие/отмена задачи
|
||
|
||
### 5. Уведомления инициатору
|
||
|
||
Инициатор должен получать уведомления, когда:
|
||
- задача принята в работу
|
||
- задача переведена в другой статус
|
||
- добавлен файл
|
||
- добавлен комментарий
|
||
- задача завершена
|
||
- задача отменена
|
||
|
||
### 6. Трассировка между источником и целью
|
||
|
||
Связь между источником и целевой задачей должна быть явной и восстановимой.
|
||
|
||
Нельзя делать фичу как “создали задачу и забыли”.
|
||
|
||
## Архитектурный подход
|
||
|
||
## Общая схема
|
||
|
||
Используем существующий intake bridge как транспортный слой:
|
||
- создаем `Issue` в целевом проекте
|
||
- создаем `IntakeIssue`
|
||
- сразу переводим bridge в `ACCEPTED`
|
||
- целевая задача попадает в default-state проекта
|
||
|
||
Но только этого уже недостаточно.
|
||
|
||
Из-за требований на статусную пришлепку, зеркалирование файлов и уведомления нужен еще source-side слой отображения.
|
||
|
||
## Что остается от текущей идеи варианта 2
|
||
|
||
Сохраняем:
|
||
- reuse intake backend-механики
|
||
- отдельный orchestration endpoint
|
||
- отдельный фронтовый модуль `Внешние контуры`
|
||
|
||
Расширяем:
|
||
- добавляем источник правды для source-side карточки
|
||
- добавляем синхронизацию изменений из target issue в source representation
|
||
- добавляем уведомления
|
||
|
||
## Рекомендуемая модель данных для первой итерации
|
||
|
||
### Обязательная связь
|
||
|
||
Нужна явная пара:
|
||
- `source_project_id`
|
||
- `source_request_id`
|
||
- `target_project_id`
|
||
- `target_issue_id`
|
||
|
||
### Метаданные bridge
|
||
|
||
В `IntakeIssue.extra` храним:
|
||
- тип моста: `external-contours`
|
||
- источник
|
||
- цель
|
||
- автора
|
||
- временные метки
|
||
|
||
Пример:
|
||
|
||
```json
|
||
{
|
||
"bridge": "external-contours",
|
||
"source_project_id": "uuid",
|
||
"source_project_name": "Менеджеры",
|
||
"target_project_id": "uuid",
|
||
"target_project_name": "Бухгалтерия",
|
||
"requested_by_id": "uuid",
|
||
"requested_by_name": "Иван Петров",
|
||
"requested_at": "2026-04-18T19:00:00Z"
|
||
}
|
||
```
|
||
|
||
### Source-side представление
|
||
|
||
Для source-side части есть два пути:
|
||
|
||
1. Легкая проекция без отдельной таблицы
|
||
- список `Отправленные` собирается по `IntakeIssue.extra`
|
||
- детали берутся из целевой задачи
|
||
|
||
2. Отдельная source-side сущность или shadow-record
|
||
- отдельная запись для внешнего контура в проекте-источнике
|
||
- в ней хранится mirrored state
|
||
|
||
Для требований текущего этапа безопаснее считать, что source-side проекция понадобится.
|
||
|
||
Причина:
|
||
- нужен список со статусом
|
||
- нужны файлы в источнике
|
||
- нужна история изменений
|
||
- нужны уведомления
|
||
|
||
Простого “читать target issue на лету” для этого, скорее всего, будет мало.
|
||
|
||
## UX первой рабочей вертикали
|
||
|
||
## Модуль `Внешние контуры`
|
||
|
||
В проекте появляется новая вкладка:
|
||
- `Внешние контуры`
|
||
|
||
Внутри:
|
||
- кнопка `Новый внешний запрос`
|
||
- список `Открытые`
|
||
- список `Завершенные`
|
||
|
||
## Форма создания
|
||
|
||
Поля:
|
||
- целевой проект
|
||
- название
|
||
- описание
|
||
- исполнитель из целевого проекта
|
||
- приоритет
|
||
- срок
|
||
- метки
|
||
|
||
Вложения можно заложить сразу в спецификацию, но в первую техническую поставку лучше включать аккуратно.
|
||
|
||
## Карточка в списке
|
||
|
||
В строке списка должны быть:
|
||
- название
|
||
- целевой проект
|
||
- исполнитель
|
||
- дата создания
|
||
- статусная пришлепка
|
||
- индикатор новых изменений
|
||
|
||
## Детальный экран внешнего контура
|
||
|
||
Детальный экран источника не должен быть просто копией target issue.
|
||
|
||
Правильнее собрать его из блоков:
|
||
- исходный запрос
|
||
- текущий статус
|
||
- целевой проект и исполнитель
|
||
- история изменений
|
||
- синхронизированные файлы
|
||
- комментарии/обновления
|
||
|
||
Это безопаснее, чем пытаться перетирать исходное описание данными целевого проекта.
|
||
|
||
## Правила синхронизации
|
||
|
||
## Направления
|
||
|
||
### Источник -> цель
|
||
|
||
На этапе создания отправляем:
|
||
- название
|
||
- описание
|
||
- исполнителя
|
||
- приоритет
|
||
- срок
|
||
- метки
|
||
|
||
### Цель -> источник
|
||
|
||
После создания отражаем обратно:
|
||
- текущий статус
|
||
- изменения описания
|
||
- комментарии
|
||
- файлы
|
||
- итоговый результат
|
||
|
||
## Что должно быть синхронизировано в обязательном порядке
|
||
|
||
- `target issue state.name`
|
||
- `target issue updated_at`
|
||
- файлы target issue
|
||
- пользовательские комментарии
|
||
- итоговый resolution state
|
||
|
||
## Что пока не нужно считать обязательным
|
||
|
||
- полная двусторонняя редакция из источника после отправки
|
||
- редактирование чужих project labels через источник
|
||
- полный realtime-collab режим
|
||
|
||
## Уведомления
|
||
|
||
Минимальный набор событий:
|
||
- запрос создан
|
||
- задача принята
|
||
- статус изменен
|
||
- добавлен файл
|
||
- добавлен комментарий
|
||
- задача завершена
|
||
- задача отменена
|
||
|
||
Каналы первой версии:
|
||
- in-app notifications
|
||
|
||
Каналы последующих итераций:
|
||
- email
|
||
- внешние integrations
|
||
|
||
## Ограничения текущего этапа
|
||
|
||
### 1. Вложения сейчас хрупкие
|
||
|
||
Текущий runtime уже показывал хрупкость attachment flow.
|
||
|
||
Поэтому вложения нужно учитывать в дизайне, но внедрять аккуратно и тестировать отдельно.
|
||
|
||
### 2. Права сложнее, чем кажется
|
||
|
||
Отправитель должен иметь право отправлять запрос из source project, но не обязан быть участником target project.
|
||
|
||
При этом:
|
||
- target assignee должен быть участником target project
|
||
- target issue создается в target project
|
||
- источник должен иметь возможность видеть результат обработки без полного membership в target project
|
||
|
||
### 3. Простая “копия intake” уже недостаточна
|
||
|
||
Как только добавляются:
|
||
- статусная пришлепка
|
||
- файлы
|
||
- история
|
||
- уведомления
|
||
|
||
фича перестает быть просто формой создания.
|
||
|
||
Нужен отдельный источник правды для source-side представления.
|
||
|
||
## Что считаем текущим этапом
|
||
|
||
Текущий этап — это не финальная реализация, а проектирование и запуск вертикального среза.
|
||
|
||
В этот этап входят:
|
||
- фиксация терминологии
|
||
- фиксация архитектурного подхода
|
||
- разбиение на поставки
|
||
- определение обязательных требований для первой версии
|
||
- определение границ MVP
|
||
|
||
Подробная поэтапная разработка описана в:
|
||
- [phase-roadmap.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/cross-project-task-routing/phase-roadmap.md)
|