Event Contract: pin.support.arbitrage-resolved (ArbitrageResolvedKafkaEvent)
Версионируемый контракт интеграционного события «арбитражное дело завершено (решение вынесено или
эскалировано)». Consumer-документы ссылаются сюда, не переописывая payload. Событие фиксирует терминальный
исход ArbitrageCaseEntity (arbitrage-case.md) — вынесение решения (6.3) или
эскалацию администратору (6.5) — и служит информированию сторон конфликта (6.4).
Назначение
Даёт notifications факт завершения арбитража, чтобы информировать стороны (заявитель + ответчики) об
исходе без синхронного запроса в support (матрица 6.4). Событие несёт исход (Outcome), тип конфликта,
признак эскалации и id сторон — ФИО/контакты потребитель резолвит из своей реплики identity. Ручные
последствия решения (смена статуса сделки / переназначение фиксации / корректировка комиссии) выполняются в
crm/rewards через выданные support platform-scope permissions и этим событием не переносятся —
AuditRefs в ArbitrageNoteEntity фиксируют факт (arbitrage-case.md). Эскалация администратору
принимается администратором платформы (ADR-0053).
Metadata
| Поле | Значение |
|---|---|
| Event type | pin.support.arbitrage-resolved |
| Topic | pin.support.arbitrage-resolved.v1 |
| Partitions / key | 3 (низкий объём, ADR-0056) / ключ = CaseId (= AggregateId; per-case порядок) |
| ContractVersion | 1 |
| Producer | support: resolve-arbitrage-case (Resolve → Resolved) и escalate-arbitrage-case (Escalate → Escalated) — ../api/support/resolve-arbitrage-case.md, ../api/support/escalate-arbitrage-case.md |
| Статус | draft |
Событие публикуется атомарно с переходом дела в
Resolved/Escalatedи записью иммутабельногоDecision: пока изменение не зафиксировано, событие не отправляется потребителям; после фиксации — доставляется гарантированно (at-least-once). Метаданные события:MessageId(Guid v7, для дедупликации),AggregateId = CaseId(= Kafka key, per-case порядок),AggregateType = "ArbitrageCase".
Payload ArbitrageResolvedKafkaEvent
Дом полей — entity: ArbitrageCaseEntity (раздел «Доменные и интеграционные
события», VO ArbitrageDecision, jsonb ArbitrageParties); здесь перечислено только то, что реально в
событии. RespondentUserIds — типизированный список id, проекция Respondents.Items.
| Поле | Тип | Обязательность | Источник (ArbitrageCaseEntity) | Compatibility | Описание |
|---|---|---|---|---|---|
CaseId | Guid | Да | Id | Immutable | Ключ агрегата (= Kafka key). |
Number | long | Да | Number | Immutable | Номер ARB-NNN для текста уведомления/диплинка. |
TenantId | Guid | Да | TenantId | Immutable | PIN CompanyId (единый tenant платформы). |
Type | string (enum ArbitrageType) | Да | Type | Additive only (новые значения) | Тип конфликта (AgentPriorityConflict/BookingConflict/CommissionDispute/ContentComplaint/Other). |
Outcome | string (enum ArbitrageOutcome) | Да | Decision.Outcome | Additive only | Исход (FavorComplainant/FavorRespondent/SplitResolution/NoViolation/EscalatedToAdmin). |
Escalated | bool | Да | Status == Escalated | Additive only | true — дело эскалировано администратору (6.5); false — решение вынесено (6.3). |
ComplainantUserId | Guid | Да | ComplainantUserId | Immutable | Заявитель — адресат информирования (id, не PII). |
RespondentUserIds | IReadOnlyList<Guid> | Да (может быть пустым) | Respondents.Items | Additive only | Ответчики — адресаты информирования (типизированный список id, <= 50). |
RelatedDealId | Guid? | Нет | RelatedDealId | Additive only | Привязка к сделке (crm), если есть (контекст уведомления). |
DecidedByUserId | Guid | Да | Decision.DecidedByUserId | Immutable | Кто вынес решение/эскалировал (супервизор). |
DecidedAt | DateTimeOffset | Да | Decision.DecidedAt | Immutable | Момент вынесения решения/эскалации. |
Enum-значения не дублируются — дом arbitrage-case.md → «Enum ArbitrageType/ArbitrageOutcome».
Title, Description, Decision.Rationale, заметки расследования (ArbitrageNoteEntity) и ФИО/телефон
сторон в payload не входят: обоснование решения — Internal (читается по API дела с permission
support.arbitrage.view), текст уведомления notifications формирует по Outcome/Type, display-подписи —
из реплики identity.
Когда публикуется
| Условие | Переход состояния | Публикация |
|---|---|---|
Resolve (супервизор, Decision задан — INV-ARB-2) | UnderInvestigation → Resolved (Escalated = false) | атомарно со сменой состояния агрегата |
Escalate (супервизор, support.arbitrage.decide — INV-ARB-3) | UnderInvestigation → Escalated (Outcome = EscalatedToAdmin, Escalated = true) | та же |
Регистрация дела (6.1), старт расследования (6.2) и добавление заметок Kafka-события не порождают —
внешнему потребителю нужен только терминальный исход. Закрытие (→ Closed) события не публикует (пост-финал).
Потребители (consumers)
| Consumer-контекст | Side effects | Идемпотентность | Задержка (SLA) |
|---|---|---|---|
notifications | Информирование сторон (заявитель + RespondentUserIds) об исходе (6.4); при Escalated = true — уведомление о передаче администратору; каналы получателей — своя реплика identity | дедупликация по MessageId + per-case порядок по ключу | < 1 мин |
Отображаемые имена сторон консюмер берёт из собственных реплик identity, не из этого события; список
получателей вычисляется из ComplainantUserId + RespondentUserIds.
Доставка и восстановление. At-least-once; дедупликация по MessageId (first-seen) — терминальный исход
одного дела информируется ровно один раз даже при повторной доставке. Транзиентный сбой — ретраи, исчерпание
→ DLQ с алертом (без блокировки партиции). Событие терминально и самодостаточно (Outcome/Escalated/Type
- id сторон); межтопикового порядка с событиями тикета нет (арбитраж — отдельный агрегат/ключ
CaseId), см. README.md («Гарантии доставки, порядка и восстановления»).
Версионирование и совместимость
ContractVersion = 1; приVersion != ContractVersionconsumer логирует warning и продолжает обработку. Топик кодирует версию суффиксом.v1по конвенции.- Additive-only для minor: новые optional-поля с безопасным default — без bump. Новые значения enum
ArbitrageType/ArbitrageOutcome— additive. - Breaking —
ContractVersion = 2+ новый топикpin.support.arbitrage-resolved.v2+ dual-publish + deadline миграции consumers + sunset.v1. - Unknown enum (
Type/Outcome) — fallback: сохранить строку как есть, warning, не падать (уведомление с нейтральной формулировкой исхода).
Безопасность
Событие несёт только идентификаторы, enum-значения, флаг и метку времени — прямого PII нет по
построению: ФИО/телефон/email сторон исключены (консюмер резолвит из своей реплики identity); текст
обоснования (Rationale, Internal) в payload не выносится.
| Поле | Класс данных | Правило |
|---|---|---|
CaseId, Number, TenantId, ComplainantUserId, RespondentUserIds, RelatedDealId, DecidedByUserId | Internal | include (id/номер, не PII) |
Type, Outcome, Escalated | Internal | include |
DecidedAt | Internal | include |
Событие НЕ содержит secrets, tokens, ФИО/телефон/email сторон, Rationale/описание дела, заметки
расследования, аудит-ссылки, вложения. Доступ к топику — m2m ACL Kafka (notifications).
Обратные ссылки
Автоссылки: где используется этот документ.
- Домен (CQRS) (1): Entity / Aggregate: ArbitrageCaseEntity (+ ArbitrageNoteEntity)
- API (2): POST /api/support/arbitrage-cases/{id}/escalate — Эскалация дела администратору, POST /api/support/arbitrage-cases/{id}/resolve — Вынести решение по делу
- Use Cases (2): UC-SUP-003. Арбитраж конфликта через аудит, UC-SUP-005. Эскалация администратору
- События (4): События сервиса support: карта топиков и решения об интеграциях, Event Contract: pin.support.ticket-created (TicketCreatedKafkaEvent), Event Contract: pin.support.ticket-message-posted (TicketMessagePostedKafkaEvent), Event Contract: pin.support.ticket-status-changed (TicketStatusChangedKafkaEvent)
- Дашборды (1): Панель Наблюдаемости: support-overview (эксплуатация)
- registries (1): Реестр событий PIN
- index.md (1): Support Service
Связанные документы
- Источник (операции): ../api/support/resolve-arbitrage-case.md,
../api/support/escalate-arbitrage-case.md; сущность —
arbitrage-case.md (
ArbitrageOutcome,ArbitrageDecision, INV-ARB-1..3). - Соседние контракты топиков
support: ticket-created.md, ticket-status-changed.md; карта — README.md. - Границы эскалации — ADR-0053.