План переработки системы прав доступа
Этап 1: Глубокое изучение (результаты сканирования)
1.1 Места проверки роли и прав
Фронт:

**App.tsx** — ROLE_NAMES, ROLE_ACCESS; расчёт allowedSections из me.allowedSections или fallback по `ROLE_ACCESS[currentUser.role]; `userPermissions из me.permissions; редирект при смене вкладки по allowedSections; передача allowedSections, userPermissions в дочерние компоненты и в PermissionsProvider.
**Navigation.tsx** — дубликат ROLE_ACCESS; видимость пунктов меню: allowedSections (из пропсов) или `ROLE_ACCESS[currentUserRole]`.
**constants/permissions.ts** — единственный источник разделов/подразделов и функций: canAccessSub, getPermissionLevel, allowedSubsForSection, permissionKey, parsePermissionLevel, PERMISSION_LEVEL_LABELS, SECTION_LABELS, SECTION_SUBS, ALL_SECTION_KEYS.
**contexts/PermissionsContext.tsx** — провайдер permissions; хук useSubPermission(section, subId) → canReadSub, canEditSub, isScopeOwn.
Модули с вкладками используют только allowedSubsForSection(allowedPermissions, section) для списка вкладок: AdminModule.tsx, ApplicationsModule.tsx, DevelopmentModule.tsx, FinanceModule.tsx, HRModule.tsx, LegalModule.tsx, OfficeModule.tsx, PRModule.tsx. FinanceModule.tsx дополнительно использует useSubPermission('finance', activeTab) для кнопок и фильтра «только своё».
DashboardNavigation.tsx — canAccessSub(allowedPermissions, 'objects') для доступа к блоку «Объекты».
Админка: UsersSection.tsx, PermissionsSection.tsx — работа с разделами/подразделами и уровнями через getPermissionLevel, permissionKey, SECTION_LABELS, SECTION_SUBS из constants/permissions.ts; дубликат ROLE_NAMES в обоих.
Бэкенд:

**backend/server.js** — константы ROLE_ACCESS, SECTION_IDS; allowedSectionsFromPermissions(permissions); в GET /api/auth/me и дублирующем эндпоинте: если permissions не пустой — allowedSections = allowedSectionsFromPermissions(row.permissions), иначе allowedSections из `ROLE_ACCESS[row.role]; возврат `scope, assignedDistrictIds (из employee_districts + fallback на e.assigned_district_id).
**backend/routes/buildings.js — при scope === 'own_district' фильтр домов по **только e.assigned_district_id (участок из employees), без учёта employee_districts — несоответствие с тем, что в /auth/me отдаются несколько assignedDistrictIds.
Счета на оплату: scope=own в query — фильтр по created_by = req.user.employeeId (свои счета). Workflow согласования использует таблицу user_roles (роли: manager, finance_manager, director и т.д.), не портальные роли.
Уведомления: backend/notificationService.js не использует роли портала; рассылка по конкретным user_id (portal_users.id).

1.2 Разделы и подразделы (permissions.ts) и использование в UI/API
Источник истины: constants/permissions.ts — SECTION_LABELS, SECTION_SUBS (все вкладки по разделам).
В UI вкладки фильтруются через allowedSubsForSection(allowedPermissions, section) во всех перечисленных модулях.
На бэкенде уровни по подразделам (read/edit/own) не проверяются в API: при выдаче данных используется только факт входа в раздел (через allowedSections или middleware по секции). Детальные уровни (read/edit/own) используются только на фронте (например, кнопки в FinanceModule по useSubPermission).
1.3 Обращения к БД
portal_users: server.js — выборки по id/employee_id для auth/me, обновление role/permissions/scope; админка (GET/POST/PUT portal-users); dbInit — колонки role, permissions, scope.
permission_templates: server.js — CRUD шаблонов (name, description, permissions, scope, for_position, suggested_role); dbInit — таблица и колонки scope, for_position, suggested_role.
employees.assigned_district_id: используется в GET auth/me (fallback для assignedDistrictIds), в buildings.js для фильтра домов при scope=own_district, при создании/обновлении сотрудника.
employee_districts: server.js — чтение для assignedDistrictIds в auth/me; обновление при PUT /api/employees/:id; при создании сотрудника; в отчёте укомплектованности. В buildings.js не используется — при own_district учитывается только assigned_district_id.
1.4 Роли портала vs user_roles (workflow)
Портал (portal_users.role): DIRECTOR, ENGINEER, MASTER, LAWYER, FINANCIER, HR_MANAGER, PR_MANAGER. Определяют доступ к разделам при пустом permissions и отображаются в админке.
Workflow (user_roles): manager, finance_manager, financier, finance_director, director, top_management. Таблица backend/migrations/create_user_roles.sql. Используются только в paymentInvoiceWorkflow.js и эндпоинтах назначения ролей для согласования счетов. Связь: user_roles.user_id — идентификатор пользователя портала (какой именно id — в коде используется из req.body/запроса). С ролями портала не связаны: можно быть DIRECTOR в портале и не иметь роли в user_roles, и наоборот.
1.5 Выявленные несоответствия
| Проблема | Где |

