# Межпроектная маршрутизация задач

## Цель

Добавить в `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 из целевого контура
- отправитель может поправить ошибку в `заголовке` и `описании`, пока запрос открыт
- отправитель может принять результат во внутренний контур или вернуть запрос обратно во внешний контур с комментарием причины

На этом месте разработка следующего шага останавливается до фиксации продуктовых решений.

## Что нужно решить перед продолжением

- Что именно делает действие `Принять`:
  - только фиксирует решение источника
  - создает отдельную сущность во `Внутреннем контуре`
  - или переводит внешний запрос в отдельный внутренний режим без дублирования сущностей
- Должен ли принятый запрос оставаться во `Внешних контурах` как историческая карточка, или он должен исчезать из рабочего списка и жить только во `Внутреннем контуре`
- Нужен ли отдельный статус или отдельная вкладка для запросов, которые уже приняты во `Внутренний контур`
- Должна ли коммуникация по комментариям быть полностью двусторонней, или 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/cross-project-task-routing/phase-roadmap.md)
