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

GET /api/v1/profile/persons/{personId} — Получение персоны (getPerson)

Назначение

Вернуть одну персону текущего инвестора с расшифрованными персональными данными — для карточки/формы редактирования персоны в ЛК. Документы персоны отдаёт отдельный метод list-person-documents.md (агрегат в ответе не разворачивается — UI загружает документы лениво по табу). Вызывает инвестор-владелец персоны.

Metadata

ПолеЗначение
Сервис/контекстprofile
API areapublic
Feature grouppersons
Статусdraft
Документdocs/06-services/profile/api/public/get-person.md

Актор и доступ

ПроверкаЗначение
Actor typeUser (Bearer JWT), UserType = Investor
Auth policy / Permissionsauthenticated; permission profile.personal.view-self
Scope (RBAC)self
Record-levelPersonEntity.OwnerUserId = UserId; чужой personId → 404 (не раскрываем существование)
Tenant isolationне применяется (ADR-0052)
Auditread-sensitive: self-расшифровка не аудируется; значения в логи не пишутся

HTTP-контракт

ПолеЗначение
MethodGET
Route/api/v1/profile/persons/{personId}
Success status200
Idempotency headerне применяется
Correlationсквозной trace через заголовок traceparent

Входные данные / параметры запроса

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
UserIdidentity claims (sub)GuidДавалидный JWT401 без токена
personIdrouteGuidДаNotEmpty; существующая персона владельцачужая → 404

Модель ответа PersonModel

Дом модели — list-persons.md (без переописания): id, relation, status, расшифрованные firstName/lastName/middleName/birthDate, citizenshipCountryId, gender, documentsCount, createdAt, updatedAt, version.

Алгоритм

  1. Контекст и доступ. Операцию выполняет инвестор (UserId из токена); tenant не применяется; требуется право profile.personal.view-self.
  2. Проверка входа. personId задан. Нарушение → ValidationError.
  3. Проверка предусловий. Профиль владельца существует; иначе PROFILE_NOT_FOUND. Тип пользователя — Investor (иначе PROFILE_PERSONS_NOT_ALLOWED_FOR_USER_TYPE, INV-PRF-4). Персона personId существует и принадлежит владельцу; иначе PROFILE_PERSON_NOT_FOUND — единый 404, чтобы не раскрывать существование чужих id. Архивная персона возвращается (read допустим; UI показывает бейдж «в архиве»).
  4. Маппинг с расшифровкой. Расшифровать firstName/lastName/middleName/birthDate ключом версии записи; недоступность ключей — fail-closed PROFILE_CRYPTO_UNAVAILABLE. Спроецировать поле-в-поле по таблице PersonModel (list-persons.md).
  5. Результат. Модель PersonModel; HTTP 200.

Побочные эффекты

ТипДетали
Внешние вызовыпровайдер ключей шифрования (in-process кэш) для расшифровки ФИО/даты рождения; недоступность → PROFILE_CRYPTO_UNAVAILABLE

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
— (auth)401Нет/просрочен JWTбез телаre-login
ValidationError400Пустой personIdперечень невалидных полейno retry
PROFILE_NOT_FOUND404Профиль не создан консюмером«Профиль ещё создаётся»retry с backoff
PROFILE_PERSONS_NOT_ALLOWED_FOR_USER_TYPE403UserType != Investor«Раздел доступен только инвесторам»no retry
PROFILE_PERSON_NOT_FOUND404Персона не существует или принадлежит другому пользователю«Персона не найдена»no retry
PROFILE_CRYPTO_UNAVAILABLE503Недоступны ключи шифрования«Сервис временно недоступен»retry

Совместимость и наблюдаемость

  • Additive-расширение PersonModel — см. list-persons.md.
  • Logs: UserId, PersonId (без значений); metrics: profile_api_operations_total{operation="getPerson",result}; traces — OTel.

Acceptance Criteria

  • Given активная персона владельца, When GET /persons/{personId}, Then 200; firstName/lastName/middleName/birthDate расшифрованы ключом версии записи; документы в ответе не разворачиваются (грузятся отдельным методом).
  • Given архивная персона владельца, When GET, Then 200 — чтение допустимо (UI показывает бейдж «в архиве»).
  • Given personId чужой или несуществующий, When GET, Then PROFILE_PERSON_NOT_FOUND (404) — единый 404, существование чужих id не раскрывается.
  • Given ключи шифрования недоступны, When GET, Then PROFILE_CRYPTO_UNAVAILABLE (503), fail-closed.
  • Given UserType != Investor, When GET, Then PROFILE_PERSONS_NOT_ALLOWED_FOR_USER_TYPE (403).
  • Given профиль ещё не создан консюмером identity, When GET, Then PROFILE_NOT_FOUND (404), retry.
  • Given любой успешный ответ, Then расшифрованные значения возвращаются только владельцу (record-level по OwnerUserId) и никогда не пишутся в логи.

Обратные ссылки

Автоссылки: где используется этот документ.

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