@@ -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.