Skip to the content.

Hercules Studio — System Design

Связанные документы: README.md, ARCHITECTURE.md, ROADMAP.md

1. Контекст и цели

Hercules Studio — десктопное IDE-приложение для управления несколькими агентами Hercules с одного рабочего места. Studio подключается к уже запущенным агентам по HTTP REST API, не spawns их сама.

Главные user stories:

Non-goals (на MVP):

2. Высокоуровневая архитектура

┌──────────────────────────────────────────────────────────────────────┐
│                         Hercules Studio (Electron)                     │
│                                                                        │
│  ┌────────────────────────── Main Process (Node.js) ───────────────┐  │
│  │                                                                 │  │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌────────────────┐ │  │
│  │  │ Window   │  │ Agent    │  │ Native   │  │ SQLite         │ │  │
│  │  │ Manager  │  │ Scanner  │  │ Bridge   │  │ (better-       │ │  │
│  │  │          │  │ (ports + │  │ (fs,     │  │  sqlite3)      │ │  │
│  │  │          │  │ procs)   │  │  shell,  │  │ studio.db      │ │  │
│  │  │          │  │          │  │  keys,   │  │                │ │  │
│  │  │          │  │          │  │  notify, │  │ ┌────────────┐ │ │  │
│  │  │          │  │          │  │  tray)   │  │ │chat_history│ │ │  │
│  │  │          │  │          │  │          │  │ │skill_drafts│ │ │  │
│  │  │          │  │          │  │          │  │ │workflows   │ │ │  │
│  │  │          │  │          │  │          │  │ │scan_cache  │ │ │  │
│  │  └──────────┘  └──────────┘  └──────────┘  │ └────────────┘ │ │  │
│  │                                              └────────────────┘ │  │
│  │  ┌──────────────────────────────────────────────────────────┐ │  │
│  │  │ Connection Manager                                        │ │  │
│  │  │  - source registry (userData/connections.json)           │ │  │
│  │  │  - API keys in safeStorage (OS keychain)                  │ │  │
│  │  │  - health polling (30s) + exponential backoff reconnect  │ │  │
│  │  │  - CheckIn/CheckOut heartbeat (60s TTL)                  │ │  │
│  │  └──────────────────────────────────────────────────────────┘ │  │
│  └────────────────────────────────────────────────────────────────┘  │
│                                │                                       │
│                    IPC (contextBridge, preload)                        │
│                                ▼                                       │
│  ┌────────────────────────── Renderer (Vue 3 + Vite) ───────────────┐ │
│  │                                                                   │ │
│  │  ┌──────────┐  ┌──────────┐  ┌────────────────────────────────┐  │ │
│  │  │ Activity │  │ Sidebar  │  │ Main Workbench                  │  │ │
│  │  │ Bar      │  │          │  │                                 │  │ │
│  │  │          │  │ Agent    │  │ ┌─────┐ ┌─────┐ ┌─────┐        │  │ │
│  │  │ Agents   │  │ tree /   │  │ │Chat │ │Skill│ │Mesh │ ...    │  │ │
│  │  │ Chat     │  │ skill    │  │ │View │ │Edit │ │Expl │        │  │ │
│  │  │ Skills   │  │ list /   │  │ └─────┘ └─────┘ └─────┘        │  │ │
│  │  │ Mesh     │  │ mesh     │  │                                 │  │ │
│  │  │ Tools    │  │ nodes /  │  │ ┌─────────────────────────┐    │  │ │
│  │  │ Config   │  │ ...      │  │ │ Bottom Panel             │    │  │ │
│  │  │ Workflow │  │          │  │ │ (xterm.js terminal,      │    │  │ │
│  │  │ Consensus│  │          │  │ │  logs, problems)         │    │  │ │
│  │  └──────────┘  └──────────┘  │ └─────────────────────────┘    │  │ │
│  │                              └────────────────────────────────┘  │ │
│  │  ┌──────────┐  ┌──────────┐  ┌────────────────────────────────┐  │ │
│  │  │ Status   │  │ Command  │  │ Pinia Stores                    │  │ │
│  │  │ Bar      │  │ Palette  │  │ connections, activeAgent,        │  │ │
│  │  │ (agent,  │  │ (Ctrl+   │  │ chat, skills, mesh, tools,       │  │ │
│  │  │  status, │  │  Shift+P)│  │ config, workflow, notifications  │  │ │
│  │  │  latency,│  │          │  │                                 │  │ │
│  │  │  tokens, │  │          │  │ SDK: HerculesClient (TS)        │  │ │
│  │  │  checkin)│  │          │  │ (endpoints, DTOs, auth)         │  │ │
│  │  └──────────┘  └──────────┘  └────────────────────────────────┘  │ │
│  └───────────────────────────────────────────────────────────────────┘
└──────────────────────────────────────────────────────────────────────┘
                                │
                                │ HTTP REST (X-Api-Key, contribute/system)
                                ▼