|----------|-----|

| Дублирование ROLE_ACCESS | App.tsx, Navigation.tsx, server.js |

| Дублирование ROLE_NAMES | App.tsx, UsersSection.tsx, PermissionsSection.tsx |

| Дублирование списка разделов | permissions.ts (ALL_SECTION_KEYS) vs server.js (SECTION_IDS) |

| scope=own_district для домов учитывает только assigned_district_id | backend/routes/buildings.js — не учитывает employee_districts (несколько участков у мастера) |

| Проверки только по роли без permissions | На бэкенде при выдаче данных по разделам явной проверки «доступен ли раздел по permissions» нет — опора на то, что фронт не вызовет лишнее; для домов проверяется только scope + один участок |

| Уровни по подразделам (read/edit/own) на бэкенде не проверяются | API не различает «только чтение» и «редактирование» по подразделу |

---

Этап 2: Отчёт №1 — Роли и ограничения (для согласования с заказчиком)
Сформировать документ (отдельный файл в репозитории или в docs), содержащий:

2.1 Список ролей портала (после переработки)
Рекомендуется сохранить текущие коды: DIRECTOR, ENGINEER, MASTER, LAWYER, FINANCIER, HR_MANAGER, PR_MANAGER.
Для каждой роли указать: код (как в БД), название для UI, краткое описание назначения (1–2 предложения). Взять за основу текущие ROLE_NAMES и типичные обязанности (Директор — полный доступ; Гл. инженер — производство, участки, заявки, офис, развитие; Мастер — участки и заявки; и т.д.).
2.2 Ограничения по каждой роли
Разделы по умолчанию: таблица или список (как в ROLE_ACCESS): какие разделы доступны без кастомных permissions.
Уровень по умолчанию: сейчас по роли на бэкенде не различают read/edit/own; при «по роли» на фронте в permissions.ts при пустом permissions возвращается «все подразделы» и уровень edit. Зафиксировать: по умолчанию для роли — «редактирование» по всем подразделам доступных разделов, либо явно ввести матрицу «роль × подраздел → уровень» в отчёте.
Ограничение по данным: «все участки» (scope=all) или «только свой участок» (scope=own_district). Указать по ролям: у кого по умолчанию all, у кого own_district (например, MASTER — own_district, остальные all).
Особые ограничения: например, «только свои заявки», «только свои счета» — если нужны, описать текстом по ролям/разделам.
2.3 Связь с БД
portal_users: роль в role (VARCHAR), ограничения по разделам/подразделам в permissions (JSONB); ограничение по участкам в scope (all | own_district). При пустом permissions — применять права по роли (из единого справочника).
employees: assigned_district_id (один участок, обратная совместимость); employee_districts — многие ко многим. Указать: при scope=own_district список доступных участков для фильтрации данных — из employee_districts, с fallback на assigned_district_id.
Новые поля/таблицы: при необходимости описать (например, таблица «роли по умолчанию» с полной матрицей раздел×подраздел×уровень, если решат хранить не только в коде).
2.4 user_roles (workflow) и роли портала
Кратко: user_roles используются только для цепочки согласования счетов; роли там (manager, finance_manager, director и т.д.) не определяют доступ к разделам портала. Связывать с portal_users.role не обязательно; при желании можно выводить в админке подсказку «роль в workflow» отдельно от «роль портала».
---

Этап 3: Отчёт №2 — Таблица доступов и план переписывания
После согласования отчёта №1 подготовить второй документ.

3.1 Большая таблица доступов
Строки: раздел + подраздел (например, «Участки → Обзор участков», «Участки → Дома», «Заявки → Реестр», …) — все пары из SECTION_SUBS в constants/permissions.ts.
Столбцы: каждая роль портала (DIRECTOR, ENGINEER, MASTER, …).
Ячейки: уровень доступа (нет / чтение / редактирование / только своё). Отдельная строка или блок: «Ограничение по участкам» — для каждой роли указать «все» или «только свой участок».
Заполнить таблицу на основе утверждённого отчёта №1 (роли и ограничения по умолчанию).

