# 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", "target_url": "https://api.example.com/v1/leads", "target_action": "POST", "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=` Ответ: - `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.