diff --git a/docs/guides/frontend/04-PATTERNS.md b/docs/guides/frontend/04-PATTERNS.md
index 79cc27e9..178add9c 100644
--- a/docs/guides/frontend/04-PATTERNS.md
+++ b/docs/guides/frontend/04-PATTERNS.md
@@ -74,6 +74,19 @@
- `frontend/src/components/requests/RequestUserBadge.tsx`
+### Object detail screens
+
+Если один detail-route обслуживает и обычный просмотр, и управление объектом:
+
+- базовый режим должен быть `showcase-first`, а не выглядеть как обрубленная админка
+- management controls встраиваются в ту же anatomy, а не создают второй отдельный layout
+- главный акцент у сильного header и одного основного рабочего блока
+- secondary-настройки должны быть заметно спокойнее главного контента
+
+Референс по духу:
+
+- `frontend/src/app/departments/[id]/page.tsx`
+
### Compose forms
Compose-паттерн должен восприниматься как рабочее пространство, а не как список независимых инпутов.
diff --git a/docs/guides/frontend/06-COMPONENT-INVENTORY.md b/docs/guides/frontend/06-COMPONENT-INVENTORY.md
index b3922e9c..580f5b79 100644
--- a/docs/guides/frontend/06-COMPONENT-INVENTORY.md
+++ b/docs/guides/frontend/06-COMPONENT-INVENTORY.md
@@ -231,10 +231,11 @@
Использовать как референс для:
-- detail screen, который должен быть полноценным management workspace, а не бедной карточкой-описанием
+- detail screen, который должен уметь переключаться между `showcase` и `management` без смены route и без ощущения двух разных страниц
- page-level controller для domain actions вокруг одного объекта: overview, members, head management, roles
-- richer detail layout, где есть сильный header, один основной roster-блок и один secondary-блок настроек, без раздувания служебных summary-panels
+- richer detail layout, где есть сильный header, один основной roster-блок и один secondary-блок ролей, без раздувания служебных summary-panels
- member roster с role assignment и person-chip подачей вместо сырых строк участников
+- role management на уровне названий ролей и назначений участникам, без фронтового permission-editor
С оговоркой:
diff --git a/docs/guides/frontend/09-FRONTEND-AUDIT-MAP.md b/docs/guides/frontend/09-FRONTEND-AUDIT-MAP.md
index 1cd22501..076acf6e 100644
--- a/docs/guides/frontend/09-FRONTEND-AUDIT-MAP.md
+++ b/docs/guides/frontend/09-FRONTEND-AUDIT-MAP.md
@@ -34,7 +34,7 @@
| `users/directory` | `mixed` | `users/page.tsx` и `employees/page.tsx` уже живут в app-surface language, сценарии user/employee navigation выровнены и читаются как один cluster | список людей всё ещё проще и беднее по interaction density, чем основные рабочие модули, поэтому это не полноценный stylistic reference | считать baseline-pass завершённым и трогать дальше только при появлении richer directory requirements |
| `home/feed` | `mixed` | сильный app-shell fit, хорошая operational density, уже много app primitives | page очень большой, комментарии и post-compose logic перегружены, встречаются legacy `rounded-md` fragments | использовать как reference по feed density, но разрезать modal/comments/post flows и дочистить geometry |
| `notifications` | `mixed` | близок к operational app-style, фильтры и list hierarchy уже читаются системно | page-level logic пока монолитная, нет выделенного feature controller, есть место для уплотнения и симметрии с messages/requests | после people cluster сделать короткий structural pass без крупного редизайна |
-| `departments` | `mixed` | detail screen уже поднят до полноценного management workspace: сильный header, команда как основной блок, роли как secondary-блок, page-level controller вынесен в hook | список отделов всё ещё проще detail screen, а сам модуль ещё не проверен длинным visual-pass и живым backend-сценарием | считать `departments/[id]` baseline reference для object-management pages и затем при желании подтянуть list screen до той же richness |
+| `departments` | `mixed` | detail screen уже работает как dual-mode page: showcase-first для обычного просмотра и встроенный management-layer для управленцев, page-level controller вынесен в hook | список отделов всё ещё проще detail screen, а сам модуль ещё не проверен длинным visual-pass и живым backend-сценарием | считать `departments/[id]` baseline reference для object-detail pages с mixed audience и затем при желании подтянуть list screen до той же richness |
| `auth/legal` | `mixed` | изолированные flows уже отделены от app-shell, общая подача аккуратная | `rounded-[2rem]` и локальная hero-card геометрия образуют мини-систему отдельно от app shell | не смешивать с operational refactor; сделать отдельный compact pass по auth/legal geometry |
| `documents/dashboard` | `legacy-heavy` | есть готовые data blocks | заметны старые rounded patterns и мелкие utility-решения | включить в documents refactor pass |
@@ -177,8 +177,8 @@
Что делать:
- у `settings` после controller extraction резать section-level UI и только затем geometry
-- у `departments` поднять богатство patterns до общего уровня app
-- detail screen `departments/[id]` уже не считать пустой зоной; дальнейшие работы здесь должны быть про polishing, а не про изобретение management UI с нуля
+- у `departments` держать detail screen в логике `showcase + management layer`, а не возвращать его в mini-admin panel
+- detail screen `departments/[id]` уже не считать пустой зоной; дальнейшие работы здесь должны быть про polishing, а не про возврат permission-editor и служебных панелей
- у `auth/legal` выровнять isolated geometry отдельно от app-shell жанра
### Волна 7. Calendar special audit
diff --git a/frontend/src/app/departments/[id]/page.tsx b/frontend/src/app/departments/[id]/page.tsx
index 8eeb658e..788f2c54 100644
--- a/frontend/src/app/departments/[id]/page.tsx
+++ b/frontend/src/app/departments/[id]/page.tsx
@@ -15,31 +15,30 @@ import {
Users,
} from "lucide-react";
+import { AppShell } from "@/components/AppShell";
import { DepartmentPersonChip } from "@/components/departments/DepartmentPersonChip";
import { SearchableSelectSingle } from "@/components/shared/SearchableSelect";
-import { AppShell } from "@/components/AppShell";
import { Modal } from "@/components/ui/Modal";
import { useDepartmentPage } from "@/hooks/useDepartmentPage";
-import type {
- DepartmentMemberLink,
- DepartmentPermissionChoice,
- DepartmentRole,
-} from "@/types/api";
+import type { DepartmentMemberLink, DepartmentRole } from "@/types/api";
-function PermissionBadge({
- active,
+function MetaChip({
children,
+ tone = "neutral",
}: {
- active: boolean;
children: ReactNode;
+ tone?: "neutral" | "accent" | "warning";
}) {
+ const className =
+ tone === "accent"
+ ? "app-selected app-accent-text"
+ : tone === "warning"
+ ? "app-feedback-warning"
+ : "app-badge";
+
return (
{children}
@@ -72,98 +71,104 @@ function DepartmentMemberRow({
onSetHead: (employeeId: number) => Promise;
}) {
const isHead = currentHeadId === member.employee.id;
- const isBusy = pendingKey === `member-remove-${member.employee.id}`;
+ const isRemoving = pendingKey === `member-remove-${member.employee.id}`;
const isRoleBusy = pendingKey === `member-role-${member.employee.id}`;
- const subtitle = member.employee.position?.name || member.employee.email || null;
- const roleItems = roleOptions.map((role) => ({ id: role.id, name: role.name }));
+ const subtitle =
+ member.employee.position?.name || member.employee.email || null;
+ const managementMode = canAssignRoles || canChangeHead || canManage;
return (
+ {isManagementMode
+ ? "Ты видишь рабочий экран отдела и можешь управлять составом и ролями."
+ : "Здесь можно посмотреть состав отдела и его внутренние роли без лишнего admin-шумa."}
+
+
+
-
-
-
-
-
Команда отдела
+
+
+
+
Команда отдела
+
+ {isManagementMode
+ ? "Основной рабочий блок: состав команды, роли участников и быстрые действия."
+ : "Состав отдела, роли участников и текущая структура команды."}
+
+
+ {h.userPerms.can_manage ? (
+
+ ) : null}
+
+
+
+
+
+ h.setMembersQuery(event.target.value)}
+ placeholder="Поиск по участникам, почте, должности или роли"
+ className="app-input w-full rounded-lg py-2.5 pl-9 pr-3 text-sm"
+ />
+
- Основной рабочий блок отдела: состав команды, роли участников и быстрые действия.
+ Измени поисковый запрос или включи показ неактивных связей.
- {h.userPerms.can_manage ? (
-
- ) : null}
-
+ )}
+
+
-
-
-
- h.setMembersQuery(event.target.value)}
- placeholder="Поиск по участникам, почте, должности или роли"
- className="app-input w-full rounded-lg py-2.5 pl-9 pr-3 text-sm"
- />
-
-
+
+
+
+
Роли отдела
+
+ {isManagementMode
+ ? "Именованные роли внутри отдела: их можно создавать, переименовывать и назначать участникам."
+ : "Справочный список ролей, которые используются внутри отдела."}
+
- Наборы прав для участников. Это secondary-настройка состава, а не основной центр страницы.
+ {isManagementMode
+ ? "Создай первую роль, если внутри отдела нужно разделить обязанности."
+ : "В этом отделе пока не заведены отдельные внутренние роли."}