17 KiB
Этапы разработки
Общий принцип
Не делаем сразу тяжелую доменную платформу.
Идем вертикальными поставками:
- сначала транспорт и создание задачи
- потом source-side представление
- потом синхронизация
- потом уведомления и полировка
Freeze point на 2026-04-19
Текущий вертикальный срез временно заморожен.
На момент freeze point уже есть:
- отправка запроса из source project в target project того же
workspace - отсутствие требования прямого membership в target project для отправки
- source-side список
Открытые / Завершенные - source-side карточка на shell
Предложений - source-side редактирование открытого запроса по
заголовкуиописанию - зеркалирование статуса, комментариев, вложений и activity из целевого контура
- source-side действия
Принять,Отклонить,Ответ во внешний контур - индикатор непрочитанных изменений
- карточка
Маршрутизацияв целевом формате3 x 3
Дальше по roadmap пока не идем, пока не приняты продуктовые решения по внутреннему жизненному циклу принятого запроса.
Этап 0. Термины и навигация
Цель
Подготовить интерфейс и словарь сущностей без ломки backend-логики.
Что входит
Рабочие элементы->Внутренний контур- новая вкладка
Внешние контуры - подготовка i18n-ключей и текстов
- фиксация терминов в продуктовой документации
Результат
В проекте уже есть новая структура навигации, но бизнес-логика еще не внедрена.
Этап 1. Маршрутизация запроса в целевой проект
Цель
Сделать рабочий сценарий отправки задачи из source project в target project.
Что входит
- новая create-form во
Внешних контурах - выбор целевого проекта
- выбор исполнителя из целевого проекта
- orchestration endpoint
- использование intake bridge как backend-моста
- немедленный перевод в default-state целевого проекта
- создание target issue
- запись source/target metadata
Что не входит
- полноценная синхронизация файлов
- полноценная зеркальная история
- сложные уведомления
Критерий приемки
- пользователь отправляет внешний запрос
- в целевом проекте появляется обычная задача
- задача не зависает в triage
- source-side список уже видит факт отправки
Статус
Реализовано.
Что работает фактически:
POST /external-contours/создает target issue в целевом проекте- target issue сразу попадает в обычный workflow целевого проекта
- source-side
GET /external-contours/возвращает отправленные запросы с metadata источника и цели - target contour теперь выбирается по policy
same workspace + intake enabled, а не только из joined projects - прямое membership в target project для отправки не требуется
Этап 2. Source-side список и статусная пришлепка
Цель
Дать инициатору читаемый контроль за отправленными запросами.
Что входит
- список
Открытые - список
Завершенные - текущий статус задачи как пришлепка
- отображение целевого проекта
- отображение исполнителя
- отображение даты обновления
- индикатор новых изменений
Критерий приемки
- в проекте-источнике виден список отправленных запросов
- у каждой записи отображается актуальный статус целевой задачи
Статус
Реализовано частично в рамках текущего вертикального среза.
Что уже работает:
- source-side список
Открытые / Завершенные - status pill по фактическому state целевой задачи
- отображение целевого проекта
- отображение исполнителей целевого контура
- отображение фактической даты последнего изменения
- индикатор новых изменений в source-side списке на базе unread уведомлений
- открытие source-side detail экрана
Что еще остается на следующие этапы:
- полноценная зеркальная activity/history
- уведомления
Дополнительно реализовано:
- source-side detail показывает блок маршрутизации
- в карточке видны источник, цель, отправитель, дата отправки и связанная целевая задача
Этап 3. Source-side детальный экран и зеркалирование изменений
Цель
Сделать так, чтобы отправитель видел ход исполнения не только по одной плашке статуса.
Что входит
- детальный экран внешнего контура
- блок
Исходный запрос - блок
Текущий статус - mirrored activity stream
- mirrored comments
- mirrored files
- mirrored description updates
Важное правило
Исходный запрос не должен теряться.
Поэтому target-изменения лучше показывать отдельным блоком истории, а не просто затирать исходное описание.
Критерий приемки
- если в target issue добавили файл, инициатор видит его в source-side карточке
- если в target issue поменяли статус, это видно в source-side карточке
- если в target issue написали комментарий, это видно в source-side карточке
Статус
Реализовано частично.
Что уже работает:
- source-side detail использует отдельный экран
Внешних контуров - в карточке отображается блок маршрутизации с ключевой source-target связью
- у отправителя открытый внешний запрос редактируется прямо из source-side карточки по полям
заголовокиописание, даже без membership в target project - текущий статус берется из фактического state целевой задачи
- если у инициатора нет membership в target project, карточка переключается в source-side readonly режим без прямого открытия чужого проекта
- блок
Маршрутизацияперестроен в фиксированный формат3 x 3 - в
МаршрутизациюперенесеныНазначенныйиСрок выполнения - в блоке
Свойстваубраны дублиВнешний контур,НазначенныйиСрок выполнения - название исходного внутреннего контура в карточке маршрутизации берется из живого проекта, а не из застывшего metadata snapshot
- для закрытого внешнего запроса доступны source-side действия
ПринятьиОтклонить Принятьфиксирует решение источника в bridge metadata и помечает запрос как принятый во внутренний контурОтклонитьтребует комментарий причины, возвращает target issue в default-state целевого проекта и переносит source-side карточку обратно в списокОткрытые- source-side readonly карточка зеркалит актуальные комментарии, вложения и activity целевой задачи
- вложения доступны через proxy download endpoint без прямого membership в target project
- detail карточка source-only пользователя обновляется polling-ом и подтягивает новые комментарии без ручной перезагрузки
- инициатор может отправить комментарий обратно во внешний контур прямо из source-side карточки
Что остается:
- зеркалирование inline-файлов из комментариев и описания, а не только issue attachments
- realtime вместо polling
- отдельная сущность или шаг для переноса принятого результата во
Внутренний контур
Этап 4. Уведомления
Цель
Не заставлять инициатора вручную проверять изменения.
Что входит
- in-app notification на:
- принятие
- перевод статуса
- добавление файла
- новый комментарий
- завершение
- отмену
Критерий приемки
- инициатор получает уведомления по ключевым событиям жизненного цикла внешнего запроса
Статус
Реализовано частично.
Что уже работает:
- создаются in-app уведомления по изменениям целевой задачи внешнего контура
- покрыты события:
- смена статуса
- новый комментарий
- изменение описания
- новое вложение
- уведомление привязано к source project, а не требует membership в target project
- notification payload несет
external contour request idиtarget issue id - список уведомлений помечает такие записи как
is_external_contour = true - notification preview может открыть source-side карточку внешнего контура, а не обычный issue preview
- открытие source-side карточки помечает связанные unread уведомления как прочитанные и снимает индикатор новых изменений в списке
Что остается:
- in-app уведомления на явные source-side решения
Принять / Отклонить - отдельный индикатор новых изменений в списке
Открытые / Завершенные - push/realtime канал вместо обычного цикла обновления UI
Этап 5. Полировка и правила эксплуатации
Что входит
- edge cases
- повторная отправка
- отмена
- защита от удаления target issue
- аудит прав
- тест-кейсы
- регламент эксплуатации
Технические решения, которые желательно держать с самого начала
1. Не ломать штатный intake
Он остается отдельным продуктовым модулем.
2. Явно хранить source/target связь
Даже если первая версия идет через IntakeIssue.extra, связь не должна быть неявной.
3. Использовать фактический статус target issue
В source-side плашке лучше показывать не abstract intake status, а реальный текущий статус исполнения.
4. Не пытаться делать полную двустороннюю редакцию сразу
На старте безопаснее сделать:
- создание из источника
- исполнение в цели
- синхронизацию результата обратно в источник
Открытые вопросы
1. Что именно делает Принять
Нужно зафиксировать конечную бизнес-логику:
Принятьтолько ставит source-side решениеacceptedПринятьсоздает отдельную сущность воВнутреннем контуреПринятьпереводит карточку в отдельный внутренний статус без создания дубликата
Это главный блокирующий вопрос перед следующим этапом.
2. Где дальше живет принятый запрос
Нужно решить:
- карточка остается во
Внешних контурахкак историческая запись - карточка уходит во
Внутренний контур - карточка одновременно видна в обоих местах, но с разной ролью
3. Нужна ли отдельная сущность source-side
Нужно принять решение:
- достаточно ли текущей source-side проекции поверх bridge metadata
- или уже пора вводить отдельную таблицу/модель для внешних контуров
4. Файлы
Нужно решить:
- достаточно ли proxy-доступа к файлам целевой задачи
- или файлы надо физически копировать в source-side representation
- нужно ли зеркалировать inline-файлы из описания и комментариев
5. Комментарии
Нужно решить:
- source-side reply остается облегченной обратной связью
- или нужен полноценный двусторонний поток комментариев как единый discussion-thread
6. Уровень realtime
Нужно решить:
- хватает ли polling для PoC
- или следующий этап уже должен включать push/realtime события
7. Счетчики и вкладки
Нужно решить:
- нужен ли отдельный unread-counter по вкладкам
Открытые / Завершенные - нужен ли отдельный сегмент для запросов, принятых во
Внутренний контур
8. Право редактирования после отправки
Нужно решить:
- отправитель редактирует только
заголовокиописание - или после отправки он может менять еще
срок,назначенного,приоритет,метки
9. Доступ к target issue
Нужно решить:
- должен ли инициатор иметь прямую ссылку на target issue
- или source-side карточка должна оставаться единственной точкой просмотра для пользователей без membership
Текущее решение:
- при отсутствии membership в target project прямой переход в target issue скрывается
- карточка остается доступной из source project
Рекомендуемый порядок фактической разработки
- Этап 0
- Этап 1
- Этап 2
- Этап 3
- Этап 4
- Этап 5
Это даст быстрый полезный результат и не загонит проект в ранний тяжелый refactor.