┌──────────────────────────────────────────────────────────────────────┐
│              Hercules.WebApi (.NET) — Agent instances                  │
│                                                                        │
│  Agent A (port 8421)    Agent B (port 8422)    Agent C (port 8423)    │
│  ┌────────────────┐     ┌────────────────┐     ┌────────────────┐    │
│  │ data/          │     │ data/          │     │ data/          │    │
│  │  Skills/       │     │  Skills/       │     │  Skills/       │    │
│  │  Memory/       │     │  Memory/       │     │  Memory/       │    │
│  │  sessions.db   │     │  sessions.db   │     │  sessions.db   │    │
│  │  manifest.json │     │  manifest.json │     │  manifest.json │    │
│  └────────────────┘     └────────────────┘     └────────────────┘    │
│         │                      │                      │              │
│         └────────── mesh ──────┴──────────────────────┘              │
└──────────────────────────────────────────────────────────────────────┘
                                │
                                │ /api/mesh/intent (workflow-server → agents)
                                ▼
┌──────────────────────────────────────────────────────────────────────┐
│         hercules-workflow-server (.NET) — Stage 8 production          │
│  - workflow definitions (graph models)                                │
│  - executor/interpreter                                               │
│  - triggers: webhook + cron (MVP), file watcher + event bus later     │
│  - clientId/clientSecret auth                                         │
│  - execution history, state                                            │
└──────────────────────────────────────────────────────────────────────┘

3. Компоненты

3.1 Main Process (Node.js / TypeScript)

Компонент Ответственность
WindowManager Создание BrowserWindow, lifecycle, single-instance lock
AgentScanner Port range scan (8421-8521 + legacy 5000), Windows process scan, manifest probe
ConnectionManager Persists connections, health polling (30s), reconnect (exp backoff), CheckIn/CheckOut heartbeat (60s TTL)
NativeBridge fs (read/write skill files), shell (open external, xterm spawn), safeStorage (API keys), Notification, Tray
SQLiteStore better-sqlite3, tables: chat_history, skill_drafts, workflows, scan_cache
LicenseManager First-run consent, AGPL/commercial indicator, userData/license-consent.json
IpcHandler contextBridge API surface, typed IPC contracts (shared/protocol.ts)

3.2 Renderer (Vue 3 + Vite)

Компонент Ответственность
ActivityBar Вертикальный бар иконок: Agents, Chat, Skills, Mesh, Tools, Config, Workflow, Consensus
Sidebar Контекстный контент под активной activity (agent tree, skill list, mesh nodes, etc.)
MainWorkbench Табы с views, drag-and-drop splitting (future)
StatusBar Активный агент, статус, latency, token usage, check-in status, версия Studio
BottomPanel xterm.js terminal (test-run + общий), logs, problems
CommandPalette Ctrl+Shift+P, простой вариант на MVP
Pinia stores connections, activeAgent, chat, skills, mesh, tools, config, workflow, notifications
HerculesClient (SDK) TypeScript клиент к Hercules API: endpoints, DTOs, auth (contribute/system)

3.3 Views