3.2 Шаблоны прав
Список рекомендуемых шаблонов (например, «Мастер участка», «Начальник PR»): для каждого — название, разделы/подразделы и уровни, рекомендуемая роль портала, scope. Описать, как шаблоны отображаются относительно большой таблицы (отдельные столбцы или справочник с ссылкой на строки таблицы).
3.3 План переписывания прав
Единый источник прав:

Один модуль констант (роли, разделы, подразделы, уровни, матрица «роль → разделы/уровни/scope»), используемый и на фронте, и на бэкенде. Варианты: общий пакет (например, shared/constants/permissions), либо генерация из одного JSON/файла в код фронта и бэкенда. Убрать дубли ROLE_ACCESS, ROLE_NAMES, SECTION_IDS.
Изменения в БД:

Миграции при необходимости: сохранение формата portal_users (role, permissions, scope), приведение в соответствие с новой моделью; при scope=own_district единообразно использовать список участков из employee_districts с fallback на assigned_district_id во всех API, где идёт фильтр по участку.
Фронт:

Заменить все проверки «по роли» на единые функции из общего модуля прав с учётом permissions и scope (уже в основном через allowedSections/userPermissions; привести к одному источнику констант и убрать дубли).
Все компоненты, использующие allowedSubsForSection / canAccessSub / useSubPermission, оставить на той же логике, но питать данные из единого контекста/источника констант.
Бэкенд:

Все API, отдающие данные в зависимости от прав: использовать единую функцию вычисления прав (allowedSections, уровни по подразделам при необходимости, фильтр по участку). Для фильтра по участку при scope=own_district — единая функция: разрешённые district_id из employee_districts + fallback assigned_district_id, передавать в запросы (buildings, при необходимости заявки, отчёты и т.д.).
Админка:

Создание/редактирование пользователей и шаблонов — сохранение в формате, соответствующем новой модели (те же поля; при необходимости расширить под полную матрицу или шаблоны по подразделам).
3.4 Чек-лист файлов для правок
| Файл | Что менять |

|------|------------|

| Единый источник (новый или рефакторинг) | Вынести роли, разделы, подразделы, ROLE_ACCESS (матрицу по умолчанию), SECTION_IDS в один модуль; при необходимости shared-пакет или генерация. |

| constants/permissions.ts | Оставить/перенести разделы и подразделы; подключать роли и матрицу по умолчанию из единого источника. |

| types.ts | UserRole — при добавлении/переименовании ролей синхронизировать с единым источником. |

| App.tsx | Удалить локальные ROLE_ACCESS, ROLE_NAMES; импорт из единого модуля; логика allowedSections/userPermissions без изменений сути. |

| components/Navigation.tsx | Удалить ROLE_ACCESS; импорт из единого модуля. |

| components/admin/UsersSection.tsx | Удалить ROLE_NAMES; импорт из единого модуля. |

| components/admin/PermissionsSection.tsx | Удалить ROLE_NAMES; импорт из единого модуля. |

| backend/server.js | Удалить локальные ROLE_ACCESS, SECTION_IDS; использовать единый модуль (или сгенерированный константы); allowedSectionsFromPermissions оставить, но секции/роли из общего источника. |

| backend/routes/buildings.js | При scope=own_district получать список district_id из employee_districts + fallback assigned_district_id; фильтровать дома по этому списку (IN (...)), а не по одному assigned_district_id. |

| Другие API в server.js | Найти все места, где подразумевается «доступ по разделу» или «фильтр по участку»; подключить единую функцию прав и единый расчёт участков для scope=own_district. |

| Миграции (при необходимости) | Добавить миграции для portal_users/permission_templates, если появятся новые поля или таблица ролей по умолчанию. |

---

Порядок выполнения
Этап 1 — выполнен в рамках данного плана (результаты сканирования зафиксированы выше).
Этап 2 — оформить отчёт №1 в виде документа (Markdown в docs/ или отдельный файл), согласовать с заказчиком.
Этап 3 — после утверждения отчёта №1 подготовить отчёт №2 (таблица доступов, шаблоны, план переписывания и чек-лист файлов).
Реализация — только после согласования обоих отчётов: миграции БД, единый источник прав, правки фронта и бэкенда по чек-листу.
---

Диаграмма текущей логики прав (для справки)
Backend
Frontend
/auth/me permissions/ROLE_ACCESS
allowedSectionsFromPermissions
buildings scope+assigned_district_id
payment_invoices scope=own
App allowedSections userPermissions
Navigation visible items
Modules allowedSubsForSection
useSubPermission Finance
portal_users permission_templates employees employee_districts
Отдельно: user_roles (workflow) используется только в payment invoice approval, не в E→A.

