Files
crank/docs/database-schema.md
T
2026-03-28 00:58:56 +03:00

13 KiB
Raw Blame History

Схема БД

1. Назначение документа

Этот документ фиксирует структуру хранения конфигураций, версий операций, загруженных артефактов и published runtime-view. Его цель - дать основу для SQL-миграций и для реализации crank-registry.

В документе предполагается реляционная модель, ориентированная на PostgreSQL. Канонической считается схема, совместимая с PostgreSQL.

2. Общие принципы хранения

2.1. Версионирование обязательно

Конфигурация operation не должна храниться только в одной "живой" записи. Каждое существенное изменение должно приводить к появлению новой версии конфигурации.

Для MVP в registry version snapshot хранит protocol-specific конфигурацию, схемы, mapping и execution settings. Поля identity и listing view (name, display_name, protocol) считаются стабильными и хранятся в operations.

2.2. Published и draft разделяются логически

  • draft может меняться;
  • published должна ссылаться на конкретную зафиксированную версию;
  • runtime читает только опубликованные версии.

2.3. Артефакты и конфигурация не смешиваются

.proto, descriptor set, sample JSON и YAML import payload не должны храниться в той же структуре, что и runtime-ready configuration.

2.4. Секреты не хранятся внутри operation

В БД operation должны храниться только ссылки на auth profiles или secret references.

Для MVP рекомендуется отдельная таблица auth_profiles, где metadata и secret refs отделены от operation versions.

2.5. Тестовая изоляция

Integration tests для registry должны выполняться на реальной PostgreSQL, но без влияния на runtime-данные. Предпочтительный способ:

  • отдельная test database;
  • либо отдельная временная schema на время теста;
  • обязательная очистка после завершения тестов.

3. Основные таблицы

Минимальный набор таблиц:

  • operations
  • operation_versions
  • published_operations
  • operation_samples
  • descriptors
  • auth_profiles
  • yaml_import_jobs

Опционально позже:

  • operation_test_runs
  • audit_log

4. Таблица operations

Хранит стабильную сущность операции, не зависящую от конкретной версии.

Поля

  • id text primary key
  • name text not null unique
  • display_name text not null
  • protocol text not null
  • status text not null
  • current_draft_version integer not null default 1
  • latest_published_version integer null
  • created_at timestamptz not null
  • updated_at timestamptz not null
  • published_at timestamptz null

Назначение

  • быстрый список операций;
  • стабильный идентификатор для UI и MCP;
  • привязка к актуальному draft и опубликованной версии.

5. Таблица operation_versions

Хранит полную сериализованную конфигурацию конкретной версии operation.

Поля

  • operation_id text not null
  • version integer not null
  • status text not null
  • target_json jsonb not null
  • input_schema_json jsonb not null
  • output_schema_json jsonb not null
  • input_mapping_json jsonb not null
  • output_mapping_json jsonb not null
  • execution_config_json jsonb not null
  • tool_description_json jsonb not null
  • samples_json jsonb null
  • generated_draft_json jsonb null
  • config_export_json jsonb null
  • change_note text null
  • created_at timestamptz not null
  • created_by text null

Ключи

  • primary key: (operation_id, version)
  • foreign key: operation_id -> operations(id)
  • рекомендованный composite foreign key для связанных таблиц: (operation_id, version)

Почему так

Для MVP выгоднее хранить version snapshot целиком, а не дробить по десятку связанных таблиц. Это:

  • упрощает versioning;
  • упрощает откат;
  • упрощает YAML export;
  • хорошо сочетается с JSON-oriented доменной моделью.

6. Таблица published_operations

Хранит явную published-привязку, которую читает runtime.

Поля

  • operation_id text primary key
  • version integer not null
  • published_at timestamptz not null
  • published_by text null

Назначение

  • быстрый доступ к published runtime-view;
  • отсутствие двусмысленности, какая именно версия сейчас активна;
  • простой invalidation для runtime cache.

Рекомендуемая целостность

  • operation_id -> operations(id)
  • (operation_id, version) -> operation_versions(operation_id, version)

7. Таблица operation_samples

Хранит метаданные и ссылки на sample artifacts.

Поля

  • id text primary key
  • operation_id text not null
  • version integer not null
  • sample_kind text not null
  • storage_ref text not null
  • content_type text not null
  • file_name text null
  • created_at timestamptz not null

Варианты sample_kind

  • input_json
  • output_json
  • yaml_import_source

Назначение

  • не класть большие sample payload в основные version records;
  • иметь возможность переиспользовать или пересобирать draft mapping;
  • отслеживать, из каких sample-данных строился черновик.

Рекомендуемая целостность

  • operation_id -> operations(id)
  • (operation_id, version) -> operation_versions(operation_id, version)

