NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-r.../README.md

493 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Межпроектная маршрутизация задач
## Цель
Добавить в `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
- workspace-wide выбор целевого внешнего контура по policy:
- тот же `workspace`
- у целевого проекта включен модуль
- прямой membership в target project не требуется
- source-side карточка как основная точка работы отправителя, если у него нет доступа в целевой проект
- source-side редактирование открытого запроса:
- `заголовок`
- `описание`
- source-side действия:
- `Принять`
- `Отклонить`
- `Ответ во внешний контур`
- зеркалирование из целевой задачи в source-side карточку:
- комментарии
- вложения
- activity
- обновления статуса
- proxy download для вложений без прямого membership в target project
- unread-индикатор новых изменений по source-side карточке
- блок `Маршрутизация` в фиксированном формате `3 x 3`
## Freeze point на 2026-04-19
Текущий этап временно заморожен.
Заморозка делается после достижения рабочего вертикального среза:
- запрос можно отправить из проекта-источника в другой проект того же `workspace`
- в целевом проекте создается обычная задача и сразу попадает в обычный workflow
- отправитель видит свой source-side список и карточку без обязательного доступа в чужой проект
- в source-side карточке видны статус, маршрут, назначенный, срок, комментарии, вложения и activity из целевого контура
- отправитель может поправить ошибку в `заголовке` и `описании`, пока запрос открыт
- отправитель может принять результат во внутренний контур или вернуть запрос обратно во внешний контур с комментарием причины
На этом месте разработка следующего шага останавливается до фиксации продуктовых решений.
## Зафиксированные продуктовые решения на 2026-04-20
После freeze point приняты дополнительные продуктовые решения по следующему циклу развития `Внешних контуров`.
### 1. Нужны две обязательные системные зоны
Во `Внешних контурах` должны появиться:
- `Исходящие`
- `Входящие`
`Исходящие` обязательны, потому что пользователь должен видеть запросы, которые он сам отправил в другие контуры, до и после обработки.
`Входящие` обязательны, потому что проект должен видеть запросы, пришедшие к нему из других контуров, в отдельном специализированном режиме работы, а не только как обычные задачи `Внутреннего контура`.
### 2. Обе зоны должны фильтроваться так же гибко, как во `Внутреннем контуре`
Минимальный целевой принцип:
- фильтрация по пользователям
- фильтрация по статусам
- фильтрация по назначенным
- фильтрация по автору
- фильтрация по контурам и связанным проектам
То есть `Внешние контуры` должны получить не просто статичный список, а управляемое рабочее представление.
### 3. Карточка деталей внешнего контура должна перейти на тот же UX-паттерн, что и во `Внутреннем контуре`
При клике по карточке должна открываться панель того же класса:
- закрыть просмотр
- открыть на весь экран
- переключить макет
- подписка или отписка
- копирование ссылки
- меню дополнительных действий
При этом:
- действие удаления в этом shell не является обязательным
- тело карточки остается внешнеконтурным, а не превращается в обычную карточку внутренней задачи
### 4. Внешний контур — это не workflow-kanban
Важно зафиксировать заранее:
- пользователь не должен перетаскивать задачи между блоками
- блоки во `Внешних контурах` — это представления и выборки, а не стадии исполнения
- нельзя переносить сюда механику drag-and-drop из `Внутреннего контура`
### 5. Пользовательские колонки нужны, но не входят в ближайший обязательный срез
Собственные пользовательские блоки и сортировки нужны как следующий этап развития, но не должны размыть ближайшие обязательные поставки:
1. единый shell карточки внешнего контура
2. двусторонняя доска `Исходящие / Входящие`
### 6. Архитектура должна остаться расширяемой
Следующий слой развития не ограничивается только внешними контурами.
Дальше в проекте могут появиться:
- новые типы досок
- агентные доски
- специализированные мониторинговые представления
- пользовательские рабочие поверхности под разные роли
Поэтому нельзя решать следующий этап только переобертками и точечными хаками.
Но и полный демонтаж текущего проекта ради абстрактной платформы тоже недопустим.
Рабочий принцип:
- не ломать текущий runtime
- не дублировать уже существующие механики без причины
- выносить только те контракты, которые реально переиспользуются дальше
## Что нужно решить перед продолжением
- Что именно делает действие `Принять`:
- только фиксирует решение источника
- создает отдельную сущность во `Внутреннем контуре`
- или переводит внешний запрос в отдельный внутренний режим без дублирования сущностей
- Должен ли принятый запрос оставаться во `Внешних контурах` как историческая карточка, или он должен исчезать из рабочего списка и жить только во `Внутреннем контуре`
- Нужен ли отдельный статус или отдельная вкладка для запросов, которые уже приняты во `Внутренний контур`
- Должна ли коммуникация по комментариям быть полностью двусторонней, или source-side ответов достаточно только для возврата и уточнений
- Нужно ли физически копировать файлы в source-side представление, или для PoC достаточно proxy-доступа к файлам целевой задачи
- Нужно ли переводить обновление карточки с polling на realtime/push уже в следующем этапе, или polling пока приемлем
- Нужны ли отдельные счетчики непрочитанных изменений по вкладкам `Открытые` и `Завершенные`
- Должен ли отправитель после создания запроса иметь право менять только `заголовок` и `описание`, или еще и `назначенного`, `срок`, `приоритет`, `метки`
- Нужно ли сохранять запрет на прямой переход в целевую задачу для пользователей без membership в target project как постоянное правило
- Какой финальный lifecycle должен быть у запроса после возврата, принятия, завершения и отмены, чтобы source-side карточка не стала второй несогласованной системой учета
## Обязательные требования
### 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/1_STEP_cross-project-task-routing/phase-roadmap.md)
- [11_STEP_external-contours-detail-shell.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/11_STEP_external-contours-detail-shell.md)
- [12_STEP_external-contours-bidirectional-board.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/12_STEP_external-contours-bidirectional-board.md)
- [13_STEP_external-contours-board-data-contract.md](/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/docs_prod/1_STEP_cross-project-task-routing/13_STEP_external-contours-board-data-contract.md)