View Stage Описание
AgentList 1 Список подключённых агентов, статус, manage, restart
DiscoverAgents 1 Результаты сканирования, add connection
Chat 2 Чат с активным агентом, история, typing effect, markdown
SkillEditor 2 Monaco: skill.prompt.md, skill.meta.json (form + raw), skill.description.md
SkillPush 3 Push skill на агента (POST/PUT/import), cross-agent install
MeshExplorer 4 Vue Flow graph: topology, health, router, shared memory, circuits
Tools 5 Tool registry: list, enable/disable, health
McpManager 5 MCP servers: list, add, edit, delete, reload, pre-check
Config 6 LLM providers, roles, mesh endpoints, quotas, context budget, raw JSON editor
Consensus 7 Multi-agent chat, columns side-by-side, LLM-judge + manual pick
WorkflowDesigner 8 Vue Flow BPMN canvas, palette, run, live monitoring
EmptyState 0 Welcome + marketing carousel + quickstart

4. Потоки данных

4.1 Подключение к агенту

User → "Add Connection" form (URL + API key)
  → ConnectionManager.validate(url, key)
    → GET /api/health (no auth)
    → GET /agent.manifest.json (X-Api-Key)
    → validate agentId non-empty
  → safeStorage.set(key)
  → connections.json.add({name, baseUrl, agentId, displayName, authScheme})
  → POST /api/system/checkin (X-Api-Key, studioId)
  → Pinia.connections.add()
  → StatusBar update
  → heartbeat timer (60s)

4.2 Сканирование агентов

User → "Scan for agents" (or auto on startup)
  → AgentScanner.scanPorts(8421-8521 + 5000)
    → parallel (50 concurrent, 300ms timeout)
    → for each open port: GET /agent.manifest.json
    → validate manifest (agentId, capabilities)
    → if 401: mark "auth required"
  → AgentScanner.scanProcesses("Hercules.WebApi.exe")
    → for each process: query listening ports
    → probe manifest on found ports
  → SQLite.scan_cache.update()
  → Pinia.discovered.set(results)
  → UI shows found agents, "Add" button per agent

4.3 Редактирование и push навыка

