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

Identity Company-User API — реестр методов и общие правила области

Реестр методов управления своей компанией (контекст identity, area company-user): сотрудник компании (менеджер застройщика / агент-руководитель агентства) управляет пользователями, ролями (Scoped-RBAC) и назначениями внутри своего tenant. Здесь собраны общие правила области: модель актора (User + permission в scope), tenancy TenantId = CompanyId, общий поток мутации. Документы методов описывают дельту относительно этих правил; investor/admin/internal — отдельные реестры.

Metadata

ПолеЗначение
Сервис/контекстidentity
API areacompany-user (сотрудник компании, Scoped-RBAC)
Тип документаapi (area-registry, не единичная операция)
Статусdraft
OwnerPIN Platform Core
Область действиякомпания/пользователи/роли/назначения/каталог permissions в границах своего tenant; investor/admin/internal — отдельные реестры (../README.md, ../admin/, ../internal/)
Assumptionspermissions — из SEED-каталога ../../domain/permission.md; scope-назначения и наследование — ../../domain/role.md (INV-R8)

Реестр методов

Route-префикс области — /api/v1/. Все мутации проверяют permission в scope актора (Scoped-RBAC).

#МетодRouteFeature groupPermissionДокумент
1GET/api/v1/companies/mycompaniesidentity.companies.viewget-my-company.md
2PUT/api/v1/companies/mycompaniesidentity.companies.manageupdate-my-company.md
3GET/api/v1/companies/my/userscompaniesidentity.users.viewlist-company-users.md
4POST/api/v1/companies/my/users/invitationscompaniesidentity.users.manageinvite-company-user.md
5POST/api/v1/companies/my/users/{userId}/blockcompaniesidentity.users.blockblock-company-user.md
15POST/api/v1/companies/my/agent-invitationsagent-onboardingidentity.users.manageinvite-agent-by-phone.md
16POST/api/v1/companies/my/agent-invitations/{invitationId}/revokeagent-onboardingidentity.users.managerevoke-invitation.md
6GET/api/v1/rolesrolesidentity.roles.viewlist-company-roles.md
7POST/api/v1/rolesrolesidentity.roles.managecreate-company-role.md
8PUT/api/v1/roles/{roleId}rolesidentity.roles.manageupdate-company-role.md
9POST/api/v1/roles/{roleId}/archiverolesidentity.roles.managearchive-company-role.md
10PUT/api/v1/roles/{roleId}/permissionsrolesidentity.roles.manageset-role-permissions.md
11POST/api/v1/role-assignmentsrole-assignmentsidentity.role-assignments.manage (INV-R8)grant-role-assignment.md
12POST/api/v1/role-assignments/{assignmentId}/revokerole-assignmentsidentity.role-assignments.manage (INV-R8)revoke-role-assignment.md
13GET/api/v1/permissionspermissionsauthenticatedlist-permission-catalog.md
14GET/api/v1/users/{userId}/effective-permissionspermissionsself: authenticated; чужой: identity.role-assignments.viewget-user-effective-permissions.md

Модель актора и доступ

ПроверкаЗначение
Actor typeUser — сотрудник компании (менеджер застройщика, агент-руководитель, сотрудник ПИН на платформенном scope)
AuthBearer JWT (подпись, exp, notBefore); CompanyId — из claim tenant_id
AuthzScoped-RBAC: требуемый permission должен присутствовать в эффективных правах актора в применимом scope (платформа/организация/группа проектов/проект) с наследованием — формула ../../domain/role.md
Ограничение по типуменеджеры застройщика, реплицированные из Talent (ContactsManagedBy = TalentSync), не редактируют свой профиль/контакты через self-service

Tenancy: область tenanted по CompanyId

Каждый запрос области выполняется в границах TenantId = CompanyId (ADR-0052): актор видит и мутирует только сущности своей компании (роли компании, пользователи компании, назначения в её scope). Системные роли и платформенные назначения — вне области (admin, ../admin/). Cross-tenant запрещён, кроме платформенных permissions.

Общий поток мутации области

Скелет, общий для мутаций (метод описывает только дельту):

  1. Контекст и доступ. JWT определяет актора и CompanyId (tenant); для мутаций принимается Idempotency-Key.
  2. Проверка входа. Синтаксис, длины, enum, структурные модели входа; нарушение — ValidationError.
  3. Проверка прав. Требуемый permission должен присутствовать в эффективных правах актора в применимом scope; для назначений действует INV-R8 (нельзя выдать право, которого нет у себя); иначе — FORBIDDEN.
  4. Загрузка. Целевой агрегат (RoleDefinition / RoleAssignment / UserEntity) читается в границах tenant; при мутации по версии сверяется ожидаемая версия (иначе — CONCURRENCY_CONFLICT).
  5. Правила и переходы. Применяются инварианты и переходы статусов; фиксируется, кто и когда изменил сущность; при смене состава прав/назначений формируется факт «доступ пользователя изменился».
  6. Изменения. Сущность создаётся/обновляется; архив роли — мягкое удаление; история RoleAssignment не удаляется (audit).
  7. Согласованность и события. Изменение сущности и интеграционные события (pin.identity.access.v1 при смене прав, pin.identity.users.v1 при смене учётки) фиксируются в одном согласованном изменении; массовый fan-out прав делегируется джобе ../../background/access-fan-out.md.
  8. Результат. Модель результата и статус 200/201; списки возвращаются постранично; при отказе — код ошибки.

Распространение изменений доступа (окно согласованности)

Единые правила для мутаций области, меняющих права/учётку — что закладывать при интеграции:

  • Смена прав (создание/изменение/архив роли, grant/revoke назначения) → на каждого затронутого пользователя UserAccessChangedKafkaEvent (pin.identity.access.v1, key = UserId) с пересобранным списком активных назначений. Потребители (gateway, crm, catalog, chessboard) сбрасывают кэш авторизации по событию; кэш эффективных прав perm:{userId} инвалидируется после фиксации (best-effort, консистентность добивает событие).
  • Смена учётки (блокировка, профиль) → UserUpsertedKafkaEvent/UserBlockedKafkaEvent (pin.identity.users.v1, key = UserId).
  • Массовый fan-out. Если изменение затрагивает > 100 пользователей (архив роли с большим числом назначений), рассылка делегируется background-джобе батчами (../../background/access-fan-out.md) — вместо N синхронных событий фиксируется маркер задачи.
  • Немедленность vs лаг. Изменение видно в самом identity сразу после коммита; downstream применяет с лагом в секунды. Access-JWT, выданные до изменения, живут до истечения TTL (≤ 15 мин) — на привилегированных операциях gateway дополнительно вызывает internal permission-check по актуальному состоянию (см. ../internal/).

Общие коды ошибок области

КодHTTPУсловиеRetry
ValidationError400Синтаксис/enum/длины/структурные моделиno retry
UNAUTHORIZED401Нет/просрочен JWTno retry
FORBIDDEN403Нет требуемого permission в scope / нарушение INV-R8no retry
IDENTITY_*_NOT_FOUND404Роль/назначение/пользователь вне tenant или не существуетno retry
CONCURRENCY_CONFLICT409Ожидаемая версия не совпала / конфликт оптимистичной блокировкиretry после перечитки

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