Identity Company-User API — реестр методов и общие правила области
Реестр методов управления своей компанией (контекст identity, area company-user): сотрудник
компании (менеджер застройщика / агент-руководитель агентства) управляет пользователями, ролями
(Scoped-RBAC) и назначениями внутри своего tenant. Здесь собраны общие правила области: модель актора
(User + permission в scope), tenancy TenantId = CompanyId, общий поток мутации. Документы методов
описывают дельту относительно этих правил; investor/admin/internal — отдельные реестры.
Metadata
| Поле | Значение |
|---|---|
| Сервис/контекст | identity |
| API area | company-user (сотрудник компании, Scoped-RBAC) |
| Тип документа | api (area-registry, не единичная операция) |
| Статус | draft |
| Owner | PIN Platform Core |
| Область действия | компания/пользователи/роли/назначения/каталог permissions в границах своего tenant; investor/admin/internal — отдельные реестры (../README.md, ../admin/, ../internal/) |
| Assumptions | permissions — из SEED-каталога ../../domain/permission.md; scope-назначения и наследование — ../../domain/role.md (INV-R8) |
Реестр методов
Route-префикс области — /api/v1/. Все мутации проверяют permission в scope актора (Scoped-RBAC).
| # | Метод | Route | Feature group | Permission | Документ |
|---|---|---|---|---|---|
| 1 | GET | /api/v1/companies/my | companies | identity.companies.view | get-my-company.md |
| 2 | PUT | /api/v1/companies/my | companies | identity.companies.manage | update-my-company.md |
| 3 | GET | /api/v1/companies/my/users | companies | identity.users.view | list-company-users.md |
| 4 | POST | /api/v1/companies/my/users/invitations | companies | identity.users.manage | invite-company-user.md |
| 5 | POST | /api/v1/companies/my/users/{userId}/block | companies | identity.users.block | block-company-user.md |
| 15 | POST | /api/v1/companies/my/agent-invitations | agent-onboarding | identity.users.manage | invite-agent-by-phone.md |
| 16 | POST | /api/v1/companies/my/agent-invitations/{invitationId}/revoke | agent-onboarding | identity.users.manage | revoke-invitation.md |
| 6 | GET | /api/v1/roles | roles | identity.roles.view | list-company-roles.md |
| 7 | POST | /api/v1/roles | roles | identity.roles.manage | create-company-role.md |
| 8 | PUT | /api/v1/roles/{roleId} | roles | identity.roles.manage | update-company-role.md |
| 9 | POST | /api/v1/roles/{roleId}/archive | roles | identity.roles.manage | archive-company-role.md |
| 10 | PUT | /api/v1/roles/{roleId}/permissions | roles | identity.roles.manage | set-role-permissions.md |
| 11 | POST | /api/v1/role-assignments | role-assignments | identity.role-assignments.manage (INV-R8) | grant-role-assignment.md |
| 12 | POST | /api/v1/role-assignments/{assignmentId}/revoke | role-assignments | identity.role-assignments.manage (INV-R8) | revoke-role-assignment.md |
| 13 | GET | /api/v1/permissions | permissions | authenticated | list-permission-catalog.md |
| 14 | GET | /api/v1/users/{userId}/effective-permissions | permissions | self: authenticated; чужой: identity.role-assignments.view | get-user-effective-permissions.md |
Модель актора и доступ
| Проверка | Значение |
|---|---|
| Actor type | User — сотрудник компании (менеджер застройщика, агент-руководитель, сотрудник ПИН на платформенном scope) |
| Auth | Bearer JWT (подпись, exp, notBefore); CompanyId — из claim tenant_id |
| Authz | Scoped-RBAC: требуемый permission должен присутствовать в эффективных правах актора в применимом scope (платформа/организация/группа проектов/проект) с наследованием — формула ../../domain/role.md |
| Ограничение по типу | менеджеры застройщика, реплицированные из Talent (ContactsManagedBy = TalentSync), не редактируют свой профиль/контакты через self-service |
Tenancy: область tenanted по CompanyId
Каждый запрос области выполняется в границах TenantId = CompanyId (ADR-0052): актор видит и мутирует
только сущности своей компании (роли компании, пользователи компании, назначения в её scope). Системные
роли и платформенные назначения — вне области (admin, ../admin/). Cross-tenant запрещён,
кроме платформенных permissions.
Общий поток мутации области
Скелет, общий для мутаций (метод описывает только дельту):
- Контекст и доступ. JWT определяет актора и
CompanyId(tenant); для мутаций принимаетсяIdempotency-Key. - Проверка входа. Синтаксис, длины, enum, структурные модели входа; нарушение —
ValidationError. - Проверка прав. Требуемый permission должен присутствовать в эффективных правах актора в
применимом scope; для назначений действует INV-R8 (нельзя выдать право, которого нет у себя);
иначе —
FORBIDDEN. - Загрузка. Целевой агрегат (
RoleDefinition/RoleAssignment/UserEntity) читается в границах tenant; при мутации по версии сверяется ожидаемая версия (иначе —CONCURRENCY_CONFLICT). - Правила и переходы. Применяются инварианты и переходы статусов; фиксируется, кто и когда изменил сущность; при смене состава прав/назначений формируется факт «доступ пользователя изменился».
- Изменения. Сущность создаётся/обновляется; архив роли — мягкое удаление; история
RoleAssignmentне удаляется (audit). - Согласованность и события. Изменение сущности и интеграционные события (
pin.identity.access.v1при смене прав,pin.identity.users.v1при смене учётки) фиксируются в одном согласованном изменении; массовый fan-out прав делегируется джобе ../../background/access-fan-out.md. - Результат. Модель результата и статус
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 |
|---|---|---|---|
ValidationError | 400 | Синтаксис/enum/длины/структурные модели | no retry |
UNAUTHORIZED | 401 | Нет/просрочен JWT | no retry |
FORBIDDEN | 403 | Нет требуемого permission в scope / нарушение INV-R8 | no retry |
IDENTITY_*_NOT_FOUND | 404 | Роль/назначение/пользователь вне tenant или не существует | no retry |
CONCURRENCY_CONFLICT | 409 | Ожидаемая версия не совпала / конфликт оптимистичной блокировки | retry после перечитки |
Связанные документы
- Дома полей: ../../domain/company.md, ../../domain/user.md, ../../domain/role.md (роли/назначения/scope, INV-R8), ../../domain/permission.md (SEED-каталог), ../../domain/company-invitation.md (приглашение агента по телефону, ADR-0061).
- События: ../../events/user-access-changed.md, ../../events/user-upserted.md; fan-out — ../../background/access-fan-out.md.
- Use cases: ../../use-cases/UC-IDN-005-company-role-create-and-assign.md, ../../use-cases/UC-IDN-006-invite-company-manager.md.
- Решения: ADR-0052 (tenancy
TenantId = CompanyId), ADR-0056 (simplicity-first). - Соседние реестры: ../README.md (public/investor),
../admin/,../internal/.