Идентификаторы сущностей¶
Требования применяются к техническим идентификаторам хранимых сущностей, которые серверный компонент назначает в принадлежащей ему модели данных. Технический идентификатор — это суррогатное неизменяемое значение, отличающее сущность независимо от изменяемых бизнес-атрибутов.
Вне области документа находятся идентификаторы, заданные внешним стандартом
или назначенные внешней системой, естественные бизнес-ключи, идентификаторы
запросов, сообщений и событий, секреты и токены доступа, а также значения,
которые создаются и используются только в локальном хранилище browser- или
mobile-приложения. Уровни обязательности определены в корневом README.md.
DATA-ID-001. UUIDv7 для нового технического идентификатора¶
Уровень: MUST
Применяется к: новому полю технического идентификатора, впервые
добавляемому в хранимую модель после подключения требования, если условие
DATA-ID-003 не выполняется
Генератор должен создавать Universally Unique Identifier (UUID) версии 7 по
RFC 9562. Поле версии должно быть
равно 7, а variant — двоичному шаблону 10xx, определённому RFC 9562.
Обоснование¶
Единый формат устраняет расхождение представления идентификатора между сервисами и хранилищами. Упорядоченный по времени префикс UUIDv7 улучшает локальность вставки в индекс по сравнению со случайным UUID. Последовательный целочисленный идентификатор раскрывает объём данных и темп их создания.
Проверка¶
- unit-тест генератора с зафиксированными часами: поле версии равно
7, variant соответствует RFC 9562, аunix_ts_msсовпадает с временем генерации; - проверка схемы новой модели и конфигурации генератора;
- проверка значения по тестовому вектору RFC 9562.
Исключения¶
Поле, существовавшее до подключения требования, MAY сохранять действующий
формат. Его миграция на UUIDv7 должна сохранять совместимость по BE-MIG-001,
если схема одновременно используется несколькими версиями приложения.
DATA-ID-002. Каноническое представление во внешнем контракте¶
Уровень: MUST
Применяется к: сериализации технического идентификатора по DATA-ID-001
или DATA-ID-003 в HTTP API, GraphQL, gRPC, событии, сообщении или
экспортируемом файле
Идентификатор должен передаваться как строка формы hex-and-dash по RFC 9562: 36 символов и пять групп, разделённых дефисами. Корпоративная каноническая форма должна использовать шестнадцатеричные цифры в нижнем регистре. Машинно-проверяемый контракт должен ограничивать форму, выбранную версию и variant эквивалентом одного из шаблонов:
- для UUIDv7 —
^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; - для UUIDv4 —
^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$.
Представление без дефисов, в верхнем регистре, в base32, в base64 или в виде целого числа запрещено. Получатель не должен принимать некорректную форму и молча приводить её к канонической.
Обоснование¶
Расхождение регистра и кодировки превращает один идентификатор в несколько различных строковых значений в логах, кэшах, ключах идемпотентности и клиентских хранилищах, из-за чего записи об одной сущности перестают связываться.
Проверка¶
- проверка машинной схемы на выбранный шаблон версии и variant;
- контрактный тест ответа API, входного значения и payload события;
- негативные тесты значения другой версии, неверного variant, верхнего регистра и формы без дефисов.
Исключения¶
Не допускаются. Хранение значения в 128-битном типе внутри хранилища не является представлением во внешнем контракте.
DATA-ID-003. UUIDv4 при запрете раскрытия времени генерации¶
Уровень: MUST
Применяется к: новому полю технического идентификатора, для которого
политика по DATA-CLS-001 запрещает получателю идентификатора узнавать момент
его генерации
Генератор должен создавать UUID версии 4 по RFC 9562. Схема поля и, при наличии, внешний контракт должны фиксировать UUIDv4 и отклонять UUID другой версии. Все значения одного поля должны иметь одну версию UUID.
Обоснование¶
UUIDv7 содержит временную метку генерации unix_ts_ms с точностью до
миллисекунды. Это значение может раскрывать темп регистрации, примерный объём
операций и связь между записями. UUIDv4 не содержит временного поля и сохраняет
общий формат представления UUID.
Проверка¶
- сопоставление информации, извлекаемой из идентификатора, с политикой классификации и получателями;
- unit-тест генератора: поле версии равно
4, а variant соответствует RFC 9562; - проверка схемы контракта и однородности версии в хранилище.
Исключения¶
Не допускаются.
DATA-ID-004. Идентификатор не является средством доступа¶
Уровень: MUST NOT
Применяется к: техническому идентификатору, который получатель предъявляет для выбора сущности во внешней операции
Сервис не должен считать знание или предъявление идентификатора достаточным
условием доступа к сущности и не должен обходить проверку по SEC-AUTHZ-002.
Технический идентификатор не должен использоваться как маркер, одно
предъявление которого предоставляет доступ, токен приглашения, токен
восстановления доступа, секрет публичной ссылки или иной секрет.
Обоснование¶
RFC 9562 запрещает считать UUID security capability и предупреждает, что UUID не следует считать трудно угадываемым. Технический идентификатор также может попадать в URL, логи, метрики и внешние системы, предназначенные для несекретных значений.
Проверка¶
- негативный тест доступа к чужой защищённой сущности по известному идентификатору;
- review публичных ссылок, приглашений и flow восстановления доступа на отсутствие технического идентификатора в роли секрета.
Исключения¶
Не допускаются.
DATA-ID-005. UUID не задаёт бизнес-время и глобальный порядок¶
Уровень: MUST NOT
Применяется к: запросу, отчёту или прикладной логике, использующим UUIDv7 для определения времени или порядка
Временная метка из UUIDv7 не должна использоваться как время бизнес-события, источник времени для отчёта, срока хранения или подтверждение момента фиксации транзакции. Сравнение UUID не должно использоваться как доказательство глобального либо причинного порядка. Сортировка по UUID не должна заменять явное поле времени, версии или последовательности, когда контракт требует соответствующую семантику.
Обоснование¶
Временная метка UUIDv7 определяется часами генератора, может не совпадать с моментом фиксации транзакции и не устанавливает порядок между узлами. Скрытая зависимость от неё делает отчёты и выборки неверными без явного отказа.
Проверка¶
- статический поиск извлечения timestamp из UUID и сортировки только по UUID;
- review запросов, retention-правил и отчётов, использующих идентификатор для интервала или порядка;
- тест логики порядка при рассинхронизации часов и конкурентной генерации на нескольких узлах.
Исключения¶
UUID MAY использоваться как детерминированный tie-breaker после явных полей порядка и как компонент ключа пагинации. Это исключение не разрешает интерпретировать UUID как порядок создания.
DATA-ID-006. Стабильность, уникальность и конфликт идентификатора¶
Уровень: MUST
Применяется к: жизненному циклу сущности с техническим идентификатором
Компонент должен назначить идентификатор один раз при создании сущности и сохранять его неизменным. Источник истины должен предотвращать назначение одного значения двум существующим сущностям одной логической модели. Коллизия между разными создаваемыми сущностями не должна перезаписывать, объединять или возвращать существующую сущность как результат создания. До успешного сохранения компонент MAY повторить генерацию с новым значением. Удаление сущности не должно инициировать намеренное повторное назначение её идентификатора.
Обоснование¶
Вероятность коллизии UUID мала, но не равна нулю. Без проверки уникальности коллизия или конкурентное создание может незаметно изменить другую сущность и нарушить ссылочную целостность.
Проверка¶
- проверка уникального ключа, условного create или эквивалентной гарантии источника истины;
- тест неизменности идентификатора при обновлении сущности;
- fault-injection с принудительно совпавшими значениями и проверкой безопасного отказа без изменения существующей сущности.
Исключения¶
Замена идентификатора в контролируемой миграции требует ADR, явного
сопоставления старых и новых значений и соблюдения BE-MIG-001.
DATA-ID-007. Представление отсутствующего идентификатора¶
Уровень: MUST
Применяется к: отсутствующему значению технического идентификатора в хранимой модели или внешнем контракте
Контракт должен задавать отсутствие идентификатора как отдельное состояние:
пропущенное поле либо null согласно схеме. Пустая строка, число 0, Nil UUID
00000000-0000-0000-0000-000000000000 и иное фиктивное значение не должны
обозначать отсутствие. Если поле обязательно, отсутствующее значение должно
отклоняться валидацией.
Обоснование¶
Фиктивный идентификатор смешивает отсутствие связи с реально переданным значением, создаёт ложные связи и обходит ограничения обязательности и уникальности.
Проверка¶
- проверка nullability и required-полей машинной схемы;
- boundary-тесты пропущенного поля,
null, пустой строки и Nil UUID; - проверка хранилища на фиктивные значения.
Исключения¶
Не допускаются.