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

События invest-analytics: карта контрактов

Индекс-каталог events/. Контекст invest-analytics публикует два интеграционных Kafka-события; топики по конвенции pin.invest-analytics.<event>.v1. Отдельные не-событийные потоки (история цен, расчётные серии) по-прежнему читаются через public API — обоснование сохранено ниже.

Produced-события (интеграционные, Kafka)

СобытиеТопикКогда публикуетсяПотребителиКонтракт
PropertyObjectMetricsUpdatedKafkaEventpin.invest-analytics.property-object-metrics.v1Пересчёт витринных метрик доходности объекта недвижимости (триггеры: изменение цены, правка эконом-модели, плановый пересчёт)catalog (денормализация метрик карточки/ленты)property-object-metrics.md
EconomicModelChangedKafkaEventpin.invest-analytics.model-changed.v1Правка эконом-модели админом (scope Global / PropertyObjectType)invest-analytics (self — internal recompute job → переиздание property-object-metrics.v1)model-changed.md

Поток замыкается внутри: model-changed (правка модели) → recompute job → property-object-metrics (снапшот метрик) → catalog (витрина). Так каталог остаётся denormalized-конечной точкой и не знает об эконом-модели (ADR-0056). Оба события публикуются через транзакционный outbox, атомарно с мутацией агрегата/фиксацией пересчёта.

Гарантии доставки produced-событий

Аспектmodel-changed.v1property-object-metrics.v1
Доставкаat-least-once (транзакционный outbox)at-least-once (транзакционный outbox)
Ключ партиционирования / порядокChangeScope (правки модели редки)PropertyObjectId — порядок snapshot-ов по объекту сохранён
Идемпотентность подписчикамонотонный guard по (ChangeScope, GroupId, Version)монотонный guard по AsOf
Публикация no-opне публикуется, если данные не изменилисьне публикуется, если snapshot совпал при том же AsOf
Исчерпание retryсообщение в DLQ + алерт; метрики затронутого scope остаются на прежних значенияхсообщение в DLQ + алерт; карточка сохраняет прежние метрики

Оба события несут snapshot/scope-семантику, а не дельту: повторная доставка или переигрывание топика приводит подписчика к тому же конечному состоянию (перечитать модель по scope / применить более свежий snapshot). Это делает rebuild проекций каталога и replay топика безопасными.

Что НЕ стало событием (осознанно)

#ДанныеПочему pull (public API), а не push
1История цен объекта недвижимостиНужна фронту (график /lots/[id]/analytics) и investor-owner (динамика портфеля) — оба читают public API GET property-objects/{propertyObjectId}/price-history по запросу. Факт «цена изменилась» уже существует у владельца — pin.chessboard.property-object-price-changed.v1; ретрансляция создала бы второй источник того же факта
2Расчётные серии (InvestorMonth[]/AnalyticsSeries/AsideMetrics)Вычисляются на каждый запрос и не персистятся (решение №3 ../README.md) — детального ряда нечего анонсировать. В событие уходит только компактная витринная проекция метрик (property-object-metrics.v1), нужная каталогу для ленты без синхронных запросов (ADR-0056 «одна строка без джойнов»)
3Эффективные коэффициенты эконом-моделиВ model-changed уходит scope инвалидации, а не значения (Internal-данные наружу не раскрываются) — подписчик перечитывает актуальную модель при пересчёте

Доменные события (in-memory, не Kafka)

Доменные события поднимаются агрегатами PG-модели и обрабатываются при сохранении внутри сервиса — audit-лог admin-правок; в том же согласованном изменении upsert/delete/replace конфигурации кладёт outbox-запись model-changed (см. таблицу выше).

СобытиеАгрегатКогда→ outbox model-changedДокумент агрегата
EconomicModelConfigUpdatedEventEconomicModelConfigУспешный PUT model-configGlobal/Upserted../domain/economic-model-config.md
PropertyObjectTypeConfigUpsertedEventPropertyObjectTypeConfigСоздание/правка типа объекта недвижимостиPropertyObjectType/Upserted../domain/property-object-type-config.md
PropertyObjectTypeConfigDeletedEventPropertyObjectTypeConfigУдаление типа объекта недвижимостиPropertyObjectType/Deleted../domain/property-object-type-config.md
PropertyObjectTypeMonthOverridesReplacedEventPropertyObjectTypeConfig (child PropertyObjectTypeMonthOverride)Replace-all помесячных оверрайдовPropertyObjectType/MonthOverridesReplaced../domain/property-object-type-month-override.md

Consumed-события (для полноты карты)

Правила добавления новых produced-событий

Новое produced-событие вводится (отдельным контрактом в этом каталоге + строка в таблице «Produced» выше и в ../README.md), когда появляется конкретный consumer, которому нужен push — не «на вырост» (ADR-0056). Пример нереализованного кандидата: уведомление инвестора о росте цены его объекта недвижимости сверх порога — сначала оценить, не решается ли это на стороне investor-owner поверх public API истории цен.

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

  • ../README.md (таблица «Events И Consumers»).
  • ADR-0056 (simplicity-first); ADR-0058 (rename Lot*PropertyObject*).