Files
crank/docs/data-model.md
T
2026-05-03 22:22:16 +00:00

588 lines
14 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.
# Модель данных
## 1. Назначение документа
Этот документ фиксирует целевую формальную модель данных платформы. Его цель - определить такие структуры, которые можно без существенных изменений перенести в:
- Rust domain types;
- HTTP DTO;
- структуру таблиц БД;
- runtime-представление операций и агентов;
- UI-формы и конфигурационные экраны.
## 2. Общие принципы модели
### 2.1. Одна операция - один интеграционный контракт
Каждая `Operation` соответствует одному интеграционному контракту:
- GraphQL -> один конкретный `query` или `mutation`;
- gRPC -> один unary method или один server-streaming method в bounded execution mode;
- REST -> один endpoint-сценарий.
Однако MCP tool публикуется не напрямую из operation, а через `AgentOperationBinding` внутри конкретного `Agent`.
### 2.2. Внутренний транспортный формат - JSON
Независимо от внешнего протокола внутри системы данные представлены в JSON-ориентированном виде.
### 2.3. Mapping всегда явный
Даже если система умеет строить черновой mapping по примерам данных, итоговая конфигурация mapping сохраняется явно.
### 2.4. JSONPath как единый язык адресации
Для input и output mapping используется `JSONPath`.
### 2.5. Workspace - обязательная граница данных
Все продуктовые сущности принадлежат одному `Workspace`.
Минимальный набор workspace-scoped сущностей:
- `Secret`
- `SecretVersion`
- `Operation`
- `OperationVersion`
- `AuthProfile`
- `Agent`
- `AgentKey`
- `InvocationLog`
- `UsageRollup`
### 2.6. YAML как формат обмена конфигурацией
Помимо канонической JSON-модели система поддерживает импорт и экспорт конфигураций в `YAML`.
### 2.7. Streaming operation обязана быть bounded
Если операция использует upstream streaming, она должна работать в одном из execution modes:
- `window`
- `session`
- `async_job`
Бесконечный passthrough stream не является допустимой моделью `Operation`.
### 2.8. Execution model важнее transport-specific особенностей
Каждая операция в системе определяется двумя измерениями:
- `protocol`
- `execution_mode`
Это позволяет описывать:
- REST unary;
- REST SSE window;
- gRPC server-stream session;
- WebSocket event feed;
- SOAP request-response;
в рамках одной общей модели runtime и MCP publishing.
### 2.9. Уровень защиты задается операцией
Обязательная политика машинного доступа задается на уровне `Operation`, а не на уровне `Agent`.
Допустимые значения:
- `standard`
- `elevated`
- `strict`
Принцип:
- если операция требует более строгий режим доступа, агент не может его ослабить;
- один агент может публиковать операции с разной критичностью данных;
- `mcp-server` сравнивает тип представленного credential с требуемым `security_level`.
## 3. Корневые сущности
### 3.1. `Workspace`
Поля:
- `id`
- `slug`
- `display_name`
- `status`
- `settings`
- `created_at`
- `updated_at`
Назначение:
- логическая изоляция команд;
- scoping для операций, агентов, ключей и логов;
- основа для multi-tenant MCP endpoints.
### 3.2. `Operation`
Поля:
- `id`
- `workspace_id`
- `name`
- `display_name`
- `category`
- `protocol`
- `status`
- `version`
- `target`
- `input_schema`
- `output_schema`
- `input_mapping`
- `output_mapping`
- `execution_config`
- `security_level`
- `tool_description`
- `samples`
- `generated_draft`
- `config_export`
- `streaming_config`
- `created_at`
- `updated_at`
- `published_at`
### 3.3. `Agent`
`Agent` - пользовательская MCP-поверхность, которая собирает ограниченный набор published operations.
Поля:
- `id`
- `workspace_id`
- `slug`
- `display_name`
- `description`
- `status`
- `current_draft_version`
- `latest_published_version`
- `created_at`
- `updated_at`
- `published_at`
### 3.4. `AgentVersion`
Снимок конфигурации агента.
Поля:
- `agent_id`
- `version`
- `status`
- `instructions`
- `tool_selection_policy`
- `bindings`
- `created_at`
### 3.5. `AgentOperationBinding`
Связь published operation с agent version.
Поля:
- `operation_id`
- `operation_version`
- `tool_name`
- `tool_title`
- `tool_description_override`
- `enabled`
### 3.6. `Secret`
Секрет для доступа к внешней системе.
Поля:
- `id`
- `workspace_id`
- `name`
- `kind`
- `status`
- `current_version`
- `created_at`
- `updated_at`
Значение:
- plaintext не возвращается в list/get endpoints;
- текущее значение хранится в зашифрованном виде через `SecretVersion`;
- rotate создает новую версию секрета без потери ссылочной целостности.
### 3.7. `SecretVersion`
Зашифрованное значение секрета.
Поля:
- `secret_id`
- `version`
- `ciphertext`
- `key_version`
- `created_at`
### 3.8. `AuthProfile`
Используется только для доступа к внешним системам.
Поля:
- `id`
- `workspace_id`
- `name`
- `kind`
- `config`
Принцип:
- `AuthProfile` не хранит plaintext;
- config ссылается на `secret_id` или пару `secret_id`, если auth-схема составная;
- runtime применяет profile к запросу только в момент вызова upstream.
### 3.9. `AgentKey`
Отдельная сущность для машинного доступа к инструментам одного конкретного AI-агента.
Поля:
- `id`
- `workspace_id`
- `agent_id`
- `name`
- `prefix`
- `scopes`
- `status`
- `created_at`
- `last_used_at`
- `expires_at`
Секрет:
- полное значение ключа показывается только один раз при создании;
- в persistent storage сохраняется только `secret_hash`;
- ключ не должен использоваться как основной рабочий токен вызова в целевой защищенной модели;
- ключ используется для выпуска короткоживущего токена доступа.
### 3.10. `IssuedAgentToken`
Учет выданных машинных токенов для вызова MCP-инструментов.
Поля:
- `id`
- `workspace_id`
- `agent_id`
- `agent_key_id`
- `platform_client_id`
- `token_kind`
- `status`
- `scopes`
- `max_uses`
- `used_count`
- `cnf_jkt`
- `expires_at`
- `created_at`
- `used_at`
Принцип:
- токен живет ограниченное время;
- токен может быть одноразовым;
- токен может быть привязан к ключевой паре клиента;
- токен выражает более узкие права, чем длинноживущий ключ агента.
### 3.11. `User`
Поля:
- `id`
- `email`
- `display_name`
- `password_hash`
- `status`
- `created_at`
Пароль:
- хранится только как `Argon2id` hash;
- plaintext пароль не сохраняется;
- верификация использует `password_pepper` из env.
### 3.11. `UserSession`
Поля:
- `id`
- `user_id`
- `secret_hash`
- `status`
- `expires_at`
- `last_seen_at`
- `created_at`
Секрет:
- браузеру выдается только opaque session token;
- в persistent storage сохраняется только `secret_hash`;
- подпись и верификация используют `session_secret` из env.
### 3.12. `Membership`
Поля:
- `workspace_id`
- `user_id`
- `role`
- `created_at`
### 3.13. `InvitationToken`
Поля:
- `id`
- `workspace_id`
- `email`
- `role`
- `status`
- `expires_at`
- `created_at`
Токен:
- полный invite token показывается только один раз при создании;
- в persistent storage сохраняется только `token_hash`.
### 3.14. `InvocationLog`
Продуктовая запись о вызове tool.
Поля:
- `id`
- `workspace_id`
- `agent_id`
- `operation_id`
- `request_id`
- `level`
- `status`
- `duration_ms`
- `error_kind`
- `request_preview`
- `response_preview`
- `created_at`
### 3.15. `UsageRollup`
Агрегированная статистика по периоду.
Поля:
- `workspace_id`
- `agent_id`
- `operation_id`
- `period_kind`
- `period_start`
- `calls_total`
- `calls_ok`
- `calls_error`
- `p50_ms`
- `p95_ms`
- `p99_ms`
### 3.16. `StreamSession`
Поля:
- `id`
- `workspace_id`
- `agent_id`
- `operation_id`
- `mode`
- `status`
- `cursor`
- `state`
- `expires_at`
- `last_poll_at`
- `created_at`
- `closed_at`
Назначение:
- хранение bounded session state для streaming tools;
- поддержка `start/poll/stop`;
- cleanup orphaned и expired sessions.
### 3.17. `AsyncJobHandle`
Поля:
- `id`
- `workspace_id`
- `agent_id`
- `operation_id`
- `status`
- `progress`
- `result`
- `error`
- `expires_at`
- `created_at`
- `updated_at`
- `finished_at`
Назначение:
- поддержка `start/status/result/cancel` для long-running upstream actions.
## 4. `Target`
`Target` описывает конкретный внешний вызов. Это discriminated union по протоколу.
### 4.1. `RestTarget`
- `kind`
- `base_url`
- `method`
- `path_template`
- `static_headers`
### 4.2. `GraphqlTarget`
- `kind`
- `endpoint`
- `operation_type`
- `operation_name`
- `query_template`
- `response_path`
### 4.3. `GrpcTarget`
- `kind`
- `server_addr`
- `package`
- `service`
- `method`
- `descriptor_ref`
- `descriptor_set_b64`
### 4.4. `WebSocketTarget`
- `kind`
- `url`
- `subprotocols`
- `subscribe_message_template`
- `unsubscribe_message_template`
- `static_headers`
### 4.5. `SoapTarget`
- `kind`
- `wsdl_ref`
- `service_name`
- `port_name`
- `operation_name`
- `endpoint_override`
- `soap_version`
- `soap_action`
- `binding_style`
- `headers`
- `fault_contract`
- `metadata`
## 5. `ProtocolOptions`
`ProtocolOptions` хранит protocol-specific runtime tuning, который не должен смешиваться с общей `ExecutionConfig`.
### 5.1. `GrpcProtocolOptions`
- `use_tls`
### 5.2. `WebsocketProtocolOptions`
- `heartbeat_interval_ms`
- `reconnect_max_attempts`
- `reconnect_backoff_ms`
### 5.3. `SoapProtocolOptions`
- `use_tls`
- `validate_certificate`
- `ws_security_profile`
## 6. `ExecutionConfig`
`ExecutionConfig` хранит общие runtime-настройки операции.
Ключевые поля:
- `timeout_ms`
- `retry_policy`
- `response_cache`
- `auth_profile_ref`
- `headers`
- `protocol_options`
- `streaming`
### 6.1. `ResponseCachePolicy`
Первый поддержанный вариант response cache policy:
- `ttl_ms`
Ограничения стартовой реализации:
- policy задается явно на операции;
- response cache допускается только для read-only вызовов;
- в открытой редакции первый поддержанный путь:
- `REST`
- `GET`
- без `auth_profile_ref`
- cache key должен строиться не глобально, а минимум в контексте:
- `workspace`
- `agent`
- `operation`
- `request fingerprint`
Это позволяет избежать неявного кэширования ответов, зависящих от upstream credentials.
## 7. XML normalization model
Для SOAP/XSD-пайплайна `crank-schema` теперь фиксирует XML-origin metadata отдельными code-level types:
- `XmlNodeKind`
- `XmlQualifiedName`
- `XmlSchemaBinding`
Они описывают:
- является ли узел element / attribute / text;
- локальное имя и namespace;
- repeated / nillable semantics.
## 8. `Schema`
`Schema` - нормализованное описание входа или выхода.
Поддерживаются:
- скалярные поля;
- вложенные объекты;
- массивы;
- enum;
- nullable-поля;
- `oneof` для protobuf.
## 9. Принцип совместимости
Если UI требует сущность, которой нет в текущем backend, эта сущность должна быть сначала явно добавлена в эту модель данных, а уже потом в код и БД.
Для upstream credentials это означает:
- placeholder-строки вида `${secrets.API_KEY}` не считаются реальной моделью данных;
- рабочая продуктовая модель строится только через `Secret` + `AuthProfile`.
Для `Operations` и `Wizard` дополнительный уровень контрактной детализации закреплен в:
- `docs/operations-workspace-contracts.md`