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

Event Contract: pin.profile.verification-request-submitted (VerificationRequestSubmittedKafkaEvent)

Версионируемый контракт интеграционного события «заявка на верификацию инвестора отправлена на ревью». Consumer-документы ссылаются сюда, не переописывая payload. Дом полей — entity: VerificationRequestEntity (раздел «Доменные и интеграционные события»).

Назначение

Фиксирует переход заявки KYC/AML Draft → Submitted (метод Submit агрегата, verification-request.md): инвестор заполнил ФИО, дату рождения, паспортные данные, приложил сканы (инварианты INV-VRF-2 CompleteOnSubmit, INV-VRF-4 AdultOnly), и заявка с зафиксированным иммутабельным зашифрованным снапшотом встала в очередь ревью сотрудников ПИН (FIFO по SubmittedAt).

Событие — сигнальное, без PII: потребителям (notifications, support) достаточно знать, что появилась работа для очереди ревью; сами данные заявки доступны только ревьюеру через admin API profile (viewVerificationSnapshot, аудируемая расшифровка). Итог рассмотрения публикуется отдельным контрактом того же топика — verification-completed (покрывает оба исхода: Approved и Rejected).

Metadata

ПолеЗначение
Event typepin.profile.verification-request-submitted
C# typeVerificationRequestSubmittedKafkaEvent
Topicpin.profile.verification-requests.v1 (общий с VerificationCompletedKafkaEvent; общий key = порядок per-user)
Partitions / key3 партиции (ADR-0056: 1–10k активных) / key = OwnerUserId — строгий порядок submitted/completed per user
ContractVersionstatic int ContractVersion = 1
Producerprofile: handler submitVerification (public API, permission profile.verification.submit)
Owning teamPIN Platform Core
Статусdraft

Метаданные события — идентификатор сообщения, время события CreatedAt, версия (= ContractVersion), payload, AggregateId = Id (заявка), AggregateType = "VerificationRequest". Trace — на outbox-записи. Событие публикуется через транзакционный outbox атомарно с фиксацией снапшота заявки и обновлением Profile.VerificationStatus → Pending (одно согласованное изменение: заявка + ProfileEntity + событие).

TenantId отсутствует: инвестор вне tenant (ADR-0052); изоляция record-level по OwnerUserId.

Payload VerificationRequestSubmittedKafkaEvent

ПолеТипОбязательностьИсточник (поле агрегата)CompatibilityОписание
IdGuidДаVerificationRequestEntity.IdImmutableИдентификатор заявки (= AggregateId). Один Id может быть отправлен повторно после Revoke → доработка → повторный Submit (см. идемпотентность потребителей).
OwnerUserIdGuidДаVerificationRequestEntity.OwnerUserIdImmutableВерифицируемая учётная запись (= Kafka key); получатель подтверждения «заявка принята».
SubmittedAtDateTimeOffsetДаVerificationRequestEntity.SubmittedAtImmutable per submitМомент постановки в очередь ревью (FIFO-сортировка очереди). При повторном Submit после Revoke — новое значение.

Вложенных моделей нет. Снапшот заявки (VerificationSnapshotModel), PersonId, сканы, статусы — в payload не входят: PII не публикуется, а статусная детализация потребителям сигнала не нужна.

Когда публикуется

УсловиеПереход состоянияТранзакция
submitVerification: метод Submit собрал и зашифровал снапшот (INV-VRF-2, INV-VRF-4, INV-VRF-7)Draft → Submitted; параллельно `Profile.VerificationStatus: NotVerifiedRejected → Pending`
Повторный Submit той же заявки после Revoke (доработка инвестором)Draft → Submitted (новый снапшот, новый SubmittedAt)та же

Переход Submitted → Draft (Revoke) события не публикует: заявка просто исчезает из очереди ревью (admin API читает очередь из БД profile по Status = Submitted), а потребители-сигналы отзыва не обрабатывают (тикет support закрывается вручную/при итоговом событии).

Потребители (consumers)

Consumer-контекстConsumerSide effectsИдемпотентностьЗадержка (SLA)
notificationsNotificationsVerificationSubmittedConsumerПодтверждение инвестору «заявка принята, рассматривается» (канал по настройкам получателя); служебное уведомление команде ревью о новой заявке в очередиMessageId + business key Id:SubmittedAt (повторный Submit — новое уведомление, дубль доставки — skip)< 5 мин
supportSupportVerificationSubmittedConsumerТикет в очереди ревью KYC (маршрутизация на сотрудников с profile.verification.review); тикет содержит только Id/OwnerUserId — данные заявки открываются в admin API profileтот же business key< 5 мин

Consumer-документы — будущие пути docs/06-services/notifications/consumers/profile-verification-submitted.md и docs/06-services/support/consumers/profile-verification-submitted.md (контексты по будущим ТЗ; конвенция ссылок).

Доставка и восстановление

  • At-least-once через транзакционный outbox. Событие фиксируется в одном согласованном изменении с переходом заявки Draft → Submitted и Profile.VerificationStatus → Pending; недоступность брокера не откатывает отправку заявки (снапшот зафиксирован в БД), публикация досылается ретраем. Возможны дубли.
  • Порядок per-user по key = OwnerUserIdsubmitted и completed одного пользователя упорядочены.
  • Повторный Submit после Revoke порождает новое событие того же Id с новым SubmittedAt; потребитель различает попытки по business key Id:SubmittedAt (новая попытка — новое уведомление/тикет; дубль доставки той же попытки — skip).
  • Revoke (Submitted → Draft) события не публикует: заявка исчезает из очереди ревью (admin API читает очередь из БД по Status = Submitted); тикет support закрывается вручную или по итоговому verification-completed.
  • Poison-message. Необрабатываемое после ретраев событие → DLQ контекста-потребителя + alert; заявка в profile остаётся источником истины (очередь читается из БД), восстановление — ре-плей из DLQ.

Версионирование и совместимость (реальность SDK)

  • ContractVersion = 1; при envelope.Version != ContractVersion consumer логирует warning и продолжает (upcasting в SDK нет).
  • Additive-only: новые optional-поля с default — без bump.
  • Breaking — ContractVersion = 2 + топик pin.profile.verification-requests.v2 + dual-publish обоих контрактов топика + deadline миграции consumers + sunset .v1.
  • Enum-полей в payload нет — unknown enum handling не применяется.
  • Порядок per-user гарантирован key = OwnerUserId (submitted и completed одного пользователя упорядочены между собой).

Безопасность

ПолеКласс данныхПравило
Id, OwnerUserId, SubmittedAtInternalinclude

Событие НЕ содержит PII (ФИО/дата рождения/паспортные данные — только в зашифрованном SnapshotCipher БД profile), ссылок на сканы, secrets, tokens. Доступ к топику — m2m ACL Kafka (notifications, support). Уведомления потребителей не должны включать значения данных заявки — только факт и ссылку на ЛК/admin.

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

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

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

  • Сущность (дом полей, инварианты, stateDiagram): verification-request.md; денормализация статуса: profile.md (ProfileVerificationStatus).
  • Соседний контракт того же топика: verification-completed.md.
  • Источник (операция): submitVerification — карта API в README; admin-очередь ревью — listVerificationQueue/takeVerificationInReview (там же).
  • Решения: ADR-0052 (инвестор вне tenant), ADR-0056 (simplicity-first).