Files
mdm-ordinis/docs/integration/api/x-references.md
T

201 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Cross-references (FK между справочниками)
JSON Schema extension `x-references` объявляет, что значение поля должно
ссылаться на active record в указанном словаре.
## Синтаксис
```json
{
"type": "object",
"properties": {
"satelliteTypeCode": {
"type": "string",
"x-references": "satellite_type.code"
}
}
}
```
Format: `"<dictionary_name>.<field_name>"`. Когда POST/PUT приходит, Ordinis
делает lookup в `satellite_type` где `data->>code == satelliteTypeCode`.
Если не найден / не активен / вне scope — `422 Validation Error`.
## Текущие FK в bundle cuod
| Source | Target | Поле |
|---|---|---|
| `spacecraft.satelliteTypeCode` | `satellite_type` | `code` |
| `spacecraft.statusCode` | `spacecraft_status` | `code` |
| `mission.spacecraftCodes` (array) | `spacecraft` | `businessKey` |
| `instrument.spacecraftCodes` (array) | `spacecraft` | `businessKey` |
| `instrument.supportedFormatCodes` (array) | `data_format` | `businessKey` |
| `instrument.supportedLevelCodes` (array) | `processing_level` | `businessKey` |
(Точное число и список могут меняться с bundle versions — см.
[Bundle cuod](bundle-cuod.md).)
## Server-side validation
При POST/PUT ReferenceValidator проверяет каждое x-references поле:
| Симптом | Error code | Описание |
|---|---|---|
| Referenced dictionary не существует | `x_references_dict_not_found` | Опечатка в schema. |
| Referenced record не найден / inactive | `x_references_target_not_found` | Bad value либо record закрыт. |
| Value не string (для v1) | `x_references_non_string` | v1 поддерживает только string refs. |
| Schema spec malformed | `x_references_malformed` | Bad schema. |
Response:
```json
{
"errors": [
{
"path": "/satelliteTypeCode",
"code": "x_references_target_not_found",
"message": "Referenced record not found in 'satellite_type' for code='UNKNOWN-TYPE'"
}
]
}
```
## Scope hiding
Если referenced dictionary — INTERNAL/RESTRICTED, а consumer имеет только
PUBLIC scope, ReferenceValidator возвращает тот же error
(`x_references_target_not_found`) что и на real not-found. Ordinis **не leak'ает**
existence of out-of-scope dictionary через differential errors.
## Orphan references
Возможна ситуация когда referenced record **закрывается**, а referencing
record остаётся:
```
1. spacecraft.RESURS-P-3 references satellite_type.EARTH-OPTICAL
2. Admin closes satellite_type.EARTH-OPTICAL (record.closed event emitted)
3. spacecraft.RESURS-P-3 теперь имеет dangling FK
```
Ordinis периодически детектирует такие orphan'ы серверной стороной — данные
**не корректируются автоматически** (может быть intentional state до
update referencing записей), но Ordinis team получает уведомление и
может coordinate fix с data stewards.
Consumer-side defensiveness:
- При получении event `record.closed` для записи на которую ты ссылаешься —
invalidate свой cache + либо fetch свежую версию referencing
записи (если она тоже обновилась), либо handle dangling FK явно.
## Cascade rules — roadmap (v2)
Сегодня закрытие источника НЕ closes referencing automatically. Это
дoлжно явно делаться через bulk close либо individual updates.
В v2 планируется schema extension `x-references-on-close`:
```json
{
"satelliteTypeCode": {
"type": "string",
"x-references": "satellite_type.code",
"x-references-on-close": "block"
}
}
```
Опции:
- **block** — закрытие источника невозможно пока есть active referencing (default).
- **warn** — закрытие проходит, в response warning.
- **cascade** — все referencing закрываются в той же транзакции, отдельные
events emit'ятся per record.
Конкретный timeline и финальная семантика будут опубликованы перед
deployment v2 — следи за анонсами от Ordinis team.
## Lineage discovery — roadmap (v2)
Сегодня нет endpoint для "что depends on X". В v2 планируется:
- `GET /api/v1/dictionaries/{name}/dependents` — словари которые ссылаются.
- `GET /api/v1/records/{dict}/{key}/dependents` — конкретные записи.
Это позволит consumer'ам и UI узнавать связи без чтения всех schemas
руками. Spec будет опубликован перед deployment v2.
## Best practices
1. **Используй businessKey как target field** для большинства FK. Это
стабильный идентификатор. Альтернатива (`code`, `name`) работает но
требует поддержки `x-unique` в target (иначе ambiguous matches).
2. **Не делай deeply nested refs** — v1 поддерживает только top-level
fields. Nested objects с x-references — пропустят validation.
3. **Array refs работают** — если поле `type: array, items: {type: string,
x-references: ...}`, каждый элемент валидируется. (Но в v1.2.1 это
делается на каждый элемент отдельно — for large arrays медленно. Будет
batch'нуто в v2.)
4. **Document FK в displayName** — `"description": "FK на satellite_type
через code"` помогает при ревью schemas.
## Связанные schema extensions
### `x-localized` — мультиязычные поля
```json
{ "type": "object", "x-localized": true }
```
См. [read-endpoints.md](read-endpoints.md) `?lang=` параметр.
### `x-section` — bucketing полей в admin-UI form
Hint для admin-UI: в какую визуальную секцию формы (`identity`,
`references`, `description`, `dates`, `geometry`, `physical`, `extra`,
либо custom string) сгруппировать поле.
```json
{
"type": "number",
"x-section": "orbital_geometry"
}
```
Если `x-section` не задан, admin-UI применяет эвристику:
- `x-references` → `references`
- `x-localized` → `description`
- `format=date|date-time` → `dates`
- key matches `/^(geo|geom|wkt|lon|lng|lat|altitude|coord)/` → `geometry`
- `required` → `identity`
- else → `extra`
Predefined IDs получают i18n labels (Связи / Описание / Даты / Геометрия /
Физические параметры / Идентификация / Дополнительно). Custom IDs
humanize'ятся: `orbital_geometry` → `Orbital Geometry`.
Только UI hint — backend не validate'ит и не reject'ит unknown values.
### `x-id-source` — авто-derive businessKey
```json
{ "x-id-source": "code" }
```
При CREATE businessKey берётся из `data.code` automatically (UI скрывает
поле). См. ReferenceValidator.
### `x-unique` — уникальность поля в dict'е
```json
{ "type": "string", "x-unique": true }
```
Backend enforce'ит при CREATE/UPDATE. Используется для `code` полей в
target dicts которые ссылаются по `x-references`.
## Дальше
- [Bundle cuod](bundle-cuod.md) — список текущих FK в проде
- [События](events.md) — учитывай cascade closure при инвалидации
- [Schema workflow](schema-workflow.md) — как менять schema через approval flow