Files
mdm-ordinis/docs/integration/api/x-references.md
T
Zimin A.N. bcfb07f547 docs: split integrator guide (Diplodoc) vs internal docs + add build-docs CI
Чёткое разделение audiences:
- docs/ — consumer-facing only, Diplodoc-built. Public contract для
  интеграторов (Альтум, BI, third-party).
- docs-internal/ — operator runbooks, status snapshots, legacy tech pages.
  НЕ в Diplodoc build, НЕ публикуются.

Изменения:
- Move docs/{ops,status,tech} → docs-internal/{ops,status,tech}
- docs/toc.yaml: убраны секции Operations, Архитектура (legacy), Status
- docs/index.md: убран tab "оператор / on-call", focus на integrators
- docs/README.md: rewritten — scope только integrator guide, editorial
  guidelines (no leak internal architecture, stable API contract)
- .yfm: убран явный ignore status/* (теперь не нужно — папка переехала)
- docs-internal/README.md: index для внутренней документации с rationale
  разделения

Scrubbing implementation details из Diplodoc страниц:
- events.md: убраны Strimzi/cluster.142 references, OutboxPoller детали,
  internal alert names (OrdinisOutboxLagHigh, OrdinisOutboxDLQNonEmpty),
  metric names (nsi_outbox_*). Заменены на consumer-observable contract.
- webhooks.md: убраны metric names (nsi_webhook_ssrf_rejected_total),
  alert table (OrdinisWebhookHighFailureRate и т.д.). Retry policy
  переписана на user-side perspective.
- errors.md: убран alert name OrdinisReadApiErrorBudgetBurnFast, Tempo
  endpoint URL, internal connection details.
- x-references.md: OrphanReferenceScanner → general "Ordinis периодически
  детектирует". Убраны metric/alert names. Cascade roadmap без link на
  internal design doc.
- auth.md: убран file path ScopeContext.java.
- bundle-cuod.md: убран Maven module path.
- caching.md: cascade design link заменён на text reference.

CI:
- .gitlab-ci.yml: новый job build-docs (stage: build) — Node 20 alpine,
  pnpm install --frozen-lockfile + pnpm build, artifact docs/_dist на
  неделю. Triggers: auto на docs/**, либо manual web. Готов к follow-up
  pages-deploy job когда host решён.
- Новый pattern .docs-changes для rules.

Build verified clean: 13 HTML pages, 6.9M, no broken links/refs.
2026-05-07 23:27:03 +03:00

6.1 KiB
Raw Blame History

Cross-references (FK между справочниками)

JSON Schema extension x-references объявляет, что значение поля должно ссылаться на active record в указанном словаре.

Синтаксис

{
  "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.)

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:

{
  "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:

{
  "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.

Дальше

  • Bundle cuod — список текущих FK в проде
  • События — учитывай cascade closure при инвалидации