chore: publish clean community baseline
Deploy / deploy (push) Successful in 2m44s
CI / Rust Checks (push) Successful in 5m31s
CI / UI Checks (push) Successful in 5s
CI / Deployment Manifests (push) Successful in 2s
CI / Frontend E2E (push) Successful in 4m24s

This commit is contained in:
github-ops
2026-06-17 06:15:46 +00:00
commit ba29ac7b94
320 changed files with 73936 additions and 0 deletions
+116
View File
@@ -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`
+53
View File
@@ -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.
+202
View File
@@ -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).
+96
View File
@@ -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 агрегируют вызовы по периодам.
+65
View File
@@ -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` хранит агрегированную статистику.
+81
View File
@@ -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>
```
+229
View File
@@ -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.
+183
View File
@@ -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 напрямую.
+149
View File
@@ -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
}
```
+53
View File
@@ -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
+183
View File
@@ -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`;
- только потом фиксировать результат в текущем рабочем трекере.
+106
View File
@@ -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.
+112
View File
@@ -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.
+101
View File
@@ -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`
+313
View File
@@ -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.
+316
View File
@@ -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;
- код читается за счет имен и декомпозиции, а не за счет комментариев.
+183
View File
@@ -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 еще не занесен.
+122
View File
@@ -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 сценарий должен быть воспроизводим автоматически.