feat(cuod): spacecraft.mission — x-localized текст → FK на mission.code

mission у КА хранился свободным x-localized текстом (краткое описание),
дублировался, рассинхронизировался, не был связан со справочником
mission (где уже есть программы миссий + поле spacecraft_codes).

Теперь mission — строка-код, x-references → mission.code. Референсная
целостность + единый источник.

Маппинг 14 КА → 9 миссий взят из mission.spacecraft_codes (обратная
связь уже была в данных). Проверено: все 14 мапятся однозначно,
0 пропусков, 0 конфликтов.

- 0027-spacecraft-mission-fk.xml — Liquibase-миграция существующих БД:
  схема + 14 записей одной транзакцией прямым SQL (смена типа поля —
  chicken-and-egg, как 0020 raw SQL минует Envers/outbox; forward-only).
  schema_version → 2.0.0.
- cuod-bundle: spacecraft.schema.json mission → x-references,
  records/spacecraft.records.json — 14 mission → код, manifest 2.0.0.
  Свежие установки получают новую форму сразу.

Caveat: миграция через raw SQL не пишет Envers _AUD и Kafka outbox —
проекции read-api нужно пересобрать после деплоя (как при 0020).
This commit is contained in:
Zimin A.N.
2026-05-21 16:21:46 +03:00
parent 2a82a875c8
commit 656da8c9b9
5 changed files with 95 additions and 29 deletions
@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.27.xsd">
<!--
spacecraft.mission: x-localized свободный текст → FK на mission.code.
Было: mission = { "ru-RU": "...", "en-US": "..." } (краткое описание).
Стало: mission = "RESURS_P" (строка-код, x-references → mission.code).
Зачем: описание миссии дублировалось свободным текстом в каждом КА,
рассинхронизировалось, не связывалось со справочником mission (где уже
есть программы миссий + поле spacecraft_codes). FK даёт референсную
целостность и единый источник.
Маппинг КА → миссия взят из mission.spacecraft_codes (обратная связь
уже была в данных). Проверено: все 14 КА однозначно мапятся на 9 миссий,
0 пропусков, 0 конфликтов.
Смена типа поля — chicken-and-egg между схемой и записями (любой из них
по отдельности невалиден против другого), поэтому схема + данные
мигрируются одной транзакцией прямым SQL. Как и 0020-fix-draft-status —
raw SQL минует Envers _AUD и Kafka outbox; для разовой контролируемой
миграции это допустимо (потребители ре-синхронизируются, проекции
read-api пересоберутся). Forward-only, без rollback (исходный свободный
текст лоссится).
На свежей БД (spacecraft ещё не создан) — no-op: UPDATE'ы затрагивают
0 строк, cuod-bundle создаст spacecraft сразу в новой форме (v2.0.0).
-->
<changeSet id="0027-1-spacecraft-mission-fk" author="ordinis">
<comment>spacecraft.mission: x-localized текст → FK mission.code (схема + 14 записей, одна транзакция)</comment>
<!-- 1. Схема: поле mission → string + x-references, bump до 2.0.0 (breaking). -->
<sql>
UPDATE dictionary_definitions
SET schema_json = jsonb_set(
schema_json,
'{properties,mission}',
'{"type":"string","description":"Программа миссии — FK на mission.code","x-references":"mission.code"}'::jsonb
),
schema_version = '2.0.0',
updated_at = NOW()
WHERE name = 'spacecraft';
</sql>
<!-- 2. Данные: mission каждого КА → код миссии (маппинг из mission.spacecraft_codes). -->
<sql>
UPDATE dictionary_records r
SET data = jsonb_set(r.data, '{mission}', to_jsonb(m.code), true),
updated_at = NOW()
FROM (VALUES
('1999-068A', 'TERRA_AQUA'),
('2014-016A', 'SENTINEL_1'),
('2015-028A', 'SENTINEL_2'),
('2024-149E', 'KONDOR_FKA'),
('2013-030A', 'RESURS_P'),
('2014-085A', 'RESURS_P'),
('2016-016A', 'RESURS_P'),
('2024-046A', 'RESURS_P'),
('2012-039A', 'KANOPUS_V'),
('2017-076A', 'KANOPUS_V'),
('2014-037A', 'METEOR_M'),
('2019-038A', 'METEOR_M'),
('2015-074A', 'ELEKTRO_L'),
('2021-016A', 'ARKTIKA_M')
) AS m(bk, code)
WHERE r.business_key = m.bk
AND r.dictionary_id = (SELECT id FROM dictionary_definitions WHERE name = 'spacecraft');
</sql>
</changeSet>
</databaseChangeLog>
@@ -36,5 +36,6 @@
<include file="changes/0024-notification-read-state.xml" relativeToChangelogFile="true"/>
<include file="changes/0025-notification-prefs-event-type.xml" relativeToChangelogFile="true"/>
<include file="changes/0026-notification-quiet-hours.xml" relativeToChangelogFile="true"/>
<include file="changes/0027-spacecraft-mission-fk.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>