8. Таблица descriptors

Хранит gRPC schema artifacts.

Поля

  • id text primary key
  • operation_id text null
  • version integer null
  • descriptor_kind text not null
  • storage_ref text not null
  • source_name text null
  • package_index_json jsonb null
  • created_at timestamptz not null

Варианты descriptor_kind

  • proto_upload
  • descriptor_set
  • reflection_snapshot

Назначение

  • связывать gRPC operation с конкретной схемой;
  • не хранить binary descriptor внутри основной operation version;
  • иметь отдельную точку для discovery metadata.

Рекомендуемая целостность

  • если descriptor привязан к version, то (operation_id, version) -> operation_versions(operation_id, version)

9. Таблица yaml_import_jobs

Для MVP можно импортировать YAML синхронно, но таблицу под журнал импорта лучше предусмотреть сразу.

Поля

  • id text primary key
  • source_sample_id text null
  • status text not null
  • format_version text not null
  • mode text not null
  • result_operation_id text null
  • result_version integer null
  • error_text text null
  • created_at timestamptz not null
  • finished_at timestamptz null

Назначение

  • аудит импортов;
  • разбор ошибок валидации;
  • поддержка будущего async import pipeline.

10. Таблица auth_profiles

Хранит переиспользуемые профили аутентификации для внешних вызовов.

Поля

  • id text primary key
  • name text not null unique
  • kind text not null
  • config_json jsonb not null
  • created_at timestamptz not null
  • updated_at timestamptz not null

Варианты kind

  • bearer
  • basic
  • api_key_header
  • api_key_query

Правило

config_json должен содержать только secret_ref, а не открытые секреты.

11. Предлагаемая SQL-форма

create table operations (
  id text primary key,
  name text not null unique,
  display_name text not null,
  protocol text not null,
  status text not null,
  current_draft_version integer not null default 1,
  latest_published_version integer null,
  created_at timestamptz not null,
  updated_at timestamptz not null,
  published_at timestamptz null
);

create table operation_versions (
  operation_id text not null references operations(id),
  version integer not null,
  status text not null,
  target_json jsonb not null,
  input_schema_json jsonb not null,
  output_schema_json jsonb not null,
  input_mapping_json jsonb not null,
  output_mapping_json jsonb not null,
  execution_config_json jsonb not null,
  tool_description_json jsonb not null,
  samples_json jsonb null,
  generated_draft_json jsonb null,
  config_export_json jsonb null,
  change_note text null,
  created_at timestamptz not null,
  created_by text null,
  primary key (operation_id, version)
);

create table published_operations (
  operation_id text primary key references operations(id),
  version integer not null,
  published_at timestamptz not null,
  published_by text null,
  foreign key (operation_id, version)
    references operation_versions(operation_id, version)
);

create table auth_profiles (
  id text primary key,
  name text not null unique,
  kind text not null,
  config_json jsonb not null,
  created_at timestamptz not null,
  updated_at timestamptz not null
);

12. Индексы

Минимально нужны:

  • index on operations(protocol)
  • index on operations(status)
  • index on operation_versions(operation_id, created_at desc)
  • index on published_operations(version)
  • index on operation_samples(operation_id, version)
  • index on descriptors(operation_id, version)
  • index on auth_profiles(kind)

13. Versioning flow

Создание операции

  1. Создается запись в operations.
  2. Создается версия 1 в operation_versions.
  3. current_draft_version = 1.

Изменение draft

  1. Читается текущий draft.
  2. Создается новая версия n + 1.
  3. В operations.current_draft_version пишется новая версия.
  4. Published версия не меняется.

Публикация

  1. Берется текущий draft version.
  2. В published_operations upsert-ится ссылка на эту версию.
  3. В operations.latest_published_version пишется та же версия.
  4. Runtime cache получает сигнал на reload.

Импорт YAML

  1. YAML валидируется.
  2. Определяется create или update сценарий.
  3. Создается новая запись в operation_versions.
  4. При необходимости создается запись в yaml_import_jobs.

14. Что не должно храниться в БД в таком виде

  • секреты в открытом виде;
  • runtime cache;
  • скомпилированные adapter clients;
  • невалидированные черновики, не приводимые к доменной модели.

15. Практический итог

Для MVP рекомендован такой подход:

  • operations - стабильная идентичность;
  • operation_versions - полные version snapshots;
  • published_operations - текущая активная версия;
  • operation_samples и descriptors - внешние артефакты;
  • auth_profiles - переиспользуемая внешняя аутентификация;
  • yaml_import_jobs - журнал импортов.

Эта схема хорошо ложится на sqlx, не требует избыточной нормализации и соответствует JSON-oriented модели домена.