244 lines
14 KiB
Markdown
244 lines
14 KiB
Markdown
# Ревью 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).
|