chore: publish clean community baseline
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
# Admin API
|
||||
|
||||
Admin API используется UI для управления Crank Community.
|
||||
|
||||
Base path:
|
||||
|
||||
```text
|
||||
/api/admin
|
||||
```
|
||||
|
||||
## Auth
|
||||
|
||||
- `POST /api/auth/login`
|
||||
- `POST /api/auth/logout`
|
||||
- `GET /api/auth/session`
|
||||
- `GET /api/auth/profile`
|
||||
- `PATCH /api/auth/profile`
|
||||
- `POST /api/auth/current-workspace`
|
||||
- `POST /api/auth/password`
|
||||
|
||||
Авторизация основана на email/password и HttpOnly session cookie.
|
||||
|
||||
## Capabilities
|
||||
|
||||
- `GET /api/admin/capabilities`
|
||||
- `GET /api/admin/workspaces/{workspace_id}/protocol-capabilities`
|
||||
|
||||
Community capabilities:
|
||||
|
||||
- supported protocol: `rest`
|
||||
- supported security level: `standard`
|
||||
- machine access mode: static agent key
|
||||
|
||||
## Workspaces
|
||||
|
||||
- `GET /api/admin/workspaces`
|
||||
- `POST /api/admin/workspaces`
|
||||
- `GET /api/admin/workspaces/{workspace_id}`
|
||||
- `PATCH /api/admin/workspaces/{workspace_id}`
|
||||
- `DELETE /api/admin/workspaces/{workspace_id}`
|
||||
- `GET /api/admin/workspaces/{workspace_id}/members`
|
||||
- `PATCH /api/admin/workspaces/{workspace_id}/members/{user_id}`
|
||||
- `DELETE /api/admin/workspaces/{workspace_id}/members/{user_id}`
|
||||
|
||||
## Operations
|
||||
|
||||
- `GET /api/admin/workspaces/{workspace_id}/operations`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/operations`
|
||||
- `GET /api/admin/workspaces/{workspace_id}/operations/{operation_id}`
|
||||
- `PATCH /api/admin/workspaces/{workspace_id}/operations/{operation_id}`
|
||||
- `DELETE /api/admin/workspaces/{workspace_id}/operations/{operation_id}`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/versions`
|
||||
- `GET /api/admin/workspaces/{workspace_id}/operations/{operation_id}/versions/{version}`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/publish`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/archive`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/test-runs`
|
||||
- `GET /api/admin/workspaces/{workspace_id}/operations/{operation_id}/export`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/operations/import`
|
||||
|
||||
Community принимает только `protocol = rest`.
|
||||
|
||||
## Samples
|
||||
|
||||
- `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/samples/input-json`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/samples/output-json`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/drafts/generate`
|
||||
|
||||
## Secrets
|
||||
|
||||
- `GET /api/admin/workspaces/{workspace_id}/secrets`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/secrets`
|
||||
- `GET /api/admin/workspaces/{workspace_id}/secrets/{secret_id}`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/secrets/{secret_id}/rotate`
|
||||
- `DELETE /api/admin/workspaces/{workspace_id}/secrets/{secret_id}`
|
||||
|
||||
Create-response может вернуть plaintext secret только один раз. List/read endpoints
|
||||
возвращают только metadata.
|
||||
|
||||
## Auth profiles
|
||||
|
||||
- `GET /api/admin/workspaces/{workspace_id}/auth-profiles`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/auth-profiles`
|
||||
- `GET /api/admin/workspaces/{workspace_id}/auth-profiles/{auth_profile_id}`
|
||||
- `PATCH /api/admin/workspaces/{workspace_id}/auth-profiles/{auth_profile_id}`
|
||||
- `DELETE /api/admin/workspaces/{workspace_id}/auth-profiles/{auth_profile_id}`
|
||||
|
||||
Auth profile хранит ссылки на secrets и способ применения credential к REST request.
|
||||
|
||||
## Agents
|
||||
|
||||
- `GET /api/admin/workspaces/{workspace_id}/agents`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/agents`
|
||||
- `GET /api/admin/workspaces/{workspace_id}/agents/{agent_id}`
|
||||
- `PATCH /api/admin/workspaces/{workspace_id}/agents/{agent_id}`
|
||||
- `DELETE /api/admin/workspaces/{workspace_id}/agents/{agent_id}`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/agents/{agent_id}/versions`
|
||||
- `GET /api/admin/workspaces/{workspace_id}/agents/{agent_id}/versions/{version}`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/agents/{agent_id}/publish`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/agents/{agent_id}/unpublish`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/agents/{agent_id}/archive`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/agents/{agent_id}/bindings`
|
||||
- `DELETE /api/admin/workspaces/{workspace_id}/agents/{agent_id}/bindings/{operation_id}`
|
||||
|
||||
## Agent API keys
|
||||
|
||||
- `GET /api/admin/workspaces/{workspace_id}/agents/{agent_id}/platform-api-keys`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/agents/{agent_id}/platform-api-keys`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/agents/{agent_id}/platform-api-keys/{key_id}/revoke`
|
||||
- `DELETE /api/admin/workspaces/{workspace_id}/agents/{agent_id}/platform-api-keys/{key_id}`
|
||||
|
||||
Полное значение ключа доступно только в create-response.
|
||||
|
||||
## Logs и usage
|
||||
|
||||
- `GET /api/admin/workspaces/{workspace_id}/logs`
|
||||
- `GET /api/admin/workspaces/{workspace_id}/usage`
|
||||
@@ -0,0 +1,53 @@
|
||||
# Архитектура
|
||||
|
||||
Crank Community публикует REST API как MCP tools.
|
||||
|
||||
## Сервисы
|
||||
|
||||
- `ui` — web-интерфейс.
|
||||
- `admin-api` — HTTP API для авторизации, operations, agents, secrets, logs и settings.
|
||||
- `mcp-server` — MCP Streamable HTTP endpoint для published agents.
|
||||
|
||||
## Основные сущности
|
||||
|
||||
- `Workspace` — граница данных.
|
||||
- `Operation` — REST integration contract.
|
||||
- `Agent` — опубликованный MCP surface с ограниченным набором tools.
|
||||
- `Secret` и `AuthProfile` — безопасное применение upstream credentials.
|
||||
- `InvocationLog` и `UsageRollup` — observability.
|
||||
|
||||
## Flow
|
||||
|
||||
1. Пользователь создает REST operation.
|
||||
2. Пользователь настраивает target, schemas и mapping.
|
||||
3. `admin-api` сохраняет draft и version.
|
||||
4. Runtime выполняет test call через REST adapter.
|
||||
5. Пользователь публикует operation.
|
||||
6. Пользователь привязывает operation к agent.
|
||||
7. `mcp-server` открывает published operation как MCP tool.
|
||||
|
||||
## Runtime path
|
||||
|
||||
```text
|
||||
MCP client
|
||||
-> mcp-server
|
||||
-> crank-runtime
|
||||
-> crank-adapter-rest
|
||||
-> upstream REST API
|
||||
```
|
||||
|
||||
Input mapping переводит MCP arguments в REST request. Output mapping переводит
|
||||
REST response в MCP tool result.
|
||||
|
||||
## Хранилище
|
||||
|
||||
PostgreSQL хранит:
|
||||
|
||||
- users и sessions;
|
||||
- workspaces;
|
||||
- operations и versions;
|
||||
- agents и bindings;
|
||||
- secrets и auth profiles;
|
||||
- logs и usage.
|
||||
|
||||
Файловое хранилище используется для samples и YAML import payloads.
|
||||
@@ -0,0 +1,202 @@
|
||||
# Authenticated Staging Pass
|
||||
|
||||
## 1. Назначение
|
||||
|
||||
Этот документ описывает тот кусок Community staging smoke, который нельзя честно закрыть одними `curl` и unauthenticated route checks.
|
||||
|
||||
Он покрывает:
|
||||
|
||||
- login/logout;
|
||||
- UI shell после входа;
|
||||
- `Secrets -> Auth Profiles -> Wizard -> Test run`;
|
||||
- `REST` smoke через UI и MCP.
|
||||
|
||||
Использовать вместе с:
|
||||
|
||||
- [deploy-and-staging-smoke.md](deploy-and-staging-smoke.md)
|
||||
- [staging-regression-notes.md](staging-regression-notes.md)
|
||||
- [manual-regression-checklist.md](manual-regression-checklist.md)
|
||||
|
||||
## 2. Что нужно заранее
|
||||
|
||||
- свежий deploy уже прошел helper smoke:
|
||||
- `just staging-smoke https://<domain>`
|
||||
- Community deploy был собран из `deploy/community/docker-compose.yml`
|
||||
- automated browser-authenticated smoke при необходимости запускается так:
|
||||
- `CRANK_STAGING_ADMIN_EMAIL=... CRANK_STAGING_ADMIN_PASSWORD=... just authenticated-staging-smoke https://<domain>`
|
||||
- известны bootstrap admin credentials;
|
||||
- на стенде есть demo data или подготовленный disposable workspace;
|
||||
- браузер открыт с devtools, чтобы фиксировать network и console findings.
|
||||
|
||||
## 3. Канонический проход
|
||||
|
||||
Перед ручным проходом можно прогнать automated baseline:
|
||||
|
||||
```bash
|
||||
export CRANK_STAGING_ADMIN_EMAIL=owner@example.com
|
||||
export CRANK_STAGING_ADMIN_PASSWORD=secret
|
||||
just authenticated-staging-smoke https://<domain>
|
||||
```
|
||||
|
||||
После завершения прохода готовый блок для [staging-regression-notes.md](staging-regression-notes.md) можно сгенерировать так:
|
||||
|
||||
```bash
|
||||
just staging-note-block <domain> <deploy-sha> "codex + operator"
|
||||
```
|
||||
|
||||
### 3.1. Login and shell
|
||||
|
||||
1. Открыть `/login`
|
||||
2. Проверить:
|
||||
- invalid login -> корректная ошибка;
|
||||
- valid login -> redirect на `/`;
|
||||
- нет redirect loop;
|
||||
- password-only note видна;
|
||||
3. После входа проверить:
|
||||
- current workspace в navbar;
|
||||
- user identity;
|
||||
- language switch;
|
||||
- logout.
|
||||
|
||||
### 3.2. Core UI pages
|
||||
|
||||
После повторного входа открыть:
|
||||
|
||||
- `/`
|
||||
- `/agents`
|
||||
- `/api-keys`
|
||||
- `/secrets`
|
||||
- `/logs`
|
||||
- `/usage`
|
||||
- `/workspace-setup`
|
||||
- `/settings`
|
||||
- `/wizard/`
|
||||
|
||||
Для каждой страницы зафиксировать:
|
||||
|
||||
- `status: passed | partial | failed`
|
||||
- есть ли console errors;
|
||||
- есть ли failing XHR или fetch;
|
||||
- есть ли broken layout.
|
||||
|
||||
### 3.3. Secrets and auth profiles
|
||||
|
||||
1. Открыть `/secrets`
|
||||
2. Создать disposable `token` secret
|
||||
3. При необходимости создать еще:
|
||||
- `header`
|
||||
- `username_password`
|
||||
4. Проверить:
|
||||
- list/update timestamps;
|
||||
- rotate;
|
||||
- delete;
|
||||
- usage references
|
||||
|
||||
### 3.4. Wizard auth flow
|
||||
|
||||
1. Открыть `/wizard/`
|
||||
2. На шаге 2:
|
||||
- выбрать `No auth`;
|
||||
- выбрать existing auth profile;
|
||||
- создать quick secret;
|
||||
- создать quick auth profile;
|
||||
3. Сохранить upstream
|
||||
4. Дойти до `Test run`
|
||||
5. Подтвердить, что:
|
||||
- нет `${secrets.*}`;
|
||||
- upstream сохраняется;
|
||||
- test run отрабатывает с `auth_profile_ref`.
|
||||
|
||||
### 3.5. REST protocol smoke
|
||||
|
||||
Использовать:
|
||||
|
||||
- [public-smoke-targets.md](public-smoke-targets.md)
|
||||
|
||||
Обязательный кейс:
|
||||
|
||||
- `REST`
|
||||
|
||||
Порядок:
|
||||
|
||||
1. создать или открыть operation;
|
||||
2. выполнить `Test run`;
|
||||
3. publish;
|
||||
4. привязать к agent;
|
||||
5. выполнить MCP smoke:
|
||||
- `tools/list`
|
||||
- `tools/call`
|
||||
|
||||
## 4. Что нужно занести в staging notes
|
||||
|
||||
По итогам authenticated pass в [staging-regression-notes.md](staging-regression-notes.md) обязательно добавить:
|
||||
|
||||
- deploy commit;
|
||||
- кто проходил smoke;
|
||||
- что именно проверено;
|
||||
- что прошло;
|
||||
- findings с severity;
|
||||
- infra notes;
|
||||
- explicit status для:
|
||||
- auth;
|
||||
- secrets/auth profiles;
|
||||
- wizard;
|
||||
- REST;
|
||||
- MCP smoke.
|
||||
|
||||
## 5. Готовый блок для вставки
|
||||
|
||||
Этот же блок можно получить через:
|
||||
|
||||
```bash
|
||||
just staging-note-block <domain> <deploy-sha> "codex + operator"
|
||||
```
|
||||
|
||||
```md
|
||||
## YYYY-MM-DD HH:MM TZ — rmcp.itexp.me (authenticated pass)
|
||||
|
||||
- deploy commit: `<sha>`
|
||||
- checked by: `<name>`
|
||||
- smoke status: `passed | partial | failed`
|
||||
- scope:
|
||||
- auth
|
||||
- ui shell
|
||||
- operations
|
||||
- wizard
|
||||
- agents
|
||||
- api keys
|
||||
- secrets
|
||||
- logs
|
||||
- usage
|
||||
- rest smoke
|
||||
- mcp smoke
|
||||
|
||||
### Passed
|
||||
|
||||
- login/logout completed
|
||||
- shell pages open after auth
|
||||
- secrets/auth profile flow status: `<passed|partial|failed>`
|
||||
- REST smoke: `<passed|partial|failed>`
|
||||
- MCP smoke: `<passed|partial|failed>`
|
||||
|
||||
### Findings
|
||||
|
||||
- none
|
||||
|
||||
### Infra notes
|
||||
|
||||
- ...
|
||||
|
||||
### Follow-up
|
||||
|
||||
- ...
|
||||
```
|
||||
|
||||
## 6. Почему automated smoke недостаточно
|
||||
|
||||
Скрипт [scripts/authenticated-staging-smoke.sh](../scripts/authenticated-staging-smoke.sh) полезен как быстрый sanity check, но он:
|
||||
|
||||
- проверяет только минимальный browser flow;
|
||||
- не создает реальный disposable operation;
|
||||
- не заменяет ручной `REST -> publish -> MCP call` проход;
|
||||
- не должен отмечаться как `passed`, пока результаты не занесены в [staging-regression-notes.md](staging-regression-notes.md).
|
||||
@@ -0,0 +1,96 @@
|
||||
# Модель данных
|
||||
|
||||
Документ фиксирует текущую Community data model.
|
||||
|
||||
## Workspace
|
||||
|
||||
Workspace содержит:
|
||||
|
||||
- operations;
|
||||
- agents;
|
||||
- secrets;
|
||||
- auth profiles;
|
||||
- logs;
|
||||
- usage.
|
||||
|
||||
## Operation
|
||||
|
||||
Operation описывает один REST integration contract.
|
||||
|
||||
Основные поля:
|
||||
|
||||
- `id`
|
||||
- `workspace_id`
|
||||
- `name`
|
||||
- `display_name`
|
||||
- `category`
|
||||
- `protocol = rest`
|
||||
- `status`
|
||||
- `target`
|
||||
- `input_schema`
|
||||
- `output_schema`
|
||||
- `input_mapping`
|
||||
- `output_mapping`
|
||||
- `execution_config`
|
||||
- `tool_description`
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
|
||||
## REST target
|
||||
|
||||
REST target содержит:
|
||||
|
||||
- `base_url`
|
||||
- `method`
|
||||
- `path_template`
|
||||
- `static_headers`
|
||||
|
||||
Поддерживаемые методы:
|
||||
|
||||
- `GET`
|
||||
- `POST`
|
||||
- `PUT`
|
||||
- `PATCH`
|
||||
- `DELETE`
|
||||
|
||||
## Agent
|
||||
|
||||
Agent определяет MCP endpoint и набор published operations.
|
||||
|
||||
Основные поля:
|
||||
|
||||
- `id`
|
||||
- `workspace_id`
|
||||
- `slug`
|
||||
- `display_name`
|
||||
- `description`
|
||||
- `status`
|
||||
|
||||
Operation публикуется в agent через binding.
|
||||
|
||||
## Secrets и auth profiles
|
||||
|
||||
`Secret` хранит encrypted secret material.
|
||||
|
||||
`AuthProfile` описывает, как применить secret к REST request:
|
||||
|
||||
- bearer token;
|
||||
- basic auth;
|
||||
- API key header;
|
||||
- API key query parameter.
|
||||
|
||||
Plaintext secret не возвращается через API после создания.
|
||||
|
||||
## Logs и usage
|
||||
|
||||
Invocation logs фиксируют:
|
||||
|
||||
- workspace;
|
||||
- agent;
|
||||
- operation;
|
||||
- request id;
|
||||
- status;
|
||||
- latency;
|
||||
- structured error context.
|
||||
|
||||
Usage rollups агрегируют вызовы по периодам.
|
||||
@@ -0,0 +1,65 @@
|
||||
# Схема БД
|
||||
|
||||
Основная БД Crank Community — PostgreSQL.
|
||||
|
||||
## Основные таблицы
|
||||
|
||||
- `workspaces`
|
||||
- `users`
|
||||
- `user_sessions`
|
||||
- `memberships`
|
||||
- `invitation_tokens`
|
||||
- `operations`
|
||||
- `operation_versions`
|
||||
- `published_operations`
|
||||
- `operation_samples`
|
||||
- `agents`
|
||||
- `agent_versions`
|
||||
- `agent_operation_bindings`
|
||||
- `published_agents`
|
||||
- `platform_api_keys`
|
||||
- `secrets`
|
||||
- `secret_versions`
|
||||
- `auth_profiles`
|
||||
- `invocation_logs`
|
||||
- `usage_rollups`
|
||||
- `yaml_import_jobs`
|
||||
|
||||
## Operations
|
||||
|
||||
`operations` хранит текущую карточку operation.
|
||||
|
||||
`operation_versions` хранит versioned JSON contract:
|
||||
|
||||
- REST target;
|
||||
- schemas;
|
||||
- mappings;
|
||||
- execution config;
|
||||
- tool description;
|
||||
- samples metadata.
|
||||
|
||||
`published_operations` указывает на опубликованную version.
|
||||
|
||||
## Agents
|
||||
|
||||
`agents` хранит карточку agent.
|
||||
|
||||
`agent_versions` хранит versioned agent contract.
|
||||
|
||||
`agent_operation_bindings` связывает agent и published operations.
|
||||
|
||||
`published_agents` указывает на опубликованную version.
|
||||
|
||||
## Secrets
|
||||
|
||||
`secrets` хранит metadata.
|
||||
|
||||
`secret_versions` хранит encrypted value.
|
||||
|
||||
`auth_profiles` хранит способ применения secrets к REST request.
|
||||
|
||||
## Observability
|
||||
|
||||
`invocation_logs` хранит события runtime/MCP вызовов.
|
||||
|
||||
`usage_rollups` хранит агрегированную статистику.
|
||||
@@ -0,0 +1,81 @@
|
||||
# Demo Runbook
|
||||
|
||||
Документ описывает минимальный Community demo flow.
|
||||
|
||||
## Предусловия
|
||||
|
||||
- PostgreSQL доступен.
|
||||
- `admin-api` и `mcp-server` имеют доступ к PostgreSQL.
|
||||
- Заданы `CRANK_MASTER_KEY`, `CRANK_SESSION_SECRET` и `CRANK_PASSWORD_PEPPER`.
|
||||
- Bootstrap admin user задан через environment variables.
|
||||
- UI собран или запущен локально.
|
||||
|
||||
## Локальный backend
|
||||
|
||||
```bash
|
||||
cargo run -p admin-api
|
||||
```
|
||||
|
||||
Во втором терминале:
|
||||
|
||||
```bash
|
||||
cargo run -p mcp-server
|
||||
```
|
||||
|
||||
## UI
|
||||
|
||||
```bash
|
||||
cd apps/ui
|
||||
npm ci
|
||||
npm run build
|
||||
```
|
||||
|
||||
## Health checks
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:3001/health
|
||||
curl http://127.0.0.1:3002/health
|
||||
```
|
||||
|
||||
Ожидаемые ответы:
|
||||
|
||||
```json
|
||||
{"service":"admin-api","status":"ok"}
|
||||
{"service":"mcp-server","status":"ok"}
|
||||
```
|
||||
|
||||
## REST operation demo
|
||||
|
||||
1. Войти под bootstrap admin user.
|
||||
2. Создать REST operation в wizard.
|
||||
3. Настроить upstream URL, method, schemas и mapping.
|
||||
4. Выполнить test call.
|
||||
5. Сохранить draft.
|
||||
6. Опубликовать operation.
|
||||
7. Привязать published operation к agent.
|
||||
8. Создать agent API key.
|
||||
9. Вызвать `tools/list` через agent MCP endpoint.
|
||||
10. Вызвать published REST tool через `tools/call`.
|
||||
|
||||
## YAML roundtrip
|
||||
|
||||
YAML roundtrip считается рабочим, если:
|
||||
|
||||
1. REST operation экспортируется в YAML.
|
||||
2. Экспортированный YAML импортируется в режиме `upsert`.
|
||||
3. Imported draft создает новую version operation.
|
||||
4. Новую version можно протестировать и опубликовать.
|
||||
|
||||
## Post-deploy smoke
|
||||
|
||||
```bash
|
||||
just staging-smoke https://<domain>
|
||||
```
|
||||
|
||||
Authenticated browser smoke:
|
||||
|
||||
```bash
|
||||
export CRANK_STAGING_ADMIN_EMAIL=owner@example.com
|
||||
export CRANK_STAGING_ADMIN_PASSWORD=secret
|
||||
just authenticated-staging-smoke https://<domain>
|
||||
```
|
||||
@@ -0,0 +1,229 @@
|
||||
# Deploy And Staging Smoke
|
||||
|
||||
## 1. Назначение
|
||||
|
||||
Этот документ фиксирует обязательный post-deploy smoke pass для `Community` staging или production-like окружения.
|
||||
|
||||
Он нужен для двух задач:
|
||||
|
||||
- быстро проверить, что свежий deploy реально жив, а не просто `docker compose up -d` завершился без ошибок;
|
||||
- дать оператору и следующему агенту один канонический сценарий проверки после релиза.
|
||||
|
||||
Для Community-поставки source of truth для runtime manifests:
|
||||
|
||||
- `deploy/community/docker-compose.yml`
|
||||
- `deploy/community/.env.example`
|
||||
|
||||
Результаты прохождения этого checklist нужно заносить в [staging-regression-notes.md](staging-regression-notes.md).
|
||||
|
||||
Для полного browser-authenticated прохода использовать отдельный документ:
|
||||
|
||||
- [authenticated-staging-pass.md](authenticated-staging-pass.md)
|
||||
|
||||
## 2. Когда использовать
|
||||
|
||||
Запускать после:
|
||||
|
||||
- merge в `main` и успешного `Deploy`;
|
||||
- изменений `nginx` или routing;
|
||||
- изменений auth/session;
|
||||
- изменений `mcp-server`;
|
||||
- изменений secrets/auth profiles;
|
||||
- изменений UI routing и login flow;
|
||||
- изменений `deploy/community/*`.
|
||||
|
||||
## 3. Предусловия
|
||||
|
||||
Нужно иметь:
|
||||
|
||||
- задеплоенный стек `ui`, `admin-api`, `mcp-server`, `postgres`;
|
||||
- корректный `.env` на сервере;
|
||||
- валидный deploy через `.gitea/workflows/deploy.yml`;
|
||||
- server deployment path, собранный из `deploy/community/docker-compose.yml`;
|
||||
- `CRANK_DEMO_SEED=true`, если нужен предзаполненный smoke state;
|
||||
- bootstrap admin credentials для входа в UI.
|
||||
|
||||
## 3.1. Быстрый automated smoke
|
||||
|
||||
Есть helper script:
|
||||
|
||||
```bash
|
||||
just staging-smoke https://<domain>
|
||||
```
|
||||
|
||||
или напрямую:
|
||||
|
||||
```bash
|
||||
bash scripts/staging-smoke.sh https://<domain>
|
||||
```
|
||||
|
||||
Он проверяет:
|
||||
|
||||
- public routes;
|
||||
- `/api/auth/session` JSON contract;
|
||||
- `/mcp/health`;
|
||||
- legacy `/html/...` redirects.
|
||||
|
||||
Это не заменяет ручной smoke pass ниже, а только быстро отсеивает грубые deploy или routing поломки.
|
||||
|
||||
## 4. Server-side smoke
|
||||
|
||||
На сервере:
|
||||
|
||||
```bash
|
||||
cd /opt/rmcp
|
||||
docker compose ps
|
||||
docker compose logs --tail=100 admin-api
|
||||
docker compose logs --tail=100 mcp-server
|
||||
```
|
||||
|
||||
Ожидаемо:
|
||||
|
||||
- `admin-api` в `Up` или `healthy`;
|
||||
- `mcp-server` в `Up` или `healthy`;
|
||||
- нет циклических restart-ов;
|
||||
- нет `password authentication failed`, `panic`, `invalid transition` и аналогичных fatal ошибок.
|
||||
|
||||
Проверка health endpoints:
|
||||
|
||||
```bash
|
||||
curl --fail --silent http://127.0.0.1:3001/health
|
||||
curl --fail --silent http://127.0.0.1:3002/health
|
||||
```
|
||||
|
||||
## 5. Reverse proxy smoke
|
||||
|
||||
Проверить снаружи:
|
||||
|
||||
```bash
|
||||
curl -I https://<domain>/
|
||||
curl -I https://<domain>/login
|
||||
curl -I https://<domain>/agents
|
||||
curl -I https://<domain>/secrets
|
||||
curl -I https://<domain>/wizard/
|
||||
curl -I https://<domain>/api/auth/session
|
||||
curl -I https://<domain>/mcp/health
|
||||
```
|
||||
|
||||
Ожидаемо:
|
||||
|
||||
- `/`, `/login`, `/agents`, `/secrets`, `/wizard/` -> `200`;
|
||||
- `/api/auth/session` -> `200` или `401` с JSON, но не HTML fallback;
|
||||
- `/mcp/health` -> `200`;
|
||||
- старые `/html/...` пути редиректят на clean routes.
|
||||
|
||||
Дополнительно проверить:
|
||||
|
||||
```bash
|
||||
curl -I https://<domain>/html/login.html
|
||||
curl -I https://<domain>/html/agents.html
|
||||
curl -I https://<domain>/html/wizard/
|
||||
```
|
||||
|
||||
Ожидаемо:
|
||||
|
||||
- `302` на `/login`, `/agents`, `/wizard/`.
|
||||
|
||||
## 6. UI smoke
|
||||
|
||||
В браузере:
|
||||
|
||||
1. Открыть `/login`
|
||||
2. Проверить:
|
||||
- нет redirect loop;
|
||||
- invalid login показывает ошибку;
|
||||
- страница честно помечает password-only flow;
|
||||
3. Выполнить login.
|
||||
4. Проверить navbar:
|
||||
- workspace switch;
|
||||
- user identity;
|
||||
- clean routing без `/html/...`.
|
||||
|
||||
## 7. Core page smoke
|
||||
|
||||
После входа открыть и проверить:
|
||||
|
||||
- `/`
|
||||
- `/agents`
|
||||
- `/api-keys`
|
||||
- `/secrets`
|
||||
- `/logs`
|
||||
- `/usage`
|
||||
- `/workspace-setup`
|
||||
- `/settings`
|
||||
- `/wizard/`
|
||||
|
||||
Для каждой страницы:
|
||||
|
||||
- данные грузятся;
|
||||
- нет бесконечных spinners;
|
||||
- нет console errors;
|
||||
- empty/loading/error states выглядят корректно;
|
||||
- language switch не ломает layout.
|
||||
|
||||
## 8. Auth and secrets smoke
|
||||
|
||||
Обязательная связка:
|
||||
|
||||
1. Открыть `/secrets`
|
||||
2. Создать secret
|
||||
3. Создать или выбрать auth profile
|
||||
4. Открыть `/wizard/`
|
||||
5. На шаге 2:
|
||||
- выбрать existing auth profile;
|
||||
- проверить quick-create secret;
|
||||
- проверить quick-create auth profile;
|
||||
6. Сохранить upstream
|
||||
7. Выполнить `Test run`
|
||||
|
||||
Smoke считается успешным, если:
|
||||
|
||||
- wizard не требует `${secrets.*}`;
|
||||
- `auth_profile_ref` реально доезжает до execution path;
|
||||
- plaintext не возвращается после create или rotate.
|
||||
|
||||
## 9. MCP and REST smoke
|
||||
|
||||
Использовать пример из [public-smoke-targets.md](public-smoke-targets.md).
|
||||
|
||||
Обязательный ручной кейс:
|
||||
|
||||
- `REST` -> `Open-Meteo`
|
||||
|
||||
Порядок:
|
||||
|
||||
1. создать operation;
|
||||
2. выполнить `Test run`;
|
||||
3. publish;
|
||||
4. привязать к agent;
|
||||
5. проверить MCP path;
|
||||
6. выполнить `tools/list` и `tools/call`.
|
||||
|
||||
## 10. Acceptance criteria
|
||||
|
||||
Deploy или staging smoke считается успешным, если:
|
||||
|
||||
- server health зеленый;
|
||||
- reverse proxy отдает правильные routes;
|
||||
- login/session живы;
|
||||
- все core pages открываются;
|
||||
- связка `Secrets -> Auth Profiles -> Wizard -> Test run` работает;
|
||||
- минимум один `REST` operation проходит `create -> test-run -> publish -> MCP call`;
|
||||
- нет критичных JS ошибок в браузере.
|
||||
|
||||
## 11. Если что-то падает
|
||||
|
||||
Порядок разбора:
|
||||
|
||||
1. `docker compose ps`
|
||||
2. `docker compose logs --tail=100 admin-api`
|
||||
3. `docker compose logs --tail=100 mcp-server`
|
||||
4. `curl` локальных `/health`
|
||||
5. `curl -I` публичных routes
|
||||
6. browser devtools:
|
||||
- network;
|
||||
- console;
|
||||
- `/api/auth/session`;
|
||||
- page-specific API requests
|
||||
|
||||
Не надо сразу трогать БД, env или `nginx`, пока не найден точный failing layer.
|
||||
@@ -0,0 +1,183 @@
|
||||
# Deployment
|
||||
|
||||
Документ описывает поддерживаемый путь деплоя Crank Community.
|
||||
|
||||
Crank Community запускается как три application containers за reverse proxy:
|
||||
|
||||
- `ui`
|
||||
- `admin-api`
|
||||
- `mcp-server`
|
||||
|
||||
Приложение использует внешний PostgreSQL. Compose manifest не поднимает
|
||||
PostgreSQL самостоятельно.
|
||||
|
||||
## Runtime topology
|
||||
|
||||
```text
|
||||
reverse proxy
|
||||
/ -> ui:3000
|
||||
/api/admin/ -> admin-api:3001
|
||||
/mcp/ -> mcp-server:3002
|
||||
|
||||
admin-api -> PostgreSQL
|
||||
mcp-server -> PostgreSQL
|
||||
admin-api -> optional Valkey/Redis
|
||||
mcp-server -> optional Valkey/Redis
|
||||
```
|
||||
|
||||
## Deployment files
|
||||
|
||||
- `deploy/community/docker-compose.yml`
|
||||
- `deploy/community/.env.example`
|
||||
- `.gitea/workflows/ci.yml`
|
||||
- `.gitea/workflows/deploy.yml`
|
||||
- `.gitea/workflows/release.yml`
|
||||
|
||||
## Порты
|
||||
|
||||
Default service ports:
|
||||
|
||||
- `ui`: `3000`
|
||||
- `admin-api`: `3001`
|
||||
- `mcp-server`: `3002`
|
||||
- optional `valkey`: `6379`, только loopback
|
||||
|
||||
`CRANK_PUBLISH_BIND` управляет публикацией application ports:
|
||||
|
||||
- `127.0.0.1`, если reverse proxy работает на том же host;
|
||||
- `0.0.0.0`, если reverse proxy работает на другом host.
|
||||
|
||||
## Reverse proxy
|
||||
|
||||
Пример `nginx`:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name crank.example.com;
|
||||
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name crank.example.com;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/crank.example.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/crank.example.com/privkey.pem;
|
||||
|
||||
client_max_body_size 25m;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
location / {
|
||||
proxy_pass http://192.168.1.106:3000;
|
||||
}
|
||||
|
||||
location /api/admin/ {
|
||||
proxy_pass http://192.168.1.106:3001/;
|
||||
}
|
||||
|
||||
location /mcp/ {
|
||||
proxy_pass http://192.168.1.106:3002/;
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
proxy_read_timeout 300s;
|
||||
proxy_send_timeout 300s;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Замените `192.168.1.106` на адрес deployment host.
|
||||
|
||||
## Compose
|
||||
|
||||
Проверка manifest:
|
||||
|
||||
```bash
|
||||
docker compose \
|
||||
-f deploy/community/docker-compose.yml \
|
||||
--env-file deploy/community/.env.example \
|
||||
config -q
|
||||
```
|
||||
|
||||
Запуск без внешнего cache:
|
||||
|
||||
```bash
|
||||
docker compose \
|
||||
-f deploy/community/docker-compose.yml \
|
||||
--env-file deploy/community/.env.example \
|
||||
up -d
|
||||
```
|
||||
|
||||
Запуск со встроенным Valkey:
|
||||
|
||||
```bash
|
||||
docker compose \
|
||||
-f deploy/community/docker-compose.yml \
|
||||
--env-file deploy/community/.env.example \
|
||||
--profile cache \
|
||||
up -d
|
||||
```
|
||||
|
||||
Для встроенного Valkey:
|
||||
|
||||
```text
|
||||
CRANK_CACHE_BACKEND=valkey
|
||||
CRANK_CACHE_URL=redis://valkey:6379/0
|
||||
CRANK_CACHE_DEFAULT_TTL_MS=60000
|
||||
```
|
||||
|
||||
## Health checks
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:3001/health
|
||||
curl http://127.0.0.1:3002/health
|
||||
```
|
||||
|
||||
Ожидаемые ответы:
|
||||
|
||||
```json
|
||||
{"service":"admin-api","status":"ok"}
|
||||
{"service":"mcp-server","status":"ok"}
|
||||
```
|
||||
|
||||
UI root должен возвращать `200 OK`:
|
||||
|
||||
```bash
|
||||
curl -I http://127.0.0.1:3000/
|
||||
```
|
||||
|
||||
## Gitea CI/CD
|
||||
|
||||
Репозиторий использует Gitea Actions:
|
||||
|
||||
- `.gitea/workflows/ci.yml` запускает Rust, UI, E2E и deployment manifest checks.
|
||||
- `.gitea/workflows/deploy.yml` собирает images и деплоит `main`.
|
||||
- `.gitea/workflows/release.yml` собирает release artifacts для tags.
|
||||
|
||||
Deploy workflow читает из Gitea secrets только OpenBao bootstrap credentials:
|
||||
|
||||
- `BAO_ADDR`
|
||||
- `BAO_ROLE_ID`
|
||||
- `BAO_SECRET_ID`
|
||||
|
||||
Дальше workflow читает KV v2 secrets из OpenBao:
|
||||
|
||||
```text
|
||||
ci/shared/registry
|
||||
ci/shared/deploy-ssh
|
||||
ci/projects/crank/deploy
|
||||
ci/projects/crank/runtime
|
||||
```
|
||||
|
||||
## Operational notes
|
||||
|
||||
- Бэкапы БД должны жить вне application host.
|
||||
- Runtime secrets хранятся в OpenBao, не в Git.
|
||||
- Для rollback используйте immutable image tags.
|
||||
- `CRANK_PUBLISH_BIND=0.0.0.0` нужен только если другой host должен обращаться к published ports напрямую.
|
||||
@@ -0,0 +1,149 @@
|
||||
# Диаграммы
|
||||
|
||||
## 1. Назначение документа
|
||||
|
||||
Этот документ собирает диаграммы целевой модели проекта:
|
||||
|
||||
- компонентную структуру;
|
||||
- связи между доменными сущностями;
|
||||
- хранение данных в БД.
|
||||
|
||||
Примечание:
|
||||
|
||||
- диаграммы требуют следующего обновления по слою машинного доступа;
|
||||
- вместо `PlatformApiKey` целевая модель проекта теперь использует `AgentKey`, `IssuedAgentToken` и при необходимости `PlatformClientCredential`;
|
||||
- детальная схема зафиксирована в `docs/agent-auth-model.md`.
|
||||
|
||||
## 2. Компонентная диаграмма
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
UI[crank-ui]
|
||||
ADMIN[admin-api]
|
||||
MCP[mcp-server]
|
||||
REG[crank-registry]
|
||||
RUN[crank-runtime]
|
||||
CORE[crank-core]
|
||||
SCHEMA[crank-schema]
|
||||
MAP[crank-mapping]
|
||||
REST[adapter-rest]
|
||||
DB[(PostgreSQL)]
|
||||
STORE[(Artifact Storage)]
|
||||
OBS[(Usage and Logs)]
|
||||
|
||||
UI --> ADMIN
|
||||
MCP --> REG
|
||||
MCP --> RUN
|
||||
ADMIN --> REG
|
||||
ADMIN --> RUN
|
||||
REG --> DB
|
||||
REG --> CORE
|
||||
REG --> SCHEMA
|
||||
REG --> MAP
|
||||
RUN --> CORE
|
||||
RUN --> SCHEMA
|
||||
RUN --> MAP
|
||||
RUN --> REST
|
||||
ADMIN --> STORE
|
||||
REG --> OBS
|
||||
ADMIN --> OBS
|
||||
```
|
||||
|
||||
## 3. Структурная диаграмма доменной модели
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Workspace {
|
||||
+id
|
||||
+slug
|
||||
+display_name
|
||||
}
|
||||
|
||||
class Operation {
|
||||
+id
|
||||
+workspace_id
|
||||
+name
|
||||
+display_name
|
||||
+protocol
|
||||
+status
|
||||
}
|
||||
|
||||
class Agent {
|
||||
+id
|
||||
+workspace_id
|
||||
+slug
|
||||
+display_name
|
||||
+status
|
||||
}
|
||||
|
||||
class AgentBinding {
|
||||
+operation_id
|
||||
+operation_version
|
||||
+tool_name
|
||||
+enabled
|
||||
}
|
||||
|
||||
class PlatformApiKey {
|
||||
+id
|
||||
+workspace_id
|
||||
+name
|
||||
+prefix
|
||||
+scopes
|
||||
+status
|
||||
}
|
||||
|
||||
class InvocationLog {
|
||||
+workspace_id
|
||||
+agent_id
|
||||
+operation_id
|
||||
+status
|
||||
+duration_ms
|
||||
}
|
||||
|
||||
Workspace --> Operation : owns
|
||||
Workspace --> Agent : owns
|
||||
Workspace --> PlatformApiKey : owns
|
||||
Agent --> AgentBinding : contains
|
||||
AgentBinding --> Operation : references
|
||||
InvocationLog --> Workspace : belongs_to
|
||||
InvocationLog --> Agent : belongs_to
|
||||
InvocationLog --> Operation : belongs_to
|
||||
```
|
||||
|
||||
## 4. ER-диаграмма БД
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
WORKSPACES ||--o{ OPERATIONS : owns
|
||||
WORKSPACES ||--o{ AGENTS : owns
|
||||
WORKSPACES ||--o{ AUTH_PROFILES : owns
|
||||
WORKSPACES ||--o{ PLATFORM_API_KEYS : owns
|
||||
WORKSPACES ||--o{ INVOCATION_LOGS : owns
|
||||
OPERATIONS ||--o{ OPERATION_VERSIONS : has
|
||||
OPERATIONS ||--o| PUBLISHED_OPERATIONS : publishes
|
||||
AGENTS ||--o{ AGENT_VERSIONS : has
|
||||
AGENTS ||--o| PUBLISHED_AGENTS : publishes
|
||||
AGENT_VERSIONS ||--o{ AGENT_OPERATION_BINDINGS : contains
|
||||
OPERATIONS ||--o{ AGENT_OPERATION_BINDINGS : exposed_by
|
||||
|
||||
WORKSPACES {
|
||||
text id PK
|
||||
text slug
|
||||
text display_name
|
||||
}
|
||||
OPERATIONS {
|
||||
text id PK
|
||||
text workspace_id FK
|
||||
text name
|
||||
text display_name
|
||||
text protocol
|
||||
text status
|
||||
}
|
||||
AGENTS {
|
||||
text id PK
|
||||
text workspace_id FK
|
||||
text slug
|
||||
text display_name
|
||||
text status
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,53 @@
|
||||
# Crank
|
||||
|
||||
Crank Community is a self-hosted platform for publishing REST APIs as MCP tools.
|
||||
|
||||
It lets operators describe an upstream REST endpoint, test it, publish it, and
|
||||
expose it to LLM clients through MCP without writing a custom MCP server for
|
||||
each integration.
|
||||
|
||||
## Features
|
||||
|
||||
- REST operation creation from the web UI or YAML.
|
||||
- MCP input mapping into REST query, body, and header fields.
|
||||
- REST response mapping into structured MCP tool output.
|
||||
- Agent-scoped MCP endpoints with curated tool catalogs.
|
||||
- Operation drafts, versions, samples, mappings, logs, and usage in PostgreSQL.
|
||||
- Simple admin authentication with a bootstrap admin user.
|
||||
- PostgreSQL-backed secrets and auth profiles for upstream REST APIs.
|
||||
- Docker Compose deployment.
|
||||
|
||||
## Community Scope
|
||||
|
||||
This repository contains only the Community feature set:
|
||||
|
||||
- REST protocol only.
|
||||
- Single self-hosted deployment.
|
||||
- Simple admin authentication.
|
||||
- Static agent API keys for MCP access.
|
||||
- PostgreSQL as the system database.
|
||||
- Optional Valkey/Redis cache for runtime coordination.
|
||||
- Gitea Actions CI/CD.
|
||||
|
||||
The repository is focused only on the scope listed above.
|
||||
|
||||
## Architecture
|
||||
|
||||
Core concepts:
|
||||
|
||||
- `Workspace` is the data boundary for operations, agents, secrets, and logs.
|
||||
- `Operation` is a versioned REST integration contract.
|
||||
- `Agent` is an MCP surface that exposes a curated set of operations.
|
||||
|
||||
Runtime flow:
|
||||
|
||||
1. An operator creates or imports a REST operation.
|
||||
2. Crank validates the schema and mapping.
|
||||
3. The operator runs a test call against the upstream REST API.
|
||||
4. The operation is published.
|
||||
5. An agent exposes the published operation as an MCP tool.
|
||||
6. MCP clients call the tool through `mcp-server`.
|
||||
|
||||
## License
|
||||
|
||||
GNU Affero General Public License v3.0 only
|
||||
@@ -0,0 +1,183 @@
|
||||
# Ручной regression checklist
|
||||
|
||||
## 1. Назначение
|
||||
|
||||
Этот документ фиксирует post-integration baseline для Community UI, auth, secrets и REST/MCP slices.
|
||||
|
||||
Цель:
|
||||
|
||||
- дать воспроизводимый regression pass после крупных вертикальных срезов;
|
||||
- отделить автоматический baseline от ручного smoke на стенде;
|
||||
- не заставлять следующего агента заново собирать сценарии по всему проекту.
|
||||
|
||||
## 2. Автоматический baseline
|
||||
|
||||
Локальный regression baseline на `2026-04-07`:
|
||||
|
||||
- `cargo check --workspace` -> passed;
|
||||
- `cd apps/ui && npm run e2e` -> `11 passed`;
|
||||
- e2e стек поднимает:
|
||||
- `postgres`;
|
||||
- `admin-api`;
|
||||
- `mcp-server`;
|
||||
- локальный UI proxy.
|
||||
|
||||
Покрытые автоматикой сценарии:
|
||||
|
||||
- login;
|
||||
- operations catalog;
|
||||
- agents;
|
||||
- api keys;
|
||||
- logs;
|
||||
- usage;
|
||||
- workspace/settings;
|
||||
- wizard;
|
||||
- REST draft/test/publish flow.
|
||||
|
||||
## 3. Когда запускать этот pass
|
||||
|
||||
Запускать обязательно после изменений в:
|
||||
|
||||
- auth/session;
|
||||
- workspace switching;
|
||||
- operations/wizard;
|
||||
- agents;
|
||||
- secrets/auth profiles;
|
||||
- MCP transport;
|
||||
- deploy routing/UI routes.
|
||||
|
||||
## 4. Обязательные команды перед ручным проходом
|
||||
|
||||
```bash
|
||||
cargo check --workspace
|
||||
cd apps/ui && npm run e2e
|
||||
```
|
||||
|
||||
Если одна из команд не проходит, ручной regression pass не считается завершенным.
|
||||
|
||||
## 5. Ручной smoke checklist
|
||||
|
||||
### 5.1. Auth и shell
|
||||
|
||||
- открыть `/login`;
|
||||
- проверить, что страница не зацикливается на redirect;
|
||||
- проверить invalid login;
|
||||
- войти bootstrap admin-пользователем;
|
||||
- убедиться, что после входа открывается `/`;
|
||||
- проверить logout;
|
||||
- войти повторно;
|
||||
- проверить header identity;
|
||||
- проверить language switch;
|
||||
- проверить workspace switch в navbar.
|
||||
|
||||
### 5.2. Operations
|
||||
|
||||
- открыть `/`;
|
||||
- убедиться, что demo operations загружены;
|
||||
- проверить search;
|
||||
- проверить protocol/category/agent filters;
|
||||
- открыть edit существующей operation;
|
||||
- удалить operation из demo workspace только если это безопасно для текущего стенда;
|
||||
- проверить success/error toasts;
|
||||
- проверить clean routes без `/html/...`.
|
||||
|
||||
### 5.3. Wizard
|
||||
|
||||
- открыть `/wizard/`;
|
||||
- убедиться, что доступна только `REST` protocol card;
|
||||
- для нового upstream проверить режимы auth:
|
||||
- `No auth`
|
||||
- `Use existing auth profile`
|
||||
- `Create auth profile now`
|
||||
- создать quick secret из wizard;
|
||||
- создать quick auth profile из wizard;
|
||||
- сохранить upstream;
|
||||
- убедиться, что `execution_config.auth_profile_ref` попадает в draft/test flow;
|
||||
- проверить sample upload;
|
||||
- проверить YAML export/import;
|
||||
- проверить `Test run`;
|
||||
- проверить `Publish`.
|
||||
|
||||
### 5.4. Agents
|
||||
|
||||
- открыть `/agents`;
|
||||
- проверить cards и lifecycle badges;
|
||||
- открыть drawer;
|
||||
- проверить bindings;
|
||||
- создать или обновить agent;
|
||||
- проверить publish/unpublish/archive flow;
|
||||
- проверить copy MCP endpoint.
|
||||
|
||||
### 5.5. API Keys
|
||||
|
||||
- открыть `/api-keys`;
|
||||
- создать key;
|
||||
- убедиться, что raw key показывается один раз;
|
||||
- проверить copy;
|
||||
- проверить revoke;
|
||||
- проверить delete;
|
||||
- проверить `last_used_at` после реального machine-auth вызова при необходимости.
|
||||
|
||||
### 5.6. Secrets
|
||||
|
||||
- открыть `/secrets`;
|
||||
- проверить list/create/rotate/delete;
|
||||
- создать:
|
||||
- `token`;
|
||||
- `username_password`;
|
||||
- `header`;
|
||||
- `generic`;
|
||||
- убедиться, что plaintext не возвращается после create/rotate;
|
||||
- проверить usage references через auth profiles;
|
||||
- проверить, что wizard quick-create синхронизируется с этой страницей.
|
||||
|
||||
### 5.7. Logs и Usage
|
||||
|
||||
- открыть `/logs`;
|
||||
- проверить loading/error/empty states;
|
||||
- проверить detail expansion;
|
||||
- открыть `/usage`;
|
||||
- проверить summary cards;
|
||||
- проверить timeline chart;
|
||||
- проверить CSV export.
|
||||
|
||||
### 5.8. Workspace и Settings
|
||||
|
||||
- открыть `/workspace-setup`;
|
||||
- проверить members;
|
||||
- проверить invitations;
|
||||
- проверить role change;
|
||||
- проверить remove member;
|
||||
- проверить export workspace;
|
||||
- проверить delete workspace только на disposable workspace;
|
||||
- открыть `/settings`;
|
||||
- проверить profile update;
|
||||
- проверить password change.
|
||||
|
||||
## 6. Protocol smoke pass
|
||||
|
||||
Для smoke-проверки MCP использовать готовый public target из [public-smoke-targets.md](public-smoke-targets.md).
|
||||
|
||||
Обязательный кейс:
|
||||
|
||||
- REST: [rest-open-meteo.operation.json](../examples/mcp-smoke/rest-open-meteo.operation.json)
|
||||
|
||||
## 7. Acceptance criteria
|
||||
|
||||
Regression pass считается завершенным, если одновременно выполнены условия:
|
||||
|
||||
- `cargo check --workspace` passed;
|
||||
- Playwright suite passed;
|
||||
- login/shell/manual navigation не ломаются;
|
||||
- `Secrets -> Auth Profiles -> Wizard -> Test run` связка работает;
|
||||
- public REST smoke target проходит;
|
||||
- нет критичных UI regressions на clean routes, i18n и auth redirects.
|
||||
|
||||
## 8. Если что-то падает
|
||||
|
||||
- сначала фиксировать failing automated spec;
|
||||
- потом чинить ручной smoke regression;
|
||||
- после фикса повторять:
|
||||
- `cargo check --workspace`;
|
||||
- `cd apps/ui && npm run e2e`;
|
||||
- только потом фиксировать результат в текущем рабочем трекере.
|
||||
@@ -0,0 +1,106 @@
|
||||
# MCP Interface
|
||||
|
||||
Crank Community публикует REST operations как MCP tools поверх Streamable HTTP.
|
||||
|
||||
## Transport
|
||||
|
||||
MCP server запускается отдельным приложением `mcp-server`.
|
||||
|
||||
Поддерживается:
|
||||
|
||||
- MCP Streamable HTTP;
|
||||
- JSON-RPC requests через `POST`;
|
||||
- optional server-to-client stream через `GET`;
|
||||
- explicit session close через `DELETE`.
|
||||
|
||||
`stdio` не входит в Community deployment.
|
||||
|
||||
## Endpoint model
|
||||
|
||||
Canonical endpoint:
|
||||
|
||||
```text
|
||||
/mcp/v1/{workspace_slug}/{agent_slug}
|
||||
```
|
||||
|
||||
Endpoint определяет:
|
||||
|
||||
- workspace;
|
||||
- published agent;
|
||||
- curated tool catalog агента;
|
||||
- labels для logs и usage.
|
||||
|
||||
## Authentication
|
||||
|
||||
Community использует static agent API keys.
|
||||
|
||||
Правила:
|
||||
|
||||
- каждый published agent может иметь собственные API keys;
|
||||
- key принадлежит одному workspace и одному agent;
|
||||
- `mcp-server` показывает только tools, привязанные к этому agent;
|
||||
- unsupported token issuance modes отклоняются.
|
||||
|
||||
## Tool catalog
|
||||
|
||||
Одна published REST operation становится одним MCP tool.
|
||||
|
||||
Tool definition строится из:
|
||||
|
||||
- operation name или binding-level tool name;
|
||||
- tool title и description;
|
||||
- input schema;
|
||||
- published operation version.
|
||||
|
||||
Draft operations никогда не публикуются через MCP.
|
||||
|
||||
## Supported methods
|
||||
|
||||
MCP methods:
|
||||
|
||||
- `initialize`
|
||||
- `notifications/initialized`
|
||||
- `ping`
|
||||
- `tools/list`
|
||||
- `tools/call`
|
||||
|
||||
Transport endpoints:
|
||||
|
||||
- `POST /mcp/v1/{workspace_slug}/{agent_slug}`
|
||||
- `GET /mcp/v1/{workspace_slug}/{agent_slug}`
|
||||
- `DELETE /mcp/v1/{workspace_slug}/{agent_slug}`
|
||||
|
||||
## `tools/list`
|
||||
|
||||
1. Client authenticates через agent API key.
|
||||
2. `mcp-server` resolves workspace и agent из path.
|
||||
3. Server loads published agent catalog.
|
||||
4. Server returns only tools bound to that agent.
|
||||
|
||||
## `tools/call`
|
||||
|
||||
1. Client вызывает tool.
|
||||
2. `mcp-server` валидирует input по tool schema.
|
||||
3. Runtime maps MCP input в REST request.
|
||||
4. REST adapter вызывает upstream API.
|
||||
5. Runtime maps REST response в tool output.
|
||||
6. `mcp-server` возвращает normalized result.
|
||||
|
||||
## Refresh
|
||||
|
||||
Published catalog refresh управляется `CRANK_MCP_REFRESH_MS`.
|
||||
|
||||
После публикации operation или agent `mcp-server` подхватывает новый catalog без
|
||||
restart.
|
||||
|
||||
## Error categories
|
||||
|
||||
MCP responses различают:
|
||||
|
||||
- authentication errors;
|
||||
- missing workspace или agent;
|
||||
- missing tool;
|
||||
- schema validation errors;
|
||||
- mapping errors;
|
||||
- upstream REST errors;
|
||||
- internal runtime errors.
|
||||
@@ -0,0 +1,112 @@
|
||||
# REST
|
||||
|
||||
## 1. Роль протокола в проекте
|
||||
|
||||
REST - базовый и первый по очередности реализации протокол платформы. На нем должна быть обкатана общая модель `Operation`, схема входа и выхода, маппинг, тестовый запуск и публикация MCP tool.
|
||||
|
||||
## 2. Что поддерживается в целевом продукте
|
||||
|
||||
- HTTP methods: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`
|
||||
- загрузка примера входного `JSON`
|
||||
- загрузка примера выходного `JSON`
|
||||
- path parameters
|
||||
- query parameters
|
||||
- headers
|
||||
- JSON request body
|
||||
- JSON response body
|
||||
- auth: `Bearer`, `Basic`, API key
|
||||
- timeout и базовые transport settings
|
||||
- request mapping
|
||||
- response mapping
|
||||
- автогенерация чернового mapping
|
||||
- ручная донастройка через `JSONPath`
|
||||
- тестовый вызов перед публикацией
|
||||
|
||||
## 3. Что отложено
|
||||
|
||||
- multipart/form-data
|
||||
- file upload/download как отдельный сценарий
|
||||
- XML payload как основной формат
|
||||
- OpenAPI import с автоматическим созданием mappings
|
||||
- webhooks
|
||||
- long polling как специальный режим
|
||||
- `HEAD` и `OPTIONS` как отдельные пользовательские сценарии
|
||||
|
||||
## 4. Внутренняя модель REST operation
|
||||
|
||||
REST operation в системе описывается следующими основными частями:
|
||||
|
||||
- `base_url`
|
||||
- `method`
|
||||
- `path_template`
|
||||
- `headers`
|
||||
- `auth_profile`
|
||||
- `input_schema`
|
||||
- `input_mapping`
|
||||
- `output_schema`
|
||||
- `output_mapping`
|
||||
- `tool_description`
|
||||
|
||||
На слое MCP REST operation всегда выглядит как вызов `запрос -> ответ` с фиксированной схемой входа и выхода.
|
||||
|
||||
## 5. Как оператор настраивает REST operation
|
||||
|
||||
1. Указывает `base_url`.
|
||||
2. Выбирает HTTP method.
|
||||
3. Указывает `path_template`.
|
||||
4. При необходимости загружает пример входного и выходного `JSON`.
|
||||
5. Система строит черновую схему и стартовый mapping.
|
||||
6. Описывает или уточняет входные MCP-параметры.
|
||||
7. Сопоставляет параметры с `path`, `query`, `headers` и `body`.
|
||||
8. Указывает, откуда извлекать полезные данные в ответе.
|
||||
9. При необходимости уточняет mapping через `JSONPath`.
|
||||
10. Запускает тест.
|
||||
11. Публикует operation как MCP tool.
|
||||
|
||||
## 6. Требования к маппингу
|
||||
|
||||
Input mapping должен поддерживать:
|
||||
|
||||
- `$.mcp.* -> $.request.path.*`
|
||||
- `$.mcp.* -> $.request.query.*`
|
||||
- `$.mcp.* -> $.request.headers.*`
|
||||
- `$.mcp.* -> $.request.body.*`
|
||||
- константы
|
||||
- значения по умолчанию
|
||||
|
||||
Output mapping должен поддерживать:
|
||||
|
||||
- `$.response.body.* -> $.output.*`
|
||||
- извлечение вложенных полей
|
||||
- нормализацию отсутствующих значений
|
||||
|
||||
`JSONPath` является основным способом адресации конкретных параметров при работе со вложенными объектами и массивами.
|
||||
|
||||
## 7. Поведение runtime
|
||||
|
||||
При выполнении REST operation runtime должен:
|
||||
|
||||
1. Валидировать вход по нормализованной схеме.
|
||||
2. Применить input mapping.
|
||||
3. Собрать HTTP request.
|
||||
4. Выполнить вызов через `reqwest`.
|
||||
5. Преобразовать ответ в нормализованный JSON.
|
||||
6. Применить output mapping.
|
||||
7. Вернуть итоговый результат MCP server.
|
||||
|
||||
## 8. Нюансы и ограничения
|
||||
|
||||
- `DELETE` допускается, но body для него не считается обязательным сценарием совместимости.
|
||||
- `PATCH` требует аккуратной работы с частичными payload, поэтому mapping должен позволять заполнять только выбранные поля.
|
||||
- Успешный HTTP status сам по себе не гарантирует корректность бизнес-ответа, если response mapping не может извлечь ожидаемые данные.
|
||||
- REST adapter не должен содержать бизнес-логику маппинга, только transport-логику.
|
||||
- Загруженные JSON-примеры используются для генерации черновика, но не заменяют явную конфигурацию operation.
|
||||
|
||||
## 9. Почему REST выделен как основной сценарий Community
|
||||
|
||||
REST выбран как основной сценарий Community, потому что:
|
||||
|
||||
- контракт определяется URL, методом и payload;
|
||||
- semantics HTTP methods важны;
|
||||
- поведение интеграции часто завязано на headers и auth;
|
||||
- REST легко проверять через простой test run до публикации MCP tool.
|
||||
@@ -0,0 +1,101 @@
|
||||
# Public Smoke Targets
|
||||
|
||||
Этот документ фиксирует публичный upstream-сервис, который можно использовать для ручной проверки `REST` operation в `crank-community` без поднятия своего тестового backend-а.
|
||||
|
||||
Для Community канонический smoke target только один:
|
||||
|
||||
- `REST`
|
||||
|
||||
Коммерческие протоколы и их smoke targets живут в private репозиториях и не входят в Community release baseline.
|
||||
|
||||
Все примеры ниже дублируются готовыми payload-файлами в [examples/mcp-smoke](../examples/mcp-smoke).
|
||||
|
||||
## 1. Источник
|
||||
|
||||
- REST: Open-Meteo Weather Forecast API
|
||||
`https://open-meteo.com/en/docs`
|
||||
|
||||
## 2. Готовые operation payload-ы
|
||||
|
||||
- REST: [rest-open-meteo.operation.json](../examples/mcp-smoke/rest-open-meteo.operation.json)
|
||||
- REST test input: [rest-open-meteo.test-input.json](../examples/mcp-smoke/rest-open-meteo.test-input.json)
|
||||
|
||||
## 3. Как использовать
|
||||
|
||||
### 3.1. Через UI
|
||||
|
||||
1. Создать operation вручную в `Wizard`.
|
||||
2. Подставить значения из `rest-open-meteo.operation.json`.
|
||||
3. На шаге теста использовать `rest-open-meteo.test-input.json`.
|
||||
|
||||
### 3.2. Через admin-api
|
||||
|
||||
Пример для `ws_default`:
|
||||
|
||||
```bash
|
||||
curl -sS -X POST \
|
||||
https://rmcp.itexp.me/api/admin/workspaces/ws_default/operations \
|
||||
-H 'content-type: application/json' \
|
||||
-b cookie.txt \
|
||||
--data @examples/mcp-smoke/rest-open-meteo.operation.json
|
||||
```
|
||||
|
||||
Потом test-run:
|
||||
|
||||
```bash
|
||||
curl -sS -X POST \
|
||||
https://rmcp.itexp.me/api/admin/workspaces/ws_default/operations/<operation_id>/test-runs \
|
||||
-H 'content-type: application/json' \
|
||||
-b cookie.txt \
|
||||
--data '{
|
||||
"version": 1,
|
||||
"input": '"$(cat examples/mcp-smoke/rest-open-meteo.test-input.json)"'
|
||||
}'
|
||||
```
|
||||
|
||||
Логин перед этим:
|
||||
|
||||
```bash
|
||||
curl -sS -c cookie.txt \
|
||||
-H 'content-type: application/json' \
|
||||
-X POST https://rmcp.itexp.me/api/auth/login \
|
||||
--data '{"email":"<your-email>","password":"<your-password>"}'
|
||||
```
|
||||
|
||||
## 4. Что именно проверяет пример
|
||||
|
||||
### 4.1. REST: Open-Meteo
|
||||
|
||||
- Protocol: `REST`
|
||||
- Endpoint: `https://api.open-meteo.com/v1/forecast`
|
||||
- Проверка:
|
||||
- query mapping
|
||||
- fixed query defaults
|
||||
- JSON response extraction
|
||||
|
||||
Ожидаемый upstream response shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"timezone": "Europe/Moscow",
|
||||
"current": {
|
||||
"time": "2026-04-05T22:30",
|
||||
"temperature_2m": 3.4,
|
||||
"wind_speed_10m": 8.3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Практическая рекомендация
|
||||
|
||||
Для первого smoke pass использовать operation:
|
||||
|
||||
- `weather_current_open_meteo`
|
||||
|
||||
Этого достаточно, чтобы проверить весь путь:
|
||||
|
||||
- create operation
|
||||
- test-run
|
||||
- publish
|
||||
- bind to agent
|
||||
- MCP call через `workspace + agent`
|
||||
@@ -0,0 +1,313 @@
|
||||
# Runtime Config
|
||||
|
||||
## 1. Назначение документа
|
||||
|
||||
Этот документ фиксирует конфигурацию окружения, storage и базовые operational assumptions для MVP.
|
||||
|
||||
Его задача - убрать неявные решения, которые обычно всплывают уже в процессе написания кода.
|
||||
|
||||
## 2. Базовые решения для MVP
|
||||
|
||||
- каноническая БД: `PostgreSQL`
|
||||
- локальная разработка и тесты используют ту же `PostgreSQL`-модель хранения
|
||||
- artifact storage: локальная файловая система
|
||||
- MCP transport: `Streamable HTTP`
|
||||
- admin API и mcp-server запускаются как отдельные приложения
|
||||
|
||||
## 3. Artifact storage
|
||||
|
||||
В MVP sample JSON, `.proto`, `descriptor set` и YAML import payload должны храниться в локальном файловом storage.
|
||||
|
||||
Требования:
|
||||
|
||||
- все файлы кладутся в контролируемый базовый каталог;
|
||||
- в БД хранится только `storage_ref`;
|
||||
- структура каталогов должна быть детерминированной;
|
||||
- storage слой должен быть абстрагирован, чтобы потом заменить его на S3-compatible backend.
|
||||
|
||||
Рекомендуемая структура:
|
||||
|
||||
```text
|
||||
var/crank/
|
||||
samples/
|
||||
descriptors/
|
||||
yaml-imports/
|
||||
```
|
||||
|
||||
## 4. Секреты и auth profiles
|
||||
|
||||
Для целевой модели:
|
||||
|
||||
- operation хранит только `auth_profile_ref`;
|
||||
- `AuthProfile` хранит только ссылки на `secret_id`;
|
||||
- plaintext секреты не должны попадать в YAML export;
|
||||
- plaintext секреты не должны логироваться;
|
||||
- runtime получает секрет только на короткое время перед upstream вызовом.
|
||||
|
||||
Стартовая реализация:
|
||||
|
||||
- `PostgreSQL`-backed secret store;
|
||||
- `ciphertext` хранится в БД;
|
||||
- шифрование выполняется через `CRANK_MASTER_KEY`;
|
||||
- ключ шифрования приходит только из env.
|
||||
|
||||
## 5. Переменные окружения
|
||||
|
||||
Минимально ожидаются:
|
||||
|
||||
- `POSTGRES_HOST`
|
||||
- `POSTGRES_PORT`
|
||||
- `POSTGRES_DB`
|
||||
- `POSTGRES_USER`
|
||||
- `POSTGRES_PASSWORD`
|
||||
- `POSTGRES_MAX_CONNECTIONS`
|
||||
- `POSTGRES_MIN_CONNECTIONS`
|
||||
- `POSTGRES_ACQUIRE_TIMEOUT_MS`
|
||||
- `POSTGRES_IDLE_TIMEOUT_MS`
|
||||
- `POSTGRES_MAX_LIFETIME_MS`
|
||||
- `CRANK_ADMIN_API_IMAGE`
|
||||
- `CRANK_MCP_SERVER_IMAGE`
|
||||
- `CRANK_UI_IMAGE`
|
||||
- `CRANK_STORAGE_ROOT`
|
||||
- `CRANK_PUBLISH_BIND`
|
||||
- `CRANK_ADMIN_BIND`
|
||||
- `CRANK_ADMIN_RATE_LIMIT_RPS`
|
||||
- `CRANK_ADMIN_RATE_LIMIT_BURST`
|
||||
- `CRANK_MCP_BIND`
|
||||
- `CRANK_MCP_REFRESH_MS`
|
||||
- `CRANK_MCP_RATE_LIMIT_RPS`
|
||||
- `CRANK_MCP_RATE_LIMIT_BURST`
|
||||
- `CRANK_RUNTIME_MAX_CONCURRENT_UNARY`
|
||||
- `CRANK_RUNTIME_MAX_CONCURRENT_WINDOW`
|
||||
- `CRANK_RUNTIME_MAX_CONCURRENT_SESSIONS`
|
||||
- `CRANK_RUNTIME_MAX_CONCURRENT_JOBS`
|
||||
- `CRANK_LOG_LEVEL`
|
||||
- `CRANK_MASTER_KEY`
|
||||
- `CRANK_BASE_URL`
|
||||
|
||||
Опционально:
|
||||
|
||||
- `CRANK_ADMIN_TOKEN`
|
||||
- `CRANK_DEMO_SEED`
|
||||
- `CRANK_CACHE_BACKEND`
|
||||
- `CRANK_CACHE_URL`
|
||||
- `CRANK_CACHE_DEFAULT_TTL_MS`
|
||||
|
||||
Стартовое значение для refresh published tools:
|
||||
|
||||
- `CRANK_ADMIN_RATE_LIMIT_RPS=30`
|
||||
- `CRANK_ADMIN_RATE_LIMIT_BURST=60`
|
||||
- `CRANK_MCP_REFRESH_MS=5000`
|
||||
- `CRANK_MCP_RATE_LIMIT_RPS=60`
|
||||
- `CRANK_MCP_RATE_LIMIT_BURST=120`
|
||||
|
||||
Стартовые значения для runtime concurrency limits:
|
||||
|
||||
- `CRANK_RUNTIME_MAX_CONCURRENT_UNARY=64`
|
||||
- `CRANK_RUNTIME_MAX_CONCURRENT_WINDOW=16`
|
||||
- `CRANK_RUNTIME_MAX_CONCURRENT_SESSIONS=16`
|
||||
- `CRANK_RUNTIME_MAX_CONCURRENT_JOBS=16`
|
||||
|
||||
## 6. Логирование и трассировка
|
||||
|
||||
Для MVP нужно использовать:
|
||||
|
||||
- structured logging через `tracing`;
|
||||
- correlation id для test runs и runtime execution;
|
||||
- раздельные стадии ошибок: schema, mapping, adapter, external service.
|
||||
|
||||
## 7. Таймауты и retries
|
||||
|
||||
Рекомендуемые стартовые значения:
|
||||
|
||||
- default timeout: `10s`
|
||||
- retry default: `1` attempt, то есть без автоматического повтора
|
||||
|
||||
Причина:
|
||||
|
||||
- сначала важнее детерминированность и прозрачность;
|
||||
- aggressive retries могут маскировать реальные ошибки интеграции.
|
||||
|
||||
## 8. Режимы запуска
|
||||
|
||||
Минимально нужны два режима:
|
||||
|
||||
- local development
|
||||
- demo/deployment
|
||||
|
||||
Local development:
|
||||
|
||||
- локальное окружение должно иметь доступ к `PostgreSQL`;
|
||||
- локальный storage;
|
||||
- app-level auth и bootstrap admin user через `.env`.
|
||||
- при необходимости UI можно наполнить живыми demo-данными через `CRANK_DEMO_SEED=true`.
|
||||
|
||||
Demo/deployment:
|
||||
|
||||
- `PostgreSQL`;
|
||||
- локальный или сетевой storage;
|
||||
- включенная app-level auth-защита admin-api;
|
||||
- стабильный `Streamable HTTP` endpoint для MCP.
|
||||
- containerized runtime через `Docker` и `docker-compose`.
|
||||
- optional shared cache layer через `Valkey/Redis`.
|
||||
- registry-backed image rollout через Gitea Container Registry или совместимый registry.
|
||||
|
||||
### Cache env
|
||||
|
||||
Для optional cache/coordination layer должны быть предусмотрены:
|
||||
|
||||
- `CRANK_CACHE_BACKEND`
|
||||
- `CRANK_CACHE_URL`
|
||||
- `CRANK_CACHE_DEFAULT_TTL_MS`
|
||||
|
||||
Рекомендуемая модель:
|
||||
|
||||
- `CRANK_CACHE_BACKEND=memory` по умолчанию;
|
||||
- `CRANK_CACHE_BACKEND=valkey` или `redis` при наличии внешнего cache store;
|
||||
- без этих переменных система должна оставаться полностью работоспособной.
|
||||
|
||||
### Cache boundaries
|
||||
|
||||
В платформе должны существовать два разных cache-контура:
|
||||
|
||||
- `platform / coordination cache`
|
||||
- `response cache`
|
||||
|
||||
Первый контур хранит служебное краткоживущее состояние:
|
||||
|
||||
- ingress rate limiting;
|
||||
- replay guard;
|
||||
- ephemeral coordination state;
|
||||
- shared snapshots published MCP catalogs between instances;
|
||||
|
||||
Второй контур хранит только кэшируемые ответы операций.
|
||||
|
||||
Текущий безопасный runtime scope для response cache:
|
||||
|
||||
- `REST GET`;
|
||||
|
||||
Это не означает автоматическое кэширование всех REST-вызовов. Кэширование
|
||||
разрешается только для безопасных `GET` operations без upstream auth profile.
|
||||
|
||||
Эти контуры не должны смешивать ключи друг с другом.
|
||||
|
||||
### Cache key isolation
|
||||
|
||||
Базовое правило изоляции:
|
||||
|
||||
- разные `workspace` не должны делить одни и те же cache keys;
|
||||
- разные `agent` внутри одного `workspace` тоже не должны делить одни и те же response cache keys по умолчанию;
|
||||
- разные `operation` внутри одного `agent` не должны попадать в общий response cache namespace.
|
||||
|
||||
Стартовая модель namespace для response cache:
|
||||
|
||||
- `workspace + agent + operation + operation version + request fingerprint`
|
||||
|
||||
Стартовая модель namespace для platform / coordination cache:
|
||||
|
||||
- `workspace + agent + cache scope + logical key`
|
||||
|
||||
Это позволяет безопасно использовать один внешний `Valkey/Redis` сразу для нескольких агентов и рабочих областей без взаимного пересечения данных.
|
||||
|
||||
### Auth env
|
||||
|
||||
Для app-level auth нужны:
|
||||
|
||||
- `CRANK_SESSION_SECRET`
|
||||
- `CRANK_PASSWORD_PEPPER`
|
||||
- `CRANK_BOOTSTRAP_ADMIN_EMAIL`
|
||||
- `CRANK_BOOTSTRAP_ADMIN_PASSWORD`
|
||||
- `CRANK_BOOTSTRAP_ADMIN_DISPLAY_NAME`
|
||||
|
||||
Для secret store foundation нужен:
|
||||
|
||||
- `CRANK_MASTER_KEY`
|
||||
|
||||
`CRANK_MASTER_KEY` обязателен и для `admin-api`, и для `mcp-server`, потому что оба приложения
|
||||
должны уметь резолвить `secret_id` в runtime.
|
||||
|
||||
Для опционального demo-seed:
|
||||
|
||||
- `CRANK_DEMO_SEED=true`
|
||||
|
||||
В deployment workflow больше не используется монолитный `DEPLOY_ENV_FILE`.
|
||||
|
||||
`.env` на сервере собирается из OpenBao. В Gitea Actions хранятся только AppRole credentials
|
||||
`BAO_ADDR`, `BAO_ROLE_ID` и `BAO_SECRET_ID`, а внутри OpenBao ключи проекта
|
||||
`projects/crank/runtime` совпадают с именами runtime env-переменных. Это значит, что:
|
||||
|
||||
- `CRANK_MASTER_KEY` хранится в OpenBao как ключ `CRANK_MASTER_KEY`;
|
||||
- `CRANK_DEMO_SEED` хранится в OpenBao как ключ `CRANK_DEMO_SEED`;
|
||||
- и так же для остальных runtime-переменных.
|
||||
|
||||
Для БД основной runtime-контракт теперь компонентный:
|
||||
|
||||
- `POSTGRES_HOST`
|
||||
- `POSTGRES_PORT`
|
||||
- `POSTGRES_DB`
|
||||
- `POSTGRES_USER`
|
||||
- `POSTGRES_PASSWORD`
|
||||
- `POSTGRES_MAX_CONNECTIONS`
|
||||
- `POSTGRES_MIN_CONNECTIONS`
|
||||
- `POSTGRES_ACQUIRE_TIMEOUT_MS`
|
||||
- `POSTGRES_IDLE_TIMEOUT_MS`
|
||||
- `POSTGRES_MAX_LIFETIME_MS`
|
||||
|
||||
Для pool behavior используются явные defaults:
|
||||
|
||||
- `POSTGRES_MAX_CONNECTIONS=20`
|
||||
- `POSTGRES_MIN_CONNECTIONS=2`
|
||||
- `POSTGRES_ACQUIRE_TIMEOUT_MS=5000`
|
||||
- `POSTGRES_IDLE_TIMEOUT_MS=600000`
|
||||
- `POSTGRES_MAX_LIFETIME_MS=1800000`
|
||||
|
||||
Для runtime concurrency используются явные defaults:
|
||||
|
||||
- `CRANK_RUNTIME_MAX_CONCURRENT_UNARY=64`
|
||||
- `CRANK_RUNTIME_MAX_CONCURRENT_WINDOW=16`
|
||||
- `CRANK_RUNTIME_MAX_CONCURRENT_SESSIONS=16`
|
||||
- `CRANK_RUNTIME_MAX_CONCURRENT_JOBS=16`
|
||||
|
||||
Для MCP transport ingress throttling используются явные defaults:
|
||||
|
||||
- `CRANK_MCP_RATE_LIMIT_RPS=60`
|
||||
- `CRANK_MCP_RATE_LIMIT_BURST=120`
|
||||
|
||||
Для admin-api ingress throttling используются явные defaults:
|
||||
|
||||
- `CRANK_ADMIN_RATE_LIMIT_RPS=30`
|
||||
- `CRANK_ADMIN_RATE_LIMIT_BURST=60`
|
||||
|
||||
`CRANK_DATABASE_URL` допускается только как backward-compatible fallback для локальных тестов и
|
||||
переходного периода, но не как основная deployment-модель.
|
||||
|
||||
## 8.1. Delivery artifacts
|
||||
|
||||
Для production-like запуска проект должен поставляться с:
|
||||
|
||||
- `Dockerfile` для backend приложений;
|
||||
- `deploy/community/docker-compose.yml` как canonical Community deployment manifest;
|
||||
- `deploy/community/.env.example` как canonical Community env template;
|
||||
- optional `Valkey` service как рекомендованный, но не обязательный компонент Community deployment;
|
||||
- root `docker-compose.yml` и root `.env.example` только как local development convenience files;
|
||||
- healthcheck endpoints;
|
||||
- reverse proxy configuration examples.
|
||||
|
||||
Подробности вынесены в `docs/deployment.md`.
|
||||
|
||||
## 9. Что важно не допустить
|
||||
|
||||
- пути к storage, зашитые в код;
|
||||
- секреты в `.yaml` exports;
|
||||
- разные конфигурационные модели для local и production без причины;
|
||||
- смешивание runtime config и business config operation.
|
||||
|
||||
## 10. Практический итог
|
||||
|
||||
До старта разработки должны быть приняты как минимум такие решения:
|
||||
|
||||
- где лежит БД;
|
||||
- где лежат artifacts;
|
||||
- как резолвятся `secret_id` и как ротируется `CRANK_MASTER_KEY`;
|
||||
- на каких bind-address запускаются `admin-api` и `mcp-server`;
|
||||
- какой transport использует MCP server.
|
||||
@@ -0,0 +1,316 @@
|
||||
# Rust Code Rules
|
||||
|
||||
## 1. Назначение документа
|
||||
|
||||
Этот документ фиксирует Rust-specific правила кода для проекта:
|
||||
|
||||
- toolchain;
|
||||
- linting;
|
||||
- formatting;
|
||||
- ошибки;
|
||||
- async;
|
||||
- ownership;
|
||||
- visibility;
|
||||
- dependency hygiene.
|
||||
|
||||
Цель документа - убрать плавающие договоренности по стилю и практике командной Rust-разработки.
|
||||
|
||||
## 2. Toolchain
|
||||
|
||||
### 2.1. Версия Rust
|
||||
|
||||
Для проекта должен быть зафиксирован `rust-toolchain.toml`.
|
||||
|
||||
В нем должны быть определены:
|
||||
|
||||
- стабильный `channel`;
|
||||
- `protocol`;
|
||||
- при необходимости `components`.
|
||||
|
||||
Рекомендуемый состав:
|
||||
|
||||
- `rustfmt`
|
||||
- `clippy`
|
||||
|
||||
### 2.2. MSRV
|
||||
|
||||
Нужно зафиксировать `MSRV` - минимально поддерживаемую версию Rust.
|
||||
|
||||
Правило:
|
||||
|
||||
- без необходимости не использовать возможности языка новее зафиксированного `MSRV`;
|
||||
- обновление `MSRV` - это отдельное осознанное решение.
|
||||
|
||||
## 3. Formatting и linting
|
||||
|
||||
### 3.1. Formatting
|
||||
|
||||
Обязательное правило:
|
||||
|
||||
- весь код форматируется через `cargo fmt`.
|
||||
|
||||
Ручной стиль форматирования не обсуждается и не поддерживается.
|
||||
|
||||
### 3.2. Clippy
|
||||
|
||||
Обязательное правило:
|
||||
|
||||
- `cargo clippy --all-targets --all-features -- -D warnings`
|
||||
|
||||
Предупреждения считаются ошибками, если нет явно зафиксированного исключения.
|
||||
|
||||
### 3.3. CI quality gates
|
||||
|
||||
Минимально в CI должны запускаться:
|
||||
|
||||
- `cargo fmt --check`
|
||||
- `cargo clippy --all-targets --all-features -- -D warnings`
|
||||
- `cargo test`
|
||||
|
||||
Опционально позже:
|
||||
|
||||
- `cargo deny`
|
||||
- `cargo audit`
|
||||
|
||||
## 4. `unsafe`
|
||||
|
||||
Для проекта принимается правило:
|
||||
|
||||
- `unsafe` запрещен по умолчанию.
|
||||
|
||||
Если когда-либо потребуется `unsafe`, то:
|
||||
|
||||
- это должно быть отдельное осознанное решение;
|
||||
- причина должна быть технически обоснована;
|
||||
- блок должен быть минимальным;
|
||||
- вокруг него должны быть тесты.
|
||||
|
||||
Для MVP можно считать:
|
||||
|
||||
- `unsafe_code = deny`
|
||||
|
||||
## 5. Panic policy
|
||||
|
||||
В production code запрещены:
|
||||
|
||||
- `unwrap()`
|
||||
- `expect()`
|
||||
- `todo!()`
|
||||
- `unimplemented!()`
|
||||
- `dbg!()`
|
||||
- необоснованные `panic!()`
|
||||
|
||||
Допускается:
|
||||
|
||||
- в тестах;
|
||||
- в очень раннем bootstrap-коде, если это действительно аварийное завершение и не часть доменной логики.
|
||||
|
||||
Базовое правило:
|
||||
|
||||
- ошибки возвращаются через `Result`, а не через panic.
|
||||
|
||||
## 6. Правила ошибок
|
||||
|
||||
### 6.1. Domain и service errors
|
||||
|
||||
В домене и сервисах использовать типизированные ошибки.
|
||||
|
||||
Рекомендуемо:
|
||||
|
||||
- `thiserror`
|
||||
|
||||
### 6.2. Application boundary
|
||||
|
||||
На верхних слоях приложений допускается агрегирование ошибок, если это упрощает wiring.
|
||||
|
||||
При необходимости:
|
||||
|
||||
- `anyhow` только на внешних границах приложения, не в доменной модели.
|
||||
|
||||
### 6.3. Error context
|
||||
|
||||
Ошибка должна сохранять стадию отказа:
|
||||
|
||||
- schema
|
||||
- mapping
|
||||
- adapter
|
||||
- persistence
|
||||
- external service
|
||||
- internal runtime
|
||||
|
||||
## 7. Visibility rules
|
||||
|
||||
Правило:
|
||||
|
||||
- по умолчанию все приватное;
|
||||
- `pub(crate)` предпочтительнее `pub`;
|
||||
- публичный API должен быть минимальным.
|
||||
|
||||
Нельзя:
|
||||
|
||||
- открывать модуль наружу "на всякий случай";
|
||||
- делать `pub` просто ради удобства из соседнего файла;
|
||||
- реэкспортировать целые деревья модулей без причины.
|
||||
|
||||
## 8. Ownership и данные
|
||||
|
||||
### 8.1. Клонирование
|
||||
|
||||
Правило:
|
||||
|
||||
- не клонировать данные без необходимости;
|
||||
- клон должен быть осознанным, а не способом обойти borrow checker без понимания причины.
|
||||
|
||||
### 8.2. Shared mutability
|
||||
|
||||
Правило:
|
||||
|
||||
- не использовать `Arc<Mutex<_>>` как универсальный контейнер состояния;
|
||||
- shared mutability допускается только там, где она действительно нужна по архитектуре.
|
||||
|
||||
### 8.3. ID types
|
||||
|
||||
Идентификаторы должны быть отдельными типами, а не просто `String`.
|
||||
|
||||
Примеры:
|
||||
|
||||
- `OperationId`
|
||||
- `DescriptorId`
|
||||
- `AuthProfileId`
|
||||
|
||||
## 9. Async rules
|
||||
|
||||
### 9.1. Где допускается `async`
|
||||
|
||||
`async` используется только там, где есть:
|
||||
|
||||
- I/O;
|
||||
- network;
|
||||
- storage;
|
||||
- async boundary приложения.
|
||||
|
||||
### 9.2. Где `async` не нужен
|
||||
|
||||
Нельзя превращать:
|
||||
|
||||
- schema validation;
|
||||
- mapping;
|
||||
- чистую доменную логику;
|
||||
- небольшие derived methods
|
||||
|
||||
в `async fn` без причины.
|
||||
|
||||
### 9.3. `tokio`
|
||||
|
||||
`tokio` должен находиться:
|
||||
|
||||
- в приложениях;
|
||||
- в I/O слоях;
|
||||
- в адаптерах и runtime orchestration, если там есть реальный async.
|
||||
|
||||
Доменный слой не должен зависеть от `tokio`.
|
||||
|
||||
## 10. API design rules
|
||||
|
||||
### 10.1. Конструкторы
|
||||
|
||||
Использовать:
|
||||
|
||||
- `new()` для гарантированно валидного и простого создания;
|
||||
- `try_new()` там, где есть валидация и возможна ошибка.
|
||||
|
||||
### 10.2. Builders
|
||||
|
||||
Если структура имеет много параметров и прямой конструктор становится нечитаемым, допускается builder.
|
||||
|
||||
Но:
|
||||
|
||||
- builder не должен маскировать плохую модель данных;
|
||||
- builder не должен использоваться как замена нормальной декомпозиции.
|
||||
|
||||
### 10.3. DTO отдельно от domain
|
||||
|
||||
Если HTTP payload начинает расходиться с доменной моделью, нужно вводить отдельный DTO слой.
|
||||
|
||||
Нельзя:
|
||||
|
||||
- тащить `serde`-ориентированный API payload прямо в домен только ради удобства.
|
||||
|
||||
## 11. Dependency rules
|
||||
|
||||
### 11.1. Внешние crates
|
||||
|
||||
Правило:
|
||||
|
||||
- сначала использовать `std`;
|
||||
- потом существующие внутренние abstractions;
|
||||
- только потом тянуть новый внешний crate.
|
||||
|
||||
Нельзя:
|
||||
|
||||
- добавлять зависимость "на всякий случай";
|
||||
- дублировать crates с пересекающейся функцией без причины.
|
||||
|
||||
### 11.2. Макросы
|
||||
|
||||
Правило:
|
||||
|
||||
- не злоупотреблять макросами там, где обычный Rust-код читается лучше;
|
||||
- derive-макросы допустимы;
|
||||
- сложные процедурные макросы без сильной причины не нужны.
|
||||
|
||||
## 12. Serialization rules
|
||||
|
||||
### 12.1. JSON/YAML
|
||||
|
||||
Правило:
|
||||
|
||||
- доменная модель одна;
|
||||
- `JSON` и `YAML` - только два формата сериализации;
|
||||
- нельзя допускать, чтобы YAML export стал отдельной несовместимой моделью.
|
||||
|
||||
### 12.2. Secrets
|
||||
|
||||
Никогда не сериализовать:
|
||||
|
||||
- реальные токены;
|
||||
- пароли;
|
||||
- API keys
|
||||
|
||||
в exports, logs и test snapshots.
|
||||
|
||||
## 13. Тестовые практики на уровне Rust-кода
|
||||
|
||||
Минимально:
|
||||
|
||||
- unit tests рядом с модулем или в `tests`;
|
||||
- integration tests для crate boundaries;
|
||||
- фикстуры для schema/mapping/proto/yaml roundtrip.
|
||||
|
||||
Полезное правило:
|
||||
|
||||
- баг сначала воспроизводится тестом, потом фиксится кодом.
|
||||
|
||||
## 14. Что часто запрещают в Rust-командах
|
||||
|
||||
Практически всегда под запретом:
|
||||
|
||||
- `unwrap()` в production code;
|
||||
- `unsafe` без review;
|
||||
- giant modules;
|
||||
- giant enums со всем подряд;
|
||||
- giant services, где смешаны orchestration и transport;
|
||||
- абстракции "на будущее" без второго реального кейса.
|
||||
|
||||
## 15. Практический итог
|
||||
|
||||
Для этого проекта правильный Rust-профиль такой:
|
||||
|
||||
- фиксированный toolchain;
|
||||
- обязательные `fmt` и `clippy`;
|
||||
- `unsafe` запрещен по умолчанию;
|
||||
- panics запрещены в production code;
|
||||
- ошибки типизированы;
|
||||
- `pub` минимизируется;
|
||||
- `async` только на реальных async boundaries;
|
||||
- код читается за счет имен и декомпозиции, а не за счет комментариев.
|
||||
@@ -0,0 +1,183 @@
|
||||
# Staging Regression Notes
|
||||
|
||||
## 2026-04-07 12:53 MSK — rmcp.itexp.me
|
||||
|
||||
- deploy commit: `unknown`
|
||||
- checked by: `codex + operator`
|
||||
- smoke status: `partial`
|
||||
- scope:
|
||||
- auth
|
||||
- ui shell
|
||||
- mcp health
|
||||
- clean routes
|
||||
- legacy redirects
|
||||
|
||||
### Passed
|
||||
|
||||
- `bash scripts/staging-smoke.sh https://rmcp.itexp.me` passed.
|
||||
- public routes returned `200`:
|
||||
- `/`
|
||||
- `/login`
|
||||
- `/agents`
|
||||
- `/secrets`
|
||||
- `/wizard/`
|
||||
- `/mcp/health`
|
||||
- `/api/auth/session` returned `401` with `application/json`, not HTML fallback:
|
||||
- `{"error":{"code":"unauthorized","message":"authentication required"}}`
|
||||
- legacy routes redirected correctly:
|
||||
- `/html/login.html` -> `/login`
|
||||
- `/html/agents.html` -> `/agents`
|
||||
- `/html/wizard/` -> `/wizard/`
|
||||
|
||||
### Findings
|
||||
|
||||
- none in this pass
|
||||
|
||||
### Infra notes
|
||||
|
||||
- this pass covered only unauthenticated public or staging smoke;
|
||||
- authenticated UI flows, MCP tool calls, secrets/auth-profile flows and REST smoke were not exercised in this entry.
|
||||
|
||||
### Follow-up
|
||||
|
||||
- run a full authenticated browser smoke after the next deploy;
|
||||
- record REST and MCP smoke results in the next entry.
|
||||
|
||||
## 1. Назначение
|
||||
|
||||
Этот документ фиксирует результаты ручных проверок на staging или production-like окружении после deploy.
|
||||
|
||||
Он нужен для трех задач:
|
||||
|
||||
- хранить пост-деплойные замечания вне чата;
|
||||
- отличать разовые сбои окружения от продуктовых регрессий;
|
||||
- дать следующему агенту нормальный handoff по реальному состоянию стенда.
|
||||
|
||||
Использовать вместе с:
|
||||
|
||||
- [deploy-and-staging-smoke.md](deploy-and-staging-smoke.md)
|
||||
- [manual-regression-checklist.md](manual-regression-checklist.md)
|
||||
- [authenticated-staging-pass.md](authenticated-staging-pass.md)
|
||||
|
||||
Если нужно сгенерировать заготовку новой записи:
|
||||
|
||||
```bash
|
||||
just staging-note-block <domain> <deploy-sha> "codex + operator"
|
||||
```
|
||||
|
||||
## 2. Как вести записи
|
||||
|
||||
Добавлять новую запись сверху документа.
|
||||
|
||||
В каждой записи обязательно фиксировать:
|
||||
|
||||
- какой deploy проверялся;
|
||||
- кто проводил проверку;
|
||||
- какой scope реально покрыт;
|
||||
- какие findings найдены;
|
||||
- какие follow-up fixes нужны.
|
||||
|
||||
Если замечание исправлено, не удалять его из истории, а отметить:
|
||||
|
||||
- `status: fixed`
|
||||
- `fixed_by: <commit>`
|
||||
|
||||
## 3. Формат записи
|
||||
|
||||
Использовать такой шаблон:
|
||||
|
||||
```md
|
||||
## YYYY-MM-DD HH:MM TZ — <environment>
|
||||
|
||||
- deploy commit: `<sha>`
|
||||
- checked by: `<name>`
|
||||
- smoke status: `passed | partial | failed`
|
||||
- scope:
|
||||
- auth
|
||||
- ui shell
|
||||
- operations
|
||||
- wizard
|
||||
- agents
|
||||
- api keys
|
||||
- secrets
|
||||
- logs
|
||||
- usage
|
||||
- rest smoke
|
||||
- mcp smoke
|
||||
|
||||
### Passed
|
||||
|
||||
- ...
|
||||
|
||||
### Findings
|
||||
|
||||
1. `<severity>` `<short title>`
|
||||
- area: `<page/service>`
|
||||
- symptom: `...`
|
||||
- reproduction: `...`
|
||||
- expected: `...`
|
||||
- actual: `...`
|
||||
- status: `open | fixed | accepted`
|
||||
- fixed_by: `<sha or ->`
|
||||
|
||||
### Infra notes
|
||||
|
||||
- ...
|
||||
|
||||
### Follow-up
|
||||
|
||||
- ...
|
||||
```
|
||||
|
||||
## 4. Severity model
|
||||
|
||||
Использовать только 4 уровня:
|
||||
|
||||
- `critical`
|
||||
deploy unusable, login broken, MCP unavailable, data corruption risk
|
||||
- `high`
|
||||
primary flow broken, но система частично работает
|
||||
- `medium`
|
||||
заметный UX или runtime дефект с обходным путем
|
||||
- `low`
|
||||
косметика, wording, layout, docs mismatch
|
||||
|
||||
## 5. Что считать finding, а что нет
|
||||
|
||||
### Считать finding
|
||||
|
||||
- broken routing;
|
||||
- redirect loop;
|
||||
- wrong auth/session behavior;
|
||||
- page-level JS exception;
|
||||
- incorrect MCP result;
|
||||
- secret/auth profile flow mismatch;
|
||||
- deploy route returning HTML instead of JSON.
|
||||
|
||||
### Не считать product finding
|
||||
|
||||
- разовый сетевой timeout;
|
||||
- локальный browser glitch без воспроизведения;
|
||||
- внешний upstream outage из public REST smoke target;
|
||||
- предупреждения, не влияющие на flow;
|
||||
- заранее известные `planned` capability blocks.
|
||||
|
||||
Такие случаи писать в `Infra notes`, а не в `Findings`.
|
||||
|
||||
## 6. Open follow-up inventory
|
||||
|
||||
Следующий полный проход должен заполнить минимум:
|
||||
|
||||
- auth/login status;
|
||||
- clean routes status;
|
||||
- `Secrets -> Auth Profiles -> Wizard -> Test run` статус;
|
||||
- REST smoke results;
|
||||
- MCP smoke result.
|
||||
|
||||
## 7. Последняя актуальная запись
|
||||
|
||||
На данный момент:
|
||||
|
||||
- automated baseline локально зеленый;
|
||||
- helper-based staging smoke на `rmcp.itexp.me` прошел;
|
||||
- полный authenticated staging pass еще не занесен.
|
||||
@@ -0,0 +1,122 @@
|
||||
# Стратегия тестирования
|
||||
|
||||
## 1. Назначение документа
|
||||
|
||||
Этот документ фиксирует, как проект должен тестироваться с самого начала разработки, чтобы архитектура не осталась "только на бумаге".
|
||||
|
||||
Цель:
|
||||
|
||||
- проверять доменную модель отдельно от транспорта;
|
||||
- ловить регрессии в mapping;
|
||||
- не дать адаптерам начать вести себя по-разному;
|
||||
- обеспечить воспроизводимость для дипломной демонстрации.
|
||||
|
||||
## 2. Уровни тестов
|
||||
|
||||
### 2.1. Unit tests
|
||||
|
||||
Покрывают:
|
||||
|
||||
- `crank-schema`
|
||||
- `crank-mapping`
|
||||
- небольшие части `crank-core`
|
||||
|
||||
Что проверять:
|
||||
|
||||
- валидацию схем;
|
||||
- `JSONPath` parsing;
|
||||
- применение input/output mapping;
|
||||
- генерацию чернового mapping;
|
||||
|
||||
### 2.2. Integration tests
|
||||
|
||||
Покрывают:
|
||||
|
||||
- `crank-registry` с реальной БД;
|
||||
- `crank-runtime` с реальными adapter contracts;
|
||||
- `admin-api` на поднятом приложении;
|
||||
- publish flow и YAML import/export.
|
||||
|
||||
Что проверять:
|
||||
|
||||
- создание operation и новой version;
|
||||
- publish и reload published tools;
|
||||
- тестовый вызов draft;
|
||||
- экспорт в YAML и повторный импорт;
|
||||
- связность БД между `operations`, `operation_versions`, `published_operations`.
|
||||
|
||||
### 2.3. Adapter tests
|
||||
|
||||
Отдельно для Community-протокола:
|
||||
|
||||
- REST adapter;
|
||||
|
||||
Что проверять:
|
||||
|
||||
- сборку request;
|
||||
- нормализацию response;
|
||||
- обработку ошибок;
|
||||
- стабильность mapping context.
|
||||
|
||||
### 2.4. End-to-end tests
|
||||
|
||||
Минимально нужны сценарии:
|
||||
|
||||
- создать REST operation -> протестировать -> опубликовать -> вызвать как MCP tool;
|
||||
|
||||
## 3. Что должно быть покрыто обязательно
|
||||
|
||||
### Обязательно с первого этапа
|
||||
|
||||
- schema validation;
|
||||
- mapping execution;
|
||||
- YAML import/export roundtrip;
|
||||
- versioning logic registry;
|
||||
- publish flow.
|
||||
|
||||
### Обязательно до первого демо
|
||||
|
||||
- хотя бы один end-to-end сценарий для REST;
|
||||
- negative tests на invalid `JSONPath`;
|
||||
|
||||
## 4. Формат тестовых данных
|
||||
|
||||
Рекомендуется использовать:
|
||||
|
||||
- JSON fixtures для sample input/output;
|
||||
- YAML golden files для export/import;
|
||||
- snapshot tests для generated draft.
|
||||
|
||||
## 5. Техническая стратегия
|
||||
|
||||
Для Rust-части:
|
||||
|
||||
- unit/integration tests через `cargo test`;
|
||||
- тестовые фикстуры в `tests/fixtures/`;
|
||||
- golden files для YAML;
|
||||
- отдельные integration suites для registry и admin-api.
|
||||
|
||||
Для frontend:
|
||||
|
||||
- unit tests для form helpers и schema rendering;
|
||||
- integration tests для critical user flows;
|
||||
- отдельная проверка mapping editor и sample upload flows.
|
||||
- отдельный regression checklist для post-integration smoke pass: [manual-regression-checklist.md](/home/a.tolmachev/code/rust/mcpaas/docs/manual-regression-checklist.md).
|
||||
|
||||
## 6. Что нельзя оставлять без тестов
|
||||
|
||||
- version increment logic;
|
||||
- publish semantics;
|
||||
- YAML import как `create|upsert`;
|
||||
- auth profile resolution;
|
||||
- generated draft application;
|
||||
- MCP tool execution path.
|
||||
|
||||
## 7. Практический итог
|
||||
|
||||
Перед активной разработкой проект должен исходить из правила:
|
||||
|
||||
- доменная логика тестируется отдельно;
|
||||
- adapters тестируются отдельно;
|
||||
- registry и admin-api тестируются на реальной БД;
|
||||
- минимум один полный end-to-end сценарий должен быть воспроизводим автоматически.
|
||||
Reference in New Issue
Block a user