Identity Service (Pin.Identity)
Назначение
identity владеет учётными записями пользователей, компаниями (workspace), ролевой моделью
(Scoped-RBAC: роли + permissions + назначения в scope) и аутентификацией (СМС-вход, пароль, пин-код,
2FA, сессии). Сюда входят учётки инвесторов и сотрудников компаний, каталог permissions, роли и
scope-назначения, а также синхронизация компаний-застройщиков и их менеджеров из внешнего
talent.microservices.identity через Kafka-события.
Metadata
| Поле | Значение |
|---|---|
| Статус | draft |
| Owning team | PIN Platform Core |
| Domain | Identity & Access |
| Data classification | Sensitive (PII: телефоны, email, ФИО; секреты — только хэши) |
| Runtime criticality | mission-critical (без identity не работает вход и авторизация всех контекстов) |
Ownership
| Artifact | Owner/Rule |
|---|---|
| PostgreSQL schema | identity |
API areas (папки api/ по актору) | investor/ (public: СМС-вход, refresh, агент-онбординг accept/decline/become-agent), company-user/ (компании/роли/назначения + приглашение/отзыв агента), agent/ (self-действия членства: leave-agency/become-investor, ADR-0061), admin/ (m2m для администраторов платформы, ADR-0053), internal/ (permission-check/introspection для gateway) |
| Owned entities | CompanyEntity, UserEntity, RoleDefinition (+RolePermission), RoleAssignment, PermissionDefinition (SEED), SignInConfirmationRequest, RefreshSession, TalentSyncState, CompanyInvitationEntity, AgentMembershipEntity (ADR-0061) |
| Produced events | pin.identity.companies.v1, pin.identity.users.v1, pin.identity.access.v1, pin.identity.sign-ins.v1, pin.identity.company-invitation-changed.v1, pin.identity.agent-membership-changed.v1 (ADR-0061) |
| Consumed events | talent.identity.tenants.v1, talent.identity.users.v1 (реплика Talent) |
| Search indexes | identity-users (Elasticsearch-проекция UserSearchDocument — поиск пользователей компании по ФИО/телефону/email; ADR-0059) — search/users.md |
| Analytics facts | none (вход/активность — контекст user-activity) |
Ответственность И Границы
- Делает: регистрация/вход (СМС/пароль/пин/2FA), учётки 5 типов пользователей, компании 5 типов, каталог permissions (SEED, 139), роли компаний и системные, назначения ролей в scope (платформа/организация/группа проектов/проект) с наследованием, реплика компаний/менеджеров из Talent, сессии и их отзыв.
- НЕ делает: администраторы платформы (живут в отдельной системе — ADR-0053); расширенный профиль,
документы, реквизиты, KYC-верификация (контекст
profile); enforcement record-level на записях (владеющие контексты, напр. crm-фиксации); реферальная привязка (referral); витрина сессий/трекинг (user-activity). - Source of truth: все owned-сущности; для Talent-компаний и их менеджеров реплика-поля — Talent (правила — domain/talent-replica.md).
- Реплики/проекции у потребителей: UserId/CompanyId + snapshot-поля через
pin.identity.*события; кэш эффективных прав — инвалидацияpin.identity.access.v1.
Зависимости
| Зависимость | Тип | Зачем Нужна | Failure mode |
|---|---|---|---|
PostgreSQL (schema identity) | db | Все агрегаты + outbox | Полный отказ сервиса (mission-critical) |
| Kafka | queue | Синк Talent (in), события pin.identity.* (out, через outbox) | Вход работает; реплики/кэши потребителей отстают (лаг-алерты) |
| СМС-verifier (внешний провайдер) | external system | Отправка кодов подтверждения | Вход по СМС недоступен; пароль/пин продолжают работать (realConfirmationCodeDispatched=false в тест-контуре) |
| Redis | cache | Rate-limit кодов (INV-S4), кэш permissions | Деградация: rate-limit по БД, permissions без кэша (медленнее) |
| talent.microservices.identity | external system | Источник компаний-застройщиков и их менеджеров | Синк отстаёт; локальные операции не затронуты |
| Администраторы платформы | consumer (m2m) | Управление пользователями/ролями через admin-API | Недоступны admin-операции |
Проекты
src/services/identity/
Pin.Identity.Api/ # public + admin + internal API areas
Pin.Identity.Application/ # прикладная логика (операции над агрегатами)
Pin.Identity.Domain/ # агрегаты domain/*.md
Pin.Identity.Infrastructure/ # EF (PostgreSQL), outbox, Redis, СМС-verifier adapter
Pin.Identity.Background/ # consumers Talent, jobs: expire-sessions, retention, access fan-out
Pin.Identity.Migrator/ # миграции + SEED (permissions, системные роли, компания ПИН)
Pin.Identity.Contracts/ # pin.identity.* event contracts
Основные Сущности
| Entity | Назначение | Source Of Truth | Документ |
|---|---|---|---|
CompanyEntity | Компания/workspace (Застройщик/Агентство/Брокер/Партнёр/ПИН), граница tenant | identity (+реплика-поля Talent) | domain/company.md |
UserEntity | Учётка (инвестор/менеджер застройщика/агент/сотрудник ПИН), секреты входа, контакты | identity (+реплика-поля Talent для DeveloperManager) | domain/user.md |
RoleDefinition + RolePermission | Роль компании/системная и её состав прав | identity | domain/role.md |
RoleAssignment (+ResourceScope) | Назначение роли пользователю в scope с наследованием | identity | domain/role.md |
CompanyInvitationEntity | Приглашение агента по телефону (Pending/Accepted/Declined/Expired/Revoked), ADR-0061 | identity | domain/company-invitation.md |
AgentMembershipEntity | Членство агента в агентстве с историей join/leave; независимый агент — без активного членства, ADR-0061 | identity | domain/agent-membership.md |
PermissionDefinition | SEED-каталог 139 permission (19 контекстов) | identity | domain/permission.md |
SignInConfirmationRequest | Одноразовый запрос кода (вход/2FA/смена email/телефона) | identity | domain/user-session.md |
RefreshSession | Refresh-сессия входа, устройства, отзыв | identity | domain/user-session.md |
TalentSyncState | Чекпоинты/конфликты синка Talent | identity | domain/talent-replica.md |
ER-обзор
API (карта областей; детали — api/ по api-method-template)
- Public (18 операций, контракт стабилен):
requestSignInCode,signUpOrSignIn,confirmSignIn,verifySignInPassword,signUp,getCurrentInvestor,updateInvestor,changePassword,setPinCode,clearPinCode,requestEnableTwoFactor,confirmEnableTwoFactor,requestDisableTwoFactor,confirmDisableTwoFactor,requestEmailChange,confirmEmailChange,requestPhoneChange,confirmPhoneChange. - Public (расширения):
refreshToken,signOut,getMySessions/revokeSession, роли компании (CRUDRoleDefinition, grant/revokeRoleAssignment), просмотр каталога permissions. - Admin (m2m, ADR-0053): пользователи (список/блокировка/архив), компании (создание Agency/Broker/Partner, suspend), назначения платформенных ролей, resolution конфликтов синка.
- Internal: интроспекция эффективных прав (
effectivePermissions(userId, resource)) для gateway/сервисов.
Use Cases
| ID | Сценарий | Документ |
|---|---|---|
| UC-IDN-001 | Вход/регистрация по СМС (signUpOrSignIn → confirmSignIn, lazy-заполнение имени, referrerUrl) | use-cases/UC-IDN-001-sms-sign-in-or-sign-up.md |
| UC-IDN-002 | Вход по паролю вместо СМС (verifySignInPassword, ветка 2FA) | use-cases/UC-IDN-002-password-sign-in.md |
| UC-IDN-003 | Включение двухфакторной аутентификации (выключение — альтернативный поток) | use-cases/UC-IDN-003-enable-two-factor.md |
| UC-IDN-004 | Смена телефона/email с подтверждением кодом (запрет self-service при TalentSync) | use-cases/UC-IDN-004-change-phone-email.md |
| UC-IDN-005 | Создание роли компании и назначение агенту в scope проекта (Scoped-RBAC) | use-cases/UC-IDN-005-company-role-create-and-assign.md |
| UC-IDN-006 | Приглашение менеджера (агента) в компанию, активация первым входом | use-cases/UC-IDN-006-invite-company-manager.md |
| UC-IDN-007 | Синхронизация компаний и менеджеров застройщиков из Talent Identity (system) | use-cases/UC-IDN-007-talent-sync-company-users.md |
| UC-IDN-008 | Проверка доступа сервисом (internal check-permission, кэши и инвалидация) | use-cases/UC-IDN-008-internal-permission-check.md |
| UC-IDN-009 | Приглашение агента по телефону и его принятие (CompanyInvitation → AgentMembership, ADR-0061) | use-cases/UC-IDN-009-invite-agent-by-phone-and-accept.md |
| UC-IDN-010 | Выход агента из агентства с сохранением метрик (независимый агент, ADR-0061) | use-cases/UC-IDN-010-agent-leaves-agency-keeps-metrics.md |
| UC-IDN-011 | Инвестор становится агентом (независимый / по приглашению, ADR-0061) | use-cases/UC-IDN-011-investor-becomes-agent.md |
Events И Consumers
| Type | Name | Topic | Назначение | Link |
|---|---|---|---|---|
| Produced | CompanyUpsertedKafkaEvent | pin.identity.companies.v1 | Snapshot компаний для catalog/crm/rewards/news | events/company-upserted.md · domain/company.md |
| Produced | CompanySuspendedKafkaEvent | pin.identity.companies.v1 | Приостановка компании: скрытие витрин, блокировка операций | events/company-suspended.md · domain/company.md |
| Produced | UserUpsertedKafkaEvent | pin.identity.users.v1 | Snapshot пользователей для referral/crm/profile/messenger/user-activity/notifications | events/user-upserted.md · domain/user.md |
| Produced | UserBlockedKafkaEvent | pin.identity.users.v1 | Блокировка пользователя у потребителей | events/user-blocked.md · domain/user.md |
| Produced | UserAccessChangedKafkaEvent | pin.identity.access.v1 | Инвалидация кэшей авторизации | events/user-access-changed.md · domain/role.md |
| Produced | UserSignedInKafkaEvent | pin.identity.sign-ins.v1 | Связывание anonymous_id, алерты о новом устройстве | events/user-signed-in.md · domain/user-session.md |
| Produced | CompanyInvitationChangedKafkaEvent | pin.identity.company-invitation-changed.v1 | Приглашение агента по телефону (найм) для notifications/crm/rewards | events/company-invitation-changed.md · domain/company-invitation.md |
| Produced | AgentMembershipChangedKafkaEvent | pin.identity.agent-membership-changed.v1 | Вступление/выход агента для crm/rewards/notifications (user-centric метрики) | events/agent-membership-changed.md · domain/agent-membership.md |
| Consumed | TenantUpserted/Blocked/Unblocked/Deleted | talent.identity.tenants.v1 | Реплика компаний | consumers/talent-identity-sync.md · domain/talent-replica.md |
| Consumed | UserUpserted/Blocked/Unblocked/Deleted | talent.identity.users.v1 | Реплика менеджеров застройщиков | consumers/talent-identity-sync.md · domain/talent-replica.md |
Гарантии доставки и порядок событий (контракт потребителя)
Общие правила для всех pin.identity.* — что потребители могут на них закладывать:
- Доставка — at-least-once через transactional outbox (событие уходит в том же согласованном изменении, что и мутация агрегата). Потребитель обязан быть идемпотентным.
- Ключ партиционирования и порядок —
UserIdдляusers/access/sign-ins/agent-membership-changed,CompanyIdдляcompanies,invitationId/адресат дляcompany-invitation-changed. Порядок событий гарантирован в пределах одной сущности (один ключ), между разными сущностями — нет. - Дедуп и устаревание — каждое событие несёт монотонную
Versionагрегата; потребитель применяет событие, только если егоVersionбольше уже применённой (last-writer-wins по версии), более старые/ повторные игнорирует. Это защищает реплики при переупорядочивании и повторной доставке. - Эволюция контракта —
ContractVersionрастёт только additive (новые optional-поля, новые enum- значения); неизвестные потребителю поля и enum-значения игнорируются (forward-compatible). Breaking- изменение — новый major топика с параллельным периодом. - Окна согласованности — инвалидация кэшей прав по
pin.identity.access.v1и обновление snapshot- реплик у потребителей — секунды при штатном лаге (алерт при > 5 мин, см. SLO). До применения события потребитель может краткий промежуток видеть прежний snapshot; критичные проверки статуса на привилегированных операциях идут через internal permission-check (не через реплику).
Runtime И Эксплуатация
| Область | Требование |
|---|---|
| Health checks | /health/live, /health/ready (PostgreSQL, Kafka, Redis), /health/startup (миграции/SEED применены) |
| SLO/SLA | confirm-операции p99 < 300 мс; интроспекция прав p99 < 50 мс (кэш); лаг синка Talent < 5 мин |
| Dashboard | identity-overview (входы, ошибки кодов, лаг синка, DLQ) |
| Alerts | лаг синка > 5 мин; DLQ > 0; всплеск IDENTITY_CONFIRMATION_RATE_LIMITED; ошибки СМС-verifier |
| Runbooks | replay DLQ синка; merge учёток (конфликт телефона R6); массовый отзыв сессий |
| Feature flags | identity.refresh-flow.enabled (поэтапный ввод refresh-flow) |
Безопасность
- Actor types: guest (только request/confirm входа), user (self-операции), company-admin (роли/пользователи в scope), platform (роли ПИН), m2m (администраторы платформы, gateway), system (consumers/jobs).
- Permission model: domain/permission.md (каталог) + domain/role.md (scope-назначения, INV-R8).
- Sensitive data: телефоны/email/ФИО (PII, маскирование в логах); PasswordHash/PinCodeHash/CodeHash/ RefreshTokenHash — только хэши (Argon2id / HMAC/SHA-256), не покидают домен.
- Audit: actor-stamping +
Versionна агрегатах; полная историяRoleAssignment(не удаляются); security-изменения — события. - Tenant isolation: ADR-0052 —
TenantId = CompanyId; инвестор — вне tenant, record-level поUserId; кросс-tenant — только платформенные permissions.
Известные Ограничения И Assumptions
- Имена топиков/контракты Talent (
talent.identity.{tenants,users}.v1) — assumption до подтверждения schema registry Talent (domain/talent-replica.md). - Группы проектов (
ResourceScope.ProjectGroupId) ссылаются наchessboardбез FK; консистентность — eventual (событие удаления проекта → отзыв назначений). - Merge учёток при конфликте телефона Talent-менеджера и инвестора — ручной процесс заботы (R6).
- Admin-identity (хранение админов, их MFA) — вне scope (ADR-0053), проектируется отдельно.
- «СуперАгент» из матриц не роль — дубль
agent(technical-assignment.md).
Связанные Документы
- Домены: company · user · role · permission · user-session · talent-replica · company-invitation · agent-membership.
- Решения: ADR-0052 (tenancy), ADR-0053 (админы), ADR-0061 (независимый агент, приглашения, переходы ролей), technical-assignment.md (решения №1, №2, №8), glossary.md, service-boundaries.md.
- Шаблоны/правила: service-readme-template, entity-template, algorithm-documentation-rules, cross-cutting-document-requirements; SDK — docs/11-backend-sdk/.