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

Event Contract: country-upserted (CountryUpsertedEvent)

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

Назначение

Фиксирует каждое изменение состояния реплики страны в контексте handbook: применённый upsert синка Talent, archive/restore администратора, повторную эмиссию при полной пересинхронизации. Событие публичное: даёт downstream-сервисам PIN актуальную запись страны без синхронного запроса в handbook и без подписки на топики Talent (ADR-0063 п.1). Compacted-топик одновременно служит источником начальной загрузки: новый потребитель получает полный справочник чтением топика с offset 0.

Metadata

ПолеЗначение
Event typecountry-upserted
Topicpin.handbook.countries.v1compacted (cleanup.policy = compact); последняя запись каждой страны хранится бессрочно
Partitions / key1 (десятки строк, строгий порядок) / key = Id записи
ContractVersion1
Producerhandbook: применённый синк (talent-handbook-sync), admin archive/restore (archive-restore-entry), полная пересинхронизация (talent-initial-import)
Статусdraft

Событие публикуется атомарно с изменением реплики (реплика + чекпоинт синка + публикация — одно согласованное изменение, правила talent-replica.md); после фиксации — доставляется гарантированно (at-least-once).

Payload CountryUpsertedEvent

Полный snapshot реплики страны на момент публикации. Служебные штампы CreatedAt/UpdatedAt в payload не входят — потребитель ведёт собственные штампы своей реплики.

ПолеТипОбязательностьИсточник (поле реплики)CompatibilityОписание
IdshortДаCountryEntity.IdImmutableИдентификатор страны = id источника (= Kafka key).
ShortNamestring?НетCountryEntity.ShortNameAdditive onlyКраткое название («Россия»).
FullNamestringДаCountryEntity.FullNameAdditive onlyПолное название («Российская Федерация»), ≤ 64. Display-имя: Name = FullName — конвенция snapshots.md, отдельного поля Name payload не несёт.
IsoCode2stringДаCountryEntity.IsoCode2Additive onlyКод ISO 3166-1 alpha-2 (RU), upper.
IsoCode3stringДаCountryEntity.IsoCode3Additive onlyКод ISO 3166-1 alpha-3 (RUS), upper.
DefaultCurrencyIdshort?НетCountryEntity.DefaultCurrencyIdAdditive onlyВалюта страны по умолчанию — ссылка на запись pin.handbook.currencies.v1; может быть ещё не известна потребителю (порядок топиков разных справочников не гарантирован).
DefaultLanguageIdshort?НетCountryEntity.DefaultLanguageIdAdditive onlyЯзык страны по умолчанию — ссылка на запись pin.handbook.languages.v1.
IsArchivedboolДаCountryEntity.IsArchivedAdditive onlySoft-архив: true — запись выведена из оборота (исчезает из lookup-выдач потребителя, исторические ссылки остаются валидными). Tombstone-записей в топике нет — архив передаётся значением.
ReplicaVersionlongДаCountryEntity.ReplicaVersionImmutable semanticsВерсия записи источника; монотонный guard у потребителей — событие с версией ≤ уже применённой пропускается (INV-HND-4).

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

УсловиеИзменение репликиПубликация
Применённый upsert синка Talent (handbooks.after-country-information-update), включая auto-restore заархивированной записисоздание / перезапись реплика-полей / IsArchived = falseатомарно с изменением реплики
Admin archive / restoreIsArchived переключёнта же
Полная пересинхронизация (Talent POST sync-handbooks re-эмитит все строки; см. talent-initial-import)re-emit всех записей справочника (в том числе без фактических изменений)та же

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

Consumer-контекстЭффектИдемпотентностьЗадержка (SLA)
chessboard (группа pin-chessboard-handbook-sync, handbook-sync)Локальная реплика chessboard.handbook_*: валидация CountryId на write-path проектов (default — Россия, CountryId = 1), гео-фильтры и карточкиguard по ReplicaVersion (стейл — skip); повтор доставки — идемпотентный no-op< 1 мин

Порядок, идемпотентность и bootstrap

  • Порядок per-key. Key = Id — все события одной страны строго упорядочены; потребитель держит guard по ReplicaVersion (событие с версией ≤ применённой — skip + метрика stale).
  • Полный snapshot — замещение, не слияние. Потребитель перезаписывает свою реплику целиком; отсутствие optional-поля означает «значение очищено», а не «оставить прежнее».
  • Compaction. Промежуточные версии записи могут быть вычищены компакцией — потребитель обязан корректно обрабатывать «скачки» ReplicaVersion (каждое событие самодостаточно). Физических удалений и tombstone-ов нет: запись выводится из оборота значением IsArchived = true.
  • Bootstrap. Новый потребитель получает полный актуальный справочник чтением топика с offset 0; re-emit при пересинхронизации для уже подписанных — идемпотентный no-op (версия не выросла).

Доставка и повторная обработка (retry/DLQ)

АспектПравило
Гарантия доставкиat-least-once; публикация атомарна с изменением реплики — «событие без изменения» и «изменение без события» исключены
Повтор у потребителяповторная доставка того же события — идемпотентный no-op (version-guard)
Transient-ошибка обработкиretry с экспоненциальным backoff, offset не коммитится, поток топика ждёт
Неустранимая ошибка обработкисобытие — в собственный DLQ потребителя + алерт; правила — в consumer-доке потребителя (handbook-sync)
Отказ применения на стороне producerсобытие не публикуется: неприменимое событие источника ушло в pin.handbook.talent-sync-dlq.v1 (см. talent-handbook-sync), реплика и топик не изменились

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

  • Версия — один ContractVersion = 1; consumer при несоответствии версии события логирует warning и продолжает обработку. Топик кодирует версию суффиксом .v1.
  • Additive-only: новые поля добавляются как optional с безопасным default — без bump; неизвестные поля потребитель игнорирует.
  • Breaking (удаление/переименование/смена типа или смысла поля) — новый ContractVersion = 2 + новый топик pin.handbook.countries.v2 + dual-publish на период миграции + deadline миграции consumers + sunset .v1.
  • Новый потребитель подключается в любой момент без участия producer — bootstrap чтением compacted-топика с offset 0.

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

ПолеКласс данныхПравило
все поля payloadPublic (нормативный справочник)include

PII, secrets, tokens в событии отсутствуют — данные публичные справочные.

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

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

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