c96b6706fc
x-id-source (auto-derive businessKey): - DictionaryRecordService.resolveBusinessKey() читает schemaJson['x-id-source']. - Если задан — businessKey берётся из data[idSource]. Если клиент явно прислал и значения не совпадают → 400 business_key_mismatch (защита от рассинхрона). - Если поле в data пустое → 400 id_source_missing. - Если x-id-source не задан и businessKey пуст → 400 business_key_required. x-unique (constraint на дубли значений): - DictionaryRecordRepository.findActiveByJsonField() — native SQL c data->>field. - DictionaryRecordService.enforceUniqueFields() walks schema.properties, для каждого property с x-unique=true ищет активные записи с тем же значением. Исключает current record на update. - Конфликт → 409 unique_field_violation с указанием business_key конфликтующей. Делается на каждом create/update в той же SERIALIZABLE транзакции что и save — без отдельного DB constraint (для MVP). Partial unique index per-field — оптимизация на потом, когда будет много справочников с x-unique.