sdlc-hub/ARCHITECTURE.md
Andrey Epifancev 4e397b563d feat(mcp): batch_create принимает path у ensure_attachment и сам загружает файл (#43)
Все файлы пакета читаются до загрузки: «файл не найден: <path>», «у ensure_attachment либо path, либо file», больше 10 МБ — до POST /files; filename по умолчанию — имя файла; описание batch_create говорит про path (решение 19). design.md: решение 20 (R-2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 01:51:44 +04:00

8.8 KiB
Raw Blame History

Архитектура

Хаб моста Jira: SQLite-зеркало задач AURORA/AWPCA, служебные заметки, очередь команд, HTTP API и MCP. Агент (jira-agent, виртуалка) опрашивает хаб, пишет в Jira и возвращает состояние; хаб Jira не вызывает.

Модули

Модуль Ответственность Зависит от
paths каталог данных (JIRA_HUB_HOME), пути базы и backups/, права 0700 (secure_dir) stdlib
db схема SQLite, миграции по schema_version (копия базы перед миграцией), connect backup, paths
settings настройки (setting), токены, темп, перенос из config.example.json db
mirror зеркало задач, связей и комментариев, apply_state (с проверкой check_comments), заметки, фильтры, снимок доски board db
commands контракт типов команд, валидация, временные ключи, оценка, подтверждение по состоянию mirror
queue пакеты, проверки постановки (_check_setup: bug без настройки, файл вложения), выдача (claim, size у ensure_attachment — deliver_params), отчёты, отмена, повтор, автообновление commands, mirror, settings, files, db
backup копии файла базы, ротация paths
files хранилище файлов вложений <данные>/files/<sha256> (каталог — параметр, Hub.files_dir): put (атомарно, одна копия на содержимое, mtime при повторе, предел 10 МБ, пустой — отказ), path/exists/size/read (только sha из 64 hex нижнего регистра), sweep (старше 30 дней, кроме файлов ensure_attachment в queued/claimed) paths
api HTTP-сервер, маршруты, авторизация по токенам, фоновый tick (автообновление и уборка files/ раз в сутки); маршруты файлов POST /files, GET /agent/files/{sha256} (каталог Hub.files_dir, 0700 при старте); раздача веб-приложения /app… (каталог web/app пакета, без токена) и перенаправление /, /links; снимок GET /board queue, mirror, settings, backup, files, relay, release
relay реле общей папки (настройка relay_dir): поток в serve, файлы req/ → свой HTTP (адрес serve, для 0.0.0.0 — 127.0.0.1) → resp/; агент с hub_url = folder:<путь> ходит через него; HTTP-обработчики о нём не знают settings
release опубликованная версия агента: release/agent.py + manifest.json в каталоге данных, publish (только вверх; запись с fsync, прежний файл на время записи — agent.py.prev, при сбое возвращается), current (проверка манифеста, предупреждение один раз на ошибку), load (с проверкой sha256 и UTF-8), подсказка hint для agent_status paths
client HTTP-клиент хаба db, paths, settings (только для from_home)
mcp_server инструменты MCP по stdio; batch_create читает файлы ensure_attachment.path и загружает их POST /files до постановки пакета client, files (только MAX_SIZE)
importer разовый импорт CSV-пакета в заметки, сверка с зеркалом mirror, settings
cli init, serve, import, mcp, tokens, agent publish api, mcp_server, importer, release, settings, db, paths

web/ — веб-приложение хаба (React + TypeScript + Vite): вход по клиентскому токену, страницы «Доска» (/app/board) и «Задачи» (/app/issues); карточка /app/issues/{key} — окно поверх страницы, с которой её открыли: shell/Layout.tsx рисует страницу по адресу из location.state.background (useRoutes с явным адресом) и issues/IssueModal.tsx поверх неё. Собирается make web в src/jira_hub/web/app/; api отдаёт сборку без токена (/app/assets/* — файлы, прочие /app… — index.html, 503 без сборки), / и /links перенаправляет на /app/board. Данные — только через HTTP API с клиентским токеном; mirror.board отдаёт зеркало без преобразований, перевод в модель доски — в web/src/board/model. Логика доски — чистые модули web/src/board/{model,analysis,layout} и storage.ts (ключи localStorage прежней страницы), отрисовка — web/src/board/components.

Цепочки: api → queue → commands/mirror/settings → db; db → backup → paths, db → paths; files → paths; api → relay → settings; mcp_server → client → HTTP API; importer → mirror/settings.

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

  • Запись в Jira: клиент (mcp_server/интерфейс) → POST /batches → queue → агент claim → Jira → POST /agent/commands/{id}/result.
  • Вложение: файл → POST /files → files/<sha256> → ensure_attachment {key, file, filename} в пакете (queue._check_setup проверяет, что файл есть) → claim (хаб дописывает size, в базе params без него) → агент GET /agent/files/{sha256} → Jira; уборка files/ — из tick раз в сутки.
  • Чтение Jira: команда refresh → агент → POST /agent/state → mirror.apply_state.
  • Агент за VPN: агент → файлы в общей папке (relay_dir) → relay → HTTP хаба → ответ файлом.
  • Самообновление агента: jira-hub agent publish → release/ → claim.agent_release → агент скачивает GET /agent/release; состояние обновления агент шлёт в claim, хаб держит в памяти (вместе с признаком agent_reported — был ли claim с запуска хаба) и отдаёт в GET /agent.
  • Токены: агентский — только /agent/*, клиентский — остальное; MCP берёт клиентский токен из базы через HubClient.from_home.

Границы

  • Зеркало пишет только mirror.apply_state по запросу агента (и заметки через PUT /issues/{key}/note); из очереди и API задач напрямую не правят.
  • Хаб не знает пароль Jira и не обращается к Jira; init не переносит auth, base_url, verify_ssl, ca_bundle.
  • queue не создаёт команд сам: повтор после failed — новый пакет. Выданная без отчёта команда довыдаётся при следующем claim (до 3 выдач, затем failed).
  • mcp_server не импортирует queue/mirror/db напрямую и ходит только через client; из files берёт только предел MAX_SIZE (файлы в хранилище кладёт хаб по POST /files).
  • commands, mirror, queue не знают про HTTP; HTTP живёт только в api, client и relay (реле — клиент своего же HTTP).
  • Веб-приложение (web/) ходит в хаб только через HTTP API (web/src/api/client.ts); словари kind_labels, link_types, status_labels берёт из GET /settings и своих копий не держит.

Открытые вопросы

  • Правки из UI в Jira (спринт, срок, связи, исполнитель) — change viewer-edit; страницы очереди, агента и настроек — позже.
  • Автоподстройка темпа по фактам 429 не реализована: хаб только показывает их.