Правила Строгой Типизации Документации
Назначение
Документ фиксирует стандарт полной типизации для API, entities, replicas, events, consumers, search documents, ClickHouse facts, JSONB document models и frontend view models. Он дополняет Правила написания документации и обязателен для новых и изменяемых файлов.
Принцип Полной Типизации
Документация является контрактом для разработки, тестирования, интеграций и сопровождения. Каждый внешний и внутренний контракт описывается строго типизированно, явно и воспроизводимо.
- Запрещены абстрактные типы
object,json,jsonb,payload,metadata,settings,data,attributes,parameters,context, если рядом нет полной таблицы полей этой модели. - Любая request/response model, view model, command, query, event payload, aggregate snapshot, replica, search document, ClickHouse fact и JSONB document model имеет имя модели и таблицу полей.
- Nested object описывается отдельной именованной моделью в том же файле или отдельным файлом
models/<feature-group>/<model>.md. - Коллекция описывает тип элемента, максимальный размер или paging/partition rule, порядок сортировки и правила усечения.
- Enum описывает все допустимые значения, смысл каждого значения, fallback для неизвестного значения и совместимость при добавлении новых значений.
- Decimal, money, rates, time, identifiers и reference values описываются доменными типами, а не строкой без правил.
- Если модель хранится в PostgreSQL
jsonb, Elasticsearch document, ClickHouse table или Kafka event, ее схема документируется с версией, правилами совместимости, ограничениями размера и security notes. - Документация не должна оставлять "договоримся при реализации": nullable behavior, masks, permission checks и observability описываются до разработки.
Справочные Идентификаторы
Центральный справочник платформы — сервис handbook (pin.handbook, ACL-реплика Talent Handbook,
ADR-0063): source of truth для стран, регионов, городов, валют и языков. В доменных моделях и API контрактах используются stable identifiers справочника — id источника Talent Handbook, не Guid: CountryId, CurrencyId, LanguageId — short; RegionId, CityId — long (коллекции — CountryIds, CurrencyIds, RegionIds и т.п. с теми же типами элементов).
CurrencyCode,LanguageCode,CountryCodeне используются как основной доменный ключ в новых документах.- ISO-коды (
IsoCode2/IsoCode3стран и языков,IsoCodeISO-4217 валют) — атрибуты записей справочникаhandbook, а не доменные ключи контрактов. Внеhandbookкод справочника может появляться только внутри snapshot-модели или в adapter-specific модели внешнего провайдера. - События и snapshots, которым нужен человекочитаемый или исторический контекст, включают snapshot-модели справочника:
CurrencySnapshot,CountrySnapshot,RegionSnapshot,CitySnapshot— единый дом моделей: handbook/domain/snapshots.md. Snapshot фиксируется на момент публикации; события с денежными суммами несутCurrencyId+CurrencySnapshot. Snapshot-модель языка не вводится: языки — реплика без текущих потребителей. - Любая фильтрация по валюте, стране, региону, городу или языку использует id справочника.
- Lookup методы возвращают
ResultEntry.Idкак id справочника, а код помещают в явно описанное поле ответа илиDescription. - При миграции старого документа с
xxxCodeнужно заменить контракт наxxxIdи указать compatibility note для consumers/readers.
Минимум Для Модели
Каждая модель содержит:
| Раздел | Что Описать |
|---|---|
| Назначение | Где и зачем используется модель. |
| Поля | Имя, тип, обязательность, описание, ограничения, источник значения. |
| Валидация | Min/max, формат, допустимые состояния, cross-field rules. |
| Nullable behavior | Когда поле отсутствует, когда равно null, кто видит значение. |
| Security | Маскирование, запрет secrets/PII, audit sensitivity. |
| Совместимость | Версия, additive changes, fallback для unknown enum. |
Структурированные Модели Вместо Плоских Полей
Плоские наборы полей, которые семантически образуют один объект, документируются одной вложенной моделью. Правило обязательно для трёх повторяющихся случаев.
Диапазоны — единое понятие, а не пара *Min/*Max
- Пара границ одного значения описывается как единое понятие «диапазон» (нижняя и верхняя граница одного поля), а не двумя плоскими полями
*Min/*Maxили*From/*To. - Пример: цена лота — диапазон
price(одно поле с нижней и верхней границей), а не параpriceMin + priceMax. Аналогично площадьareaи этажfloor. - Для каждого диапазона фиксируются: включительность границ, смысл открытой границы (нет ограничения с этой стороны) и признак «диапазон не задан» (фильтр не применяется).
- Диапазон дат описывается тем же понятием: либо с обязательными обеими границами, либо открытый по одной стороне.
Пара «id + name» — именованная ref-модель
- Пара «идентификатор + отображаемое имя» одной сущности выносится во вложенную именованную ref-модель с ПОЛНЫМИ именами полей, а не в две плоские колонки корня.
- Пример:
developer: DeveloperRefModel { DeveloperId: Guid; DeveloperName: string }вместо плоскихdeveloperId: Guid + developerName: string. - Правило распространяется на все ссылки на сущности:
project: ProjectRefModel,building: BuildingRefModel,layout: LayoutRefModel. - Полные имена полей внутри ref-модели (
DeveloperId, а неId) сохраняются намеренно — модель читается вне контекста родителя (в событиях, snapshot, view model). - Ref-модель может нести дополнительные stable-поля (
Slug,IsoCode), но не тянет полный агрегат.
Группа связанных полей — под-модель
- Набор полей, описывающих один аспект сущности, выносится в отдельную именованную под-модель, а не рассыпается по корню request/response.
- Пример: характеристики планировки объекта —
layout: PropertyObjectLayoutModel { RoomCount; TotalArea; LivingArea; KitchenArea; Floor; ... }, а не плоскиеroomCount + totalArea + livingArea + ...в корне. - Под-модель описывается по минимуму для модели: поля, валидация, nullable behavior, совместимость.
Запрещенные Упрощения
- "Поле содержит произвольный JSON".
- "Структура зависит от типа и будет уточнена при реализации".
- "Metadata для UI".
- "Payload provider-а сохраняется как есть".
- "Список ids в JSONB".
- "Currency code в контракте, потому что так проще для фронта".
- "Плоские
priceMin/priceMaxилиdateFrom/dateToвместо единого понятия «диапазон»". - "Плоские
developerId + developerNameвместоDeveloperRefModel".
Если контракт действительно расширяемый, он описывается через typed union, versioned model или bounded list of typed entries с перечислением допустимых ключей.
Связанные Правила
- API methods
- Entities
- Events
- JSONB document models
- ResultEntry
Обратные ссылки
Автоссылки: где используется этот документ.
- Домен (CQRS) (6): Entity / Aggregate: Channel (enum) + ChannelConfigEntity, Entity / Aggregate: InvestorPropertyEntity, Entity / Aggregate: NotificationTemplateEntity, Entity / Aggregate: RecipientContactEntity, Entity / Aggregate: UserNotificationSettingsEntity, Snapshot-модели справочника (единый дом платформы)
- API (1): Investor-Owner API — реестр операций и общие контрактные модели
- adr (1): ADR-0063 — справочники pin.handbook (репликация из Talent Handbook)
- index.md (1): Handbook Service
- frontend-form-field-behavior-rules.md (1): Правила Поведения Полей В Формах-Редакторах