# Межпроектная маршрутизация задач ## Цель Добавить в `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)