diff --git a/docs_prod/cross-project-task-routing/README.md b/docs_prod/cross-project-task-routing/README.md
index 447a085..29e8829 100644
--- a/docs_prod/cross-project-task-routing/README.md
+++ b/docs_prod/cross-project-task-routing/README.md
@@ -81,12 +81,56 @@
- source-side список отправленных запросов
- source-side детальный экран на базе shell `Предложений`
- status pill по фактическому состоянию target issue
-- чтение и редактирование title/description/priority/due date/assignees/labels через target issue API
+- 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`
-Текущее ограничение MVP:
-- выбор `Внешнего контура` сейчас доступен только среди проектов, в которых отправитель уже состоит
-- это осознанное упрощение первого рабочего вертикального среза
-- за счет этого source-side карточка может безопасно использовать обычные target issue API без отдельного proxy-слоя для комментариев и файлов
+## 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 карточка не стала второй несогласованной системой учета
## Обязательные требования
diff --git a/docs_prod/cross-project-task-routing/phase-roadmap.md b/docs_prod/cross-project-task-routing/phase-roadmap.md
index fc8db4d..cbe5275 100644
--- a/docs_prod/cross-project-task-routing/phase-roadmap.md
+++ b/docs_prod/cross-project-task-routing/phase-roadmap.md
@@ -10,6 +10,23 @@
3. потом синхронизация
4. потом уведомления и полировка
+## 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. Термины и навигация
### Цель
@@ -242,35 +259,64 @@
## Открытые вопросы
-### 1. Source-side сущность
+### 1. Что именно делает `Принять`
+
+Нужно зафиксировать конечную бизнес-логику:
+- `Принять` только ставит source-side решение `accepted`
+- `Принять` создает отдельную сущность во `Внутреннем контуре`
+- `Принять` переводит карточку в отдельный внутренний статус без создания дубликата
+
+Это главный блокирующий вопрос перед следующим этапом.
+
+### 2. Где дальше живет принятый запрос
+
+Нужно решить:
+- карточка остается во `Внешних контурах` как историческая запись
+- карточка уходит во `Внутренний контур`
+- карточка одновременно видна в обоих местах, но с разной ролью
+
+### 3. Нужна ли отдельная сущность source-side
Нужно принять решение:
-- достаточно ли source-side проекции
-- или нужна отдельная таблица/модель для внешних контуров
+- достаточно ли текущей source-side проекции поверх bridge metadata
+- или уже пора вводить отдельную таблицу/модель для внешних контуров
-### 2. Файлы
+### 4. Файлы
Нужно решить:
-- показываем ли мы source-side ссылку на target asset
-- или физически копируем файл в source representation
+- достаточно ли proxy-доступа к файлам целевой задачи
+- или файлы надо физически копировать в source-side representation
+- нужно ли зеркалировать inline-файлы из описания и комментариев
-### 3. Комментарии
+### 5. Комментарии
Нужно решить:
-- комментарии зеркалируются односторонне из цели в источник
-- или источник тоже может отвечать прямо из source-side карточки
+- source-side reply остается облегченной обратной связью
+- или нужен полноценный двусторонний поток комментариев как единый discussion-thread
-### 4. Уровень realtime
+### 6. Уровень realtime
Нужно решить:
-- хватит ли near-realtime через polling и existing refresh
-- или сразу нужен realtime через live-события
+- хватает ли polling для PoC
+- или следующий этап уже должен включать push/realtime события
-### 5. Доступ к target issue
+### 7. Счетчики и вкладки
+
+Нужно решить:
+- нужен ли отдельный unread-counter по вкладкам `Открытые / Завершенные`
+- нужен ли отдельный сегмент для запросов, принятых во `Внутренний контур`
+
+### 8. Право редактирования после отправки
+
+Нужно решить:
+- отправитель редактирует только `заголовок` и `описание`
+- или после отправки он может менять еще `срок`, `назначенного`, `приоритет`, `метки`
+
+### 9. Доступ к target issue
Нужно решить:
- должен ли инициатор иметь прямую ссылку на target issue
-- или доступ к target issue должен быть скрыт, а source-side карточка должна быть единственной точкой просмотра
+- или source-side карточка должна оставаться единственной точкой просмотра для пользователей без membership
Текущее решение:
- при отсутствии membership в target project прямой переход в target issue скрывается
diff --git a/plane-src/apps/web/app/(all)/[workspaceSlug]/(projects)/sidebar.tsx b/plane-src/apps/web/app/(all)/[workspaceSlug]/(projects)/sidebar.tsx
index 5279362..15dc5ce 100644
--- a/plane-src/apps/web/app/(all)/[workspaceSlug]/(projects)/sidebar.tsx
+++ b/plane-src/apps/web/app/(all)/[workspaceSlug]/(projects)/sidebar.tsx
@@ -8,13 +8,14 @@ import { isEmpty } from "lodash-es";
import { observer } from "mobx-react";
// plane helpers
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
-import { useTranslation } from "@plane/i18n";
// components
import { SidebarWrapper } from "@/components/sidebar/sidebar-wrapper";
import { SidebarFavoritesMenu } from "@/components/workspace/sidebar/favorites/favorites-menu";
import { SidebarProjectsList } from "@/components/workspace/sidebar/projects-list";
import { SidebarQuickActions } from "@/components/workspace/sidebar/quick-actions";
import { SidebarMenuItems } from "@/components/workspace/sidebar/sidebar-menu-items";
+import { SidebarUtilityRail } from "@/components/workspace/sidebar/sidebar-utility-rail";
+import { WorkspaceMenuRoot } from "@/components/workspace/sidebar/workspace-menu-root";
// hooks
import { useFavorite } from "@/hooks/store/use-favorite";
import { useUserPermissions } from "@/hooks/store/user";
@@ -22,7 +23,6 @@ import { useUserPermissions } from "@/hooks/store/user";
import { SidebarTeamsList } from "@/plane-web/components/workspace/sidebar/teams-sidebar-list";
export const AppSidebar = observer(function AppSidebar() {
- const { t } = useTranslation();
// store hooks
const { allowPermissions } = useUserPermissions();
const { groupedFavorites } = useFavorite();
@@ -36,7 +36,11 @@ export const AppSidebar = observer(function AppSidebar() {
const isFavoriteEmpty = isEmpty(groupedFavorites);
return (
- }>
+ }
+ quickActions={}
+ footer={}
+ >
{/* Favorites Menu */}
{canPerformWorkspaceMemberActions && !isFavoriteEmpty && }
diff --git a/plane-src/apps/web/ce/components/navigations/top-navigation-root.tsx b/plane-src/apps/web/ce/components/navigations/top-navigation-root.tsx
index 5a81d58..2322cb7 100644
--- a/plane-src/apps/web/ce/components/navigations/top-navigation-root.tsx
+++ b/plane-src/apps/web/ce/components/navigations/top-navigation-root.tsx
@@ -12,6 +12,7 @@ import { TopNavPowerK } from "@/components/navigation";
import { UserMenuRoot } from "@/components/workspace/sidebar/user-menu-root";
import { WorkspaceMenuRoot } from "@/components/workspace/sidebar/workspace-menu-root";
import { useAppRailPreferences } from "@/hooks/use-navigation-preferences";
+import { usePlatformOS } from "@/hooks/use-platform-os";
import { Tooltip } from "@plane/propel/tooltip";
import { AppSidebarItem } from "@/components/sidebar/sidebar-item";
import { InboxIcon } from "@plane/propel/icons";
@@ -26,6 +27,7 @@ export const TopNavigationRoot = observer(function TopNavigationRoot() {
// store hooks
const { unreadNotificationsCount, getUnreadNotificationsCount } = useWorkspaceNotifications();
const { preferences } = useAppRailPreferences();
+ const { isMobile } = usePlatformOS();
const showLabel = preferences.displayMode === "icon_with_label";
@@ -41,6 +43,8 @@ export const TopNavigationRoot = observer(function TopNavigationRoot() {
? unreadNotificationsCount.mention_unread_notifications_count
: unreadNotificationsCount.total_unread_notifications_count;
+ if (!isMobile) return null;
+
return (