# Ревью schema drafts Пошаговая инструкция: как смотреть драфт, какие проверки делать, как принимать решение. ## Где найти драфты на ревью В навигации — раздел **«Согласования»** (`/reviews`). Вкладка **«Схемы»** — ожидающие schema drafts (отсортированы по дате создания, старые сверху). Также: на странице справочника, если у него **активный draft**, появляется жёлтый банер «На согласовании: <автор>». Клик → откроется drawer с содержимым драфта. ## Окно ревью (Schema Draft Drawer) При открытии драфта видишь: ``` ┌──────────────────────────────────────────────────────────────┐ │ Согласование draft [×] │ │ автор: zimin.an · отправлен: 2026-05-12 14:00 · v1.0.0→2.0.0│ ├──────────────────────────────────────────────────────────────┤ │ Комментарий автора: │ │ «Добавляем поле frequency_band — будет FK на │ │ frequency_band.code, пока опциональное чтобы не ломать │ │ существующие записи.» │ ├──────────────────────────────────────────────────────────────┤ │ Текущая (live) schema │ Предложено │ │ { │ { │ │ "code": ... │ "code": ..., │ │ "name": ... │ "name": ..., │ │ } │ "frequency_band": { │ │ │ "x-references": │ │ │ "frequency_band.code" │ │ │ } │ │ │ } │ ├──────────────────────────────────────────────────────────────┤ │ ◯ Breaking change keys: нет │ │ ✓ Все существующие записи остаются валидными │ ├──────────────────────────────────────────────────────────────┤ │ Комментарий ревьюера: │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ ... │ │ │ └──────────────────────────────────────────────────────────┘ │ ├──────────────────────────────────────────────────────────────┤ │ [REJECT] [REQUEST CHANGES] [APPROVE] [PUBLISH] │ └──────────────────────────────────────────────────────────────┘ ``` ## Что проверять — чек-лист ### 1. Понимаешь ли ты, ЧТО автор хочет сделать? Прочти комментарий автора. Он должен объяснить: - **Зачем** менять схему (новое требование? bug fix?) - **Что** меняется (поле, тип, ограничение) - **Что с существующими записями** (мигрируем? остаются как есть?) Если непонятно — **REQUEST CHANGES** с вопросом. Не угадывай намерения. ### 2. Diff schema — что изменилось В drawer'е — side-by-side сравнение. Смотри: - **Новые поля** — выделены зелёным - **Удалённые поля** — красным - **Изменённые поля** — жёлтым (с подсветкой, что именно) - **Breaking change keys** — система автоматически помечает: `type`, `format`, `required`, `x-references`, `*Of`, удаления ### 3. Совместимость с существующими записями Откладывается всё на server: при попытке `publish` сервер прогоняет все существующие записи через новую схему и проверяет. Но ревьюер должен **проверить руками** в простых случаях: - Поле добавляется как **обязательное** (`required`) без default? → существующие записи становятся невалидными - Поле удаляется и оно **использовалось**? → потеряется данные - Меняется `enum` (убирается значение)? → записи с этим значением станут невалидны Если сомневаешься — **запроси у автора**: «прогони `GET /records?validate=new-schema` и пришли результат». Эндпоинт покажет, сколько записей сломается. ### 4. Влияние на downstream Schema change часто требует **уведомления потребителей**: - Альтум — если меняем поле, которое они используют в карточках - Геопортал — если меняем geo-поля - BI — если меняем имена / типы полей, которые ушли в их витрины Если не уверен — **REQUEST CHANGES** с просьбой согласовать с командами. Лучше потратить 2 дня на согласование, чем 2 дня на rollback. ### 5. Версионирование Схема имеет `schemaVersion` (`1.0.0`, `2.0.0`). Правила: - **Major bump** — breaking change (удаление, изменение типа, обязательность). Все консьюмеры должны быть готовы. - **Minor bump** — backward-compatible (добавление опциональных полей, расширение `enum`, новые `description`). - **Patch** — косметика (документация, examples). Если автор предлагает minor bump для breaking change — **REQUEST CHANGES** с просьбой обновить версию. ### 6. Тесты / валидация Если справочник имеет sample data в bundle — после schema change нужно проверить, что sample data всё ещё валидна. Это проверяет CI автоматически после publish, но лучше catch'нуть раньше. ## Действия ### APPROVE Изменение безопасное, можно публиковать. Кнопка переводит статус драфта в `APPROVED`. **Публикация ещё не произошла** — нужен отдельный клик «PUBLISH», который применяет схему к live справочнику. Опциональный комментарий — почему approve. Появится в audit log. ### REJECT Изменение неприемлемо в принципе, обсуждать нечего. Например: - Удаляется поле, которое critical для бизнеса - Меняется тип так, что данные потеряются необратимо Драфт переходит в `REJECTED`. **Обязателен комментарий** — почему отказ. Автор увидит, может создать новый драфт с учётом feedback. ### REQUEST CHANGES Изменение в принципе ОК, но требует доработки. Например: - Нужно изменить версию (major вместо minor) - Нужно сделать поле опциональным с default - Нужно добавить data migration script Драфт переходит в `CHANGES_REQUESTED`. Автор увидит, отредактирует, отправит заново (вернётся в `REVIEW_PENDING`). **Обязателен комментарий** — что именно править. ### WITHDRAW Только автор может withdraw свой драфт (если передумал). Ревьюер этого не делает. ### PUBLISH Только после `APPROVE`. Применяет новую схему к live справочнику: - Обновляется `schema_definition` в БД - Все будущие записи валидируются по новой схеме - Существующие записи **не модифицируются** (их данные остаются как есть) - Публикуется событие в Kafka — консьюмеры узнают о смене схемы После publish откатить **нельзя в один клик** — нужен новый draft с inverse change. ## Что произойдёт при APPROVE → PUBLISH 1. `dictionary_definitions.schema_json` обновляется до новой версии 2. `dictionary_definitions.schema_version` инкрементируется 3. В audit log пишется операция `SCHEMA_PUBLISHED` 4. В Kafka топик публикуется `DictionarySchemaUpdated` event с before/after 5. Redis projection (если включена) cascade-invalidates dependent projections 6. Frontend admin-ui получает push notification (через next polling) → баннер «новая схема» появляется у активных операторов ## Типичные паттерны ### Добавление опционального поля ``` - frequency_band: {x-references: "frequency_band.code"} ← новое, опциональное ``` Обычно **APPROVE**. Существующие записи остаются валидными (поле просто `undefined`). ### Добавление обязательного поля без default ``` - mass_kg: {type: "number"} ← новое, в required ``` Обычно **REQUEST CHANGES** — либо `default`, либо `nullable`, либо сначала миграция данных. ### Изменение `x-references` ``` - type: {x-references: "satellite_type.code"} + type: {x-references: "satellite_type_v2.name"} ``` **REQUEST CHANGES** в подавляющем большинстве случаев. Если справочник переименован — нужно migration data, не просто schema swap. ### Расширение `enum` ``` - status: {enum: ["ACTIVE", "INACTIVE"]} + status: {enum: ["ACTIVE", "INACTIVE", "MAINTENANCE"]} ``` **APPROVE** — обратно совместимо. ### Сужение `enum` ``` - status: {enum: ["ACTIVE", "INACTIVE", "MAINTENANCE"]} + status: {enum: ["ACTIVE", "INACTIVE"]} ``` **REJECT** или **REQUEST CHANGES** — записи со значением `MAINTENANCE` станут невалидны. Нужна data migration сначала. ### Удаление поля ``` - legacy_id: {type: "string", x-unique: true} ``` Опасно. Спроси: - Кто-то использует это поле в downstream? - Что мы делаем с данными в нём? - Не лучше ли его deprecate (оставить, не использовать)? Обычно **REQUEST CHANGES** с обсуждением. ## Если ошибся Ревьюеры — люди. Если approve'нул и потом понял что зря: 1. **Если PUBLISH ещё не произошёл** — попроси автора `WITHDRAW`, потом `REJECT` или создать новый 2. **Если PUBLISH произошёл** — создай **новый schema draft** с inverse change (откати изменение), пройди ревью заново 3. **Документируй в audit** — комментарий «откатываю, потому что X» — важная информация для будущих ревьюеров Это не катастрофа, но и не норма. Если ошибаешься > 1 раза в квартал — стоит пересмотреть процедуру ревью (может, нужен mandatory peer-review).