Перейти к основному содержимому

GET /api/v1/permissions — Каталог permissions (SEED)

Чтение справочника прав доступа (113 позиций, domain/permission.md) для UI настройки ролей: чекбоксы по контекстам с фильтром «назначимо компанией».

Назначение

Пользователь с правом просмотра ролей открывает конструктор роли и видит каталог прав, сгруппированный по 16 контекстам. Owning-контекст — identity. Feature group — permissions.

SEED-справочник

Каталог — SEED reference data (INV-P1): меняется только релизом, runtime-API записи нет.

Metadata

ПолеЗначение
Сервис/контекстidentity
API areapublic
Feature grouppermissions
Статусdraft
Документdocs/06-services/identity/api/company-user/list-permission-catalog.md

Актор и доступ

ПроверкаЗначение
Actor typeUser (любой аутентифицированный)
Auth policy / Permissionsauthenticated (без permission-требования)
Scope (RBAC)не применяется — платформенный справочник (не tenanted, ADR-0052 п.3)
Record-levelне применяется
Tenant isolationне применяется — данные одинаковы для всех tenant-ов
Auditnone
UI поверх открытого endpoint

Право на чтение каталога — у любого аутентифицированного пользователя (domain/permission.md: «чтение каталога — любой аутентифицированный»). Практический сценарий (конструктор роли) требует identity.roles.view для доступа к UI, но сам endpoint не приватен: каталог не содержит секретов.

HTTP-контракт

ПолеЗначение
MethodGET
Route/api/v1/permissions
Success status200
Idempotency headerне применяется
Correlationсквозной trace через заголовок traceparent

Входные данные / параметры запроса

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
UserIdidentity claimsGuidДаRequired (authenticated)
Contextquerystring?Нет<= 32; один из 16 контекстов; неизвестный → пустой список (не ошибка)
AssignableByCompaniesOnlyqueryboolНетdefault true — UI ролей компании скрывает платформенные права
IncludeDeprecatedqueryboolНетdefault false

Модель ответа GetPermissionCatalogQueryResult

ПолеТипОбязательностьИсточникMaskingОписание
ItemsIReadOnlyList<PermissionCatalogItemModel>Дакэш SEED-каталогаПрава, отсортированы по (Context, Code).

PermissionCatalogItemModel

ПолеТипОбязательностьИсточникMaskingОписание
IdGuidДаPermissionDefinition.IdДетерминированный Guid (uuid5 от Code).
CodestringДаPermissionDefinition.Code<context>.<entity>.<action>.
NamestringДаPermissionDefinition.NameНазвание по-русски.
DescriptionstringДаPermissionDefinition.DescriptionЧто разрешает.
ContextstringДаPermissionDefinition.ContextКонтекст-владелец enforcement.
MinScopeTypestring (enum ResourceScopeType)ДаPermissionDefinition.MinScopeTypeМинимальный scope назначения.
IsAssignableByCompaniesboolДаPermissionDefinition.IsAssignableByCompaniesДоступно ли ролям компаний (INV-P4).
IsDeprecatedboolДаPermissionDefinition.IsDeprecatedВыведено из употребления.

Алгоритм

  1. Контекст и доступ. Операцию выполняет любой аутентифицированный пользователь; tenant/scope не применяется — это платформенный справочник.
  2. Проверка входа. Синтаксис по таблице входных данных (Context ≤ 32); иначе — ValidationError. Ссылок на сущности нет.
  3. Что читаем. Весь каталог прав — из in-memory кэша (permission.md: ~140 строк, кэшируется на инстансе; прогрев при старте, инвалидация — только рестарт после SEED-миграции).
  4. Фильтрация и маппинг. In-memory: при Context != null — по контексту; при AssignableByCompaniesOnly — только IsAssignableByCompanies = true; при !IncludeDeprecated — только IsDeprecated = false. Сортировка (Context, Code). Маппинг поле-в-поле по таблице модели. Неизвестное значение Context — не ошибка: пустой список.
  5. Результат. Каталог прав (200). Каталог версионируется релизом (INV-P1: записи только SEED-миграцией) — расхождение между инстансами возможно только в окно rolling-deploy (безопасно: клиент получит новые коды после завершения деплоя).

Диаграмма

Побочные эффекты

ТипДетали
Проекции / кэшчтение in-memory кэша; HTTP-кэширование — Cache-Control: private, max-age=300 (справочник меняется релизом)

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
ValidationError400Context длиннее 32 симв.Список ошибокno retry
UNAUTHORIZED401Нет access-токенаretry после refresh
Неизвестный контекст — не ошибка

Неизвестное значение Context не приводит к ошибке: возвращается пустой Items (клиент не должен падать на новых контекстах).

Совместимость и наблюдаемость

  • Добавление permission — additive (permission.md «Совместимость»); удаление — deprecate → sunset через 2 релиза; клиенты обязаны игнорировать неизвестные Context/MinScopeType-значения.
  • Logs: количество отданных позиций; metrics: identity_permission_catalog_total; traces: OTel; dashboard identity-overview; runbook — не применяется.

Acceptance Criteria

  • Given любой аутентифицированный пользователь, When GET /permissions с дефолтами, Then 200; только права с IsAssignableByCompanies = true и IsDeprecated = false, отсортированы по (Context, Code).
  • Given Context = crm, When GET, Then в ответе только права контекста crm.
  • Given Context — несуществующий контекст, When GET, Then 200 с Items = [] (не ошибка — клиент не должен падать на новых контекстах).
  • Given AssignableByCompaniesOnly = false, When GET, Then в ответе присутствуют и права с IsAssignableByCompanies = false (для UI платформенных ролей).
  • Given IncludeDeprecated = true, When GET, Then права с IsDeprecated = true включены.
  • Given Context длиннее 32 символов, When GET, Then ValidationError (400).
  • Given запрос без access-токена, When GET, Then UNAUTHORIZED (401).
  • Given между двумя запросами не было релиза, When GET дважды, Then состав каталога идентичен (SEED-данные меняются только релизом, INV-P1); ответ кэшируем (Cache-Control: private, max-age=300).

Обратные ссылки

Автоссылки: где используется этот документ.

Связанные документы