docs: define operations workspace contracts
This commit is contained in:
@@ -136,6 +136,10 @@
|
||||
- draft generation;
|
||||
- gRPC descriptor upload и discovery.
|
||||
|
||||
Детальные DTO и response shapes для экранов `Operations` и `Wizard` зафиксированы отдельно в:
|
||||
|
||||
- `docs/operations-workspace-contracts.md`
|
||||
|
||||
### Agents
|
||||
|
||||
Нужны:
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user