docs: define operations workspace contracts

This commit is contained in:
a.tolmachev
2026-03-29 21:20:52 +03:00
parent c78b949050
commit d3ab565fff
5 changed files with 692 additions and 6 deletions
+4
View File
@@ -136,6 +136,10 @@
- draft generation;
- gRPC descriptor upload и discovery.
Детальные DTO и response shapes для экранов `Operations` и `Wizard` зафиксированы отдельно в:
- `docs/operations-workspace-contracts.md`
### Agents
Нужны:
+5
View File
@@ -80,6 +80,7 @@
- `workspace_id`
- `name`
- `display_name`
- `category`
- `protocol`
- `status`
- `version`
@@ -253,3 +254,7 @@
## 6. Принцип совместимости
Если UI требует сущность, которой нет в текущем backend, эта сущность должна быть сначала явно добавлена в эту модель данных, а уже потом в код и БД.
Для `Operations` и `Wizard` дополнительный уровень контрактной детализации закреплен в:
- `docs/operations-workspace-contracts.md`
+677
View File
@@ -0,0 +1,677 @@
# Operations Workspace Contracts
## 1. Назначение документа
Этот документ задает точные `workspace-scoped` контракты для экранов:
- `Operations`
- `Wizard`
Документ нужен как промежуточный слой между:
- целевым UI в `test-ui`;
- `docs/backend-gap-plan.md`;
- будущей реализацией `admin-api`.
## 2. Общие правила
Базовый префикс:
```text
/api/admin/workspaces/{workspace_id}
```
Общие принципы:
- все operation принадлежат одному workspace;
- каталог операций отдается целиком с сервера и не требует client-side merge поверх локального mock state;
- wizard работает только через backend и не опирается на `localStorage` или `sessionStorage`;
- versioning остается явным;
- текущий draft lifecycle отделен от published lifecycle;
- `PATCH /operations/{operation_id}` обновляет текущий draft;
- `POST /operations/{operation_id}/versions` создает новый explicit snapshot;
- опубликованная operation не удаляется hard delete, если на нее есть published agent bindings.
## 3. Канонические представления
### 3.1. `OperationSummary`
Используется в каталоге операций.
```json
{
"id": "op_01hr9f7q4b0w1svxv5a6j8k2np",
"workspace_id": "ws_01hr9dzv4s5ec1f1v3y8t1n7gr",
"name": "crm_create_lead",
"display_name": "Create Lead",
"protocol": "rest",
"status": "draft",
"category": "sales",
"current_draft_version": 3,
"latest_published_version": 2,
"updated_at": "2026-03-29T12:00:00Z",
"usage_summary": {
"calls_today": 4821,
"error_rate_pct": 1.8,
"avg_latency_ms": 187
},
"agent_refs": [
{
"agent_id": "agent_01hr9g3kgznn57d8s1q0h0g7qn",
"agent_slug": "sales-assistant",
"display_name": "Sales Assistant"
}
]
}
```
### 3.2. `OperationDetail`
Используется на detail page и как источник для edit-mode wizard.
```json
{
"id": "op_01hr9f7q4b0w1svxv5a6j8k2np",
"workspace_id": "ws_01hr9dzv4s5ec1f1v3y8t1n7gr",
"name": "crm_create_lead",
"display_name": "Create Lead",
"protocol": "rest",
"status": "draft",
"category": "sales",
"current_draft_version": 3,
"latest_published_version": 2,
"published_at": "2026-03-28T18:10:00Z",
"draft_version_ref": {
"version": 3,
"status": "draft"
},
"published_version_ref": {
"version": 2,
"status": "published"
},
"agent_refs": [
{
"agent_id": "agent_01hr9g3kgznn57d8s1q0h0g7qn",
"agent_slug": "sales-assistant",
"display_name": "Sales Assistant"
}
],
"created_at": "2026-03-27T09:15:00Z",
"updated_at": "2026-03-29T12:00:00Z"
}
```
### 3.3. `OperationVersionDocument`
Полная конфигурация версии. Используется wizard и detail page.
```json
{
"operation_id": "op_01hr9f7q4b0w1svxv5a6j8k2np",
"workspace_id": "ws_01hr9dzv4s5ec1f1v3y8t1n7gr",
"version": 3,
"status": "draft",
"target": {},
"input_schema": {},
"output_schema": {},
"input_mapping": {},
"output_mapping": {},
"execution_config": {},
"tool_description": {},
"samples": {
"input_json": {},
"output_json": {}
},
"generated_draft": {
"input_schema": {},
"output_schema": {},
"input_mapping": {},
"output_mapping": {}
},
"config_export": {
"format_version": "1",
"export_mode": "portable"
},
"change_note": "update request mapping",
"created_at": "2026-03-29T12:00:00Z",
"updated_at": "2026-03-29T12:45:00Z"
}
```
### 3.4. `OperationMutationResult`
Используется как ответ на create, patch, explicit version, archive и delete.
```json
{
"operation_id": "op_01hr9f7q4b0w1svxv5a6j8k2np",
"workspace_id": "ws_01hr9dzv4s5ec1f1v3y8t1n7gr",
"version": 3,
"status": "draft",
"updated_at": "2026-03-29T12:45:00Z"
}
```
## 4. Catalog endpoints
### `GET /api/admin/workspaces/{workspace_id}/operations`
Назначение:
- отдать каталог операций для списка.
Query params:
- `protocol`
- `status`
- `search`
- `category`
- `agent_id`
- `page`
- `page_size`
Ответ:
```json
{
"items": [
{
"id": "op_01hr9f7q4b0w1svxv5a6j8k2np",
"workspace_id": "ws_01hr9dzv4s5ec1f1v3y8t1n7gr",
"name": "crm_create_lead",
"display_name": "Create Lead",
"protocol": "rest",
"status": "draft",
"category": "sales",
"current_draft_version": 3,
"latest_published_version": 2,
"updated_at": "2026-03-29T12:00:00Z",
"usage_summary": {
"calls_today": 4821,
"error_rate_pct": 1.8,
"avg_latency_ms": 187
},
"agent_refs": []
}
],
"page": 1,
"page_size": 20,
"total": 48
}
```
### `GET /api/admin/workspaces/{workspace_id}/operations/{operation_id}`
Назначение:
- отдать `OperationDetail`.
### `GET /api/admin/workspaces/{workspace_id}/operations/{operation_id}/versions/{version}`
Назначение:
- отдать `OperationVersionDocument`.
## 5. Create and update contracts
### `POST /api/admin/workspaces/{workspace_id}/operations`
Назначение:
- создать operation и draft version `1`.
Тело:
```json
{
"name": "crm_create_lead",
"display_name": "Create Lead",
"protocol": "rest",
"category": "sales",
"target": {},
"input_schema": {},
"output_schema": {},
"input_mapping": {},
"output_mapping": {},
"execution_config": {},
"tool_description": {}
}
```
Ответ:
```json
{
"operation_id": "op_01hr9f7q4b0w1svxv5a6j8k2np",
"workspace_id": "ws_01hr9dzv4s5ec1f1v3y8t1n7gr",
"version": 1,
"status": "draft",
"updated_at": "2026-03-29T12:00:00Z"
}
```
### `PATCH /api/admin/workspaces/{workspace_id}/operations/{operation_id}`
Назначение:
- обновить identity metadata;
- обновить текущий draft document без создания новой версии вручную со стороны UI.
Это endpoint для обычного wizard edit-mode.
Тело:
```json
{
"display_name": "Create Lead",
"category": "sales",
"draft_document": {
"target": {},
"input_schema": {},
"output_schema": {},
"input_mapping": {},
"output_mapping": {},
"execution_config": {},
"tool_description": {}
}
}
```
Ответ:
```json
{
"operation_id": "op_01hr9f7q4b0w1svxv5a6j8k2np",
"workspace_id": "ws_01hr9dzv4s5ec1f1v3y8t1n7gr",
"version": 3,
"status": "draft",
"updated_at": "2026-03-29T12:45:00Z"
}
```
### `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/versions`
Назначение:
- создать новую explicit draft-version snapshot.
Этот endpoint нужен для сценариев:
- `Save as new version`;
- controlled version history;
- YAML import с `mode=upsert`.
Тело:
```json
{
"source_version": 3,
"change_note": "prepare release candidate",
"document": {
"target": {},
"input_schema": {},
"output_schema": {},
"input_mapping": {},
"output_mapping": {},
"execution_config": {},
"tool_description": {}
}
}
```
Ответ:
```json
{
"operation_id": "op_01hr9f7q4b0w1svxv5a6j8k2np",
"workspace_id": "ws_01hr9dzv4s5ec1f1v3y8t1n7gr",
"version": 4,
"status": "draft",
"updated_at": "2026-03-29T13:05:00Z"
}
```
## 6. Lifecycle endpoints
### `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/publish`
Назначение:
- опубликовать конкретную версию операции.
Тело:
```json
{
"version": 3
}
```
Ответ:
```json
{
"operation_id": "op_01hr9f7q4b0w1svxv5a6j8k2np",
"workspace_id": "ws_01hr9dzv4s5ec1f1v3y8t1n7gr",
"version": 3,
"status": "published",
"updated_at": "2026-03-29T13:10:00Z"
}
```
### `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/archive`
Назначение:
- перевести operation в archived lifecycle state без hard delete.
Тело:
```json
{
"reason": "deprecated by crm_create_lead_v2"
}
```
Ответ:
```json
{
"operation_id": "op_01hr9f7q4b0w1svxv5a6j8k2np",
"workspace_id": "ws_01hr9dzv4s5ec1f1v3y8t1n7gr",
"version": 3,
"status": "archived",
"updated_at": "2026-03-29T13:15:00Z"
}
```
### `DELETE /api/admin/workspaces/{workspace_id}/operations/{operation_id}`
Назначение:
- hard delete для еще не опубликованной operation.
Правила:
- hard delete допустим только для draft/unpublished operation;
- если operation уже публиковалась, UI должен использовать archive;
- если operation используется published agent-ами, endpoint возвращает `409 Conflict`.
Ответ:
```json
{
"operation_id": "op_01hr9f7q4b0w1svxv5a6j8k2np",
"workspace_id": "ws_01hr9dzv4s5ec1f1v3y8t1n7gr",
"deleted": true
}
```
## 7. Wizard-specific endpoints
### `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/test-runs`
Тело:
```json
{
"version": 3,
"input": {}
}
```
Ответ:
```json
{
"status": "ok",
"request_preview": {},
"response_preview": {},
"output": {},
"runtime_labels": {
"workspace_id": "ws_01hr9dzv4s5ec1f1v3y8t1n7gr",
"operation_id": "op_01hr9f7q4b0w1svxv5a6j8k2np"
}
}
```
### `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/samples/input-json`
Тело:
```json
{
"version": 3,
"sample": {}
}
```
Ответ:
```json
{
"operation_id": "op_01hr9f7q4b0w1svxv5a6j8k2np",
"version": 3,
"stored": true
}
```
### `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/samples/output-json`
Тело:
```json
{
"version": 3,
"sample": {}
}
```
Ответ:
```json
{
"operation_id": "op_01hr9f7q4b0w1svxv5a6j8k2np",
"version": 3,
"stored": true
}
```
### `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/drafts/generate`
Назначение:
- сгенерировать черновую схему и draft mappings по samples/descriptors.
Тело:
```json
{
"version": 3
}
```
Ответ должен возвращать полный draft payload, пригодный для прямой подстановки в wizard:
```json
{
"generated_draft": {
"input_schema": {},
"output_schema": {},
"input_mapping": {},
"output_mapping": {}
},
"input_schema": {},
"output_schema": {},
"input_mapping": {},
"output_mapping": {}
}
```
### `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/descriptors/proto`
Тело:
```json
{
"version": 3,
"file_name": "crm.proto",
"content_b64": "..."
}
```
Ответ:
```json
{
"descriptor_ref": "desc_01hr9n0m2yzdb8f8xv1gvztm2b",
"stored": true
}
```
### `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/descriptors/descriptor-set`
Тело:
```json
{
"version": 3,
"file_name": "crm-descriptor-set.bin",
"content_b64": "..."
}
```
Ответ:
```json
{
"descriptor_ref": "desc_01hr9n0m2yzdb8f8xv1gvztm2b",
"stored": true
}
```
### `GET /api/admin/workspaces/{workspace_id}/operations/{operation_id}/grpc/services?version=3`
Ответ:
```json
{
"services": [
{
"package": "crm.v1",
"service": "LeadService",
"methods": [
{
"name": "CreateLead",
"kind": "unary",
"input_schema": {},
"output_schema": {}
}
]
}
]
}
```
## 8. YAML contracts
### `GET /api/admin/workspaces/{workspace_id}/operations/{operation_id}/export`
Query:
- `mode=portable|bundle`
- `version=<optional>`
Ответ:
- `application/yaml`
### `POST /api/admin/workspaces/{workspace_id}/operations/import`
Query:
- `mode=create|upsert`
Body:
- raw YAML document
Ответ:
```json
{
"workspace_id": "ws_01hr9dzv4s5ec1f1v3y8t1n7gr",
"operation_id": "op_01hr9f7q4b0w1svxv5a6j8k2np",
"version": 4,
"status": "draft",
"result": "upserted"
}
```
## 9. Wizard lifecycle semantics
### Текущее редактирование
Wizard всегда открывается на current draft version и использует:
- `GET /operations/{operation_id}`
- `GET /operations/{operation_id}/versions/{current_draft_version}`
- `PATCH /operations/{operation_id}`
Это основной сценарий редактирования.
### Явное создание новой версии
Если UI вводит действие `Save as new version`, оно должно использовать:
- `POST /operations/{operation_id}/versions`
Это уже отдельный snapshot, а не обычное сохранение формы.
### Публикация
Публикуется конкретная version, а не “текущее состояние формы”.
Поэтому UI всегда должен передавать:
- `version`
в `POST /publish`.
## 10. Конфликты, которые закрывает этот документ
### Конфликт 1. `PATCH` против explicit version snapshots
Решение:
- wizard использует `PATCH` для текущего draft;
- controlled snapshots остаются на `POST /versions`.
### Конфликт 2. Delete semantics
Решение:
- hard delete только для unpublished drafts;
- для опубликованных операций использовать archive.
### Конфликт 3. Category source of truth
Решение:
- `category` признается частью operation identity metadata и хранится на стороне backend.
### Конфликт 4. Catalog data merge
Решение:
- каталог должен возвращать все нужные поля для UI с сервера;
- локальные overlays и tombstones в целевой реализации не используются.
## 11. Следующий шаг
После этого документа следующая реализация должна идти в таком порядке:
1. обновить `admin-api` handlers и service contracts под workspace prefix;
2. добавить `category`, `workspace_id` и update/delete/archive lifecycle в storage model;
3. перевести wizard на create/patch/version semantics из этого документа;
4. только после этого подключать `Operations` и `Wizard` к реальному UI.