feat(topbar): «Что нового» button + 2026-05-12 state.md update

This commit is contained in:
Александр Зимин
2026-05-12 17:05:24 +00:00
parent 58dd871808
commit a34c6d4c82
21 changed files with 1853 additions and 8 deletions
+70
View File
@@ -0,0 +1,70 @@
# Руководство ревьюера Ordinis
Это руководство — для **ревьюеров schema drafts**: тех, кто принимает или
отклоняет предложения изменить схему справочников.
Если ты **оператор** (заводишь записи) — смотри
[руководство оператора](../operator/index.md).
## Когда нужен ревью
Изменения схемы справочника (добавление поля, изменение типа, новое
ограничение) **не применяются автоматически**. Оператор создаёт **schema
draft** — предложение, которое проходит через ревью:
```
DRAFT → REVIEW_PENDING → APPROVED → PUBLISHED
↘ REJECTED ↘ CHANGES_REQUESTED
↘ WITHDRAWN
```
Ты как ревьюер решаешь: безопасно ли применить это изменение? Не сломает
ли оно существующих записей? Не сломает ли консьюмеров (Альтум, BI и пр.)?
## Что внутри
- [Ревью schema drafts](schema-drafts.md) — пошаговая инструкция, как
смотреть diff, какие проверки делать, как принимать решение
## Когда чаще всего стоит REJECT или REQUEST_CHANGES
| Сценарий | Что делать |
|---|---|
| Меняется тип существующего поля (string → number) | **REJECT** — поломает существующие записи. Если очень нужно, делать через миграцию данных, не через draft |
| Удаляется обязательное поле | **REJECT** или **REQUEST_CHANGES** с альтернативой (мигрировать данные) |
| Добавляется обязательное поле без default | **REQUEST_CHANGES** — нужен default или поле должно быть опциональным |
| Добавляется FK без проверки целостности | **REQUEST_CHANGES** — попроси добавить orphan check |
| Меняется `enum` (удаляется значение) | **REQUEST_CHANGES** — закрой все записи с этим значением сначала |
| Просто добавляется опциональное поле | Обычно **APPROVE** — безопасно |
| Косметика (description, examples) | **APPROVE** — это документация |
## Когда APPROVE
- Добавление опционального поля
- Расширение `enum` (новое значение)
- Уточнение `description` / `examples`
- Добавление формата валидации (`format: date`) к ранее не-валидируемому полю,
если все существующие данные ему соответствуют
## Базовые принципы
1. **Не ломай существующие записи.** Если изменение делает 1+ запись
невалидной — это breaking change, нужна data migration.
2. **Не ломай downstream.** Если поле читают Альтум / геопортал / BI — спроси
их перед изменением имени или типа.
3. **Документируй причину.** Approve / reject комментарий — это аудит.
Через год кто-то будет смотреть «почему мы так сделали».
4. **Сомневаешься — REQUEST_CHANGES.** Это не отказ, это просьба автора
уточнить. Лучше потратить день на обсуждение, чем неделю на rollback.
## Связанные материалы
- [Обзор API](../integration/api/index.md) — чтобы понять, как изменение
отразится на потребителях
- [Bitemporal модель](../integration/api/bitemporal.md) — как работают
периоды действия (важно для миграций)
- [Cross-references](../integration/api/x-references.md) — как изменения
FK влияют на зависимые справочники
+243
View File
@@ -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).