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

Event Contract: pin.selections.selection-deleted (SelectionDeletedKafkaEvent)

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

Назначение

Фиксирует soft delete подборки владельцем (DELETE /selections/{id}DeletedAt = now). Потребитель — user-activity (ActionEvent «удалил подборку», ADR-0054). Событие — уведомительный факт, а не механизм консистентности: ссылки CRM и snapshot-ы постов остаются разрешимыми благодаря soft delete, а публичное открытие удалённой подборки API само вернёт 404 (INV-SEL-009) — потребителям не нужно ничего чистить по этому событию.

Metadata

ПолеЗначение
Event typepin.selections.selection-deleted
Topicpin.selections.selection-deleted.v1
Partitions / key3 партиции / key = AggregateId = SelectionId
ContractVersion1
Producerselections: DELETE /selections/{id}
Owning teamPIN Engagement
Статусdraft

Событие публикуется атомарно с простановкой DeletedAt (переход подборки в статус Deleted): пока изменение не зафиксировано, событие не отправляется потребителям; после фиксации — доставляется гарантированно (at-least-once). Ключ агрегата — SelectionId, тип агрегата — Selection.

Payload SelectionDeletedKafkaEvent

ПолеТипОбязательностьИсточник (поле агрегата)CompatibilityОписание
SelectionIdGuidДаSelection.IdImmutableУдалённая подборка (= AggregateId, = Kafka key).
OwnerUserIdGuidДаSelection.OwnerUserIdImmutableВладелец — субъект ActionEvent (удалить может только он, INV-SEL-002).
OccurredAtDateTimeOffsetДаSelection.DeletedAtImmutableМомент soft delete (дублирует время события).

Title и состав в payload не входят: ActionEvent ленты действий ссылается на SelectionId (отображение названия удалённой подборки истории не требуется). Вложенных моделей нет.

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

УсловиеПереход состоянияПубликация
DELETE /selections/{id} — подборка владельца найдена и была активна; повторный DELETE уже удалённой — идемпотентный успех без события (INV-SEL-009: удалённая не переходит никуда)Selection: Active → Deleted (DeletedAt = now, строки и items сохраняются)атомарно с простановкой DeletedAt

Событие не публикуется при отвязке snapshot-ов (Detach, зона selection-snapshot.md) и не существует события «подборка восстановлена» — восстановление из soft delete предусмотрено только runbook-ом вручную (../README.md, Runbooks); при появлении пользовательского restore событие добавится additive (pin.selections.selection-restored.v1).

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

Consumer-контекстConsumerЭффект (событие → что меняется)ИдемпотентностьЗадержка (SLA)
user-activityUserActivitySelectionDeletedConsumer (будущий док: docs/06-services/user-activity/consumers/selections-actions.md)ActionEvent «удалил подборку» в историю действий OwnerUserIdMessageId (дубль — skip)< 1 мин

crm на топик не подписан (осознанно): CRM при открытии удалённой подборки получает 404 от GET /internal/selections/{id} и показывает «подборка удалена» — событие не обязано доходить, консистентность держится на API (selection.md, таблица событий). news не подписан: посты живут на snapshot-ах, которые soft delete подборки не трогает (FK restrict, INV-SNP-006).

Доставка и обработка отказов

  • At-least-once через outbox (атомарно с простановкой DeletedAt); повторный DELETE уже удалённой события не даёт (INV-SEL-009) — дубли на источнике исключены до Kafka.
  • Событие — уведомительный факт, а не механизм консистентности: даже полная потеря/DLQ события безопасна — публичное открытие удалённой подборки API само вернёт 404 (INV-SEL-009), ссылки CRM и snapshot-ы остаются разрешимыми (soft delete). user-activity дедуплицирует по MessageId.
  • Транзиентный сбой консюмера → повторная доставка до ack; неустранимая → DLQ + alert. Общая политика — README.md, раздел «Доставка, идемпотентность и обработка отказов».

Версионирование и совместимость

  • ContractVersion = 1; несовпадение версии события — warn-and-proceed.
  • Additive-only без bump; breaking — ContractVersion = 2 + топик pin.selections.selection-deleted.v2 + dual-publish + sunset .v1.
  • Enum-полей нет.
  • Кросс-топиковый порядок с created/updated не гарантирован — consumer упорядочивает по OccurredAt; deleted, пришедший раньше created, — терпимый кейс (проекция upsert-ом).

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

ПолеКласс данныхПравило
SelectionId, OccurredAtInternalinclude
OwnerUserIdInternalinclude
Title, Description, состав, PublicCodeInternal/зона владельцаexclude

Событие НЕ содержит secrets, tokens, PII-профиля.

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

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

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