Identity API — карта областей и реестр investor-области
HTTP-API identity разбит на области по актору (папки api/). Эта страница — реестр
public/investor-области (18 операций СМС-входа инвестора + refresh/sign-out), общие enum-ы
аутентификации и единые правила ответов/ошибок. Реестры остальных областей — в их подпапках.
Области API (папки по актору)
| Область (папка) | Актор | Что покрывает | Реестр |
|---|---|---|---|
investor/ | User / Anonymous (частный инвестор) | СМС-вход, 2FA, пин-код, профиль, смена контактов, refresh/sign-out; агент-онбординг: accept/decline приглашения, become-agent (ADR-0061) | этот файл (ниже) |
company-user/ | User (сотрудник компании) | компания, пользователи, роли (Scoped-RBAC), назначения, каталог permissions, приглашение/отзыв агента по телефону (ADR-0061) | company-user/README.md |
agent/ | User (сам агент) | self-действия над членством: выход из агентства (leave), возврат к инвестору (become-investor) — ADR-0061 | agent/README.md |
admin/ | ExternalSystem (система администрирования, m2m, ADR-0053) | блокировка/удаление/сброс факторов/отзыв сессий учёток | admin/README.md |
internal/ | ExternalSystem (gateway/сервисы, m2m) | authorize/check-permission (enforcement) | internal/README.md |
Единые правила ответов/ошибок (см. ниже) применяются во всех областях; area-специфичные правила
(policy AdminSystemOnly, tenancy CompanyId, m2m audience) — в реестрах соответствующих папок.
Metadata
| Поле | Значение |
|---|---|
| Сервис/контекст | identity |
| Статус | контракты стабильны, изменение — через migration-план |
| Owning team | PIN Platform Core |
| Область действия | investor/public area (СМС-вход, 2FA, пин-код, профиль, смена контактов) + общие правила ответов/ошибок; company-user/admin/internal — отдельные реестры (см. «Области API») |
| Assumptions | Клиент обрабатывает 200/400 типизированно; 401/429/5xx попадают в общую ветку ошибок (при 401 клиент очищает локальную сессию — refresh-flow вводится отдельно) |
| Зависимости | domain/user.md, domain/user-session.md |
Реестр операций (18)
| # | Операция | HTTP | Route | Feature group | Актор | Документ |
|---|---|---|---|---|---|---|
| 1 | requestSignInCode | POST | /api/investors/auth/request-sign-in-code | auth | Anonymous | request-sign-in-code.md |
| 2 | signUpOrSignIn | POST | /api/investors/auth/sign-up-or-sign-in | auth | Anonymous | sign-up-or-sign-in.md |
| 3 | confirmSignIn | POST | /api/investors/auth/confirm-sign-in | auth | Anonymous | confirm-sign-in.md |
| 4 | verifySignInPassword | POST | /api/investors/auth/verify-sign-in-password | auth | Anonymous | verify-sign-in-password.md |
| 5 | signUp | POST | /api/investors/auth/sign-up | auth | Anonymous | sign-up.md |
| 6 | getCurrentInvestor | GET | /api/investors/me | profile | User | get-current-investor.md |
| 7 | updateInvestor | PUT | /api/investors/me | profile | User | update-investor.md |
| 8 | changePassword | POST | /api/investors/me/password/change | security | User | change-password.md |
| 9 | setPinCode | POST | /api/investors/me/pin-code/set | security | User | set-pin-code.md |
| 10 | clearPinCode | POST | /api/investors/me/pin-code/clear | security | User | clear-pin-code.md |
| 11 | requestEnableTwoFactor | POST | /api/investors/me/2fa/enable-request | security | User | request-enable-two-factor.md |
| 12 | confirmEnableTwoFactor | POST | /api/investors/me/2fa/enable-confirm | security | User | confirm-enable-two-factor.md |
| 13 | requestDisableTwoFactor | POST | /api/investors/me/2fa/disable-request | security | User | request-disable-two-factor.md |
| 14 | confirmDisableTwoFactor | POST | /api/investors/me/2fa/disable-confirm | security | User | confirm-disable-two-factor.md |
| 15 | requestEmailChange | POST | /api/investors/me/email/change-request | contacts | User | request-email-change.md |
| 16 | confirmEmailChange | POST | /api/investors/me/email/change-confirm | contacts | User | confirm-email-change.md |
| 17 | requestPhoneChange | POST | /api/investors/me/phone/change-request | contacts | User | request-phone-change.md |
| 18 | confirmPhoneChange | POST | /api/investors/me/phone/change-confirm | contacts | User | confirm-phone-change.md |
Ответы и ошибки
Единые правила для всех областей API identity:
- Успех (200) — тело содержит модель результата операции (у каждой операции своя, описана в её документе).
- Бизнес-ошибка (400) — тело содержит список ошибок операции. У каждой ошибки: безопасный код/сообщение (без PII), опциональный контекст (пары ключ-значение — каждая операция перечисляет свои ключи в своём документе) и, для ошибок валидации входа, список ошибок по полям (имя поля + код правила валидации + локализованное сообщение). Диагностика исключений — только в non-prod контурах.
- 401 / 429 / 5xx — без специальной схемы (общая ветка ошибок); при 401 клиент очищает локальную сессию (refresh-flow вводится отдельно).
Каждый ответ несёт идентификаторы сквозной корреляции (trace/span) для диагностики.
Общие модели аутентификации
JwtTokenModel — access-токен
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
token | string | Да | Подписанный JWT (claims: sub = UserId/investorId; PII в claims отсутствует). |
notBefore | string (ISO 8601) | Да | Момент начала действия. |
type | TokenType | Да | JwtToken / RefreshToken (выдаётся JwtToken; refresh вводится отдельно). |
expirationDate | string (ISO 8601) | Да | Момент истечения. |
Enum SignInNextStep — следующий шаг входа
| Значение | Когда возвращается |
|---|---|
RequiresPassword | У инвестора установлен пароль (hasPassword = true) — фронт показывает форму пароля (verifySignInPassword). |
RequiresSmsCode | Отправлен СМС-код — фронт показывает форму кода (confirmSignIn с signInConfirmationRequestId + confirmationCode). |
RequiresPinCode | Задан пин-код (hasPinCode = true) — фронт показывает форму пин-кода (confirmSignIn с pinCode). |
Enum AuthNextAction — необязательная подсказка UI после входа
| Значение | Когда |
|---|---|
FillName | Имя пустое (lazy-регистрация) — предложить заполнить ФИО. |
FillPinCode | Пин-код не задан — предложить установить. |
FillEmail | Email не задан. |
FillPassword | Пароль не установлен. |
Не блокирует аутентификацию; сервер вычисляет первую применимую подсказку в порядке
FillName → FillPinCode → FillEmail → FillPassword.
Enum SignUpOrSignInOutcome: Registered (создан новый инвестор) / SignedIn (найден существующий).
FullName — дом полей в domain/user.md (VO: firstName, lastName, middleName?, max 128).
Общие правила безопасности (все 18 операций)
| Правило | Значение |
|---|---|
| Rate-limit отправки кодов | INV-S4 (user-session.md): ≤ 1 СМС на номер в 60 сек, ≤ 5 в час (по PhoneNumber + IpAddress) → IDENTITY_CONFIRMATION_RATE_LIMITED (429) |
| Попытки кода | INV-S2: 5 неверных вводов → запрос Exhausted, нужен новый request-шаг |
| TTL кода | INV-S3: 5 минут (ExpiresAt) |
| Lockout | INV-8 (user.md): 10 неуспешных проверок пароля/пин-кода → LockoutUntil = now + 15 мин |
| Маскирование PII | Телефон в логах/событиях UI — +7***1234; email — d***@mail; сами коды/пароли/пин-коды не логируются никогда; хранение — только хэши (HMAC-SHA256 для кодов, Argon2id для пароля/пин-кода) |
| User enumeration | Ошибки входа не раскрывают, существует ли номер: единый IDENTITY_SIGN_IN_FAILED-паттерн для неверного пароля/пин-кода; исключение: signUp возвращает конфликт телефона (DUPLICATE_PHONE-паттерн) — зафиксировано как известное поведение |
| Тест-контур | realConfirmationCodeDispatched = false — код не отправлялся реально (заглушка verifier), в тест-контуре действует фиксированный код |
Следующий шаг входа: разрешение неоднозначности
Ответ шага входа несёт ровно одно значение SignInNextStep. Если у инвестора заданы и пароль, и
пин-код, сервер выбирает шаг детерминированно (единый порядок на всех клиентах), клиент не решает сам.
RequiresSmsCode возвращается, когда сильных факторов нет (свежая lazy-регистрация) либо пользователь
явно инициировал вход по коду. Конкретный приоритет — в документе операции входа; клиент обрабатывает
любое из трёх значений и не предполагает, что вернётся именно СМС-ветка.
Асинхронные последствия входа (окно согласованности)
Успешный вход завершается синхронно выдачей JwtTokenModel (200); дальнейшие эффекты — асинхронные и
пользователь видит их с небольшим лагом (секунды):
- публикуется
UserSignedInKafkaEvent(pin.identity.sign-ins.v1, key =UserId) — по немуuser-activity/history/favorites связывают анонимную сессию (anonymous_idизreferrerUrl/клиента) с учёткой: история просмотров и избранное, накопленные до входа, «доклеиваются» к пользователю после применения события, не в момент ответа; - по тому же событию срабатывает алерт о входе с нового устройства (
notifications); - до применения события клиент может краткий промежуток не видеть смёрженную анонимную историю — это ожидаемое поведение, повторное действие не требуется.
Операции refresh-flow investor-области
Расширение auth-контракта; вводится под feature-флагом identity.refresh-flow.enabled.
| Операция | HTTP | Route | Feature group | Актор / доступ | Документ |
|---|---|---|---|---|---|
| refreshToken | POST | /api/v1/auth/refresh | auth | Anonymous (аутентификация refresh-токеном) | refresh-token.md |
| signOut | POST | /api/v1/auth/sign-out | auth | authenticated | sign-out.md |
Агент-онбординг investor-области (ADR-0061)
Self-действия инвестора-адресата приглашения и самостоятельного перехода в агенты. Авторизация accept/decline — по совпадению телефона (INV-CI2), не по tenant.
| Операция | HTTP | Route | Feature group | Актор / доступ | Документ |
|---|---|---|---|---|---|
| acceptInvitation | POST | /api/v1/me/agent-invitations/{invitationId}/accept | agent-onboarding | User (адресат, phone-match) | accept-invitation.md |
| declineInvitation | POST | /api/v1/me/agent-invitations/{invitationId}/decline | agent-onboarding | User (адресат, phone-match) | decline-invitation.md |
| becomeAgent | POST | /api/v1/me/become-agent | agent-onboarding | User (инвестор, self) | become-agent.md |
Операции остальных областей
Реестры не-investor областей — в подпапках (см. «Области API» выше); здесь только указатели:
- company-user (компании / роли / permissions / назначения, 16 операций; +приглашение и отзыв агента по телефону, ADR-0061) — company-user/README.md.
- agent (self-действия агента: выход из агентства, возврат к инвестору, ADR-0061) — agent/README.md.
- admin (блокировка / удаление / сброс факторов / отзыв сессий учёток, m2m, ADR-0053) — admin/README.md. Создание компаний Agency/Broker/Partner и платформенных ролей — отдельная система администрирования, здесь не документируется.
- internal (authorize/check-permission, m2m enforcement) — internal/README.md.
Связанные документы
- Домены: user.md (агрегат
UserEntity, INV-1..11), user-session.md (SignInConfirmationRequest, INV-S1..S8;RefreshSession). - Реестры областей: company-user/README.md, agent/README.md, admin/README.md, internal/README.md; сервис — ../README.md.