Skip to content

feat: gap-22 + gap-23 — настройки пространства везде + superadmin badge#159

Merged
NovakPAai merged 3 commits into
mainfrom
claude/jack-gap-22-23-workspace-settings-superadmin-badge
May 10, 2026
Merged

feat: gap-22 + gap-23 — настройки пространства везде + superadmin badge#159
NovakPAai merged 3 commits into
mainfrom
claude/jack-gap-22-23-workspace-settings-superadmin-badge

Conversation

@NovakPAai
Copy link
Copy Markdown
Owner

Summary

  • gap-22 (feat/ux P2): «Настройки пространства» теперь всегда видна в аватар-меню

    • Переименовано «Настройки workspace» → «Настройки пространства»
    • При наличии активного воркспейса: прямой переход в /w/:slug/settings
    • При отсутствии (страница вне воркспейса): инлайн-пикер разворачивается прямо в меню
    • Дополнительный пункт «Другое пространство ›» для смены воркспейса не покидая текущий
  • gap-23 (fix P1): Бейдж «Суперадмин» теперь корректно отображается для SUPERADMIN_EMAIL

    • listUsers() в admin.service.ts не применял fallback SUPERADMIN_EMAIL (в отличие от getMe())
    • Одна строка: isSuperadmin: u.isSuperadmin || u.email === superadminEmail

Files changed

File Change
frontend/src/components/AppLayout.tsx UserMenu — убрана prop hasSettings, добавлены workspaces/current, инлайн-пикер
backend/src/modules/admin/admin.service.ts listUsers() — SUPERADMIN_EMAIL fallback
specs/gaps/gap-22-workspace-settings-always-accessible.md BDD+SDD спека (новая)
specs/gaps/gap-23-superadmin-email-badge.md BDD+SDD спека (новая)
specs/BACKLOG.md Добавлены строки gap-22/23

Test plan

  • Войти как [email protected] → в аватар-меню видна «Настройки пространства» на любой странице
  • Открыть страницу вне воркспейса (/profile, /admin/users) → кнопка с шевроном, клик разворачивает список воркспейсов
  • Открыть страницу внутри воркспейса (/w/:slug/board) → кнопка ведёт напрямую, есть «Другое пространство ›»
  • Нет воркспейсов → кнопка «Настройки пространства» скрыта
  • GET /api/admin/users[email protected] возвращает isSuperadmin: true (даже если в БД false)
  • Пользователь без SUPERADMIN_EMAIL и без DB-флага → isSuperadmin: false
  • tsc --noEmit проходит без ошибок

gap-22: кнопка «Настройки пространства» (бывш. «Настройки workspace»)
теперь отображается на всех страницах при наличии хотя бы одного
пространства. В воркспейсе — прямая навигация на /w/:slug/settings;
вне воркспейса — инлайн-пикер выбора пространства в меню аватара.
Добавлена опция «Другое пространство ›» внутри воркспейса.

gap-23: listUsers() в admin.service.ts теперь применяет тот же
SUPERADMIN_EMAIL override что и getMe() — isSuperadmin всегда true
для email = SUPERADMIN_EMAIL независимо от флага в БД.

Specs: specs/gaps/gap-22-*, specs/gaps/gap-23-*
- setUserSuperadmin: запрет снятия роли с SUPERADMIN_EMAIL и self-demotion (ИБ HIGH)
- auth.service: SSO-bypass проверяет computed isSuperadmin, а не raw DB (ИБ MEDIUM)
- AdminUsersPage: guard ждёт authLoading перед редиректом (ИБ LOW)
- AppLayout/UserMenu: сброс pickerOpen при смене current (UX bug)
- specs gap-22/23: статус draft → done, PR #159
- UserMenu: role=menu/menuitem, aria-expanded, aria-haspopup (ARIA/клавиатура HIGH)
- AppLayout: Escape закрывает UserMenu и WorkspaceSelector
- Пикер пространств: max-height+overflow-y, шеврон вместо текстового toggle
- admin.service: isSuperadminLocked в listUsers() — UI видит, что кнопку снять нельзя
- AdminUsersPage: кнопка «Снять» скрыта для isSuperadminLocked, показан 🔒 tooltip
- AdminUser type: добавлен isSuperadminLocked?: boolean
@NovakPAai
Copy link
Copy Markdown
Owner Author

Результаты ревью + исправления (коммиты b53bd2e, 34302dd)

ИБ-ревью — закрыто

# Сев Описание Статус
ИБ-2 HIGH setUserSuperadmin() не защищал SUPERADMIN_EMAIL от снятия роли; нет backend self-demotion guard ✅ исправлено
ИБ-5 MEDIUM SSO-bypass в auth.service.ts:120 читал raw DB isSuperadmin, а не computed ✅ исправлено
ИБ-7 LOW AdminUsersPage guard редиректил до завершения authLoading ✅ исправлено
ИБ-1 MEDIUM listUsers() возвращает computed isSuperadmin=true для SUPERADMIN_EMAIL — fingerprint принято (фича gap-23 требует)
ИБ-3 LOW slug не валидируется перед navigate() принято (слаги из trusted API)
ИБ-6 LOW SUPERADMIN_EMAIL имеет дефолт в config принято (dev-удобство, prod env переопределяет)

Код-ревью — закрыто

# Сев Описание Статус
КР-1 HIGH pickerOpen не сбрасывался при смене current ✅ исправлено (useEffect)
КР-2 HIGH UserMenu: нет role=menu/menuitem, aria-expanded, aria-haspopup, Escape ✅ исправлено
КР-3 HIGH isSuperadminLocked — оператор видел кнопку «Снять» на аккаунте, которого нельзя снять ✅ исправлено (поле в API + скрытие кнопки + 🔒 tooltip)
КР-4 MEDIUM menuBg дублируется через hardcoded hex сравнение принято (рефактор за скоупом)
КР-5 MEDIUM Props UserMenu — inline тип, не named interface принято (рефактор за скоупом)
КР-6 LOW navigator.platform deprecated принято (fallback уже есть)
КР-7 LOW Nav-табы — <div> вместо <button> принято (pre-existing, отдельный тикет)

UX/UI-ревью — закрыто

# Сев Описание Статус
U2 MEDIUM pickerOpen зависал при смене current ✅ (= КР-1)
U3 LOW Текстовый toggle «Скрыть список ↑» / «Другое пространство ›» → шеврон ✅ заменён на единый текст + шеврон
U6 LOW Нет max-height на пикере — переполнение при многих пространствах ✅ maxHeight:180 + overflowY:auto
U4 LOW Нет ARIA-ролей ✅ (= КР-2)

Спеки

gap-22 и gap-23: статус draftdone, PR #159 проставлен.

@NovakPAai NovakPAai merged commit f50f37d into main May 10, 2026
8 checks passed
@NovakPAai NovakPAai deleted the claude/jack-gap-22-23-workspace-settings-superadmin-badge branch May 10, 2026 18:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants