feat(topbar): «Что нового» button + 2026-05-12 state.md update
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
# Ревью 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).
|
||||
Reference in New Issue
Block a user