User → SkillEditor (Monaco)
  → edit skill.prompt.md + skill.meta.json + skill.description.md
  → SQLite.skill_drafts.save(local draft)
  → "Test in chat" → Chat view with skill active
  → "Push to agent"
    → select target agent(s)
    → if new: POST /api/skills (contribute key)
    → if exists: PUT /api/skills/{id} (contribute key)
    → if package: POST /api/skills/import (multipart)
    → pre-check: POST /api/skills/{id}/manifest/validate (if C# — DangerousCodeScanner)
    → show validation warnings
    → confirm push
  → success toast + skill appears in agent's list

4.4 Консилиум

User → Consensus view
  → select N agents from connections
  → enter prompt
  → Studio parallel: Promise.all(agents.map(a => POST /api/chat))
  → results in columns side-by-side
  → aggregation:
    → LLM-judge: select one agent as judge, send all responses, get best
    → Manual pick: user selects best response
  → show aggregated result

4.5 Workflow execution (MVP — Studio-orchestrator)

User → WorkflowDesigner (Vue Flow)
  → design graph: Start → ServiceTask(A) → Conditional → ServiceTask(B)/ServiceTask(C) → End
  → save to SQLite.workflows
  → "Run"
    → Studio executor reads graph
    → for each ServiceTask: POST /api/mesh/intent to target agent
    → wait response, evaluate condition
    → next task
    → live update node states in UI
  → monitoring: long-poll /api/mesh/tasks/{id}/poll for AwaitingInput
  → User Task: show form (text/file/approval/choice) → submit → continue

4.6 Workflow execution (Production — hercules-workflow-server)

User → WorkflowDesigner
  → save graph → POST /api/workflows (to workflow-server, clientId/clientSecret auth)
  → "Run" → POST /api/workflows/{id}/run
  → workflow-server executor:
    → reads graph
    → for each ServiceTask: POST /api/mesh/intent to agent (workflow-server→Agent auth)
    → persists state, handles retries, schedules
    → triggers: webhook, cron
  → Studio monitors: GET /api/workflows/{id}/executions (long-poll/SSE)
  → live state per node

5. Технологический стек

Слой Технология Версия Почему
Desktop shell Electron 30+ Зрелый, Windows-фокус, Monaco, auto-updater
Build (dev) electron-vite latest HMR renderer + main, TS из коробки
Build (packaging) electron-builder latest NSIS installer, portable zip
Main process TypeScript 5.x Типизация IPC, shared типы
Renderer framework Vue 3 3.4+ Composition API, <script setup>
Bundler Vite 5+ Быстрый HMR
State Pinia 2+ Стандарт Vue, типизированные stores
UI components shadcn-vue latest Tailwind-based, копируем нужные
Styling Tailwind CSS 4+ Консистентность с hercules-web
Icons Tabler Icons latest Есть лицензия
Editor Monaco Editor latest Skill/prompt/config editing, diff
Terminal xterm.js latest Test-run output, встроенный терминал
Graph viz Vue Flow 1+ Mesh topology + BPMN designer
Local DB better-sqlite3 latest chat history, drafts, workflows, scan cache
Markdown markdown-it + highlight.js latest Chat rendering
i18n vue-i18n 9+ en/ru
HTTP ofetch / native fetch — Типизированные запросы к API
Testing (unit) Vitest latest Renderer, SDK
Testing (e2e) Playwright (_electron) latest Electron E2E
Linting Biome latest TS-native, быстрый
CI GitHub Actions (Windows) — Build + test + package

6. Структура проекта

src/hercules-studio/
├── electron/
│   ├── main/
│   │   ├── index.ts              # entry point, app lifecycle
│   │   ├── window.ts             # BrowserWindow creation, single-instance
│   │   ├── scanner.ts            # AgentScanner (ports + processes)
│   │   ├── connections.ts        # ConnectionManager (persist, health, checkin)
│   │   ├── native-bridge.ts      # fs, shell, safeStorage, notifications, tray
│   │   ├── sqlite.ts             # better-sqlite3 wrapper, migrations
│   │   ├── license.ts            # LicenseManager (consent, commercial)
│   │   └── ipc.ts                # IPC handlers, contextBridge setup
│   └── preload/
│       └── index.ts              # exposeAPI (typed, from shared/protocol.ts)
├── renderer/
│   ├── src/
│   │   ├── App.vue
│   │   ├── main.ts
│   │   ├── views/
│   │   │   ├── AgentList.vue
│   │   │   ├── DiscoverAgents.vue
│   │   │   ├── Chat.vue
│   │   │   ├── SkillEditor.vue
│   │   │   ├── SkillPush.vue
│   │   │   ├── MeshExplorer.vue
│   │   │   ├── Tools.vue
│   │   │   ├── McpManager.vue
│   │   │   ├── Config.vue
│   │   │   ├── Consensus.vue
│   │   │   ├── WorkflowDesigner.vue
│   │   │   └── EmptyState.vue
│   │   ├── components/
│   │   │   ├── layout/
│   │   │   │   ├── ActivityBar.vue
│   │   │   │   ├── Sidebar.vue
│   │   │   │   ├── MainWorkbench.vue
│   │   │   │   ├── StatusBar.vue
│   │   │   │   ├── BottomPanel.vue
│   │   │   │   └── CommandPalette.vue
│   │   │   ├── chat/
│   │   │   ├── skills/
│   │   │   ├── mesh/
│   │   │   ├── tools/
│   │   │   ├── config/
│   │   │   ├── consensus/
│   │   │   ├── workflow/
│   │   │   └── common/           # shadcn-vue components
│   │   ├── stores/
│   │   │   ├── connections.ts
│   │   │   ├── activeAgent.ts
│   │   │   ├── chat.ts
│   │   │   ├── skills.ts
│   │   │   ├── mesh.ts
│   │   │   ├── tools.ts
│   │   │   ├── config.ts
│   │   │   ├── workflow.ts
│   │   │   └── notifications.ts
│   │   ├── sdk/
│   │   │   ├── client.ts         # HerculesClient class
│   │   │   ├── types.ts          # DTO (ported from hercules-web api.ts)
│   │   │   └── endpoints/
│   │   │       ├── chat.ts
│   │   │       ├── skills.ts
│   │   │       ├── mesh.ts
│   │   │       ├── tools.ts
│   │   │       ├── mcp.ts
│   │   │       ├── config.ts
│   │   │       ├── system.ts     # checkin/checkout/restart
│   │   │       └── workflows.ts
│   │   ├── i18n/
│   │   │   ├── en.json
│   │   │   └── ru.json
│   │   ├── assets/
│   │   │   └── styles/
│   │   │       └── global.css    # Tailwind v4 entry, dark+light theme
│   │   └── composables/
│   │       ├── useConnection.ts
│   │       ├── useAgent.ts
│   │       └── useHotkeys.ts
│   ├── index.html
│   └── vite.config.ts
├── shared/
│   └── protocol.ts               # IPC contract (types shared main↔renderer)
├── resources/
│   ├── icon.ico
│   ├── tray-icon.ico
│   └── license-consent.md        # AGPL text + commercial terms
├── package.json
├── electron-builder.yml
├── electron.vite.config.ts       # electron-vite config (main + preload + renderer)
├── tsconfig.json
├── biome.json
└── README.md

7. Auth модель

7.1 Dual API keys (Agent side)

Агент генерирует при первом старте два ключа:

// data/security/keys.json
{
  "contribute": "hc_contrib_<random>",
  "system": "hc_sys_<random>"
}
Key Role Permissions
contribute operator chat, skills CRUD, memory, config GET, config PATCH (non-destructive), mesh read, tools enable/disable, marketplace install
system admin всё из contribute + restart, lifecycle destructive (decommission), config PUT (full replace), MCP add/remove, quota changes, force checkout

ApiKeyMiddleware проверяет ключи из WebApi:ApiKeys массива:

{
  "WebApi": {
    "ApiKeys": [
      { "key": "hc_contrib_...", "role": "contribute" },
      { "key": "hc_sys_...", "role": "system" }
    ]
  }
}

7.2 CheckIn/CheckOut

Endpoint Key Описание
POST /api/system/checkin contribute CheckIn: Studio занимает агента. Body: {studioId, studioName}. Возвращает {checkedOut: true, checkedOutBy: studioName} или отказ
POST /api/system/checkout contribute Release агента
POST /api/system/checkin/heartbeat contribute Heartbeat (60s TTL). Если не пришла → auto checkout
GET /api/system/checkin/status any Status: {checkedOut, checkedOutBy, checkedOutAt, ttlSeconds}
POST /api/system/checkin/force system Force checkout (отобрать)

Поведение:

7.3 Studio side

7.4 Workflow-server auth

8. Локальное хранилище Studio

8.1 SQLite (userData/studio.db)

-- Chat history per connection
CREATE TABLE chat_history (
  id TEXT PRIMARY KEY,
  connection_id TEXT NOT NULL,
  agent_id TEXT NOT NULL,
  role TEXT NOT NULL,          -- user/assistant/system
  content TEXT NOT NULL,
  metadata TEXT,               -- JSON: mode, confidence, skill, provider
  created_at TEXT NOT NULL
);

-- Skill drafts (local, before push)
CREATE TABLE skill_drafts (
  id TEXT PRIMARY KEY,
  connection_id TEXT NOT NULL,
  skill_id TEXT,               -- null for new skills
  name TEXT NOT NULL,
  prompt_md TEXT,
  meta_json TEXT,
  description_md TEXT,
  csharp_files TEXT,           -- JSON array of {filename, content}
  updated_at TEXT NOT NULL,
  pushed_at TEXT
);

-- Workflow definitions (MVP, until workflow-server)
CREATE TABLE workflows (
  id TEXT PRIMARY KEY,
  name TEXT NOT NULL,
  graph_json TEXT NOT NULL,    -- Vue Flow graph
  template BOOLEAN DEFAULT 0,
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL
);

-- Scan cache
CREATE TABLE scan_cache (
  port INTEGER PRIMARY KEY,
  agent_id TEXT,
  display_name TEXT,
  endpoint TEXT,
  auth_required BOOLEAN,
  found_at TEXT NOT NULL
);

8.2 JSON / safeStorage

Файл Хранилище Содержание
userData/connections.json FS [{name, baseUrl, agentId, displayName, authScheme, lastSeen}]
userData/settings.json FS scan range, theme, language, typing effect, compact mode
Keychain entry safeStorage API keys (contribute + system per connection)
userData/license-consent.json FS {consentVersion, acceptedAt, type: "nonprofit"|"commercial", licenseKey?}

9. IPC контракт (shared/protocol.ts)

// shared/protocol.ts — типы shared между main и renderer

export interface IpcApi {
  // Connections
  connections: {
    list(): Promise<Connection[]>;
    add(conn: NewConnection): Promise<Connection>;
    remove(id: string): Promise<void>;
    update(id: string, patch: Partial<Connection>): Promise<Connection>;
    healthCheck(id: string): Promise<HealthStatus>;
  };
  // Scanner
  scanner: {
    scan(): Promise<DiscoveredAgent[]>;
    scanProgress(callback: (progress: ScanProgress) => void): void;
  };
  // Native
  native: {
    readFile(path: string): Promise<string>;
    writeFile(path: string, content: string): Promise<void>;
    openExternal(url: string): Promise<void>;
    showNotification(title: string, body: string): Promise<void>;
    setTray(icon: string, menu: TrayMenu): Promise<void>;
  };
  // SQLite
  db: {
    query<T>(sql: string, params?: unknown[]): Promise<T[]>;
    execute(sql: string, params?: unknown[]): Promise<Changes>;
  };
  // License
  license: {
    getConsent(): Promise<LicenseConsent | null>;
    acceptConsent(type: "nonprofit" | "commercial", key?: string): Promise<void>;
  };
  // System keys
  keys: {
    getSystemKey(connectionId: string): Promise<string | null>;
    setSystemKey(connectionId: string, key: string): Promise<void>;
    promptSystemKey(): Promise<string | null>;  // shows dialog
  };
}

10. i18n

en/ru с первого дня через vue-i18n. Все строки в renderer/src/i18n/{en,ru}.json.

11. Theme

Dark + Light, switchable. Dark = базовый (консистентность с hercules-web). Tailwind v4 с CSS variables для цветов.

12. Безопасность

13. Риски и митигации

Риск Митигация
Electron ~150MB размер Приемлемо для IDE; Tauri как backup
Range scan медленный 8421-8521 (100 портов) + 50 concurrent + 300ms timeout = ~1s
Backend restart небезопасен Supervisor-протокол: POST /api/system/restart → agent ставит флаг → Studio (или watcher) перезапускает
BPMN — большой scope MVP: linear + conditional. Production: полный BPMN после MVP
MCP hot-reload не работает Доработка McpClientService:IConfigReload на Stage 6
Multi-agent API key management safeStorage per connection, OS keychain
CORS при remote Main process (Node) делает запросы, не браузер → CORS не применяется
C# LSP = тяжёлая зависимость Базовая подсветка C# для MVP, LSP позже
Studio crash → checked out forever Heartbeat TTL 60s → auto checkout
Workflow-server = отдельный сервис Архитектура заложена в Stage 0, реализация в Stage 8

15. API Codegen pipeline (OpenAPI → TypeScript)

Подробные задачи: task_109-116

Принцип

API контракт агента (.NET Minimal API) → OpenAPI 3.1 документ (/openapi/v1.json) → автоматически сгенерированный TypeScript клиент (types + Vue Query hooks + Zod). Generated files коммитятся в git. Regen — ручной (npm run gen:api).

Тот же pipeline работает для Studio и Web-UI — один источник, два потребителя.

Архитектура

┌─────────────────────────────────────────────────────────────────┐
│  Hercules.WebApi (.NET 10 Minimal API)                          │
│                                                                  │
│  Runtime: AddOpenApi() → /openapi/v1.json (OpenAPI 3.1)         │
│  Scalar UI: app.MapScalarApiReference() → /scalar               │
│  Build-Time: Microsoft.Extensions.ApiDescription.Server          │
│    → dotnet build генерирует openapi.json в корне проекта         │
│    → коммитится в git, виден в PR diff                           │
│                                                                  │
│  .Produces<T>() + .WithName() + .WithTags() на каждом endpoint  │
│  Contracts/ — named DTOs (без анонимных типов)                  │
│  XML doc comments → OpenAPI descriptions (GenerateDocumentation) │
│                                                                  │
│  Spectral lint (task_117): spectral lint openapi.json в CI       │
└────────────────┬────────────────────────────────────────────────┘
                 │
         ┌───────┴───────┐
         │               │
         │  Build-time   │  Runtime (dev)
         │  openapi.json  │  /openapi/v1.json
         │  (in git)     │  (running agent)
         └───────┬───────┘
                 │
      ┌──────────┴──────────┐
      │                     │
      ▼                     ▼
┌──────────────┐    ┌──────────────┐
│  Studio       │    │  Web-UI      │
│  (Electron)   │    │  (Astro)     │
│               │    │              │
│  npm run      │    │  npm run     │
│  gen:api      │    │  gen:api     │
│       │       │    │       │      │
│       ▼       │    │       ▼      │
│  openapi-     │    │  openapi-    │
│  typescript   │    │  typescript  │
│  → schema.ts  │    │  → schema.ts │
│               │    │              │
│  Orval        │    │  Orval       │
│  → generated/ │    │  → generated/│
│    (vue-query)│    │    (vue-query│
│  → models/    │    │  → models/   │
│    (zod)      │    │    (zod)     │
│  → *.msw.ts   │    │  → *.msw.ts  │
│    (mocks)    │    │    (mocks)   │
│               │    │              │
│  mutator.ts   │    │  mutator.ts  │
│  (per-conn    │    │  (Astro env  │
│   X-Api-Key)  │    │   vars)      │
└──────────────┘    └──────────────┘

Инструменты

Инструмент Роль Зачем
Microsoft.AspNetCore.OpenApi Producer (.NET 10 built-in) OpenAPI 3.1, без NuGet
Scalar.AspNetCore Interactive API docs UI /scalar — тест endpoints из браузера
Microsoft.Extensions.ApiDescription.Server Build-time generation dotnet build → openapi.json в git, виден в PR diff
openapi-typescript Types only Все DTOs + paths как TS interfaces, ~3KB runtime
openapi-fetch Typed fetch wrapper End-to-end typed c.GET('/api/skills')
Orval Vue Query hooks + Zod + MSW useListSkillsQuery(), useCreateSkillMutation(), runtime validation, mocks
@tanstack/vue-query Client-side data fetching Cache, retries, optimistic updates, loading/error states
Spectral Linting Проверка OpenAPI контракта на correctness, best practices, OWASP

Generated структура (Studio и Web-UI одинаковы)

src/api/
├── schema.ts              # openapi-typescript (types only, all paths + schemas)
├── mutator.ts             # custom fetch wrapper (hand-written, not generated)
├── generated/             # Orval: Vue Query hooks per domain (tags-split)
│   ├── skills/
│   │   ├── skills.ts      # useListSkillsQuery, useCreateSkillMutation...
│   │   └── skills.msw.ts  # MSW handlers for dev without agent
│   ├── chat/
│   ├── mesh/
│   ├── config/
│   └── ... (30 domains)
├── models/                # Orval: Zod schemas + DTO interfaces
└── README.md              # "Generated. Do not edit. Run: npm run gen:api"

Workflow разработчика

1. Изменить API на бэкенде (добавить endpoint, DTO, .Produces<T>())
2. dotnet build → openapi.json regenerated (build-time, task_109)
3. (опционально) spectral lint openapi.json (task_117)
4. Regenerate TS clients: cd src/hercules-studio && npm run gen:api
5. Commit: git add openapi.json src/api/ && git commit -m "regen API client"
6. PR review: openapi.json diff shows contract changes ← KEY BENEFIT
7. Использовать: import { useListSkillsQuery } from "api/generated/skills"

Build-time generation (task_109) — ключевой benefit: openapi.json генерируется при dotnet build, коммитится в git, виден в PR diff. Не нужно запускать агента для regen TS client.

Задачи pipeline

Task Что Зависимости
task_109 AddOpenApi() + MapOpenApi() + Scalar UI + build-time generation + XML docs —
task_110 .WithTags() на все 37 контроллеров task_109
task_111 .Produces<T>() + DTO рефакторинг (исключить анонимные) task_109
task_112 .WithName() на Marketplace + Template —
task_113 Studio: openapi-typescript + Orval setup task_109-112
task_114 Studio: migrate stores to Vue Query task_113
task_115 Web-UI: openapi-typescript + Orval setup task_109-112
task_116 Web-UI: migrate api.ts to Vue Query task_115
task_117 Spectral lint для openapi.json в CI task_109

16. Связанные ADR