GET /api/investors/me — Текущий инвестор (getCurrentInvestor)
Назначение
Прочитать профиль текущего аутентифицированного инвестора: ФИО, контакты и флаги безопасности
(isTwoFactorEnabled, hasPassword, hasPinCode). Вызывается клиентом при инициализации сессии; ответ
401 означает недействительный токен и приводит клиент к очистке локальной сессии. Данные отдаются только
владельцу записи.
Metadata
| Поле | Значение |
|---|---|
| Сервис/контекст | identity |
| API area | public |
| Feature group | profile |
| Статус | approved |
| Документ | docs/06-services/identity/api/investor/get-current-investor.md |
Актор и доступ
| Проверка | Значение |
|---|---|
| Actor type | User (Bearer JWT) |
| Auth policy / Permissions | authenticated; permission identity.users.view-self |
| Scope (RBAC) | self (роль не требуется) |
| Record-level | только собственная запись: UserId из claim sub |
| Tenant isolation | не применяется (инвестор вне tenant, ADR-0052); для пользователей компаний — та же операция self |
| Audit | read-sensitive (PII в ответе — только владельцу) |
HTTP-контракт
| Поле | Значение |
|---|---|
| Method | GET |
| Route | /api/investors/me |
| Success status | 200 |
| Idempotency header | не применяется (safe GET) |
| Correlation | сквозной trace через traceparent |
Входные данные / параметры запроса
Body/route/query-параметров нет.
| Поле | Источник | Тип | Обязательность | Валидация / Ограничения | Безопасность |
|---|---|---|---|---|---|
UserId | identity claims (sub) | Guid | Да | валидный JWT (подпись, exp, notBefore) | 401 при отсутствии/просрочке |
Модель ответа GetCurrentInvestorQueryResult
| Поле | Тип | Обязательность | Источник | Masking | Описание |
|---|---|---|---|---|---|
investorId | string (Guid) | Да | UserEntity.Id | — | Идентификатор инвестора. |
name | FullName | Да | VO Name (firstName, lastName, middleName?) | — (владелец) | ФИО; lastName может быть пустой строкой (lazy-регистрация). |
phoneNumber | string | Да | UserEntity.PhoneNumber (E.164) | без маскирования (владелец) | Основной логин. |
email | string? | Нет | UserEntity.Email | — (владелец) | Email, если задан. |
isTwoFactorEnabled | bool | Да | UserEntity.IsTwoFactorEnabled | — | Флаг 2FA. |
hasPassword | bool | Да | computed: пароль установлен | хэш не раскрывается | Установлен ли пароль. |
hasPinCode | bool | Да | computed: пин-код задан | хэш не раскрывается | Задан ли пин-код. |
createdAt | string (ISO 8601) | Да | UserEntity.CreatedAt | — | Дата регистрации. |
Алгоритм
- Auth-middleware проверяет валидность JWT до операции (иначе 401, клиент очищает локальную сессию).
- Получить пользователя по
UserIdиз claimsub; при статусеBlocked/Archived—IDENTITY_USER_BLOCKED. - Отдать профиль (маппинг поле-в-поле — таблица ответа); производные
hasPassword/hasPinCodeвычисляются по наличию соответствующих хэшей, сами хэши в модель не читаются. - Чтение из основного хранилища (read-your-writes): изменения только что завершённых self-операций
(
setPinCode,changePassword,confirmEmailChange) видны сразу, реплики других контекстов не задействованы. - Операция read-only — гонок и переходов статуса нет. HTTP 200.
Замечания по границам:
lastNameпри lazy-регистрации может быть пустой строкой (неnull) — контрактFullName(user.md);middleNameотсутствует, если не задан.- Та же self-операция обслуживает и пользователей компаний (менеджер застройщика, агент): для них ответ
несёт те же поля; tenant-фильтр не применяется (self по
UserId).
Отложенный отзыв (accepted degradation)
Access-JWT сессии, по которой уже выполнен sign-out, но срок exp (≤ 15 мин) ещё не истёк, продолжает
возвращать профиль — отзыв сессии на чтении профиля не проверяется (согласовано с
sign-out.md; риск ограничен коротким TTL access-токена).
Предусловия и постусловия
- Пред: запрос несёт валидный access-JWT; субъект (
sub) существует. Профиль — источник истины identity, реплики не требуются. - Пост (успех): состояние не меняется (safe GET); клиент получил актуальный снапшот профиля и флагов безопасности. Ни события, ни аудит-записи не порождаются (кроме read-sensitive-лога факта чтения).
Acceptance Criteria
- Given валидный JWT инвестора
Active, WhenGET /api/investors/me, Then200с профилем (маппинг поле-в-поле),isTwoFactorEnabled/hasPassword/hasPinCodeотражают текущее состояние, хэши пароля/пин-кода не раскрываются. - Given инвестор только что вызвал
setPinCode, WhenGET /meследующим запросом, ThenhasPinCode = trueнемедленно (read-your-writes). - Given lazy-регистрированный инвестор без фамилии, When
GET /me, Then200сname.lastName = ""(пустая строка, неnull),name.middleNameотсутствует. - Given запрос без токена / с просроченным / невалидным JWT, When
GET /me, Then401без схемы тела; клиент очищает локальную сессию и уходит на re-login. - Given учётка, ставшая
BlockedилиArchivedпосле выдачи токена, WhenGET /me, ThenIDENTITY_USER_BLOCKED(400). - Given access-JWT сессии, по которой уже выполнен
sign-out, ноexpещё не истёк, WhenGET /me, Then200(отложенный отзыв — принятая деградация в окне ≤ 15 мин).
Ошибки и failure modes
| Код | HTTP status | Условие | Сообщение | Retry |
|---|---|---|---|---|
| — (auth) | 401 | Нет/просрочен/невалиден JWT | без тела схемы (клиент очищает сессию) | re-login |
IDENTITY_USER_BLOCKED | 400 | Status ∈ {Blocked, Archived} | «Учётная запись заблокирована» | no retry |
Совместимость и наблюдаемость
- Модель используется всеми экранами личного кабинета; новые optional поля — additive; удаление/переименование — breaking (migration + rollout).
- Logs: только
UserId(без PII-значений); metrics:identity_me_requests_total; traces — OTel.
Обратные ссылки
Автоссылки: где используется этот документ.
- API (4): Identity API — карта областей и реестр investor-области, POST /api/investors/me/email/change-confirm — Подтверждение смены email (confirmEmailChange), POST /api/investors/me/pin-code/set — Установка/обновление пин-кода (setPinCode), PUT /api/investors/me — Обновление профиля инвестора (updateInvestor)
- registries (1): Реестр API-методов PIN
Связанные документы
- Сущность: user.md (дом полей;
FullNameVO). - Мутации профиля: update-investor.md; безопасность: change-password.md, set-pin-code.md, 2FA-flows.