Files
mkd/план.md
2026-02-04 00:17:04 +05:00

148 lines
19 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
План переработки системы прав доступа
Этап 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, краткое описание назначения (12 предложения). Взять за основу текущие 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.