Initialize project scaffold and domain model
This commit is contained in:
@@ -0,0 +1,355 @@
|
||||
# Схема БД
|
||||
|
||||
## 1. Назначение документа
|
||||
|
||||
Этот документ фиксирует структуру хранения конфигураций, версий операций, загруженных артефактов и published runtime-view. Его цель - дать основу для SQL-миграций и для реализации `mcpaas-registry`.
|
||||
|
||||
В документе предполагается реляционная модель, ориентированная на `PostgreSQL`. Для MVP допускается адаптация под `SQLite`, но канонической считается схема, совместимая с `PostgreSQL`.
|
||||
|
||||
## 2. Общие принципы хранения
|
||||
|
||||
### 2.1. Версионирование обязательно
|
||||
|
||||
Конфигурация operation не должна храниться только в одной "живой" записи. Каждое существенное изменение должно приводить к появлению новой версии конфигурации.
|
||||
|
||||
### 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.
|
||||
|
||||
## 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-форма
|
||||
|
||||
```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 модели домена.
|
||||
Reference in New Issue
Block a user